Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Envdefaultlocation #145

Merged
merged 4 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Release History
0.3.10
++++++
* 'az containerapp create': Fix bug with --image caused by assuming a value for --registry-server
* 'az containerapp hostname bind': Remove location set automatically by resource group
* 'az containerapp env create': Add location validation

0.3.9
++++++
Expand Down
4 changes: 1 addition & 3 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

from knack.arguments import CLIArgumentType

from azure.cli.core.commands.validators import get_default_location_from_resource_group
from azure.cli.core.commands.parameters import (resource_group_name_type, get_location_type,
file_type,
get_three_state_flag, get_enum_type, tags_type)
# from azure.cli.core.commands.validators import get_default_location_from_resource_group

from ._validators import (validate_memory, validate_cpu, validate_managed_env_name_or_id, validate_registry_server,
validate_registry_user, validate_registry_pass, validate_target_port, validate_ingress)
Expand Down Expand Up @@ -338,7 +336,7 @@ def load_arguments(self, _):

with self.argument_context('containerapp hostname list') as c:
c.argument('name', id_part=None)
c.argument('location', arg_type=get_location_type(self.cli_ctx), validator=get_default_location_from_resource_group)
c.argument('location', arg_type=get_location_type(self.cli_ctx))

with self.argument_context('containerapp hostname delete') as c:
c.argument('hostname', help='The custom domain name.')
55 changes: 2 additions & 53 deletions src/containerapp/azext_containerapp/_up_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
get_container_app_if_exists,
trigger_workflow,
_ensure_location_allowed,
register_provider_if_needed
register_provider_if_needed,
validate_environment_location
)

from ._constants import MAXIMUM_SECRET_LENGTH, LOG_ANALYTICS_RP, CONTAINER_APPS_RP, ACR_IMAGE_SUFFIX, MAXIMUM_CONTAINER_APP_NAME_LENGTH
Expand Down Expand Up @@ -810,58 +811,6 @@ def find_existing_acr(cmd, app: "ContainerApp"):
return None, None


def validate_environment_location(cmd, location):
from ._constants import MAX_ENV_PER_LOCATION
env_list = list_managed_environments(cmd)

locations = [loc["location"] for loc in env_list]
locations = list(set(locations)) # remove duplicates

location_count = {}
for loc in locations:
location_count[loc] = len([e for e in env_list if e["location"] == loc])

disallowed_locations = []
for _, value in enumerate(location_count):
if location_count[value] > MAX_ENV_PER_LOCATION - 1:
disallowed_locations.append(value)

res_locations = list_environment_locations(cmd)
res_locations = [loc for loc in res_locations if loc not in disallowed_locations]

allowed_locs = ", ".join(res_locations)

if location:
try:
_ensure_location_allowed(cmd, location, CONTAINER_APPS_RP, "managedEnvironments")
except Exception as e: # pylint: disable=broad-except
raise ValidationError("You cannot create a Containerapp environment in location {}. List of eligible locations: {}.".format(location, allowed_locs)) from e

if len(res_locations) > 0:
if not location:
logger.warning("Creating environment on location {}.".format(res_locations[0]))
return res_locations[0]
if location in disallowed_locations:
raise ValidationError("You have more than {} environments in location {}. List of eligible locations: {}.".format(MAX_ENV_PER_LOCATION, location, allowed_locs))
return location
else:
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))


def list_environment_locations(cmd):
from ._utils import providers_client_factory
providers_client = providers_client_factory(cmd.cli_ctx, get_subscription_id(cmd.cli_ctx))
resource_types = getattr(providers_client.get(CONTAINER_APPS_RP), 'resource_types', [])
res_locations = []
for res in resource_types:
if res and getattr(res, 'resource_type', "") == "managedEnvironments":
res_locations = getattr(res, 'locations', [])

res_locations = [res_loc.lower().replace(" ", "").replace("(", "").replace(")", "") for res_loc in res_locations if res_loc.strip()]

return res_locations


def check_env_name_on_rg(cmd, managed_env, resource_group_name, location):
if location:
_ensure_location_allowed(cmd, location, CONTAINER_APPS_RP, "managedEnvironments")
Expand Down
52 changes: 52 additions & 0 deletions src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1463,3 +1463,55 @@ def is_registry_msi_system(identity):
if identity is None:
return False
return identity.lower() == "system"


def validate_environment_location(cmd, location):
from ._constants import MAX_ENV_PER_LOCATION
from .custom import list_managed_environments
env_list = list_managed_environments(cmd)

locations = [loc["location"] for loc in env_list]
locations = list(set(locations)) # remove duplicates

location_count = {}
for loc in locations:
location_count[loc] = len([e for e in env_list if e["location"] == loc])

disallowed_locations = []
for _, value in enumerate(location_count):
if location_count[value] > MAX_ENV_PER_LOCATION - 1:
disallowed_locations.append(value)

res_locations = list_environment_locations(cmd)
res_locations = [loc for loc in res_locations if loc not in disallowed_locations]

allowed_locs = ", ".join(res_locations)

if location:
try:
_ensure_location_allowed(cmd, location, CONTAINER_APPS_RP, "managedEnvironments")
except Exception as e: # pylint: disable=broad-except
raise ValidationError("You cannot create a Containerapp environment in location {}. List of eligible locations: {}.".format(location, allowed_locs)) from e

if len(res_locations) > 0:
if not location:
logger.warning("Creating environment on location %s.", res_locations[0])
return res_locations[0]
if location in disallowed_locations:
raise ValidationError("You have more than {} environments in location {}. List of eligible locations: {}.".format(MAX_ENV_PER_LOCATION, location, allowed_locs))
return location
else:
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))


def list_environment_locations(cmd):
providers_client = providers_client_factory(cmd.cli_ctx, get_subscription_id(cmd.cli_ctx))
resource_types = getattr(providers_client.get(CONTAINER_APPS_RP), 'resource_types', [])
res_locations = []
for res in resource_types:
if res and getattr(res, 'resource_type', "") == "managedEnvironments":
res_locations = getattr(res, 'locations', [])

res_locations = [res_loc.lower().replace(" ", "").replace("(", "").replace(")", "") for res_loc in res_locations if res_loc.strip()]

return res_locations
5 changes: 3 additions & 2 deletions src/containerapp/azext_containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
validate_container_app_name, _update_weights, get_vnet_location, register_provider_if_needed,
generate_randomized_cert_name, _get_name, load_cert_file, check_cert_name_availability,
validate_hostname, patch_new_custom_domain, get_custom_domains, _validate_revision_name, set_managed_identity,
create_acrpull_role_assignment, is_registry_msi_system, clean_null_values, _populate_secret_values)
create_acrpull_role_assignment, is_registry_msi_system, clean_null_values, _populate_secret_values,
validate_environment_location)
from ._validators import validate_create
from ._ssh_utils import (SSH_DEFAULT_ENCODING, WebSocketConnection, read_ssh, get_stdin_writer, SSH_CTRL_C_MSG,
SSH_BACKUP_ENCODING)
Expand Down Expand Up @@ -917,7 +918,7 @@ def create_managed_environment(cmd,
else:
location = vnet_location

location = location or _get_location_from_resource_group(cmd.cli_ctx, resource_group_name)
location = validate_environment_location(cmd, location)

register_provider_if_needed(cmd, CONTAINER_APPS_RP)
_ensure_location_allowed(cmd, location, CONTAINER_APPS_RP, "managedEnvironments")
Expand Down