Unverified Commit 12f72a42 authored by mohammedabdulwahhab's avatar mohammedabdulwahhab Committed by GitHub
Browse files

fix: remove dynamo cloud login (#824)

parent d346782c
......@@ -22,7 +22,6 @@ import importlib.metadata
import typer
from rich.console import Console
from dynamo.sdk.cli.cloud import app as cloud_app
from dynamo.sdk.cli.deployment import app as deployment_app
from dynamo.sdk.cli.deployment import deploy
from dynamo.sdk.cli.env import env
......@@ -78,7 +77,6 @@ cli.command(
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
add_help_option=False,
)(run)
cli.add_typer(cloud_app, name="cloud")
cli.add_typer(deployment_app, name="deployment")
cli.command()(deploy)
cli.command()(build)
......
# SPDX-FileCopyrightText: Copyright (c) 2020 Atalaya Tech. Inc
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# #
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Modifications Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES
from __future__ import annotations
import rich
import typer
from bentoml._internal.cloud.client import RestApiClient
from bentoml._internal.cloud.config import CloudClientConfig, CloudClientContext
from bentoml._internal.configuration.containers import BentoMLContainer
from bentoml.exceptions import CLIException, CloudRESTApiClientError
app = typer.Typer(
help="Interact with your Dynamo Cloud Server",
add_completion=True,
no_args_is_help=True,
)
console = rich.console.Console()
@app.command()
def login(
endpoint: str = typer.Argument(
..., help="Dynamo Cloud endpoint", envvar="DYNAMO_CLOUD_API_ENDPOINT"
)
) -> None:
"""Connect to your Dynamo Cloud. You can find deployment instructions for this in our docs"""
try:
api_token = "" # Using empty string for now as it's not used
cloud_rest_client = RestApiClient(endpoint, api_token)
user = cloud_rest_client.v1.get_current_user()
if user is None:
raise CLIException("current user is not found")
org = cloud_rest_client.v1.get_current_organization()
if org is None:
raise CLIException("current organization is not found")
current_context_name = CloudClientConfig.get_config().current_context_name
cloud_context = BentoMLContainer.cloud_context.get()
ctx = CloudClientContext(
name=cloud_context if cloud_context is not None else current_context_name,
endpoint=endpoint,
api_token=api_token,
email=user.email,
)
ctx.save()
console.print(
f":white_check_mark: Configured Dynamo Cloud credentials (current-context: {ctx.name})"
)
console.print(
f":white_check_mark: Logged in as [blue]{user.email}[/] at [blue]{org.name}[/] organization"
)
except CloudRESTApiClientError as e:
if e.error_code == 401:
console.print(
f":police_car_light: Error validating token: HTTP 401: Bad credentials ({endpoint}/api-token)"
)
else:
console.print(
f":police_car_light: Error validating token: HTTP {e.error_code}"
)
......@@ -27,9 +27,11 @@ from typing import Any, Dict, List, Optional, TextIO
import typer
from bentoml._internal.cloud.base import Spinner
from bentoml._internal.cloud.client import RestApiClient
from bentoml._internal.cloud.config import CloudClientConfig, CloudClientContext
from bentoml._internal.cloud.deployment import Deployment, DeploymentConfigParameters
from bentoml._internal.configuration.containers import BentoMLContainer
from bentoml.exceptions import BentoMLException
from bentoml.exceptions import BentoMLException, CLIException, CloudRESTApiClientError
from rich.console import Console
from simple_di import Provide, inject
......@@ -45,10 +47,11 @@ configure_server_logging()
logger = logging.getLogger(__name__)
app = typer.Typer(
help="Deploy Dynamo applications to Kubernetes cluster",
help="Deploy Dynamo applications to Dynamo Cloud Kubernetes Platform",
add_completion=True,
no_args_is_help=True,
)
console = Console(highlight=False)
if t.TYPE_CHECKING:
......@@ -58,7 +61,7 @@ if t.TYPE_CHECKING:
def raise_deployment_config_error(err: BentoMLException, action: str) -> t.NoReturn:
if err.error_code == HTTPStatus.UNAUTHORIZED:
raise BentoMLException(
f"{err}\n* Dynamo Cloud API token is required for authorization. Run `dynamo cloud login` command to login"
f"{err}\n* Dynamo Cloud API token is required for authorization. Please provide a valid endpoint with --endpoint option."
) from None
raise BentoMLException(
f"Failed to {action} deployment due to invalid configuration: {err}"
......@@ -67,7 +70,7 @@ def raise_deployment_config_error(err: BentoMLException, action: str) -> t.NoRet
@inject
def create_deployment(
bento: Optional[str] = None,
pipeline: Optional[str] = None,
name: Optional[str] = None,
config_file: Optional[TextIO] = None,
wait: bool = True,
......@@ -86,7 +89,7 @@ def create_deployment(
config_params = DeploymentConfigParameters(
name=name,
bento=bento,
bento=pipeline,
envs=env_dicts,
secrets=None,
cli=True,
......@@ -194,7 +197,7 @@ def get_deployment(
error_msg = str(e)
if "No cloud context default found" in error_msg:
spinner.log(
"[red]:x: Error:[/] Not logged in to Dynamo Cloud. Please run 'dynamo cloud login' first."
"[red]:x: Error:[/] Not logged in to Dynamo Cloud. Please provide a valid endpoint with --endpoint option."
)
sys.exit(1)
if "404 Not Found" in error_msg or "Deployment not found" in error_msg:
......@@ -221,7 +224,7 @@ def delete_deployment(
error_msg = str(e)
if "No cloud context default found" in error_msg:
spinner.log(
"[red]:x: Error:[/] Not logged in to Dynamo Cloud. Please run 'dynamo cloud login' first."
"[red]:x: Error:[/] Not logged in to Dynamo Cloud. Please provide a valid endpoint with --endpoint option."
)
sys.exit(1)
if "404 Not Found" in error_msg or "Deployment not found" in error_msg:
......@@ -269,7 +272,7 @@ def list_deployments(
except BentoMLException as e:
if "No cloud context default found" in str(e):
spinner.log(
"[red]:x: Error:[/] Not logged in to Dynamo Cloud. Please run 'dynamo cloud login' first."
"[red]:x: Error:[/] Not logged in to Dynamo Cloud. Please provide a valid endpoint with --endpoint option."
)
sys.exit(1)
spinner.log(f"[red]:x: Error:[/] Failed to list deployments: {str(e)}")
......@@ -279,8 +282,8 @@ def list_deployments(
@app.command()
def create(
ctx: typer.Context,
bento: Optional[str] = typer.Argument(None, help="Bento to deploy"),
name: Optional[str] = typer.Option(None, "--name", "-n", help="Deployment name"),
pipeline: Optional[str] = typer.Argument(..., help="Dynamo pipeline to deploy"),
name: Optional[str] = typer.Option(..., "--name", "-n", help="Deployment name"),
config_file: Optional[typer.FileText] = typer.Option(
None, "--config-file", "-f", help="Configuration file path"
),
......@@ -290,13 +293,17 @@ def create(
timeout: int = typer.Option(
3600, "--timeout", help="Timeout for deployment to be ready in seconds"
),
endpoint: str = typer.Option(
..., "--endpoint", "-e", help="Dynamo Cloud endpoint", envvar="DYNAMO_CLOUD"
),
) -> None:
"""Create a deployment on Dynamo Cloud.
Create a deployment using parameters, or using config yaml file.
"""
login_to_cloud(endpoint)
create_deployment(
bento=bento,
pipeline=pipeline,
name=name,
config_file=config_file,
wait=wait,
......@@ -309,11 +316,15 @@ def create(
def get(
name: str = typer.Argument(..., help="Deployment name"),
cluster: Optional[str] = typer.Option(None, "--cluster", help="Cluster name"),
endpoint: str = typer.Option(
..., "--endpoint", "-e", help="Dynamo Cloud endpoint", envvar="DYNAMO_CLOUD"
),
) -> None:
"""Get deployment details from Dynamo Cloud.
Get deployment details by name.
"""
login_to_cloud(endpoint)
get_deployment(name, cluster=cluster)
......@@ -325,11 +336,19 @@ def list(
query: Optional[str] = typer.Option(
None, "--query", "-q", help="Advanced query string"
),
endpoint: str = typer.Option(
...,
"--endpoint",
"-e",
help="Dynamo Cloud endpoint",
envvar="DYNAMO_CLOUD",
),
) -> None:
"""List all deployments from Dynamo Cloud.
List and filter deployments.
"""
login_to_cloud(endpoint)
list_deployments(cluster=cluster, search=search, dev=dev, q=query)
......@@ -337,18 +356,26 @@ def list(
def delete(
name: str = typer.Argument(..., help="Deployment name"),
cluster: Optional[str] = typer.Option(None, "--cluster", help="Cluster name"),
endpoint: str = typer.Option(
...,
"--endpoint",
"-e",
help="Dynamo Cloud endpoint",
envvar="DYNAMO_CLOUD",
),
) -> None:
"""Delete a deployment from Dynamo Cloud.
Delete deployment by name.
"""
login_to_cloud(endpoint)
delete_deployment(name, cluster=cluster)
def deploy(
ctx: typer.Context,
bento: Optional[str] = typer.Argument(None, help="Bento to deploy"),
name: Optional[str] = typer.Option(None, "--name", "-n", help="Deployment name"),
pipeline: Optional[str] = typer.Argument(..., help="Dynamo pipeline to deploy"),
name: Optional[str] = typer.Option(..., "--name", "-n", help="Deployment name"),
config_file: Optional[typer.FileText] = typer.Option(
None, "--config-file", "-f", help="Configuration file path"
),
......@@ -358,16 +385,70 @@ def deploy(
timeout: int = typer.Option(
3600, "--timeout", help="Timeout for deployment to be ready in seconds"
),
endpoint: str = typer.Option(
...,
"--endpoint",
"-e",
help="Dynamo Cloud endpoint",
envvar="DYNAMO_CLOUD",
),
) -> None:
"""Create a deployment on Dynamo Cloud.
Create a deployment using parameters, or using config yaml file.
"""
login_to_cloud(endpoint)
create_deployment(
bento=bento,
pipeline=pipeline,
name=name,
config_file=config_file,
wait=wait,
timeout=timeout,
args=ctx.args if hasattr(ctx, "args") else None,
)
def login_to_cloud(endpoint: str) -> None:
"""Connect to Dynamo Cloud silently using logging for success and console for errors."""
try:
logger.info(f"Running against Dynamo Cloud at {endpoint}")
api_token = "" # Using empty string for now as it's not used
cloud_rest_client = RestApiClient(endpoint, api_token)
user = cloud_rest_client.v1.get_current_user()
if user is None:
raise CLIException("current user is not found")
org = cloud_rest_client.v1.get_current_organization()
if org is None:
raise CLIException("current organization is not found")
current_context_name = CloudClientConfig.get_config().current_context_name
cloud_context = BentoMLContainer.cloud_context.get()
ctx = CloudClientContext(
name=cloud_context if cloud_context is not None else current_context_name,
endpoint=endpoint,
api_token=api_token,
email=user.email,
)
ctx.save()
logger.debug(
f"Configured Dynamo Cloud credentials (current-context: {ctx.name})"
)
logger.debug(f"Logged in as {user.email} at {org.name} organization")
except CloudRESTApiClientError as e:
if e.error_code == 401:
console.print(
f":police_car_light: Error validating token: HTTP 401: Bad credentials ({endpoint}/api-token)"
)
else:
console.print(
f":police_car_light: Error validating token: HTTP {e.error_code}"
)
raise BentoMLException(f"Failed to login to Dynamo Cloud: {str(e)}") from e
except Exception as e:
console.print(f":police_car_light: Error connecting to Dynamo Cloud: {str(e)}")
raise BentoMLException(f"Failed to login to Dynamo Cloud: {str(e)}") from e
......@@ -50,13 +50,12 @@ export PROJECT_ROOT=$(pwd)
# Set your Kubernetes namespace (must match the namespace where Dynamo cloud is installed)
export KUBE_NS=hello-world
# Externally accessible endpoint to the `dynamo-store` service within your Dynamo Cloud installation
# Set the externally accessible endpoint to the `dynamo-store` service within your Dynamo Cloud installation
export DYNAMO_CLOUD=https://${KUBE_NS}.dev.aire.nvidia.com
# Login to the Dynamo cloud
dynamo cloud login $DYNAMO_CLOUD
```
The `DYNAMO_CLOUD` environment variable is required for all Dynamo deployment commands. Make sure it's set before running any deployment operations.
### 2. Build the Dynamo Base Image
> [!NOTE]
......
......@@ -142,9 +142,10 @@ The deployment process involves two distinct build steps:
export PROJECT_ROOT=$(pwd)
export KUBE_NS=hello-world # Must match your Kubernetes namespace
export DYNAMO_CLOUD=https://${KUBE_NS}.dev.aire.nvidia.com
dynamo cloud login $DYNAMO_CLOUD
```
The `DYNAMO_CLOUD` environment variable is required for all Dynamo deployment commands. Make sure it's set before running any deployment operations.
2. **Build the Dynamo Base Image**
> [!NOTE]
......
......@@ -185,9 +185,10 @@ You must have first followed the instructions in [deploy/dynamo/helm/README.md](
export PROJECT_ROOT=$(pwd)
export KUBE_NS=dynamo-cloud # Note: This must match the Kubernetes namespace where you installed Dynamo Cloud
export DYNAMO_CLOUD=https://${KUBE_NS}.dev.aire.nvidia.com # Externally accessible endpoint to the `dynamo-store` service within your Dynamo Cloud installation
dynamo cloud login $DYNAMO_CLOUD
```
The `DYNAMO_CLOUD` environment variable is required for all Dynamo deployment commands. Make sure it's set before running any deployment operations.
2. **Build the Dynamo Base Image**
> [!NOTE]
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment