4141 create_service_principal_for_rbac ,
4242 repo_url_to_name ,
4343 get_container_app_if_exists ,
44- trigger_workflow
44+ trigger_workflow ,
45+ _ensure_location_allowed ,
46+ _is_resource_provider_registered ,
47+ _register_resource_provider
4548)
4649
47- from ._constants import MAXIMUM_SECRET_LENGTH
50+ from ._constants import MAXIMUM_SECRET_LENGTH , LOG_ANALYTICS_RP
4851
4952from .custom import (
5053 create_managed_environment ,
@@ -62,6 +65,8 @@ def __init__(self, cmd, name: str, location: str, exists: bool = None):
6265 self .cmd = cmd
6366 self .name = name
6467 self .location = _get_default_containerapps_location (cmd , location )
68+ if self .location .lower () == "northcentralusstage" :
69+ self .location = "eastus"
6570 self .exists = exists
6671
6772 self .check_exists ()
@@ -151,7 +156,7 @@ def __init__(
151156 rg = parse_resource_id (name )["resource_group" ]
152157 if resource_group .name != rg :
153158 self .resource_group = ResourceGroup (cmd , rg , location )
154- self .location = _get_default_containerapps_location ( cmd , location )
159+ self .location = location
155160 self .logs_key = logs_key
156161 self .logs_customer_id = logs_customer_id
157162
@@ -164,7 +169,7 @@ def set_name(self, name_or_rid):
164169 self .resource_group = ResourceGroup (
165170 self .cmd ,
166171 rg ,
167- _get_default_containerapps_location ( self .cmd , self . location ) ,
172+ self .location ,
168173 )
169174 else :
170175 self .name = name_or_rid
@@ -188,6 +193,9 @@ def create_if_needed(self, app_name):
188193 ) # TODO use .info()
189194
190195 def create (self ):
196+ self .location = validate_environment_location (self .cmd , self .location )
197+ if not _is_resource_provider_registered (self .cmd , LOG_ANALYTICS_RP ):
198+ _register_resource_provider (self .cmd , LOG_ANALYTICS_RP )
191199 env = create_managed_environment (
192200 self .cmd ,
193201 self .name ,
@@ -290,8 +298,11 @@ def create_acr(self):
290298 registry_rg = self .resource_group
291299 url = self .registry_server
292300 registry_name = url [: url .rindex (".azurecr.io" )]
301+ location = "eastus"
302+ if self .env .location and self .env .location .lower () != "northcentralusstage" :
303+ location = self .env .location
293304 registry_def = create_new_acr (
294- self .cmd , registry_name , registry_rg .name , self . env . location
305+ self .cmd , registry_name , registry_rg .name , location
295306 )
296307 self .registry_server = registry_def .login_server
297308
@@ -435,7 +446,13 @@ def _get_ingress_and_target_port(ingress, target_port, dockerfile_content: "list
435446 return ingress , target_port
436447
437448
438- def _validate_up_args (source , image , repo , registry_server ):
449+ def _validate_up_args (cmd , source , image , repo , registry_server ):
450+ disallowed_params = ["--only-show-errors" , "--output" , "-o" ]
451+ command_args = cmd .cli_ctx .data .get ("safe_params" , [])
452+ for a in disallowed_params :
453+ if a in command_args :
454+ raise ValidationError (f"Argument { a } is not allowed for 'az containerapp up'" )
455+
439456 if not source and not image and not repo :
440457 raise RequiredArgumentMissingError (
441458 "You must specify either --source, --repo, or --image"
@@ -782,3 +799,69 @@ def find_existing_acr(cmd, app: "ContainerApp"):
782799 app .should_create_acr = False
783800 return acr .name , parse_resource_id (acr .id )["resource_group" ]
784801 return None , None
802+
803+
804+ def validate_environment_location (cmd , location ):
805+ from ._constants import MAX_ENV_PER_LOCATION
806+ env_list = list_managed_environments (cmd )
807+
808+ locations = [l ["location" ] for l in env_list ]
809+ locations = list (set (locations )) # remove duplicates
810+
811+ location_count = {}
812+ for loc in locations :
813+ location_count [loc ] = len ([e for e in env_list if e ["location" ] == loc ])
814+
815+ disallowed_locations = []
816+ for _ , value in enumerate (location_count ):
817+ if location_count [value ] > MAX_ENV_PER_LOCATION - 1 :
818+ disallowed_locations .append (value )
819+
820+ res_locations = list_environment_locations (cmd )
821+ res_locations = [l for l in res_locations if l not in disallowed_locations ]
822+
823+ allowed_locs = ", " .join (res_locations )
824+
825+ if location :
826+ try :
827+ _ensure_location_allowed (cmd , location , "Microsoft.App" , "managedEnvironments" )
828+ except Exception : # pylint: disable=broad-except
829+ raise ValidationError ("You cannot create a Containerapp environment in location {}. List of eligible locations: {}." .format (location , allowed_locs ))
830+
831+ if len (res_locations ) > 0 :
832+ if not location :
833+ logger .warning ("Creating environment on location {}." .format (res_locations [0 ]))
834+ return res_locations [0 ]
835+ if location in disallowed_locations :
836+ raise ValidationError ("You have more than {} environments in location {}. List of eligible locations: {}." .format (MAX_ENV_PER_LOCATION , location , allowed_locs ))
837+ return location
838+ else :
839+ raise ValidationError ("You cannot create any more environments. Environments are limited to {} per location in a subscription. Please specify an existing environment using --environment." .format (MAX_ENV_PER_LOCATION ))
840+
841+
842+ def list_environment_locations (cmd ):
843+ from ._utils import providers_client_factory
844+ providers_client = providers_client_factory (cmd .cli_ctx , get_subscription_id (cmd .cli_ctx ))
845+ resource_types = getattr (providers_client .get ("Microsoft.App" ), 'resource_types' , [])
846+ res_locations = []
847+ for res in resource_types :
848+ if res and getattr (res , 'resource_type' , "" ) == "managedEnvironments" :
849+ res_locations = getattr (res , 'locations' , [])
850+
851+ res_locations = [res_loc .lower ().replace (" " , "" ).replace ("(" , "" ).replace (")" , "" ) for res_loc in res_locations if res_loc .strip ()]
852+
853+ return res_locations
854+
855+
856+ def check_env_name_on_rg (cmd , managed_env , resource_group_name , location ):
857+ if location :
858+ _ensure_location_allowed (cmd , location , "Microsoft.App" , "managedEnvironments" )
859+ if managed_env and resource_group_name and location :
860+ env_def = None
861+ try :
862+ env_def = ManagedEnvironmentClient .show (cmd , resource_group_name , parse_resource_id (managed_env )["name" ])
863+ except :
864+ pass
865+ if env_def :
866+ if location != env_def ["location" ]:
867+ raise ValidationError ("Environment {} already exists in resource group {} on location {}, cannot change location of existing environment to {}." .format (parse_resource_id (managed_env )["name" ], resource_group_name , env_def ["location" ], location ))
0 commit comments