From 722bb124178db75220348f666d9ddc655a5b3e34 Mon Sep 17 00:00:00 2001 From: tianwei Date: Tue, 9 Aug 2022 17:56:25 +0800 Subject: [PATCH] feat(client): add --token argument for swcli instance login command (#895) add --token argument for swcli instance login command --- client/starwhale/core/instance/cli.py | 19 ++++++++++--- client/starwhale/core/instance/view.py | 39 ++++++++++++++++++++------ client/tests/core/test_instance.py | 10 +++---- client/tests/core/test_model.py | 9 ++++-- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/client/starwhale/core/instance/cli.py b/client/starwhale/core/instance/cli.py index aaa7d58358..c14fc33640 100644 --- a/client/starwhale/core/instance/cli.py +++ b/client/starwhale/core/instance/cli.py @@ -1,3 +1,4 @@ +import sys import typing as t import click @@ -28,15 +29,25 @@ def _select(instance: str) -> None: @instance_cmd.command("login") @click.argument("instance", default="") -@click.option("--username", prompt="username", required=True) -@click.password_option(confirmation_prompt=False) +@click.option("--username") +@click.option("--password") +@click.option("--token", help="Login token") @click.option("--alias", type=str, help="Starwhale instance alias name", required=True) -def _login(instance: str, username: str, password: str, alias: str) -> None: +def _login(instance: str, username: str, password: str, token: str, alias: str) -> None: """Login Starwhale Instance * INSTANCE: Instance URI, if ignore it, swcli will login current selected instance. """ - InstanceTermView().login(instance, username, password, alias) + if not bool(password and username) ^ bool(token): + click.echo("token or password+username, only choose one type") + sys.exit(1) + + if token: + kw = {"token": token} + else: + kw = {"username": username, "password": password} + + InstanceTermView().login(instance, alias, **kw) @instance_cmd.command("logout") diff --git a/client/starwhale/core/instance/view.py b/client/starwhale/core/instance/view.py index 785bee981b..06e5e45060 100644 --- a/client/starwhale/core/instance/view.py +++ b/client/starwhale/core/instance/view.py @@ -32,23 +32,21 @@ def select(self, instance: str) -> None: else: console.print(f":clap: select {self.current_instance} instance") - def login(self, instance: str, username: str, password: str, alias: str) -> None: + def login(self, instance: str, alias: str, **kw: str) -> None: if instance == STANDALONE_INSTANCE: console.print(f":pinching_hand: skip {instance} instance login") return instance = instance or self.sw_remote_addr server = fmt_http_server(instance) - url = f"{server}/api/{SW_API_VERSION}/login" - r = requests.post( - url, - timeout=DEFAULT_HTTP_TIMEOUT, - data={"userName": username, "userPwd": password}, - ) + if kw.get("token"): + r = self._login_request_by_token(server, kw["token"]) + else: + r = self._login_request_by_username(server, kw) if r.status_code == HTTPStatus.OK: console.print(f":man_cook: login {server} successfully!") - token = r.headers.get("Authorization") + token = r.headers.get("Authorization") or kw.get("token") if not token: console.print("cannot get token, please contract starwhale") sys.exit(1) @@ -58,7 +56,7 @@ def login(self, instance: str, username: str, password: str, alias: str) -> None self.update_instance( uri=server, - user_name=username, + user_name=_d.get("name", ""), user_role=_role or UserRoleType.NORMAL, sw_token=token, alias=alias, @@ -66,6 +64,29 @@ def login(self, instance: str, username: str, password: str, alias: str) -> None else: wrap_sw_error_resp(r, "login failed!", exit=True) + def _login_request_by_token(self, server: str, token: str) -> requests.Response: + url = f"{server}/api/{SW_API_VERSION}/user/current" + return requests.get( + url, + timeout=DEFAULT_HTTP_TIMEOUT, + verify=False, + headers={"Authorization": token}, + ) + + def _login_request_by_username( + self, server: str, auth_request: t.Dict[str, str] + ) -> requests.Response: + url = f"{server}/api/{SW_API_VERSION}/login" + return requests.post( + url, + verify=False, + timeout=DEFAULT_HTTP_TIMEOUT, + data={ + "userName": auth_request["username"], + "userPwd": auth_request["password"], + }, + ) + def logout(self, instance: str = "") -> None: # TODO: do real logout request instance = instance or self.current_instance diff --git a/client/tests/core/test_instance.py b/client/tests/core/test_instance.py index 8e6999162d..711de152fc 100644 --- a/client/tests/core/test_instance.py +++ b/client/tests/core/test_instance.py @@ -38,18 +38,18 @@ def test_workflow(self, rm: Mocker): @Mocker() def test_login(self, rm: Mocker): - InstanceTermView().login("local", "abc", "123", alias="local") + InstanceTermView().login("local", alias="local", username="abc", password="123") with self.assertRaises(SystemExit): InstanceTermView().select("pre-k8s") rm.request( - HTTPMethod.POST, - "http://1.1.0.0:8182/api/v1/login", - json={"data": {"role": {"roleName": "admin"}}}, + HTTPMethod.GET, + "http://1.1.0.0:8182/api/v1/user/current", + json={"data": {"name": "abc", "role": {"roleName": "admin"}}}, headers={"Authorization": "123"}, ) - InstanceTermView().login("http://1.1.0.0:8182", "abc", "123", alias="pre-k8s") + InstanceTermView().login("http://1.1.0.0:8182", alias="pre-k8s", token="123") InstanceTermView().select("pre-k8s") InstanceTermView().logout("pre-k8s") diff --git a/client/tests/core/test_model.py b/client/tests/core/test_model.py index ba6b57f502..ce3ac75e0e 100644 --- a/client/tests/core/test_model.py +++ b/client/tests/core/test_model.py @@ -152,10 +152,15 @@ def test_list_with_project(self, req: Mocker, mock_list: MagicMock): req.request( HTTPMethod.POST, f"{base_url}/login", - json={"data": {"role": {"roleName": "admin"}}}, + json={"data": {"name": "foo", "role": {"roleName": "admin"}}}, headers={"Authorization": "token"}, ) - InstanceTermView().login("http://1.1.0.0:8182", "foo", "bar", alias="remote") + InstanceTermView().login( + "http://1.1.0.0:8182", + alias="remote", + username="foo", + password="bar", + ) instances = InstanceTermView().list() assert len(instances) == 2 # local and remote