diff --git a/src/dstack/_internal/cli/commands/pool.py b/src/dstack/_internal/cli/commands/pool.py index fa8fe1ed9..c6990d8b7 100644 --- a/src/dstack/_internal/cli/commands/pool.py +++ b/src/dstack/_internal/cli/commands/pool.py @@ -1,5 +1,6 @@ import argparse import getpass +import ipaddress import time import urllib.parse from pathlib import Path @@ -291,6 +292,21 @@ def _add(self, args: argparse.Namespace) -> None: def _add_ssh(self, args: argparse.Namespace) -> None: super()._command(args) + # validate network + if args.network is not None: + try: + network = ipaddress.ip_network(args.network) + except ValueError as e: + console.print( + f"[error]Can't parse network. The address must be in the format /. Error: {e}[/]" + ) + return + if not network.is_private: + console.print( + f"[error]The network must be private network. The {network} is not private[/]" + ) + return + ssh_keys = [] if args.ssh_identity_file: try: diff --git a/src/dstack/_internal/server/background/tasks/process_instances.py b/src/dstack/_internal/server/background/tasks/process_instances.py index a07241529..b541529d9 100644 --- a/src/dstack/_internal/server/background/tasks/process_instances.py +++ b/src/dstack/_internal/server/background/tasks/process_instances.py @@ -100,7 +100,10 @@ async def process_instances() -> None: ): await add_remote(instance.id) - if instance.status == InstanceStatus.PENDING: + if ( + instance.status == InstanceStatus.PENDING + and instance.remote_connection_info is None + ): await create_instance(instance.id) if instance.status in ( @@ -257,6 +260,23 @@ async def add_remote(instance_id: UUID) -> None: network=instance_network, addresses=host_info.get("addresses", []), ) + if instance_network is not None and internal_ip is None: + instance.status = InstanceStatus.TERMINATED + instance.deleted = True + instance.deleted_at = get_current_datetime() + instance.termination_reason = ( + "Unable to locate the internal ip-address for the given network" + ) + await session.commit() + logger.warning( + "Failed to configure internal ip-address on instance %s. Terminate it", + instance.name, + extra={ + "instance_name": instance.name, + "instance_status": InstanceStatus.TERMINATED.value, + }, + ) + return region = instance.region diff --git a/src/dstack/_internal/utils/network.py b/src/dstack/_internal/utils/network.py index 411da7cf1..e42d9b028 100644 --- a/src/dstack/_internal/utils/network.py +++ b/src/dstack/_internal/utils/network.py @@ -13,12 +13,16 @@ def get_ip_from_network(network: Optional[str], addresses: Sequence[str]) -> Opt internal_network = None if network is not None: + if not ip_addresses: + return None try: internal_network = ipaddress.ip_network(network) except ValueError: - pass + return None + + if not internal_network.is_private: + return None - if internal_network is not None: for internal_ip in ip_addresses: if internal_ip in internal_network: return str(internal_ip)