From 13fcb5be5d6cc5382a81f02216bc4d238ed07b7a Mon Sep 17 00:00:00 2001 From: Egor Sklyarov Date: Mon, 24 Jul 2023 16:59:35 +0400 Subject: [PATCH 1/2] Set ControlPersist to yes --- cli/dstack/_internal/cli/commands/run/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/dstack/_internal/cli/commands/run/__init__.py b/cli/dstack/_internal/cli/commands/run/__init__.py index a8e4d49e6..41935e297 100644 --- a/cli/dstack/_internal/cli/commands/run/__init__.py +++ b/cli/dstack/_internal/cli/commands/run/__init__.py @@ -407,7 +407,7 @@ def _attach( "UserKnownHostsFile": "/dev/null", "ControlPath": config.ssh_control_path(f"{job.run_name}-host"), "ControlMaster": "auto", - "ControlPersist": "10m", + "ControlPersist": "yes", }, ) if openssh_server_port is None: @@ -431,7 +431,7 @@ def _attach( "UserKnownHostsFile": "/dev/null", "ControlPath": config.ssh_control_path(job.run_name), "ControlMaster": "auto", - "ControlPersist": "10m", + "ControlPersist": "yes", } if backend_type != "local": options["ProxyJump"] = f"{job.run_name}-host" From b56a7f5c71bac1e263c46eb0f3e1c954bf4ef324 Mon Sep 17 00:00:00 2001 From: Egor Sklyarov Date: Mon, 24 Jul 2023 17:35:23 +0400 Subject: [PATCH 2/2] Use identity mapping by default and asteriks for auto-mapping --- cli/dstack/_internal/core/configuration.py | 35 +++++++++++----------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/cli/dstack/_internal/core/configuration.py b/cli/dstack/_internal/core/configuration.py index f616dafe4..20946fe84 100644 --- a/cli/dstack/_internal/core/configuration.py +++ b/cli/dstack/_internal/core/configuration.py @@ -36,17 +36,20 @@ def parse(cls, v: str) -> "PortMapping": """ Possible values: - 8080 - - :8080 - 80:8080 + - *:8080 """ - r = re.search(r"^(?:(\d+)?:)?(\d+)?$", v) + r = re.search(r"^(?:(\d+|\*):)?(\d+)?$", v) if not r: raise ValueError(v) local_port, container_port = r.groups() - return PortMapping( - local_port=None if local_port is None else int(local_port), - container_port=container_port, - ) + if local_port is None: # identity mapping by default + local_port = int(container_port) + elif local_port == "*": + local_port = None + else: + local_port = int(local_port) + return PortMapping(local_port=local_port, container_port=int(container_port)) class Artifact(ForbidExtra): @@ -76,7 +79,7 @@ class BaseConfiguration(ForbidExtra): Field(description="The major version of Python\nMutually exclusive with the image"), ] ports: Annotated[ - List[Union[constr(regex=r"^(?:([0-9]+)?:)?[0-9]+$"), ValidPort, PortMapping]], + List[Union[constr(regex=r"^(?:([0-9]+|\*):)?[0-9]+$"), ValidPort, PortMapping]], Field(description="Port numbers/mapping to expose"), ] = [] env: Annotated[ @@ -102,17 +105,13 @@ def convert_python(cls, v, values) -> Optional[PythonVersion]: return PythonVersion(v) return v - @validator("ports") - def convert_ports(cls, v) -> List[PortMapping]: - ports = [] - for i in v: - if isinstance(i, int): - ports.append(PortMapping(container_port=i)) - elif isinstance(i, str): - ports.append(PortMapping.parse(i)) - else: - ports.append(i) - return ports + @validator("ports", each_item=True) + def convert_ports(cls, v) -> PortMapping: + if isinstance(v, int): + return PortMapping(local_port=v, container_port=v) + elif isinstance(v, str): + return PortMapping.parse(v) + return v @validator("env") def convert_env(cls, v) -> Dict[str, str]: