Skip to content

Commit 01f048b

Browse files
yurijmikhalevichpre-commit-ci[bot]
authored andcommitted
[App] fix lightning open command & better redirects (#16794)
* fix(app): URLs, create run on app run * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent c42fc4b commit 01f048b

File tree

2 files changed

+62
-48
lines changed

2 files changed

+62
-48
lines changed

src/lightning_app/runners/cloud.py

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -183,26 +183,8 @@ def open(self, name: str, cluster_id: Optional[str] = None):
183183
if getattr(run, "cluster_id", None):
184184
print(f"Running on {run.cluster_id}")
185185

186-
# TODO: We shouldn't need to create an instance here
187-
if existing_run_instance is not None:
188-
run_instance = self._api_transfer_run_instance(
189-
project.project_id,
190-
run.id,
191-
existing_run_instance.id,
192-
V1LightningappInstanceState.STOPPED,
193-
)
194-
else:
195-
run_instance = self._api_create_run_instance(
196-
cluster_id,
197-
project.project_id,
198-
cloudspace_name,
199-
cloudspace_id,
200-
run.id,
201-
V1LightningappInstanceState.STOPPED,
202-
)
203-
204186
if "PYTEST_CURRENT_TEST" not in os.environ:
205-
click.launch(self._get_app_url(project, cloudspace_name, run_instance, "code", needs_credits))
187+
click.launch(self._get_cloudspace_url(project, cloudspace_name, "code", needs_credits))
206188

207189
except ApiException as e:
208190
logger.error(e.body)
@@ -383,9 +365,7 @@ def dispatch(
383365
# TODO: Remove testing dependency, but this would open a tab for each test...
384366
if open_ui and "PYTEST_CURRENT_TEST" not in os.environ:
385367
click.launch(
386-
self._get_app_url(
387-
project, cloudspace_name, run_instance, "logs" if run.is_headless else "web-ui", needs_credits
388-
)
368+
self._get_app_url(project, run_instance, "logs" if run.is_headless else "web-ui", needs_credits)
389369
)
390370
except ApiException as e:
391371
logger.error(e.body)
@@ -1007,10 +987,24 @@ def _print_specs(run_body: CloudspaceIdRunsBody, print_format: str) -> None:
1007987
requirements_path = getattr(getattr(run_body.image_spec, "dependency_file_info", ""), "path", "")
1008988
logger.info(f"requirements_path: {requirements_path}")
1009989

990+
def _get_cloudspace_url(
991+
self, project: V1Membership, cloudspace_name: str, tab: str, need_credits: bool = False
992+
) -> str:
993+
user = self.backend.client.auth_service_get_user()
994+
action = "?action=add_credits" if need_credits else ""
995+
paths = [
996+
user.username,
997+
project.name,
998+
"apps",
999+
cloudspace_name,
1000+
tab,
1001+
]
1002+
path = "/".join([quote(path, safe="") for path in paths])
1003+
return f"{get_lightning_cloud_url()}/{path}{action}"
1004+
10101005
def _get_app_url(
10111006
self,
10121007
project: V1Membership,
1013-
cloudspace_name: str,
10141008
run_instance: Externalv1LightningappInstance,
10151009
tab: str,
10161010
need_credits: bool = False,
@@ -1021,8 +1015,8 @@ def _get_app_url(
10211015
paths = [
10221016
user.username,
10231017
project.name,
1024-
"apps",
1025-
cloudspace_name,
1018+
"jobs",
1019+
run_instance.name,
10261020
tab,
10271021
]
10281022
else:
@@ -1032,5 +1026,5 @@ def _get_app_url(
10321026
run_instance.id,
10331027
tab,
10341028
]
1035-
path = quote("/".join([path.replace(" ", "_").replace("/", "~") for path in paths]))
1029+
path = "/".join([quote(path, safe="") for path in paths])
10361030
return f"{get_lightning_cloud_url()}/{path}{action}"

tests/tests_app/runners/test_cloud.py

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import pytest
1111
from lightning_cloud.openapi import (
12-
Body4,
1312
CloudspaceIdRunsBody,
1413
Externalv1Cluster,
1514
Externalv1LightningappInstance,
@@ -1422,9 +1421,6 @@ def test_open(self, monkeypatch):
14221421

14231422
mock_client.cloud_space_service_create_cloud_space.return_value = V1CloudSpace(id="cloudspace_id")
14241423
mock_client.cloud_space_service_create_lightning_run.return_value = V1LightningRun(id="run_id")
1425-
mock_client.cloud_space_service_create_lightning_run_instance.return_value = Externalv1LightningappInstance(
1426-
id="instance_id"
1427-
)
14281424

14291425
mock_client.cluster_service_list_clusters.return_value = V1ListClustersResponse([Externalv1Cluster(id="test")])
14301426
cloud_backend = mock.MagicMock()
@@ -1445,9 +1441,6 @@ def test_open(self, monkeypatch):
14451441
cloudspace_id="cloudspace_id",
14461442
body=mock.ANY,
14471443
)
1448-
mock_client.cloud_space_service_create_lightning_run_instance.assert_called_once_with(
1449-
project_id="test-project-id", cloudspace_id="cloudspace_id", id="run_id", body=mock.ANY
1450-
)
14511444

14521445
assert mock_client.cloud_space_service_create_cloud_space.call_args.kwargs["body"].name == "test_space"
14531446

@@ -1565,10 +1558,6 @@ def test_reopen(self, monkeypatch, capsys):
15651558
body=mock.ANY,
15661559
)
15671560

1568-
mock_client.lightningapp_instance_service_update_lightningapp_instance_release.assert_called_once_with(
1569-
project_id="test-project-id", id="instance_id", body=Body4(release_id="run_id")
1570-
)
1571-
15721561
out, _ = capsys.readouterr()
15731562
assert "will not overwrite the files in your CloudSpace." in out
15741563

@@ -2012,12 +2001,11 @@ def run(self):
20122001

20132002

20142003
@pytest.mark.parametrize(
2015-
"project, cloudspace_name, run_instance, user, tab, lightning_cloud_url, expected_url",
2004+
"project, run_instance, user, tab, lightning_cloud_url, expected_url",
20162005
[
20172006
# Old style
20182007
(
20192008
V1Membership(),
2020-
"any",
20212009
Externalv1LightningappInstance(id="test-app-id"),
20222010
V1GetUserResponse(username="tester", features=V1UserFeatures()),
20232011
"logs",
@@ -2026,7 +2014,6 @@ def run(self):
20262014
),
20272015
(
20282016
V1Membership(),
2029-
"any",
20302017
Externalv1LightningappInstance(id="test-app-id"),
20312018
V1GetUserResponse(username="tester", features=V1UserFeatures()),
20322019
"logs",
@@ -2036,25 +2023,58 @@ def run(self):
20362023
# New style
20372024
(
20382025
V1Membership(name="tester's project"),
2039-
"test/app",
2040-
Externalv1LightningappInstance(),
2026+
Externalv1LightningappInstance(name="test/job"),
20412027
V1GetUserResponse(username="tester", features=V1UserFeatures(project_selector=True)),
20422028
"logs",
20432029
"https://lightning.ai",
2044-
"https://lightning.ai/tester/tester%27s_project/apps/test~app/logs",
2030+
"https://lightning.ai/tester/tester%27s%20project/jobs/test%2Fjob/logs",
20452031
),
20462032
(
20472033
V1Membership(name="tester's project"),
2048-
"test/app",
2049-
Externalv1LightningappInstance(),
2034+
Externalv1LightningappInstance(name="test/job"),
20502035
V1GetUserResponse(username="tester", features=V1UserFeatures(project_selector=True)),
20512036
"logs",
2037+
"https://localhost:9800",
2038+
"https://localhost:9800/tester/tester%27s%20project/jobs/test%2Fjob/logs",
2039+
),
2040+
],
2041+
)
2042+
def test_get_app_url(monkeypatch, project, run_instance, user, tab, lightning_cloud_url, expected_url):
2043+
mock_client = mock.MagicMock()
2044+
mock_client.auth_service_get_user.return_value = user
2045+
cloud_backend = mock.MagicMock(client=mock_client)
2046+
monkeypatch.setattr(backends, "CloudBackend", mock.MagicMock(return_value=cloud_backend))
2047+
2048+
runtime = CloudRuntime()
2049+
2050+
with mock.patch(
2051+
"lightning.app.runners.cloud.get_lightning_cloud_url", mock.MagicMock(return_value=lightning_cloud_url)
2052+
):
2053+
assert runtime._get_app_url(project, run_instance, tab) == expected_url
2054+
2055+
2056+
@pytest.mark.parametrize(
2057+
"user, project, cloudspace_name, tab, lightning_cloud_url, expected_url",
2058+
[
2059+
(
2060+
V1GetUserResponse(username="tester", features=V1UserFeatures()),
2061+
V1Membership(name="default-project"),
2062+
"test/cloudspace",
2063+
"code",
2064+
"https://lightning.ai",
2065+
"https://lightning.ai/tester/default-project/apps/test%2Fcloudspace/code",
2066+
),
2067+
(
2068+
V1GetUserResponse(username="tester", features=V1UserFeatures()),
2069+
V1Membership(name="Awesome Project"),
2070+
"The Best CloudSpace ever",
2071+
"web-ui",
20522072
"http://localhost:9800",
2053-
"http://localhost:9800/tester/tester%27s_project/apps/test~app/logs",
2073+
"http://localhost:9800/tester/Awesome%20Project/apps/The%20Best%20CloudSpace%20ever/web-ui",
20542074
),
20552075
],
20562076
)
2057-
def test_get_app_url(monkeypatch, project, cloudspace_name, run_instance, user, tab, lightning_cloud_url, expected_url):
2077+
def test_get_cloudspace_url(monkeypatch, user, project, cloudspace_name, tab, lightning_cloud_url, expected_url):
20582078
mock_client = mock.MagicMock()
20592079
mock_client.auth_service_get_user.return_value = user
20602080
cloud_backend = mock.MagicMock(client=mock_client)
@@ -2065,4 +2085,4 @@ def test_get_app_url(monkeypatch, project, cloudspace_name, run_instance, user,
20652085
with mock.patch(
20662086
"lightning_app.runners.cloud.get_lightning_cloud_url", mock.MagicMock(return_value=lightning_cloud_url)
20672087
):
2068-
assert runtime._get_app_url(project, cloudspace_name, run_instance, tab) == expected_url
2088+
assert runtime._get_cloudspace_url(project, cloudspace_name, tab) == expected_url

0 commit comments

Comments
 (0)