33from clipped .utils .lists import to_list
44
55from polyaxon ._connections import V1Connection , V1ConnectionResource
6+ from polyaxon ._env_vars .keys import ENV_KEYS_SANDBOX_TOKEN
67from polyaxon ._flow import V1Init , V1Plugins
78from polyaxon ._k8s import k8s_schemas
89from polyaxon ._runner .converter import BaseConverter as _BaseConverter
10+ from polyaxon ._sandbox .auth import derive_sandbox_token_from_env
11+ from polyaxon ._sandbox .constants import SANDBOX_BOOTSTRAP_PATH , SANDBOX_PORT
912from polyaxon .exceptions import PolyaxonConverterError
1013
1114
15+ def _has_container_port (ports , port : int ) -> bool :
16+ for container_port in to_list (ports , check_none = True ):
17+ value = getattr (container_port , "container_port" , None )
18+ if value is None and isinstance (container_port , dict ):
19+ value = container_port .get ("containerPort" ) or container_port .get (
20+ "container_port"
21+ )
22+ if str (value ) == str (port ):
23+ return True
24+ return False
25+
26+
27+ def _has_port (ports , port : int ) -> bool :
28+ return any (str (p ) == str (port ) for p in to_list (ports , check_none = True ))
29+
30+
1231class MainConverter (_BaseConverter ):
1332 def _get_main_container (
1433 self ,
@@ -33,6 +52,21 @@ def _get_main_container(
3352 if artifacts_store and not run_path :
3453 raise PolyaxonConverterError ("Run path is required for main container." )
3554
55+ if plugins and plugins .sandbox :
56+ if not main_container :
57+ raise PolyaxonConverterError (
58+ "plugins.sandbox requires a main container."
59+ )
60+ if main_container .args and not main_container .command :
61+ raise PolyaxonConverterError (
62+ "plugins.sandbox does not support args without command."
63+ )
64+ user_argv = to_list (main_container .command , check_none = True ) + to_list (
65+ main_container .args , check_none = True
66+ )
67+ main_container .command = [SANDBOX_BOOTSTRAP_PATH ]
68+ main_container .args = user_argv
69+
3670 if artifacts_store and (
3771 not plugins .collect_artifacts or plugins .mount_artifacts_store
3872 ):
@@ -59,6 +93,7 @@ def _get_main_container(
5993 use_docker_context = plugins .docker ,
6094 use_shm_context = plugins .shm ,
6195 use_tmux_context = plugins .tmux ,
96+ use_sandbox_context = plugins .sandbox ,
6297 run_path = run_path ,
6398 )
6499 if plugins
@@ -82,16 +117,38 @@ def _get_main_container(
82117 secrets = requested_secrets ,
83118 config_maps = requested_config_maps ,
84119 )
120+ if plugins and plugins .sandbox :
121+ env .append (
122+ self ._get_env_var (
123+ name = ENV_KEYS_SANDBOX_TOKEN ,
124+ value = derive_sandbox_token_from_env (self .run_uuid ),
125+ )
126+ )
85127 env += self ._get_resources_env_vars (main_container .resources )
86128
87129 # Env from
88130 env_from = self ._get_env_from_k8s_resources (
89131 secrets = requested_secrets , config_maps = requested_config_maps
90132 )
91133
134+ ports = list (to_list (ports , check_none = True ))
135+ if plugins and plugins .sandbox :
136+ ports = [
137+ port
138+ for port in ports
139+ if not _has_container_port (main_container .ports , port )
140+ ]
141+ if (
142+ plugins
143+ and plugins .sandbox
144+ and not _has_port (ports , SANDBOX_PORT )
145+ and not _has_container_port (main_container .ports , SANDBOX_PORT )
146+ ):
147+ ports .append (SANDBOX_PORT )
148+
92149 ports = [
93150 k8s_schemas .V1ContainerPort (container_port = port )
94- for port in to_list ( ports , check_none = True )
151+ for port in ports
95152 ]
96153
97154 return self ._patch_container (
0 commit comments