Skip to content

Commit

Permalink
P1s (#43)
Browse files Browse the repository at this point in the history
* Skeleton code

* az containerapp env show

* List kube/managed environments

* Create kube environment, wait doesn't work yet

* Update containerapp stubs (check if it is supported now)

* Containerapp env delete, polling not working yet

* Added polling for create and delete

* Use Microsoft.App RP for show, list, delete command

* Create containerapp env using Microsoft.App RP

* Add optional containerapp env create arguments

* Remove old kube environment code, naming fixes

* Containerapp create almost done

* Done containerapp create, except for --yaml. Need to test

* Containerapp show, list

* Fix helptext

* Containerapp delete

* Containerapp update. Needs secrets api to be implemented, and testing

* Add scale command

* Various validations, small fixes

* listSecrets API for updates, autogen log analytics for env

* Use space delimiter for secrets and env variables

* Verify sub is registered to Microsoft.ContainerRegistration if creating vnet enabled env, remove logs-type parameter

* Containerapp create --yaml

* Fix updating registry to do create or update

* Fix containerapp update command. Add image-name parameter to support multi container updates. Fix updating registries, containers and secrets

* started update with --yaml. Need to do create or update for when an attribute is a list of items

* use space delimiter for startup_command and args, instead of comma delimiter

* Traffic weights

* List and show revisions

* az containerapp revision restart, activate, deactivate

* Add ability for users to clear args/command in az containerapp update

* Various fixes, traffic weights fixes

* Verify subnet subscription is registered to Microsoft.ContainerServices

* GitHub Actions Update (#17)

* Added models. Finished transferring Calvin's previous work.

* Updated wrong models.

* Updated models in custom.py, added githubactionclient.

* Updated envelope to be correct.

* Small bug fixes.

* Updated error handling. Fixed bugs. Initial working state.

* Added better error handling.

* Added error messages for tokens with inappropriate access rights.

* Added back get_acr_cred.

* Fixed problems from merge conflict.

* Updated names of imports from ._models.py to fix pylance erros.

* Removed random imports.

Co-authored-by: Haroon Feisal <[email protected]>

* Remove --location since location must be same as managed env

* Add options for flag names: --env-vars and --registry-srever

* Empty string to clear env_vars

* Default revisions_mode to single

* Infer acr credentials if it is acr and credentials are not provided

* fix help msg

* if image is hosted on acr, and no registry server is supplied, infer the registry server

* Added subgroups (Ingress, Registry, Secret) and updated revisions (#18)

* Added ingress subgroup.

* Added help for ingress.

* Fixed ingress traffic help.

* Added registry commands.

* Updated registry remove util to clear secrets if none remaining. Added warning when updating existing registry. Added registry help.

* Changed registry delete to remove.

* Added error message if user tries to remove non assigned registry.

* Changed registry add back to registry set.

* Added secret subgroup commands.

* Removed yaml support from secret set.

* Changed secret add to secret set. Updated consistency between secret set and secret delete. Added secret help. Require at least one secret passed with --secrets for secret commands.

* Changed param name for secret delete from --secrets to --secret-names. Updated help.

* Changed registry remove to registry delete.

* Fixed bug in registry delete.

* Added revision mode set and revision copy.

* Modified update_containerapp_yaml to support updating from non-current revision.

Authored-by: Haroon Feisal <[email protected]>

* More p0 fixes (#20)

* Remove --registry-login-server, only allow --registry-server

* Rename --environment-variables to --env-vars

* If no image is supplied, use default quickstart image

* Update help text (#21)

* Update help text

* Update punctuation

* master -> main

* New 1.0.1 version

* Added identity commands + --assign-identity flag to containerapp create (#8)

* Added identity show and assign.

* Finisheed identity remove.

* Added helps, updated identity remove to work with identity names instead of requiring identity resource ids.

* Moved helper function to utils.

* Require --identities flag when removing identities.

* Added message for assign identity with no specified identity.

* Added --assign-identity flag to containerapp create.

* Moved assign-identity flag to containerapp create.

* Fixed small logic error on remove identities when passing duplicate identities. Added warnings for certain edge cases.

* Updated param definition for identity assign --identity default.

* Added identity examples in help.

* Made sure secrets were not removed when assigning identities. Added tolerance for [system] passed with capital letters.

* Fixed error from merge.

Co-authored-by: Haroon Feisal <[email protected]>

* Dapr Commands (#23)

* Added ingress subgroup.

* Added help for ingress.

* Fixed ingress traffic help.

* Added registry commands.

* Updated registry remove util to clear secrets if none remaining. Added warning when updating existing registry. Added registry help.

* Changed registry delete to remove.

* Added error message if user tries to remove non assigned registry.

* Changed registry add back to registry set.

* Added secret subgroup commands.

* Removed yaml support from secret set.

* Changed secret add to secret set. Updated consistency between secret set and secret delete. Added secret help. Require at least one secret passed with --secrets for secret commands.

* Changed param name for secret delete from --secrets to --secret-names. Updated help.

* Changed registry remove to registry delete.

* Fixed bug in registry delete.

* Added revision mode set and revision copy.

* Added dapr enable and dapr disable. Need to test more.

* Added list, show, set dapr component. Added dapr enable, disable.

* Added delete dapr delete.

* Added helps and param text.

* Changed dapr delete to dapr remove to match with dapr set.

* Commented out managed identity for whl file.

* Uncommented.

Co-authored-by: Haroon Feisal <[email protected]>

* Rename --image-name to --container-name

* Remove allowInsecure since it was messing with the api parsing

* Fix for env var being empty string

* Rename to --dapr-instrumentation-key, only infer ACR credentials if --registry-server is provided

* Remove az containerapp scale

* Fix delete containerapp errors

* Remove ingress, dapr flags from az containerapp update/revision copy

* Fix revision list -o table

* Help text fix

* Bump extension to 0.1.2

* Update managed identities and Dapr help text (#25)

* Update managed identities and Dapr help text

* Update Dapr flags

* Add secretref note

* Env var options + various bug fixes (#26)

* Moved dapr arguments to env as a subgroup.

* Added env variable options.

* Changed revision mode set to revision set-mode.

* Added env var options to revision copy.

* Fixed revision copy bug related to env secret refs.

* Changed registry and secret delete to remove. Added registry param helps. Removed replica from table output and added trafficWeight.

* Updating warning text.

* Updated warning text once more.

* Made name optional for revision copy if from-revision flag is passed.

Co-authored-by: Haroon Feisal <[email protected]>

* Fixed style issues, various bug fixes (#27)

* Moved dapr arguments to env as a subgroup.

* Added env variable options.

* Changed revision mode set to revision set-mode.

* Added env var options to revision copy.

* Fixed revision copy bug related to env secret refs.

* Changed registry and secret delete to remove. Added registry param helps. Removed replica from table output and added trafficWeight.

* Updating warning text.

* Updated warning text once more.

* Made name optional for revision copy if from-revision flag is passed.

* Fixed whitespace style issues.

* Styled clients and utils to pass pylint.

* Finished client.py pylint fixes.

* Fixed pylint issues.

* Fixed flake8 commands and custom.

* Fixed flake issues in src.

* Added license header to _sdk_models.

* Added confirmation for containerapp delete.

Co-authored-by: Haroon Feisal <[email protected]>

* Update src/containerapp/azext_containerapp/tests/latest/test_containerapp_scenario.py

Co-authored-by: Xing Zhou <[email protected]>

* Specific Error Types + Bugfixes (Help, remove app-subnet-resource-id, removed env-var alias, added help text for --name) (#28)

* Moved dapr arguments to env as a subgroup.

* Added env variable options.

* Changed revision mode set to revision set-mode.

* Added env var options to revision copy.

* Fixed revision copy bug related to env secret refs.

* Changed registry and secret delete to remove. Added registry param helps. Removed replica from table output and added trafficWeight.

* Updating warning text.

* Updated warning text once more.

* Made name optional for revision copy if from-revision flag is passed.

* Fixed whitespace style issues.

* Styled clients and utils to pass pylint.

* Finished client.py pylint fixes.

* Fixed pylint issues.

* Fixed flake8 commands and custom.

* Fixed flake issues in src.

* Added license header to _sdk_models.

* Added confirmation for containerapp delete.

* Update helps for identity, revision. Removed env-var alias for set-env-vars. Added name param help.

* Removed app-subnet-resource-id.

* Updated infrastructure subnet param help.

* Check if containerapp resource exists before attempting to delete.

* Added check before deleting managed env.

* Changed error types to be more specific.

* Removed check before deletion. Removed comments.

Co-authored-by: Haroon Feisal <[email protected]>

* Reset to 0.1.0 version, remove unneeded options-list

* Update min cli core version

* Fixed style issues. (#30)

Co-authored-by: Haroon Feisal <[email protected]>

* Fix linter issues

* Use custom-show-command

* Removed --ids from revision, secret, registry list.

* Add linter exclusions

* Fix polling on delete containerapp

* Fix error handling

* Add Container App Service

* Fix flake linter

* Fix help text

* Mark extension as preview

* Add python 3.9 and 3.10 as supported

* Remove registries and secrets from az containerapp update, in favor of registry and secret subgroup

* Fix YAML not working

* Move import to inside deserialize function

* Ingress enable --transport default. Secret list returns empty array. Secret update prints message saying user needs to restart their apps. Added show-values flag to secret list. Fixed yaml datetime field issues, replaced x00 values that also came up during testing.

* Fixed dapr in create.

* Revert "Ingress enable --transport default. Secret list returns empty array. Secret update prints message saying user needs to restart their apps. Added show-values flag to secret list. Fixed yaml datetime field issues, replaced x00 values that also came up during testing."

This reverts commit 51bc543.

* Revert "Fixed dapr in create."

This reverts commit 37030ad.

* Ingress enable --transport default. Secret list returns empty array. Secret update prints message saying user needs to restart their apps. Added show-values flag to secret list. Fixed yaml datetime field issues, replaced x00 values that also came up during testing.

* Reduced redundant code between revision copy and containerapp update.

* Fixed merge issues.

* Fixed merge conflicts, moved helper function

Co-authored-by: Calvin Chan <[email protected]>
Co-authored-by: Haroon Feisal <[email protected]>
Co-authored-by: Anthony Chu <[email protected]>
Co-authored-by: Xing Zhou <[email protected]>
  • Loading branch information
5 people authored Apr 6, 2022
1 parent 5d0bef3 commit ad34e67
Showing 1 changed file with 105 additions and 196 deletions.
301 changes: 105 additions & 196 deletions src/containerapp/azext_containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,33 +429,34 @@ def create_containerapp(cmd,
handle_raw_exception(e)


def update_containerapp(cmd,
name,
resource_group_name,
yaml=None,
image=None,
container_name=None,
min_replicas=None,
max_replicas=None,
set_env_vars=None,
remove_env_vars=None,
replace_env_vars=None,
remove_all_env_vars=False,
cpu=None,
memory=None,
revision_suffix=None,
startup_command=None,
args=None,
tags=None,
no_wait=False):
def update_containerapp_logic(cmd,
name,
resource_group_name,
yaml=None,
image=None,
container_name=None,
min_replicas=None,
max_replicas=None,
set_env_vars=None,
remove_env_vars=None,
replace_env_vars=None,
remove_all_env_vars=False,
cpu=None,
memory=None,
revision_suffix=None,
startup_command=None,
args=None,
tags=None,
no_wait=False,
from_revision=None):
_validate_subscription_registered(cmd, "Microsoft.App")

if yaml:
if image or min_replicas or max_replicas or\
set_env_vars or remove_env_vars or replace_env_vars or remove_all_env_vars or cpu or memory or\
startup_command or args or tags:
logger.warning('Additional flags were passed along with --yaml. These flags will be ignored, and the configuration defined in the yaml will be used instead')
return update_containerapp_yaml(cmd=cmd, name=name, resource_group_name=resource_group_name, file_name=yaml, no_wait=no_wait)
return update_containerapp_yaml(cmd=cmd, name=name, resource_group_name=resource_group_name, file_name=yaml, no_wait=no_wait, from_revision=from_revision)

containerapp_def = None
try:
Expand All @@ -466,6 +467,16 @@ def update_containerapp(cmd,
if not containerapp_def:
raise ResourceNotFoundError("The containerapp '{}' does not exist".format(name))

if from_revision:
try:
r = ContainerAppClient.show_revision(cmd=cmd, resource_group_name=resource_group_name, container_app_name=name, name=from_revision)
except CLIError as e:
# Error handle the case where revision not found?
handle_raw_exception(e)

_update_revision_env_secretrefs(r["properties"]["template"]["containers"], name)
containerapp_def["properties"]["template"] = r["properties"]["template"]

# Doing this while API has bug. If env var is an empty string, API doesn't return "value" even though the "value" should be an empty string
if "properties" in containerapp_def and "template" in containerapp_def["properties"] and "containers" in containerapp_def["properties"]["template"]:
for container in containerapp_def["properties"]["template"]["containers"]:
Expand Down Expand Up @@ -613,6 +624,48 @@ def update_containerapp(cmd,
handle_raw_exception(e)


def update_containerapp(cmd,
name,
resource_group_name,
yaml=None,
image=None,
container_name=None,
min_replicas=None,
max_replicas=None,
set_env_vars=None,
remove_env_vars=None,
replace_env_vars=None,
remove_all_env_vars=False,
cpu=None,
memory=None,
revision_suffix=None,
startup_command=None,
args=None,
tags=None,
no_wait=False):
_validate_subscription_registered(cmd, "Microsoft.App")

return update_containerapp_logic(cmd,
name,
resource_group_name,
yaml,
image,
container_name,
min_replicas,
max_replicas,
set_env_vars,
remove_env_vars,
replace_env_vars,
remove_all_env_vars,
cpu,
memory,
revision_suffix,
startup_command,
args,
tags,
no_wait)


def show_containerapp(cmd, name, resource_group_name):
_validate_subscription_registered(cmd, "Microsoft.App")

Expand Down Expand Up @@ -1195,177 +1248,26 @@ def copy_revision(cmd,
if not name:
name = _get_app_from_revision(from_revision)

if yaml:
if image or min_replicas or max_replicas or\
set_env_vars or replace_env_vars or remove_env_vars or \
remove_all_env_vars or cpu or memory or \
startup_command or args or tags:
logger.warning('Additional flags were passed along with --yaml. These flags will be ignored, and the configuration defined in the yaml will be used instead')
return update_containerapp_yaml(cmd=cmd, name=name, resource_group_name=resource_group_name, file_name=yaml, from_revision=from_revision, no_wait=no_wait)

containerapp_def = None
try:
containerapp_def = ContainerAppClient.show(cmd=cmd, resource_group_name=resource_group_name, name=name)
except:
pass

if not containerapp_def:
raise ResourceNotFoundError("The containerapp '{}' does not exist".format(name))

if from_revision:
try:
r = ContainerAppClient.show_revision(cmd=cmd, resource_group_name=resource_group_name, container_app_name=name, name=from_revision)
except CLIError as e:
# Error handle the case where revision not found?
handle_raw_exception(e)

_update_revision_env_secretrefs(r["properties"]["template"]["containers"], name)
containerapp_def["properties"]["template"] = r["properties"]["template"]

# Doing this while API has bug. If env var is an empty string, API doesn't return "value" even though the "value" should be an empty string
if "properties" in containerapp_def and "template" in containerapp_def["properties"] and "containers" in containerapp_def["properties"]["template"]:
for container in containerapp_def["properties"]["template"]["containers"]:
if "env" in container:
for e in container["env"]:
if "value" not in e:
e["value"] = ""

update_map = {}
update_map['scale'] = min_replicas or max_replicas
update_map['container'] = image or container_name or set_env_vars or replace_env_vars or remove_env_vars or remove_all_env_vars or cpu or memory or startup_command is not None or args is not None

if tags:
_add_or_update_tags(containerapp_def, tags)

if revision_suffix is not None:
containerapp_def["properties"]["template"]["revisionSuffix"] = revision_suffix

# Containers
if update_map["container"]:
if not container_name:
if len(containerapp_def["properties"]["template"]["containers"]) == 1:
container_name = containerapp_def["properties"]["template"]["containers"][0]["name"]
else:
raise ValidationError("Usage error: --image-name is required when adding or updating a container")

# Check if updating existing container
updating_existing_container = False
for c in containerapp_def["properties"]["template"]["containers"]:
if c["name"].lower() == container_name.lower():
updating_existing_container = True

if image is not None:
c["image"] = image

if set_env_vars is not None:
if "env" not in c or not c["env"]:
c["env"] = []
# env vars
_add_or_update_env_vars(c["env"], parse_env_var_flags(set_env_vars), is_add=True)

if replace_env_vars is not None:
if "env" not in c or not c["env"]:
c["env"] = []
# env vars
_add_or_update_env_vars(c["env"], parse_env_var_flags(replace_env_vars))

if remove_env_vars is not None:
if "env" not in c or not c["env"]:
c["env"] = []
# env vars
_remove_env_vars(c["env"], remove_env_vars)

if remove_all_env_vars:
c["env"] = []

if startup_command is not None:
if isinstance(startup_command, list) and not startup_command:
c["command"] = None
else:
c["command"] = startup_command
if args is not None:
if isinstance(args, list) and not args:
c["args"] = None
else:
c["args"] = args
if cpu is not None or memory is not None:
if "resources" in c and c["resources"]:
if cpu is not None:
c["resources"]["cpu"] = cpu
if memory is not None:
c["resources"]["memory"] = memory
else:
c["resources"] = {
"cpu": cpu,
"memory": memory
}

# If not updating existing container, add as new container
if not updating_existing_container:
if image is None:
raise ValidationError("Usage error: --image is required when adding a new container")

resources_def = None
if cpu is not None or memory is not None:
resources_def = ContainerResourcesModel
resources_def["cpu"] = cpu
resources_def["memory"] = memory

container_def = ContainerModel
container_def["name"] = container_name
container_def["image"] = image

if set_env_vars is not None:
# env vars
_add_or_update_env_vars(container_def["env"], parse_env_var_flags(set_env_vars), is_add=True)

if replace_env_vars is not None:
# env vars
_add_or_update_env_vars(container_def["env"], parse_env_var_flags(replace_env_vars))

if remove_env_vars is not None:
# env vars
_remove_env_vars(container_def["env"], remove_env_vars)

if remove_all_env_vars:
container_def["env"] = []

if startup_command is not None:
if isinstance(startup_command, list) and not startup_command:
container_def["command"] = None
else:
container_def["command"] = startup_command
if args is not None:
if isinstance(args, list) and not args:
container_def["args"] = None
else:
container_def["args"] = args
if resources_def is not None:
container_def["resources"] = resources_def

containerapp_def["properties"]["template"]["containers"].append(container_def)

# Scale
if update_map["scale"]:
if "scale" not in containerapp_def["properties"]["template"]:
containerapp_def["properties"]["template"]["scale"] = {}
if min_replicas is not None:
containerapp_def["properties"]["template"]["scale"]["minReplicas"] = min_replicas
if max_replicas is not None:
containerapp_def["properties"]["template"]["scale"]["maxReplicas"] = max_replicas

_get_existing_secrets(cmd, resource_group_name, name, containerapp_def)

try:
r = ContainerAppClient.create_or_update(
cmd=cmd, resource_group_name=resource_group_name, name=name, container_app_envelope=containerapp_def, no_wait=no_wait)

if "properties" in r and "provisioningState" in r["properties"] and r["properties"]["provisioningState"].lower() == "waiting" and not no_wait:
logger.warning('Containerapp update in progress. Please monitor the update using `az containerapp show -n {} -g {}`'.format(name, resource_group_name))

return r
except Exception as e:
handle_raw_exception(e)
return update_containerapp_logic(cmd,
name,
resource_group_name,
yaml,
image,
container_name,
min_replicas,
max_replicas,
set_env_vars,
remove_env_vars,
replace_env_vars,
remove_all_env_vars,
cpu,
memory,
revision_suffix,
startup_command,
args,
tags,
no_wait,
from_revision)


def set_revision_mode(cmd, resource_group_name, name, mode, no_wait=False):
Expand Down Expand Up @@ -1410,7 +1312,7 @@ def show_ingress(cmd, name, resource_group_name):
raise ValidationError("The containerapp '{}' does not have ingress enabled.".format(name)) from e


def enable_ingress(cmd, name, resource_group_name, type, target_port, transport, allow_insecure=False, no_wait=False): # pylint: disable=redefined-builtin
def enable_ingress(cmd, name, resource_group_name, type, target_port, transport="auto", allow_insecure=False, no_wait=False): # pylint: disable=redefined-builtin
_validate_subscription_registered(cmd, "Microsoft.App")

containerapp_def = None
Expand Down Expand Up @@ -1688,22 +1590,28 @@ def remove_registry(cmd, name, resource_group_name, server, no_wait=False):
pass


def list_secrets(cmd, name, resource_group_name):
def list_secrets(cmd, name, resource_group_name, show_values=False):
_validate_subscription_registered(cmd, "Microsoft.App")

containerapp_def = None
try:
containerapp_def = ContainerAppClient.show(cmd=cmd, resource_group_name=resource_group_name, name=name)
r = containerapp_def = ContainerAppClient.show(cmd=cmd, resource_group_name=resource_group_name, name=name)
except:
pass

if not containerapp_def:
raise ResourceNotFoundError("The containerapp '{}' does not exist".format(name))

if not show_values:
try:
return r["properties"]["configuration"]["secrets"]
except:
return []
try:
return ContainerAppClient.list_secrets(cmd=cmd, resource_group_name=resource_group_name, name=name)["value"]
except Exception as e:
raise ValidationError("The containerapp {} has no assigned secrets.".format(name)) from e
except Exception:
return []
# raise ValidationError("The containerapp {} has no assigned secrets.".format(name)) from e


def show_secret(cmd, name, resource_group_name, secret_name):
Expand Down Expand Up @@ -1796,6 +1704,7 @@ def set_secrets(cmd, name, resource_group_name, secrets,
try:
r = ContainerAppClient.create_or_update(
cmd=cmd, resource_group_name=resource_group_name, name=name, container_app_envelope=containerapp_def, no_wait=no_wait)
logger.warning("Containerapp must be restarted in order for secret changes to take effect.")
return r["properties"]["configuration"]["secrets"]
except Exception as e:
handle_raw_exception(e)
Expand Down

0 comments on commit ad34e67

Please sign in to comment.