Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions exls/nodes/adapters/gateway/sdk/sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def _(sdk_model: SdkCloudNode) -> CloudNode:
instance_type=sdk_model.instance_type,
price_per_hour=sdk_model.price_per_hour,
resources=_map_node_resources_from_sdk_model(sdk_model),
description=sdk_model.description,
warning_message=sdk_model.warning_message,
)

Expand All @@ -104,6 +105,7 @@ def _(sdk_model: SdkSelfManagedNode) -> SelfManagedNode:
username=sdk_model.username,
price_per_hour=sdk_model.price_per_hour,
resources=_map_node_resources_from_sdk_model(sdk_model),
description=sdk_model.description,
warning_message=sdk_model.warning_message,
)

Expand Down Expand Up @@ -154,6 +156,7 @@ def import_selfmanaged_node(
username=parameters.username,
ssh_key_id=parameters.ssh_key_id,
price_per_hour=parameters.price_per_hour,
description=parameters.description,
)
cmd_node_import_ssh: ImportSSHNodeSdkCommand = ImportSSHNodeSdkCommand(
self._nodes_api,
Expand Down
3 changes: 3 additions & 0 deletions exls/nodes/adapters/ui/display/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
"Import Time", value_formatter=format_datetime
),
"status": TableRenderContext.get_column("Status", value_formatter=format_status),
"description": TableRenderContext.get_column(
"Description", value_formatter=format_na
),
"warning_message": TableRenderContext.get_column("Warning", hide_if_empty=True),
"price_per_hour": TableRenderContext.get_column("Price", value_formatter=format_na),
# Hardware Resources
Expand Down
7 changes: 7 additions & 0 deletions exls/nodes/adapters/ui/flows/node_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class FlowSelfmanagedNodeSpecificationDTO(BaseModel):
ssh_key: Optional[Union[NodeSshKey, FlowNodesSshKeySpecification]] = Field(
default=None, description="The SSH key to use"
)
description: StrictStr = Field(default="", description="Description of the node")

def to_domain(self) -> ImportSelfmanagedNodeRequest:
ssh_key_val: Union[str, NodesSshKeySpecification]
Expand All @@ -71,6 +72,7 @@ def to_domain(self) -> ImportSelfmanagedNodeRequest:
username=self.username,
price_per_hour=self.price_per_hour,
ssh_key=ssh_key_val,
description=self.description or None,
)


Expand Down Expand Up @@ -205,6 +207,11 @@ def execute(
),
# We could allow to cancel the subflow of ssh key import but we would need
# to detect the cancellation and jump to a previous step.
TextInputStep[FlowSelfmanagedNodeSpecificationDTO](
key="description",
message="Description (optional):",
default="",
),
]
)

Expand Down
7 changes: 7 additions & 0 deletions exls/nodes/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ def import_selfmanaged_node(
"--ssh-key-name",
help="The name of the SSH key to import",
),
description: Optional[str] = typer.Option(
None,
"--description",
"-d",
help="An optional description for the node to import",
),
):
"""Import a self-managed node into the node pool."""
bundle: NodesBundle = _get_bundle(ctx)
Expand Down Expand Up @@ -281,6 +287,7 @@ def import_selfmanaged_node(
username=username,
price_per_hour=price_per_hour,
ssh_key=final_ssh_key,
description=description,
)
]
)
Expand Down
3 changes: 3 additions & 0 deletions exls/nodes/core/domain.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class BaseNode(BaseModel):
price_per_hour: NonNegativeFloat = Field(
..., description="The price per hour of the node"
)
description: Optional[StrictStr] = Field(
default=None, description="Description of the node"
)
warning_message: Optional[StrictStr] = Field(
default=None, description="Warning message if node is in WARNING status"
)
Expand Down
7 changes: 6 additions & 1 deletion exls/nodes/core/ports/operations.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from abc import ABC, abstractmethod
from typing import List
from typing import List, Optional

from pydantic import BaseModel, Field, NonNegativeFloat, StrictStr

Expand All @@ -21,6 +21,9 @@ class ImportSelfmanagedNodeParameters(BaseModel):
price_per_hour: NonNegativeFloat = Field(
..., description="The price per hour to use"
)
description: Optional[StrictStr] = Field(
default=None, description="Description of the node"
)

@classmethod
def from_request(
Expand All @@ -33,6 +36,7 @@ def from_request(
username=request.username,
ssh_key_id=request.ssh_key,
price_per_hour=request.price_per_hour,
description=request.description,
)

@classmethod
Expand All @@ -45,6 +49,7 @@ def to_request(
username=parameters.username,
ssh_key=parameters.ssh_key_id,
price_per_hour=parameters.price_per_hour,
description=parameters.description,
)


Expand Down
3 changes: 3 additions & 0 deletions exls/nodes/core/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class ImportSelfmanagedNodeRequest(BaseModel):
ssh_key: Union[StrictStr, NodesSshKeySpecification] = Field(
..., description="The SSH key to use"
)
description: Optional[StrictStr] = Field(
default=None, description="Description of the node"
)


class ImportCloudNodeRequest(BaseModel):
Expand Down
1 change: 1 addition & 0 deletions exls/nodes/core/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def _import_single_ssh_key(spec: NodesSshKeySpecification) -> NodeSshKey:
username=node_import_request.username,
ssh_key_id=ssh_key_id,
price_per_hour=node_import_request.price_per_hour,
description=node_import_request.description,
)
)

Expand Down
32 changes: 32 additions & 0 deletions tests/unit/nodes/test_nodes_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,38 @@ def test_import_selfmanaged_nodes_success(
assert result.imported_nodes[0].id == "node-1"
assert len(result.issues) == 0

def test_import_selfmanaged_nodes_forwards_description(
self,
nodes_service: NodesService,
mock_nodes_operations: MagicMock,
mock_ssh_key_provider: MagicMock,
mock_nodes_repository: MagicMock,
sample_ssh_key: NodeSshKey,
sample_self_managed_node: SelfManagedNode,
) -> None:
# Arrange
request = ImportSelfmanagedNodeRequest(
hostname="host1",
endpoint="1.2.3.4",
username="user",
ssh_key="key-1",
price_per_hour=2.1,
description="A100 box, lab 2",
)
mock_ssh_key_provider.list_keys.return_value = [sample_ssh_key]
mock_nodes_operations.import_selfmanaged_node.return_value = "node-1"
mock_nodes_repository.get.return_value = sample_self_managed_node

# Act
nodes_service.import_selfmanaged_nodes([request])

# Assert
mock_nodes_operations.import_selfmanaged_node.assert_called_once()
passed_parameters = (
mock_nodes_operations.import_selfmanaged_node.call_args.kwargs["parameters"]
)
assert passed_parameters.description == "A100 box, lab 2"

def test_import_selfmanaged_nodes_with_new_key(
self,
nodes_service: NodesService,
Expand Down
Loading