zenml-nightly 0.68.0.dev20241027__py3-none-any.whl → 0.68.1.dev20241101__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- README.md +17 -11
- RELEASE_NOTES.md +9 -0
- zenml/VERSION +1 -1
- zenml/__init__.py +1 -1
- zenml/analytics/context.py +16 -1
- zenml/analytics/utils.py +18 -7
- zenml/artifacts/utils.py +40 -216
- zenml/cli/__init__.py +63 -90
- zenml/cli/base.py +3 -3
- zenml/cli/login.py +951 -0
- zenml/cli/server.py +462 -353
- zenml/cli/service_accounts.py +4 -4
- zenml/cli/stack.py +77 -2
- zenml/cli/stack_components.py +5 -16
- zenml/cli/user_management.py +0 -12
- zenml/cli/utils.py +24 -77
- zenml/client.py +46 -14
- zenml/config/compiler.py +1 -0
- zenml/config/global_config.py +9 -0
- zenml/config/pipeline_configurations.py +2 -1
- zenml/config/pipeline_run_configuration.py +2 -1
- zenml/constants.py +3 -9
- zenml/enums.py +1 -1
- zenml/exceptions.py +11 -0
- zenml/integrations/github/code_repositories/github_code_repository.py +1 -1
- zenml/login/__init__.py +16 -0
- zenml/login/credentials.py +346 -0
- zenml/login/credentials_store.py +603 -0
- zenml/login/pro/__init__.py +16 -0
- zenml/login/pro/client.py +496 -0
- zenml/login/pro/constants.py +34 -0
- zenml/login/pro/models.py +25 -0
- zenml/login/pro/organization/__init__.py +14 -0
- zenml/login/pro/organization/client.py +79 -0
- zenml/login/pro/organization/models.py +32 -0
- zenml/login/pro/tenant/__init__.py +14 -0
- zenml/login/pro/tenant/client.py +92 -0
- zenml/login/pro/tenant/models.py +174 -0
- zenml/login/pro/utils.py +121 -0
- zenml/{cli → login}/web_login.py +64 -28
- zenml/materializers/base_materializer.py +43 -9
- zenml/materializers/built_in_materializer.py +1 -1
- zenml/metadata/metadata_types.py +49 -0
- zenml/model/model.py +0 -38
- zenml/models/__init__.py +3 -0
- zenml/models/v2/base/base.py +12 -8
- zenml/models/v2/base/filter.py +9 -0
- zenml/models/v2/core/artifact_version.py +49 -10
- zenml/models/v2/core/component.py +54 -19
- zenml/models/v2/core/flavor.py +13 -13
- zenml/models/v2/core/model.py +3 -1
- zenml/models/v2/core/model_version.py +3 -5
- zenml/models/v2/core/model_version_artifact.py +3 -1
- zenml/models/v2/core/model_version_pipeline_run.py +3 -1
- zenml/models/v2/core/pipeline.py +3 -1
- zenml/models/v2/core/pipeline_run.py +23 -1
- zenml/models/v2/core/run_template.py +3 -1
- zenml/models/v2/core/stack.py +7 -3
- zenml/models/v2/core/step_run.py +43 -2
- zenml/models/v2/misc/auth_models.py +11 -2
- zenml/models/v2/misc/server_models.py +2 -0
- zenml/orchestrators/base_orchestrator.py +8 -4
- zenml/orchestrators/step_launcher.py +1 -0
- zenml/orchestrators/step_run_utils.py +10 -2
- zenml/orchestrators/step_runner.py +67 -55
- zenml/orchestrators/utils.py +45 -22
- zenml/pipelines/pipeline_decorator.py +5 -0
- zenml/pipelines/pipeline_definition.py +206 -160
- zenml/pipelines/run_utils.py +11 -10
- zenml/services/local/local_daemon_entrypoint.py +4 -4
- zenml/services/service.py +2 -2
- zenml/stack/stack.py +2 -6
- zenml/stack/stack_component.py +2 -7
- zenml/stack/utils.py +26 -14
- zenml/steps/base_step.py +8 -2
- zenml/steps/step_context.py +0 -3
- zenml/steps/step_invocation.py +14 -5
- zenml/steps/utils.py +1 -0
- zenml/utils/materializer_utils.py +1 -1
- zenml/utils/requirements_utils.py +71 -0
- zenml/utils/singleton.py +15 -3
- zenml/utils/source_utils.py +39 -2
- zenml/utils/visualization_utils.py +1 -1
- zenml/zen_server/auth.py +44 -39
- zenml/zen_server/deploy/__init__.py +7 -7
- zenml/zen_server/deploy/base_provider.py +46 -73
- zenml/zen_server/deploy/{local → daemon}/__init__.py +3 -3
- zenml/zen_server/deploy/{local/local_provider.py → daemon/daemon_provider.py} +44 -63
- zenml/zen_server/deploy/{local/local_zen_server.py → daemon/daemon_zen_server.py} +50 -22
- zenml/zen_server/deploy/deployer.py +90 -171
- zenml/zen_server/deploy/deployment.py +20 -12
- zenml/zen_server/deploy/docker/docker_provider.py +9 -28
- zenml/zen_server/deploy/docker/docker_zen_server.py +19 -3
- zenml/zen_server/deploy/helm/Chart.yaml +1 -1
- zenml/zen_server/deploy/helm/README.md +2 -2
- zenml/zen_server/exceptions.py +11 -0
- zenml/zen_server/jwt.py +9 -9
- zenml/zen_server/routers/auth_endpoints.py +30 -8
- zenml/zen_server/routers/stack_components_endpoints.py +1 -1
- zenml/zen_server/routers/workspaces_endpoints.py +1 -1
- zenml/zen_server/template_execution/runner_entrypoint_configuration.py +7 -4
- zenml/zen_server/template_execution/utils.py +6 -61
- zenml/zen_server/utils.py +64 -36
- zenml/zen_stores/base_zen_store.py +4 -49
- zenml/zen_stores/migrations/versions/0.68.1_release.py +23 -0
- zenml/zen_stores/migrations/versions/c22561cbb3a9_add_artifact_unique_constraints.py +86 -0
- zenml/zen_stores/rest_zen_store.py +325 -147
- zenml/zen_stores/schemas/api_key_schemas.py +9 -4
- zenml/zen_stores/schemas/artifact_schemas.py +21 -2
- zenml/zen_stores/schemas/artifact_visualization_schemas.py +1 -1
- zenml/zen_stores/schemas/component_schemas.py +49 -6
- zenml/zen_stores/schemas/device_schemas.py +9 -4
- zenml/zen_stores/schemas/flavor_schemas.py +1 -1
- zenml/zen_stores/schemas/model_schemas.py +1 -1
- zenml/zen_stores/schemas/service_schemas.py +1 -1
- zenml/zen_stores/schemas/step_run_schemas.py +1 -1
- zenml/zen_stores/schemas/trigger_schemas.py +1 -1
- zenml/zen_stores/sql_zen_store.py +393 -140
- zenml/zen_stores/template_utils.py +3 -1
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/METADATA +18 -12
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/RECORD +124 -107
- zenml/api.py +0 -60
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/LICENSE +0 -0
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/WHEEL +0 -0
- {zenml_nightly-0.68.0.dev20241027.dist-info → zenml_nightly-0.68.1.dev20241101.dist-info}/entry_points.txt +0 -0
zenml/cli/server.py
CHANGED
@@ -14,34 +14,36 @@
|
|
14
14
|
"""CLI for managing ZenML server deployments."""
|
15
15
|
|
16
16
|
import ipaddress
|
17
|
-
import
|
18
|
-
import
|
19
|
-
from typing import Any, Dict, Optional, Union
|
17
|
+
import re
|
18
|
+
from typing import List, Optional, Union
|
20
19
|
|
21
20
|
import click
|
22
|
-
import yaml
|
23
21
|
from rich.errors import MarkupError
|
24
22
|
|
25
23
|
import zenml
|
26
24
|
from zenml.cli import utils as cli_utils
|
27
|
-
from zenml.cli.cli import cli
|
28
|
-
from zenml.cli.
|
25
|
+
from zenml.cli.cli import TagGroup, cli
|
26
|
+
from zenml.cli.login import login, logout
|
29
27
|
from zenml.client import Client
|
30
28
|
from zenml.config.global_config import GlobalConfiguration
|
31
29
|
from zenml.console import console
|
32
|
-
from zenml.
|
33
|
-
from zenml.
|
34
|
-
from zenml.exceptions import AuthorizationException, IllegalOperationError
|
30
|
+
from zenml.enums import CliCategories, StoreType
|
31
|
+
from zenml.exceptions import AuthorizationException
|
35
32
|
from zenml.logger import get_logger
|
36
|
-
from zenml.
|
37
|
-
from zenml.
|
33
|
+
from zenml.login.credentials import ServerCredentials, ServerType
|
34
|
+
from zenml.services.service_status import ServiceState
|
35
|
+
from zenml.zen_server.utils import connected_to_local_server, get_local_server
|
38
36
|
|
39
37
|
logger = get_logger(__name__)
|
40
38
|
|
41
|
-
LOCAL_ZENML_SERVER_NAME = "local"
|
42
39
|
|
40
|
+
@cli.command(
|
41
|
+
"up",
|
42
|
+
help="""Start the ZenML dashboard locally.
|
43
43
|
|
44
|
-
|
44
|
+
DEPRECATED: Please use `zenml login --local` instead.
|
45
|
+
""",
|
46
|
+
)
|
45
47
|
@click.option(
|
46
48
|
"--docker",
|
47
49
|
is_flag=True,
|
@@ -71,14 +73,6 @@ LOCAL_ZENML_SERVER_NAME = "local"
|
|
71
73
|
default=False,
|
72
74
|
type=click.BOOL,
|
73
75
|
)
|
74
|
-
@click.option(
|
75
|
-
"--connect",
|
76
|
-
is_flag=True,
|
77
|
-
help="Connect the client to the local server even when already connected "
|
78
|
-
"to a remote ZenML server.",
|
79
|
-
default=False,
|
80
|
-
type=click.BOOL,
|
81
|
-
)
|
82
76
|
@click.option(
|
83
77
|
"--image",
|
84
78
|
type=str,
|
@@ -99,7 +93,6 @@ def up(
|
|
99
93
|
] = None,
|
100
94
|
port: Optional[int] = None,
|
101
95
|
blocking: bool = False,
|
102
|
-
connect: bool = False,
|
103
96
|
image: Optional[str] = None,
|
104
97
|
ngrok_token: Optional[str] = None,
|
105
98
|
) -> None:
|
@@ -110,133 +103,44 @@ def up(
|
|
110
103
|
ip_address: The IP address to bind the server to.
|
111
104
|
port: The port to bind the server to.
|
112
105
|
blocking: Block the CLI while the server is running.
|
113
|
-
connect: Connect the client to the local server even when already
|
114
|
-
connected to a remote ZenML server.
|
115
106
|
image: A custom Docker image to use for the server, when the
|
116
107
|
`--docker` flag is set.
|
117
108
|
ngrok_token: An ngrok auth token to use for exposing the ZenML dashboard
|
118
109
|
on a public domain. Primarily used for accessing the dashboard in
|
119
110
|
Colab.
|
120
111
|
"""
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
logger.warning(
|
125
|
-
"The `--connect` flag is deprecated, has no effect, and will be "
|
126
|
-
"removed in a future release."
|
127
|
-
)
|
128
|
-
|
129
|
-
gc = GlobalConfiguration()
|
130
|
-
|
131
|
-
# Raise an error if the client is already connected to a remote server.
|
132
|
-
if gc.store_configuration.type == StoreType.REST:
|
133
|
-
if not gc.zen_store.is_local_store():
|
134
|
-
cli_utils.error(
|
135
|
-
"Your ZenML client is already connected to a remote server. If "
|
136
|
-
"you want to spin up a local ZenML server, please disconnect "
|
137
|
-
"from the remote server first by running `zenml disconnect`."
|
138
|
-
)
|
139
|
-
|
140
|
-
if docker:
|
141
|
-
from zenml.utils.docker_utils import check_docker
|
142
|
-
|
143
|
-
if not check_docker():
|
144
|
-
cli_utils.error(
|
145
|
-
"Docker does not seem to be installed on your system. Please "
|
146
|
-
"install Docker to use the Docker ZenML server local "
|
147
|
-
"deployment or use one of the other deployment options."
|
148
|
-
)
|
149
|
-
provider = ServerProviderType.DOCKER
|
150
|
-
else:
|
151
|
-
if sys.platform == "win32" and not blocking:
|
152
|
-
cli_utils.error(
|
153
|
-
"Running the ZenML server locally as a background process is "
|
154
|
-
"not supported on Windows. Please use the `--blocking` flag "
|
155
|
-
"to run the server in blocking mode, or run the server in "
|
156
|
-
"a Docker container by setting `--docker` instead."
|
157
|
-
)
|
158
|
-
else:
|
159
|
-
pass
|
160
|
-
provider = ServerProviderType.LOCAL
|
161
|
-
if cli_utils.requires_mac_env_var_warning():
|
162
|
-
cli_utils.error(
|
163
|
-
"The `OBJC_DISABLE_INITIALIZE_FORK_SAFETY` environment variable "
|
164
|
-
"is recommended to run the ZenML server locally on a Mac. "
|
165
|
-
"Please set it to `YES` and try again."
|
166
|
-
)
|
167
|
-
|
168
|
-
os.environ[ENV_ZENML_LOCAL_SERVER] = str(True)
|
169
|
-
|
170
|
-
deployer = ServerDeployer()
|
171
|
-
|
172
|
-
server = get_local_server()
|
173
|
-
if server and server.config.provider != provider:
|
174
|
-
deployer.remove_server(LOCAL_ZENML_SERVER_NAME)
|
175
|
-
|
176
|
-
config_attrs: Dict[str, Any] = dict(
|
177
|
-
name=LOCAL_ZENML_SERVER_NAME,
|
178
|
-
provider=provider,
|
112
|
+
cli_utils.warning(
|
113
|
+
"The `zenml up` command is deprecated and will be removed in a "
|
114
|
+
"future release. Please use the `zenml login --local` command instead."
|
179
115
|
)
|
180
|
-
if not docker:
|
181
|
-
config_attrs["blocking"] = blocking
|
182
|
-
elif image:
|
183
|
-
config_attrs["image"] = image
|
184
|
-
if port is not None:
|
185
|
-
config_attrs["port"] = port
|
186
|
-
if ip_address is not None and provider in [
|
187
|
-
ServerProviderType.LOCAL,
|
188
|
-
ServerProviderType.DOCKER,
|
189
|
-
]:
|
190
|
-
config_attrs["ip_address"] = ip_address
|
191
|
-
|
192
|
-
from zenml.zen_server.deploy.deployment import ServerDeploymentConfig
|
193
|
-
|
194
|
-
server_config = ServerDeploymentConfig(**config_attrs)
|
195
|
-
if blocking:
|
196
|
-
from zenml.constants import (
|
197
|
-
DEFAULT_USERNAME,
|
198
|
-
)
|
199
|
-
|
200
|
-
cli_utils.declare(
|
201
|
-
"The local ZenML dashboard is about to deploy in a "
|
202
|
-
"blocking process. You can connect to it using the "
|
203
|
-
f"'{DEFAULT_USERNAME}' username and an empty password."
|
204
|
-
)
|
205
|
-
server = deployer.deploy_server(server_config)
|
206
116
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
117
|
+
# Calling the `zenml login` command
|
118
|
+
cli_utils.declare("Calling `zenml login --local`...")
|
119
|
+
login.callback( # type: ignore[misc]
|
120
|
+
local=True,
|
121
|
+
docker=docker,
|
122
|
+
ip_address=ip_address,
|
123
|
+
port=port,
|
124
|
+
blocking=blocking,
|
125
|
+
image=image,
|
126
|
+
ngrok_token=ngrok_token,
|
127
|
+
)
|
218
128
|
|
219
|
-
if server.status and server.status.url:
|
220
|
-
cli_utils.declare(
|
221
|
-
f"The local ZenML dashboard is available at "
|
222
|
-
f"'{server.status.url}'. You can connect to it using the "
|
223
|
-
f"'{DEFAULT_USERNAME}' username and an empty password. "
|
224
|
-
)
|
225
|
-
zenml.show(
|
226
|
-
ngrok_token=ngrok_token,
|
227
|
-
username=DEFAULT_USERNAME,
|
228
|
-
password=DEFAULT_PASSWORD,
|
229
|
-
)
|
230
129
|
|
130
|
+
@cli.command(
|
131
|
+
"show",
|
132
|
+
help="""Show the ZenML dashboard.
|
231
133
|
|
134
|
+
DEPRECATED: Please use `zenml server show` instead.
|
135
|
+
""",
|
136
|
+
)
|
232
137
|
@click.option(
|
233
138
|
"--ngrok-token",
|
234
139
|
type=str,
|
235
140
|
default=None,
|
236
141
|
help="Specify an ngrok auth token to use for exposing the ZenML server.",
|
237
142
|
)
|
238
|
-
|
239
|
-
def show(ngrok_token: Optional[str] = None) -> None:
|
143
|
+
def legacy_show(ngrok_token: Optional[str] = None) -> None:
|
240
144
|
"""Show the ZenML dashboard.
|
241
145
|
|
242
146
|
Args:
|
@@ -244,31 +148,36 @@ def show(ngrok_token: Optional[str] = None) -> None:
|
|
244
148
|
on a public domain. Primarily used for accessing the dashboard in
|
245
149
|
Colab.
|
246
150
|
"""
|
247
|
-
|
248
|
-
zenml
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
@cli.command("down", help="Shut down the local ZenML dashboard.")
|
254
|
-
def down() -> None:
|
255
|
-
"""Shut down the local ZenML dashboard."""
|
256
|
-
server = get_local_server()
|
151
|
+
cli_utils.warning(
|
152
|
+
"The `zenml show` command is deprecated and will be removed in a "
|
153
|
+
"future release. Please use the `zenml server show` command "
|
154
|
+
"instead."
|
155
|
+
)
|
257
156
|
|
258
|
-
|
259
|
-
|
157
|
+
# Calling the `zenml server show` command
|
158
|
+
cli_utils.declare("Calling `zenml server show`...")
|
159
|
+
show(local=False, ngrok_token=ngrok_token)
|
260
160
|
|
261
|
-
else:
|
262
|
-
from zenml.zen_server.deploy.deployer import ServerDeployer
|
263
161
|
|
264
|
-
|
265
|
-
|
266
|
-
|
162
|
+
@cli.command(
|
163
|
+
"down",
|
164
|
+
help="""Shut down the local ZenML dashboard.
|
267
165
|
|
268
|
-
|
166
|
+
DEPRECATED: Please use `zenml logout local` instead.
|
167
|
+
""",
|
168
|
+
)
|
169
|
+
def down() -> None:
|
170
|
+
"""Shut down the local ZenML dashboard."""
|
171
|
+
cli_utils.warning(
|
172
|
+
"The `zenml down` command is deprecated and will be removed in a "
|
173
|
+
"future release. Please use the `zenml logout --local` command instead."
|
174
|
+
)
|
269
175
|
|
270
|
-
|
271
|
-
|
176
|
+
# Calling the `zenml logout` command
|
177
|
+
cli_utils.declare("Calling `zenml logout --local`...")
|
178
|
+
logout.callback( # type: ignore[misc]
|
179
|
+
local=True
|
180
|
+
)
|
272
181
|
|
273
182
|
|
274
183
|
@cli.command(
|
@@ -276,30 +185,87 @@ def down() -> None:
|
|
276
185
|
)
|
277
186
|
def status() -> None:
|
278
187
|
"""Show details about the current configuration."""
|
188
|
+
from zenml.login.credentials_store import get_credentials_store
|
189
|
+
from zenml.login.pro.client import ZenMLProClient
|
190
|
+
|
279
191
|
gc = GlobalConfiguration()
|
280
192
|
client = Client()
|
281
193
|
|
282
194
|
store_cfg = gc.store_configuration
|
283
195
|
|
284
|
-
# Write about the current ZenML
|
285
|
-
cli_utils.declare("-----ZenML
|
196
|
+
# Write about the current ZenML client
|
197
|
+
cli_utils.declare("-----ZenML Client Status-----")
|
286
198
|
if gc.uses_default_store():
|
287
199
|
cli_utils.declare(
|
288
|
-
f"Connected to
|
200
|
+
f"Connected to the local ZenML database: '{store_cfg.url}'"
|
201
|
+
)
|
202
|
+
elif connected_to_local_server():
|
203
|
+
cli_utils.declare(
|
204
|
+
f"Connected to the local ZenML server: {store_cfg.url}"
|
205
|
+
)
|
206
|
+
elif re.match(r"^mysql://", store_cfg.url):
|
207
|
+
cli_utils.declare(
|
208
|
+
f"Connected directly to a SQL database: '{store_cfg.url}'"
|
289
209
|
)
|
290
210
|
else:
|
291
|
-
|
211
|
+
credentials_store = get_credentials_store()
|
212
|
+
server = credentials_store.get_credentials(store_cfg.url)
|
213
|
+
if server:
|
214
|
+
if server.type == ServerType.PRO:
|
215
|
+
# If connected to a ZenML Pro server, refresh the server info
|
216
|
+
pro_credentials = credentials_store.get_pro_credentials(
|
217
|
+
allow_expired=False
|
218
|
+
)
|
219
|
+
if pro_credentials:
|
220
|
+
pro_client = ZenMLProClient()
|
221
|
+
pro_servers = pro_client.tenant.list(
|
222
|
+
url=store_cfg.url, member_only=True
|
223
|
+
)
|
224
|
+
if pro_servers:
|
225
|
+
credentials_store.update_server_info(
|
226
|
+
server_url=store_cfg.url,
|
227
|
+
server_info=pro_servers[0],
|
228
|
+
)
|
229
|
+
|
230
|
+
cli_utils.declare(
|
231
|
+
f"Connected to a ZenML Pro server: `{server.server_name_hyperlink}`"
|
232
|
+
f" [{server.server_id_hyperlink}]"
|
233
|
+
)
|
234
|
+
|
235
|
+
cli_utils.declare(
|
236
|
+
f" ZenML Pro Organization: {server.organization_hyperlink}"
|
237
|
+
)
|
238
|
+
if pro_credentials:
|
239
|
+
cli_utils.declare(
|
240
|
+
f" ZenML Pro authentication: {pro_credentials.auth_status}"
|
241
|
+
)
|
242
|
+
else:
|
243
|
+
cli_utils.declare(
|
244
|
+
f"Connected to a remote ZenML server: `{server.dashboard_hyperlink}`"
|
245
|
+
)
|
246
|
+
|
247
|
+
cli_utils.declare(f" Dashboard: {server.dashboard_hyperlink}")
|
248
|
+
cli_utils.declare(f" API: {server.api_hyperlink}")
|
249
|
+
cli_utils.declare(f" Server status: '{server.status}'")
|
250
|
+
cli_utils.declare(f" Server authentication: {server.auth_status}")
|
292
251
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
252
|
+
else:
|
253
|
+
cli_utils.declare(
|
254
|
+
f"Connected to a remote ZenML server: [link={store_cfg.url}]"
|
255
|
+
f"{store_cfg.url}[/link]"
|
256
|
+
)
|
257
|
+
|
258
|
+
try:
|
259
|
+
client.zen_store.get_store_info()
|
260
|
+
except Exception as e:
|
261
|
+
cli_utils.warning(f"Error while initializing client: {e}")
|
262
|
+
else:
|
263
|
+
# Write about the active entities
|
264
|
+
scope = "repository" if client.uses_local_configuration else "global"
|
265
|
+
cli_utils.declare(f" The active user is: '{client.active_user.name}'")
|
266
|
+
cli_utils.declare(
|
267
|
+
f" The active stack is: '{client.active_stack_model.name}' ({scope})"
|
268
|
+
)
|
303
269
|
|
304
270
|
if client.root:
|
305
271
|
cli_utils.declare(f"Active repository root: {client.root}")
|
@@ -310,10 +276,34 @@ def status() -> None:
|
|
310
276
|
f"Local store files are located at: '{gc.local_stores_path}'"
|
311
277
|
)
|
312
278
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
279
|
+
cli_utils.declare("\n-----Local ZenML Server Status-----")
|
280
|
+
local_server = get_local_server()
|
281
|
+
if local_server:
|
282
|
+
if local_server.status:
|
283
|
+
if local_server.status.status == ServiceState.ACTIVE:
|
284
|
+
cli_utils.declare(
|
285
|
+
f"The local {local_server.config.provider} server is "
|
286
|
+
f"running at: {local_server.status.url}"
|
287
|
+
)
|
288
|
+
else:
|
289
|
+
cli_utils.declare(
|
290
|
+
f"The local {local_server.config.provider} server is not "
|
291
|
+
"available."
|
292
|
+
)
|
293
|
+
cli_utils.declare(
|
294
|
+
f" Server state: {local_server.status.status}"
|
295
|
+
)
|
296
|
+
if local_server.status.status_message:
|
297
|
+
cli_utils.declare(
|
298
|
+
f" Status message: {local_server.status.status_message}"
|
299
|
+
)
|
300
|
+
else:
|
301
|
+
cli_utils.declare(
|
302
|
+
f"The local {local_server.config.provider} server is not "
|
303
|
+
"running."
|
304
|
+
)
|
305
|
+
else:
|
306
|
+
cli_utils.declare("The local server has not been started.")
|
317
307
|
|
318
308
|
|
319
309
|
@cli.command(
|
@@ -321,57 +311,17 @@ def status() -> None:
|
|
321
311
|
help=(
|
322
312
|
"""Connect to a remote ZenML server.
|
323
313
|
|
324
|
-
|
325
|
-
|
326
|
-
* to connect to a ZenML deployment using web login:
|
327
|
-
|
328
|
-
zenml connect --url=http://zenml.example.com:8080
|
329
|
-
|
330
|
-
* to connect to a ZenML deployment using command line arguments:
|
331
|
-
|
332
|
-
zenml connect --url=http://zenml.example.com:8080 --username=admin
|
314
|
+
DEPRECATED: Please use `zenml login` instead.
|
333
315
|
|
334
|
-
|
335
|
-
|
336
|
-
zenml connect --config=/path/to/zenml_config.yaml
|
337
|
-
|
338
|
-
* when no arguments are supplied, ZenML will attempt to connect to the
|
339
|
-
last ZenML server deployed from the local host using the 'zenml deploy'
|
340
|
-
command.
|
341
|
-
|
342
|
-
The configuration file must be a YAML or JSON file with the following
|
343
|
-
attributes:
|
344
|
-
|
345
|
-
url: The URL of the ZenML server.
|
346
|
-
|
347
|
-
username: The username to use for authentication.
|
348
|
-
|
349
|
-
password: The password to use for authentication.
|
350
|
-
|
351
|
-
verify_ssl: Either a boolean, in which case it controls whether the
|
352
|
-
server's TLS certificate is verified, or a string, in which case it
|
353
|
-
must be a path to a CA certificate bundle to use or the CA bundle
|
354
|
-
value itself.
|
316
|
+
Examples:
|
355
317
|
|
356
|
-
|
357
|
-
ZenML server to be successful before issuing a timeout error
|
358
|
-
(default: 5).
|
318
|
+
* to re-login to the current ZenML server or connect to a ZenML Pro server:
|
359
319
|
|
360
|
-
|
320
|
+
zenml connect
|
361
321
|
|
362
|
-
|
363
|
-
username: admin\n
|
364
|
-
password: Pa$$word123\n
|
365
|
-
verify_ssl: |\n
|
366
|
-
-----BEGIN CERTIFICATE-----
|
367
|
-
MIIDETCCAfmgAwIBAgIQYUmQg2LR/pHAMZb/vQwwXjANBgkqhkiG9w0BAQsFADAT
|
368
|
-
MREwDwYDVQQDEwh6ZW5tbC1jYTAeFw0yMjA5MjYxMzI3NDhaFw0yMzA5MjYxMzI3\n
|
369
|
-
...\n
|
370
|
-
ULnzA0JkRWRnFqH6uXeJo1KAVqtxn1xf8PYxx3NlNDr9wi8KKwARf2lwm6sH4mvq
|
371
|
-
1aZ/0iYnGKCu7rLJzxeguliMf69E\n
|
372
|
-
-----END CERTIFICATE-----
|
373
|
-
http_timeout: 10
|
322
|
+
* to log in to a particular ZenML server:
|
374
323
|
|
324
|
+
zenml connect --url=http://zenml.example.com:8080
|
375
325
|
"""
|
376
326
|
),
|
377
327
|
)
|
@@ -384,15 +334,15 @@ def status() -> None:
|
|
384
334
|
)
|
385
335
|
@click.option(
|
386
336
|
"--username",
|
387
|
-
help="The username that is used to authenticate with a ZenML
|
388
|
-
"omitted, the web login will be used.",
|
337
|
+
help="(Deprecated) The username that is used to authenticate with a ZenML "
|
338
|
+
"server. If omitted, the web login will be used.",
|
389
339
|
required=False,
|
390
340
|
type=str,
|
391
341
|
)
|
392
342
|
@click.option(
|
393
343
|
"--password",
|
394
|
-
help="The password that is used to authenticate with a ZenML
|
395
|
-
"omitted, a prompt will be shown to enter the password.",
|
344
|
+
help="(Deprecated) The password that is used to authenticate with a ZenML "
|
345
|
+
"server. If omitted, a prompt will be shown to enter the password.",
|
396
346
|
required=False,
|
397
347
|
type=str,
|
398
348
|
)
|
@@ -416,19 +366,6 @@ def status() -> None:
|
|
416
366
|
required=False,
|
417
367
|
type=str,
|
418
368
|
)
|
419
|
-
@click.option(
|
420
|
-
"--config",
|
421
|
-
help="Use a YAML or JSON configuration or configuration file.",
|
422
|
-
required=False,
|
423
|
-
type=str,
|
424
|
-
)
|
425
|
-
@click.option(
|
426
|
-
"--raw-config",
|
427
|
-
is_flag=True,
|
428
|
-
help="Whether to use the configuration without prompting for missing "
|
429
|
-
"fields.",
|
430
|
-
default=False,
|
431
|
-
)
|
432
369
|
def connect(
|
433
370
|
url: Optional[str] = None,
|
434
371
|
username: Optional[str] = None,
|
@@ -436,8 +373,6 @@ def connect(
|
|
436
373
|
api_key: Optional[str] = None,
|
437
374
|
no_verify_ssl: bool = False,
|
438
375
|
ssl_ca_cert: Optional[str] = None,
|
439
|
-
config: Optional[str] = None,
|
440
|
-
raw_config: bool = False,
|
441
376
|
) -> None:
|
442
377
|
"""Connect to a remote ZenML server.
|
443
378
|
|
@@ -452,132 +387,50 @@ def connect(
|
|
452
387
|
no_verify_ssl: Whether to verify the server's TLS certificate.
|
453
388
|
ssl_ca_cert: A path to a CA bundle to use to verify the server's TLS
|
454
389
|
certificate or the CA bundle value itself.
|
455
|
-
config: A YAML or JSON configuration or configuration file to use.
|
456
|
-
raw_config: Whether to use the configuration without prompting for
|
457
|
-
missing fields.
|
458
390
|
"""
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
if password is not None:
|
463
|
-
cli_utils.warning(
|
464
|
-
"Supplying password values in the command line is not safe. "
|
465
|
-
"Please consider using the prompt option."
|
466
|
-
)
|
467
|
-
|
468
|
-
# Raise an error if a local server is running when trying to connect to
|
469
|
-
# another server
|
470
|
-
active_deployment = get_local_server()
|
471
|
-
if (
|
472
|
-
active_deployment
|
473
|
-
and active_deployment.status
|
474
|
-
and active_deployment.status.url != url
|
475
|
-
):
|
476
|
-
cli_utils.error(
|
477
|
-
"You're trying to connect to a remote ZenML server but already "
|
478
|
-
"have a local server running. This can lead to unexpected "
|
479
|
-
"behavior. Please shut down the local server by running "
|
480
|
-
"`zenml down` before connecting to a remote server."
|
481
|
-
)
|
482
|
-
|
483
|
-
store_dict: Dict[str, Any] = {}
|
484
|
-
verify_ssl: Union[str, bool] = (
|
485
|
-
ssl_ca_cert if ssl_ca_cert is not None else not no_verify_ssl
|
391
|
+
cli_utils.warning(
|
392
|
+
"The `zenml connect` command is deprecated and will be removed in a "
|
393
|
+
"future release. Please use the `zenml login` command instead. "
|
486
394
|
)
|
487
395
|
|
488
|
-
if
|
489
|
-
if os.path.isfile(config):
|
490
|
-
store_dict = yaml_utils.read_yaml(config)
|
491
|
-
else:
|
492
|
-
store_dict = yaml.safe_load(config)
|
493
|
-
if not isinstance(store_dict, dict):
|
494
|
-
cli_utils.error(
|
495
|
-
"The configuration argument must be JSON/YAML content or "
|
496
|
-
"point to a valid configuration file."
|
497
|
-
)
|
498
|
-
|
499
|
-
if raw_config:
|
500
|
-
store_config = StoreConfiguration.model_validate(store_dict)
|
501
|
-
GlobalConfiguration().set_store(store_config)
|
502
|
-
return
|
503
|
-
|
504
|
-
url = store_dict.get("url", url)
|
505
|
-
username = username or store_dict.get("username")
|
506
|
-
password = password or store_dict.get("password")
|
507
|
-
api_key = api_key or store_dict.get("api_key")
|
508
|
-
verify_ssl = store_dict.get("verify_ssl", verify_ssl)
|
509
|
-
|
510
|
-
if not url:
|
511
|
-
url = click.prompt("ZenML server URL", type=str)
|
512
|
-
else:
|
513
|
-
cli_utils.declare(f"Connecting to: '{url}'...")
|
514
|
-
assert url is not None
|
515
|
-
|
516
|
-
store_dict["url"] = url
|
517
|
-
store_type = BaseZenStore.get_store_type(url)
|
518
|
-
if store_type == StoreType.REST:
|
519
|
-
store_dict["verify_ssl"] = verify_ssl
|
520
|
-
|
521
|
-
if not username and not api_key:
|
522
|
-
if store_type == StoreType.REST:
|
523
|
-
store_dict["api_token"] = web_login(url=url, verify_ssl=verify_ssl)
|
524
|
-
else:
|
525
|
-
username = click.prompt("Username", type=str)
|
526
|
-
|
527
|
-
if username:
|
396
|
+
if password is not None or username is not None:
|
528
397
|
cli_utils.warning(
|
529
398
|
"Connecting to a ZenML server using a username and password is "
|
530
|
-
"
|
531
|
-
"filesystem
|
532
|
-
"
|
533
|
-
"
|
534
|
-
"
|
399
|
+
"insecure because the password is locally stored on your "
|
400
|
+
"filesystem and is no longer supported. The web login workflow will "
|
401
|
+
"be used instead. An alternative for non-interactive environments "
|
402
|
+
"is to create and use a service account API key (see "
|
403
|
+
"https://docs.zenml.io/how-to/connecting-to-zenml/connect-with-a-service-account "
|
535
404
|
"for more information)."
|
536
405
|
)
|
537
406
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
store_dict["password"] = password
|
547
|
-
elif api_key:
|
548
|
-
store_dict["api_key"] = api_key
|
549
|
-
|
550
|
-
store_config_class = BaseZenStore.get_store_config_class(store_type)
|
551
|
-
assert store_config_class is not None
|
407
|
+
# Calling the `zenml login` command
|
408
|
+
cli_utils.declare("Calling `zenml login`...")
|
409
|
+
login.callback( # type: ignore[misc]
|
410
|
+
server=url,
|
411
|
+
api_key=api_key,
|
412
|
+
no_verify_ssl=no_verify_ssl,
|
413
|
+
ssl_ca_cert=ssl_ca_cert,
|
414
|
+
)
|
552
415
|
|
553
|
-
store_config = store_config_class.model_validate(store_dict)
|
554
|
-
try:
|
555
|
-
GlobalConfiguration().set_store(store_config)
|
556
|
-
except IllegalOperationError:
|
557
|
-
cli_utils.warning(
|
558
|
-
f"User '{username}' does not have sufficient permissions to "
|
559
|
-
f"access the server at '{url}'."
|
560
|
-
)
|
561
|
-
except AuthorizationException as e:
|
562
|
-
cli_utils.warning(f"Authorization error: {e}")
|
563
416
|
|
417
|
+
@cli.command(
|
418
|
+
"disconnect",
|
419
|
+
help="""Disconnect from a ZenML server.
|
564
420
|
|
565
|
-
|
421
|
+
DEPRECATED: Please use `zenml logout` instead.
|
422
|
+
""",
|
423
|
+
)
|
566
424
|
def disconnect_server() -> None:
|
567
425
|
"""Disconnect from a ZenML server."""
|
568
|
-
|
569
|
-
|
426
|
+
cli_utils.warning(
|
427
|
+
"The `zenml disconnect` command is deprecated and will be removed in a "
|
428
|
+
"future release. Please use the `zenml logout` command instead."
|
429
|
+
)
|
570
430
|
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
store_type = BaseZenStore.get_store_type(url)
|
575
|
-
if store_type == StoreType.REST:
|
576
|
-
deployer = ServerDeployer()
|
577
|
-
deployer.disconnect_from_server()
|
578
|
-
else:
|
579
|
-
gc.set_default_store()
|
580
|
-
cli_utils.declare("Restored default store configuration.")
|
431
|
+
# Calling the `zenml logout` command
|
432
|
+
cli_utils.declare("Calling `zenml logout`...")
|
433
|
+
logout.callback() # type: ignore[misc]
|
581
434
|
|
582
435
|
|
583
436
|
@cli.command("logs", help="Show the logs for the local ZenML server.")
|
@@ -619,20 +472,20 @@ def logs(
|
|
619
472
|
"up` first to start the ZenML dashboard locally."
|
620
473
|
)
|
621
474
|
|
622
|
-
|
623
|
-
|
624
|
-
from zenml.zen_server.deploy.deployer import ServerDeployer
|
475
|
+
from zenml.zen_server.deploy.deployer import LocalServerDeployer
|
625
476
|
|
626
|
-
deployer =
|
477
|
+
deployer = LocalServerDeployer()
|
627
478
|
|
628
|
-
cli_utils.declare(
|
479
|
+
cli_utils.declare(
|
480
|
+
f"Showing logs for the local {server.config.provider} server"
|
481
|
+
)
|
629
482
|
|
630
483
|
from zenml.zen_server.deploy.exceptions import (
|
631
484
|
ServerDeploymentNotFoundError,
|
632
485
|
)
|
633
486
|
|
634
487
|
try:
|
635
|
-
logs = deployer.get_server_logs(
|
488
|
+
logs = deployer.get_server_logs(follow=follow, tail=tail)
|
636
489
|
except ServerDeploymentNotFoundError as e:
|
637
490
|
cli_utils.error(f"Server not found: {e}")
|
638
491
|
|
@@ -645,3 +498,259 @@ def logs(
|
|
645
498
|
console.print(line)
|
646
499
|
except MarkupError:
|
647
500
|
console.print(line, markup=False)
|
501
|
+
|
502
|
+
|
503
|
+
@cli.group(cls=TagGroup, tag=CliCategories.MANAGEMENT_TOOLS)
|
504
|
+
def server() -> None:
|
505
|
+
"""Commands for managing ZenML servers."""
|
506
|
+
|
507
|
+
|
508
|
+
@server.command(
|
509
|
+
"list",
|
510
|
+
help="""List all ZenML servers that this client is authenticated to.
|
511
|
+
|
512
|
+
The CLI can be authenticated to multiple ZenML servers at the same time,
|
513
|
+
even though it can only be connected to one server at a time. You can list
|
514
|
+
all the ZenML servers that the client is currently authenticated to by
|
515
|
+
using this command.
|
516
|
+
|
517
|
+
When logged in to ZenML Pro, this list will also include all ZenML Pro
|
518
|
+
servers that the authenticated user can access or could potentially access,
|
519
|
+
including details such as their current state and the organization they
|
520
|
+
belong to.
|
521
|
+
|
522
|
+
The complete list of servers displayed by this command includes the
|
523
|
+
following:
|
524
|
+
|
525
|
+
* ZenML Pro servers that the authenticated ZenML Pro user can or could
|
526
|
+
access. The client needs to be logged to ZenML Pro via
|
527
|
+
`zenml login --pro` to access these servers.
|
528
|
+
|
529
|
+
* ZenML servers that the client has logged in to via
|
530
|
+
`zenml login --url` in the past.
|
531
|
+
|
532
|
+
* the local ZenML server started with `zenml login --local`, if one is
|
533
|
+
running.
|
534
|
+
|
535
|
+
By default, this command does not display ZenML servers that are not
|
536
|
+
accessible: servers that are not running, are no longer accessible due to
|
537
|
+
an expired authentication and ZenML Pro servers where the user is not a
|
538
|
+
member. To include these servers in the list, use the `--all` flag.
|
539
|
+
""",
|
540
|
+
)
|
541
|
+
@click.option(
|
542
|
+
"--verbose",
|
543
|
+
"-v",
|
544
|
+
is_flag=True,
|
545
|
+
help="Show verbose output.",
|
546
|
+
)
|
547
|
+
@click.option(
|
548
|
+
"--all",
|
549
|
+
"-a",
|
550
|
+
is_flag=True,
|
551
|
+
help="Show all ZenML servers, including those that are not running "
|
552
|
+
"and those with an expired authentication.",
|
553
|
+
)
|
554
|
+
def server_list(verbose: bool = False, all: bool = False) -> None:
|
555
|
+
"""List all ZenML servers that this client is authorized to access.
|
556
|
+
|
557
|
+
Args:
|
558
|
+
verbose: Whether to show verbose output.
|
559
|
+
all: Whether to show all ZenML servers.
|
560
|
+
"""
|
561
|
+
from zenml.login.credentials_store import get_credentials_store
|
562
|
+
from zenml.login.pro.client import ZenMLProClient
|
563
|
+
from zenml.login.pro.tenant.models import TenantRead, TenantStatus
|
564
|
+
|
565
|
+
credentials_store = get_credentials_store()
|
566
|
+
pro_token = credentials_store.get_pro_token(allow_expired=True)
|
567
|
+
current_store_config = GlobalConfiguration().store_configuration
|
568
|
+
|
569
|
+
# The list of ZenML Pro servers kept in the credentials store
|
570
|
+
pro_servers = credentials_store.list_credentials(type=ServerType.PRO)
|
571
|
+
# The list of regular remote ZenML servers kept in the credentials store
|
572
|
+
servers = list(credentials_store.list_credentials(type=ServerType.REMOTE))
|
573
|
+
# The list of local ZenML servers kept in the credentials store
|
574
|
+
local_servers = list(
|
575
|
+
credentials_store.list_credentials(type=ServerType.LOCAL)
|
576
|
+
)
|
577
|
+
|
578
|
+
if pro_token and not pro_token.expired:
|
579
|
+
# If the ZenML Pro authentication is still valid, we include all ZenML
|
580
|
+
# Pro servers that the current ZenML Pro user can access, even those
|
581
|
+
# that the user has never connected to (and are therefore not stored in
|
582
|
+
# the credentials store).
|
583
|
+
|
584
|
+
accessible_pro_servers: List[TenantRead] = []
|
585
|
+
try:
|
586
|
+
client = ZenMLProClient()
|
587
|
+
accessible_pro_servers = client.tenant.list(member_only=not all)
|
588
|
+
except AuthorizationException as e:
|
589
|
+
cli_utils.warning(f"ZenML Pro authorization error: {e}")
|
590
|
+
else:
|
591
|
+
if not all:
|
592
|
+
accessible_pro_servers = [
|
593
|
+
s
|
594
|
+
for s in accessible_pro_servers
|
595
|
+
if s.status == TenantStatus.AVAILABLE
|
596
|
+
]
|
597
|
+
|
598
|
+
if not accessible_pro_servers:
|
599
|
+
cli_utils.declare(
|
600
|
+
"No ZenML Pro servers that are accessible to the current "
|
601
|
+
"user could be found."
|
602
|
+
)
|
603
|
+
if not all:
|
604
|
+
cli_utils.declare(
|
605
|
+
"Hint: use the `--all` flag to show all ZenML servers, "
|
606
|
+
"including those that the client is not currently "
|
607
|
+
"authorized to access or are not running."
|
608
|
+
)
|
609
|
+
|
610
|
+
# We update the list of stored ZenML Pro servers with the ones that the
|
611
|
+
# client is a member of
|
612
|
+
for accessible_server in accessible_pro_servers:
|
613
|
+
for idx, stored_server in enumerate(pro_servers):
|
614
|
+
if stored_server.server_id == accessible_server.id:
|
615
|
+
# All ZenML Pro servers accessible by the current ZenML Pro
|
616
|
+
# user have an authentication that is valid at least until
|
617
|
+
# the current ZenML Pro authentication token expires.
|
618
|
+
stored_server.update_server_info(
|
619
|
+
accessible_server,
|
620
|
+
)
|
621
|
+
updated_server = stored_server.model_copy()
|
622
|
+
# Replace the current server API token with the current
|
623
|
+
# ZenML Pro API token to reflect the current authentication
|
624
|
+
# status.
|
625
|
+
updated_server.api_token = pro_token
|
626
|
+
pro_servers[idx] = updated_server
|
627
|
+
break
|
628
|
+
else:
|
629
|
+
stored_server = ServerCredentials(
|
630
|
+
url=accessible_server.url or "",
|
631
|
+
api_token=pro_token,
|
632
|
+
)
|
633
|
+
stored_server.update_server_info(accessible_server)
|
634
|
+
pro_servers.append(stored_server)
|
635
|
+
|
636
|
+
elif pro_servers:
|
637
|
+
cli_utils.warning(
|
638
|
+
"The ZenML Pro authentication has expired. Please re-login "
|
639
|
+
"to ZenML Pro using `zenml login` to include all ZenML Pro servers "
|
640
|
+
"that you are a member of in the list."
|
641
|
+
)
|
642
|
+
|
643
|
+
# We add the local server to the list of servers, if it is running
|
644
|
+
local_server = get_local_server()
|
645
|
+
if local_server:
|
646
|
+
url = (
|
647
|
+
local_server.status.url if local_server.status else None
|
648
|
+
) or local_server.config.url
|
649
|
+
status = local_server.status.status if local_server.status else ""
|
650
|
+
local_servers.append(
|
651
|
+
ServerCredentials(
|
652
|
+
url=url or "",
|
653
|
+
status=status,
|
654
|
+
version=zenml.__version__,
|
655
|
+
server_id=GlobalConfiguration().user_id,
|
656
|
+
server_name=f"local {local_server.config.provider} server",
|
657
|
+
)
|
658
|
+
)
|
659
|
+
|
660
|
+
all_servers = pro_servers + local_servers + servers
|
661
|
+
|
662
|
+
if not all:
|
663
|
+
# Filter out servers that are expired or not running
|
664
|
+
all_servers = [s for s in all_servers if s.is_available]
|
665
|
+
|
666
|
+
if verbose:
|
667
|
+
columns = [
|
668
|
+
"type",
|
669
|
+
"server_id_hyperlink",
|
670
|
+
"server_name_hyperlink",
|
671
|
+
"organization_hyperlink" if pro_servers else "",
|
672
|
+
"version",
|
673
|
+
"status",
|
674
|
+
"dashboard_url",
|
675
|
+
"api_hyperlink",
|
676
|
+
"auth_status",
|
677
|
+
]
|
678
|
+
elif all:
|
679
|
+
columns = [
|
680
|
+
"type",
|
681
|
+
"server_id_hyperlink",
|
682
|
+
"server_name_hyperlink",
|
683
|
+
"organization_hyperlink" if pro_servers else "",
|
684
|
+
"version",
|
685
|
+
"status",
|
686
|
+
"api_hyperlink",
|
687
|
+
]
|
688
|
+
else:
|
689
|
+
columns = [
|
690
|
+
"type",
|
691
|
+
"server_id_hyperlink" if pro_servers else "",
|
692
|
+
"server_name_hyperlink",
|
693
|
+
"organization_hyperlink" if pro_servers else "",
|
694
|
+
"version",
|
695
|
+
"api_hyperlink" if servers else "",
|
696
|
+
]
|
697
|
+
|
698
|
+
# Remove empty columns
|
699
|
+
columns = [c for c in columns if c]
|
700
|
+
|
701
|
+
# Figure out if the client is already connected to one of the
|
702
|
+
# servers in the list
|
703
|
+
current_server: List[ServerCredentials] = []
|
704
|
+
if current_store_config.type == StoreType.REST:
|
705
|
+
current_server = [
|
706
|
+
s for s in all_servers if s.url == current_store_config.url
|
707
|
+
]
|
708
|
+
|
709
|
+
cli_utils.print_pydantic_models( # type: ignore[type-var]
|
710
|
+
all_servers,
|
711
|
+
columns=columns,
|
712
|
+
rename_columns={
|
713
|
+
"server_name_hyperlink": "name",
|
714
|
+
"server_id_hyperlink": "ID",
|
715
|
+
"organization_hyperlink": "organization",
|
716
|
+
"dashboard_url": "dashboard URL",
|
717
|
+
"api_hyperlink": "API URL",
|
718
|
+
"auth_status": "auth status",
|
719
|
+
},
|
720
|
+
active_models=current_server,
|
721
|
+
show_active=True,
|
722
|
+
)
|
723
|
+
|
724
|
+
|
725
|
+
@server.command(
|
726
|
+
"show",
|
727
|
+
help="Show the ZenML dashboard for the server that the client is connected to.",
|
728
|
+
)
|
729
|
+
@click.option(
|
730
|
+
"--local",
|
731
|
+
is_flag=True,
|
732
|
+
help="Show the ZenML dashboard for the local server.",
|
733
|
+
default=False,
|
734
|
+
type=click.BOOL,
|
735
|
+
)
|
736
|
+
@click.option(
|
737
|
+
"--ngrok-token",
|
738
|
+
type=str,
|
739
|
+
default=None,
|
740
|
+
help="Specify an ngrok auth token to use for exposing the local ZenML "
|
741
|
+
"server. Only used when `--local` is set. Primarily used for accessing the "
|
742
|
+
"local dashboard in Colab.",
|
743
|
+
)
|
744
|
+
def show(local: bool = False, ngrok_token: Optional[str] = None) -> None:
|
745
|
+
"""Show the ZenML dashboard.
|
746
|
+
|
747
|
+
Args:
|
748
|
+
local: Whether to show the ZenML dashboard for the local server.
|
749
|
+
ngrok_token: An ngrok auth token to use for exposing the ZenML dashboard
|
750
|
+
on a public domain. Primarily used for accessing the local dashboard
|
751
|
+
in Colab.
|
752
|
+
"""
|
753
|
+
try:
|
754
|
+
zenml.show(ngrok_token=ngrok_token)
|
755
|
+
except RuntimeError as e:
|
756
|
+
cli_utils.error(str(e))
|