2121from neuro_config_client import Cluster , ResourcePreset , TPUResource
2222from yarl import URL
2323
24- from platform_api .config import NO_ORG , STORAGE_URI_SCHEME , Config
24+ from platform_api .config import STORAGE_URI_SCHEME , Config
2525from platform_api .log import log_debug_time
2626from platform_api .orchestrator .job import (
2727 JOB_NAME_SEPARATOR ,
@@ -250,16 +250,15 @@ def _set_preset_resources(payload: dict[str, Any]) -> dict[str, Any]:
250250def create_job_cluster_org_name_validator (
251251 * ,
252252 default_cluster_name : str ,
253- default_org_name : str | None ,
253+ default_org_name : str ,
254254 default_project_name : str ,
255255) -> t .Trafaret :
256256 return t .Dict (
257257 {
258258 t .Key (
259259 "cluster_name" , default = default_cluster_name
260260 ): create_cluster_name_validator (),
261- t .Key ("org_name" , default = default_org_name ): create_org_name_validator ()
262- | t .Null ,
261+ t .Key ("org_name" , default = default_org_name ): create_org_name_validator (),
263262 t .Key (
264263 "project_name" , default = default_project_name
265264 ): create_project_name_validator (),
@@ -550,7 +549,7 @@ def infer_permissions_from_container(
550549 container : Container ,
551550 registry_host : str ,
552551 cluster_name : str ,
553- org_name : str | None ,
552+ org_name : str ,
554553 * ,
555554 project_name : str ,
556555) -> list [Permission ]:
@@ -563,7 +562,7 @@ def infer_permissions_from_container(
563562 if container .belongs_to_registry (registry_host ):
564563 permissions .append (
565564 Permission (
566- uri = str (container .to_image_uri (registry_host , cluster_name )),
565+ uri = str (container .to_image_uri (registry_host , cluster_name , org_name )),
567566 action = "read" ,
568567 )
569568 )
@@ -695,26 +694,51 @@ async def create_job(self, request: aiohttp.web.Request) -> aiohttp.web.Response
695694 cluster_configs = await self ._jobs_service .get_user_cluster_configs (user )
696695 self ._check_user_can_submit_jobs (cluster_configs )
697696 default_cluster_name = cluster_configs [0 ].config .name
698- cluster_for_default_org = (
699- orig_payload .get ("cluster_name" ) or default_cluster_name
700- )
701- cluster_config_for_default_org = next (
702- (
703- cluster_config
704- for cluster_config in cluster_configs
705- if cluster_config .config .name == cluster_for_default_org
706- ),
707- None ,
708- )
709- # always use NO_ORG as default if a user has direct access to cluster.
710- # if cluster_config_for_default_org is None,
711- # the validator below will raise an error
712- default_org_name = None
713- if (
714- cluster_config_for_default_org is not None
715- and None not in cluster_config_for_default_org .orgs
716- ):
717- default_org_name = cluster_config_for_default_org .orgs [0 ]
697+
698+ # Check if user explicitly specified a cluster they don't have access to
699+ requested_cluster = orig_payload .get ("cluster_name" )
700+ if requested_cluster is not None :
701+ cluster_config_for_default_org = next (
702+ (
703+ cluster_config
704+ for cluster_config in cluster_configs
705+ if cluster_config .config .name == requested_cluster
706+ ),
707+ None ,
708+ )
709+ if cluster_config_for_default_org is None :
710+ raise aiohttp .web .HTTPForbidden (
711+ text = json .dumps (
712+ {
713+ "error" : (
714+ "User is not allowed to submit jobs to the "
715+ "specified cluster"
716+ )
717+ }
718+ ),
719+ content_type = "application/json" ,
720+ )
721+ if not cluster_config_for_default_org .orgs :
722+ raise aiohttp .web .HTTPForbidden (
723+ text = json .dumps (
724+ {
725+ "error" : (
726+ "User is not allowed to submit jobs to the "
727+ "specified cluster as a member of given organization"
728+ )
729+ }
730+ ),
731+ content_type = "application/json" ,
732+ )
733+ else :
734+ cluster_config_for_default_org = cluster_configs [0 ]
735+ if not cluster_config_for_default_org .orgs :
736+ raise aiohttp .web .HTTPForbidden (
737+ text = json .dumps ({"error" : "User must have at least one org" }),
738+ content_type = "application/json" ,
739+ )
740+
741+ default_org_name = cluster_config_for_default_org .orgs [0 ]
718742
719743 job_cluster_org_name_validator = create_job_cluster_org_name_validator (
720744 default_cluster_name = default_cluster_name ,
@@ -1108,7 +1132,7 @@ def create_from_query(self, query: MultiDictProxy) -> JobFilter: # type: ignore
11081132 for cluster_name in query .getall ("cluster_name" , [])
11091133 }
11101134 orgs = {
1111- self ._parse_org_name (org_name )
1135+ self ._org_name_validator . check (org_name )
11121136 for org_name in query .getall ("org_name" , [])
11131137 }
11141138 projects = {
@@ -1154,13 +1178,6 @@ def create_from_query(self, query: MultiDictProxy) -> JobFilter: # type: ignore
11541178 ** bool_filters , # type: ignore
11551179 )
11561180
1157- def _parse_org_name (self , org_name : str ) -> str | None :
1158- return (
1159- None
1160- if org_name .upper () == NO_ORG
1161- else self ._org_name_validator .check (org_name )
1162- )
1163-
11641181
11651182@dataclass (frozen = True )
11661183class BulkJobFilter :
@@ -1180,11 +1197,11 @@ def __init__(
11801197 self ._has_access_to_all : bool = False
11811198 self ._has_clusters_shared_all : bool = False
11821199 self ._has_orgs_shared_all : bool = False
1183- self ._clusters_shared_any : dict [str , dict [str | None , dict [str , set [str ]]]] = (
1200+ self ._clusters_shared_any : dict [str , dict [str , dict [str , set [str ]]]] = (
11841201 defaultdict (lambda : defaultdict (lambda : defaultdict (set )))
11851202 )
11861203 self ._projects_shared_any : set [str ] = set ()
1187- self ._orgs_shared_any : set [str | None ] = set ()
1204+ self ._orgs_shared_any : set [str ] = set ()
11881205 self ._shared_ids : set [str ] = set ()
11891206
11901207 def build (self ) -> BulkJobFilter :
@@ -1239,10 +1256,6 @@ def _traverse_clusters(self, tree: ClientAccessSubTreeView) -> None:
12391256 self ._clusters_shared_any [cluster_name ] = {}
12401257 else :
12411258 self ._traverse_orgs (sub_tree , cluster_name )
1242- if self ._query_filter .orgs and None not in self ._query_filter .orgs :
1243- # skipping None org
1244- continue
1245- self ._traverse_projects (sub_tree , cluster_name , None )
12461259
12471260 def _traverse_orgs (self , tree : ClientAccessSubTreeView , cluster_name : str ) -> None :
12481261 for org_name , sub_tree in tree .children .items ():
@@ -1267,7 +1280,7 @@ def _traverse_projects(
12671280 self ,
12681281 tree : ClientAccessSubTreeView ,
12691282 cluster_name : str ,
1270- org_name : str | None ,
1283+ org_name : str ,
12711284 ) -> None :
12721285 for project , sub_tree in tree .children .items ():
12731286 if not sub_tree .can_list ():
@@ -1294,7 +1307,7 @@ def _traverse_jobs(
12941307 self ,
12951308 tree : ClientAccessSubTreeView ,
12961309 cluster_name : str ,
1297- org_name : str | None ,
1310+ org_name : str ,
12981311 project_name : str ,
12991312 ) -> None :
13001313 for name , sub_tree in tree .children .items ():
@@ -1365,7 +1378,7 @@ def _create_bulk_filter(self) -> JobFilter | None:
13651378
13661379 def _optimize_clusters_projects (
13671380 self ,
1368- orgs : AbstractSet [str | None ],
1381+ orgs : AbstractSet [str ],
13691382 projects : AbstractSet [str ],
13701383 name : str | None ,
13711384 ) -> None :
0 commit comments