Skip to content

Commit

Permalink
Containerapp - add workload profile support and bump version to 11-01…
Browse files Browse the repository at this point in the history
…-preview (#6081)

* bump version

* Updated to preview api version and reran all tests. (#147)

* Ran tests.

* Update src/containerapp/azext_containerapp/_clients.py

Co-authored-by: Silas Strawn <strawnsc@gmail.com>

Co-authored-by: Haroon Feisal <haroonfeisal@microsoft.com>
Co-authored-by: Silas Strawn <strawnsc@gmail.com>

* initial premium sku implementation

* bump version

* Custom Domains on Managed Environments (#152)

* initial no dockerfile support for up

* bump version

* add to help text, history text

* Fill in Cormac's link for oryx runtimes (see here microsoft/Oryx#1502)

* pass target port to ACR task; add better error information

* bump version

* fix bug with containerapp create

* add test case

* bump version

* Updated to preview api version and reran all tests. (#147)

* Ran tests.

* Update src/containerapp/azext_containerapp/_clients.py

Co-authored-by: Silas Strawn <strawnsc@gmail.com>

Co-authored-by: Haroon Feisal <haroonfeisal@microsoft.com>
Co-authored-by: Silas Strawn <strawnsc@gmail.com>

* resolve anthony's comments

* Revert "`az containerapp up`: Support No Dockerfile Scenario"

* Revert "Revert "`az containerapp up`: Support No Dockerfile Scenario""

* Added custom domain support to env create.

* Updated param help group text.

* Added test.

* Wrote env update, wrote test for env update with custom domains.

* Minor update.

* Added help to env update.

Co-authored-by: Silas Strawn <strawnsc@gmail.com>
Co-authored-by: Haroon Feisal <haroonfeisal@microsoft.com>

* add/update premium sku features -- updates for api changes, up/containerapp create support, env update support, add help text

* workaround for updating workload profiles

* start testing; handle logging differently in update

* private preview

* automatically add WP to environment if needed

* unhardcode premium sku

* wlp changes

* fix auto lowercase

* change version

* change version

* merge conflicts

* fix wlp commands

* fix enable wlp

* change log analytics

* wlp updates

* wlp commands

* fix lowercase issues

* v1.0.4 add name and change type

* reset to v1.0.3

* v1.0.3 fix optional workload profile name

* update to 1.0.5, create containerapp with friendly name

* fix param names for 1.0.5

* change put to patch for update managed env

* 1.0.6, fix update container app and make wlp type optional

* fix other conflicts

* switch to 11-01-preview

* fix failing test scenario

* update workload profile tests

* add help for wlp commands

* cleanup some comments

* fix styling

* fix polling

* fix unintended rebasing change

* fix lint

* revert appLogsConfiguration in create_managedenvironment and fix pylint

* remove useless file and fix liner

* fix

* fix tags patch bug

* re run test

* change enable-workload-profiles

* remove usless test yml file

* revert poll change

* add preview flag

* fix preview

---------

Co-authored-by: Silas Strawn <strawnsc@gmail.com>
Co-authored-by: Haroon Feisal <38823870+haroonf@users.noreply.github.com>
Co-authored-by: Haroon Feisal <haroonfeisal@microsoft.com>
Co-authored-by: p-bouchon <pbouchon@microsoft.com>
Co-authored-by: xinyu pang <1042945277@qq.com>
Co-authored-by: xinyu pang <46143499+Greedygre@users.noreply.github.com>
  • Loading branch information
7 people authored Mar 31, 2023
1 parent dccea39 commit 29df418
Show file tree
Hide file tree
Showing 74 changed files with 368,549 additions and 115,970 deletions.
14 changes: 12 additions & 2 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@
Release History
===============
Upcoming
+++++++
0.3.25
++++++
* 'az containerapp create/update': --yaml support properties for api-version 2022-10-01 (e.g. exposedPort,clientCertificateMode,corsPolicy)
* 'az containerapp env update': fix bugs in update environment.
* Fix YAML create with user-assigned identity
* Fix polling logic for long running operations.
* 'az containerapp env create': add support for workload profiles
* 'az containerapp env update': add support for workload profiles
* 'az containerapp create': add support for workload profiles
* 'az containerapp update': add support for workload profiles
* Add 'az containerapp env workload-profile delete' to support deleting a workload profile from an environment
* Add 'az containerapp env workload-profile list' to support listing all workload profiles in an environment
* Add 'az containerapp env workload-profile list-supported' to support listing all available workload profile types in a region
* Add 'az containerapp env workload-profile set' to support creating or updating an existing workload profile in an environment
* Add 'az containerapp env workload-profile show' to support showing details of a single workload profile in an environment
* Upgrade api-version from 2022-10-01 to 2022-11-01-preview
* Add `az containerapp ingress update` Command to Update Container App Ingress

0.3.24
Expand Down
6 changes: 6 additions & 0 deletions src/containerapp/azext_containerapp/_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ def handle_raw_exception(e):

stringErr = str(e)

if "WorkloadProfileNameRequired" in stringErr:
raise CLIInternalError("Workload profile name is required. Please provide --workload-profile-name.")

if "Unknown properties Name in Microsoft.ContainerApps.WebApi.Views.Version20221101Preview.WorkloadProfile are not supported" in stringErr:
raise CLIInternalError("Bad Request: Workload profile name is not yet supported in this region.")

if "{" in stringErr and "}" in stringErr:
jsonError = stringErr[stringErr.index("{"):stringErr.rindex("}") + 1]
jsonError = json.loads(jsonError)
Expand Down
35 changes: 34 additions & 1 deletion src/containerapp/azext_containerapp/_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
logger = get_logger(__name__)

PREVIEW_API_VERSION = "2022-11-01-preview"
CURRENT_API_VERSION = "2022-10-01"
CURRENT_API_VERSION = "2022-11-01-preview"
POLLING_TIMEOUT = 600 # how many seconds before exiting
POLLING_SECONDS = 2 # how many seconds between requests
POLLING_TIMEOUT_FOR_MANAGED_CERTIFICATE = 1500 # how many seconds before exiting
Expand Down Expand Up @@ -859,6 +859,39 @@ def get_auth_token(cls, cmd, resource_group_name, name):
return r.json()


class WorkloadProfileClient():
@classmethod
def list_supported(cls, cmd, location):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
api_version = CURRENT_API_VERSION
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/providers/Microsoft.App/locations/{}/availableManagedEnvironmentsWorkloadProfileTypes?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
location,
api_version)

r = send_raw_request(cmd.cli_ctx, "GET", request_url)
return r.json().get("value")

@classmethod
def list(cls, cmd, resource_group_name, env_name):
management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager
api_version = CURRENT_API_VERSION
sub_id = get_subscription_id(cmd.cli_ctx)
url_fmt = "{}/subscriptions/{}/resourcegroups/{}/providers/Microsoft.App/managedEnvironments/{}/workloadProfileStates?api-version={}"
request_url = url_fmt.format(
management_hostname.strip('/'),
sub_id,
resource_group_name,
env_name,
api_version)

r = send_raw_request(cmd.cli_ctx, "GET", request_url)
return r.json().get("value")


class GitHubActionClient():
@classmethod
def create_or_update(cls, cmd, resource_group_name, name, github_action_envelope, headers, no_wait=False):
Expand Down
50 changes: 50 additions & 0 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,56 @@
az containerapp env storage remove -g MyResourceGroup --storage-name MyStorageName -n MyEnvironment
"""

helps['containerapp env workload-profile'] = """
type: group
short-summary: Manage the workload profiles of a Container Apps environment
"""

helps['containerapp env workload-profile delete'] = """
type: command
short-summary: Delete a workload profile from a Container Apps environment
examples:
- name: Delete a workload profile from a Container Apps environment
text: |
az containerapp env workload-profile delete -g MyResourceGroup -n MyEnvironment --workload-profile-name my-wlp
"""

helps['containerapp env workload-profile list'] = """
type: command
short-summary: List the workload profiles from a Container Apps environment
examples:
- name: List the workload profiles from a Container Apps environment
text: |
az containerapp env workload-profile list -g MyResourceGroup -n MyEnvironment
"""

helps['containerapp env workload-profile show'] = """
type: command
short-summary: Show a workload profile from a Container Apps environment
examples:
- name: Show a workload profile from a Container Apps environment
text: |
az containerapp env workload-profile show -g MyResourceGroup -n MyEnvironment --workload-profile-name my-wlp
"""

helps['containerapp env workload-profile list-supported'] = """
type: command
short-summary: List the supported workload profiles in a region
examples:
- name: List the supported workload profiles in a region
text: |
az containerapp env workload-profile list-supported -l region
"""

helps['containerapp env workload-profile set'] = """
type: command
short-summary: Create or update an existing workload profile in a Container Apps environment
examples:
- name: Create or update an existing workload profile in a Container Apps environment
text: |
az containerapp env workload-profile set -g MyResourceGroup -n MyEnvironment --workload-profile-name my-wlp --workload-profile-type D4 --min-nodes 1 --max-nodes 2
"""

# Certificates Commands
helps['containerapp env certificate'] = """
type: group
Expand Down
7 changes: 2 additions & 5 deletions src/containerapp/azext_containerapp/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

VnetConfiguration = {
"infrastructureSubnetId": None,
"runtimeSubnetId": None,
"dockerBridgeCidr": None,
"platformReservedCidr": None,
"platformReservedDnsIP": None
Expand All @@ -16,14 +15,12 @@
ManagedEnvironment = {
"location": None,
"tags": None,
"sku": {
"name": "Consumption",
},
"properties": {
"daprAIInstrumentationKey": None,
"vnetConfiguration": None, # VnetConfiguration
"appLogsConfiguration": None,
"customDomainConfiguration": None # CustomDomainConfiguration
"customDomainConfiguration": None, # CustomDomainConfiguration,
"workloadProfiles": None
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def load_arguments(self, _):

with self.argument_context('containerapp create') as c:
c.argument('traffic_weights', nargs='*', options_list=['--traffic-weight'], help="A list of revision weight(s) for the container app. Space-separated values in 'revision_name=weight' format. For latest revision, use 'latest=weight'")
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help="Name of the workload profile to run the app on.", is_preview=True)

with self.argument_context('containerapp create', arg_group='Identity') as c:
c.argument('user_assigned', nargs='+', help="Space-separated user identities to be assigned.")
Expand All @@ -131,6 +132,7 @@ def load_arguments(self, _):

with self.argument_context('containerapp update', arg_group='Container') as c:
c.argument('image', options_list=['--image', '-i'], help="Container image, e.g. publisher/image-name:tag.")
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help='The friendly name for the workload profile', is_preview=True)

with self.argument_context('containerapp scale') as c:
c.argument('min_replicas', type=int, help="The minimum number of replicas.")
Expand Down Expand Up @@ -165,10 +167,16 @@ def load_arguments(self, _):

with self.argument_context('containerapp env create') as c:
c.argument('zone_redundant', options_list=["--zone-redundant", "-z"], help="Enable zone redundancy on the environment. Cannot be used without --infrastructure-subnet-resource-id. If used with --location, the subnet's location must match")
c.argument('enable_workload_profiles', options_list=["--enable-workload-profiles", "-w"], help="Allow this environment to have workload profiles --infrastructure-subnet-resource-id/-s is required for workload profiles to be enabled", is_preview=True)

with self.argument_context('containerapp env update') as c:
c.argument('name', name_type, help='Name of the Container Apps environment.')
c.argument('tags', arg_type=tags_type)
# c.argument('plan', help="The sku of the containerapp environment. Downgrading from premium to consumption is not supported. Environment must have a subnet to be upgraded to premium sku.", arg_type=get_enum_type(['consumption', 'premium', None], default=None))
c.argument('workload_profile_type', help='The type of workload profile to add or update in this environment, --workload-profile-name required')
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help='The friendly name for the workload profile')
c.argument('min_nodes', help='The minimum nodes for this workload profile, --workload-profile-name required')
c.argument('max_nodes', help='The maximum nodes for this workload profile, --workload-profile-name required')

with self.argument_context('containerapp env delete') as c:
c.argument('name', name_type, help='Name of the Container Apps Environment.')
Expand Down Expand Up @@ -238,6 +246,7 @@ def load_arguments(self, _):
with self.argument_context('containerapp revision copy') as c:
c.argument('from_revision', help='Revision to copy from. Default: latest revision.')
c.argument('image', options_list=['--image', '-i'], help="Container image, e.g. publisher/image-name:tag.")
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help='The friendly name for the workload profile', is_preview=True)

with self.argument_context('containerapp revision label') as c:
c.argument('name', id_part=None)
Expand Down Expand Up @@ -310,6 +319,7 @@ def load_arguments(self, _):
c.argument('source', help='Local directory path containing the application source and Dockerfile for building the container image. Preview: If no Dockerfile is present, a container image is generated using Oryx. See the supported Oryx runtimes here: https://github.com/microsoft/Oryx/blob/main/doc/supportedRuntimeVersions.md.')
c.argument('image', options_list=['--image', '-i'], help="Container image, e.g. publisher/image-name:tag.")
c.argument('browse', help='Open the app in a web browser after creation and deployment, if possible.')
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help='The friendly name for the workload profile')

with self.argument_context('containerapp up', arg_group='Log Analytics (Environment)') as c:
c.argument('logs_customer_id', options_list=['--logs-workspace-id'], help='Workspace ID of the Log Analytics workspace to send diagnostics logs to. You can use \"az monitor log-analytics workspace create\" to create one. Extra billing may apply.')
Expand Down Expand Up @@ -391,3 +401,12 @@ def load_arguments(self, _):
c.argument('environment', options_list=['--environment', '-e'], help='Name or resource id of the Container App environment.')
c.argument('compose_file_path', options_list=['--compose-file-path', '-f'], help='Path to a Docker Compose file with the configuration to import to Azure Container Apps.')
c.argument('transport_mapping', options_list=['--transport-mapping', c.deprecate(target='--transport', redirect='--transport-mapping')], action='append', nargs='+', help="Transport options per Container App instance (servicename=transportsetting).")

with self.argument_context('containerapp env workload-profile') as c:
c.argument('env_name', options_list=['--name', '-n'], help="The name of the Container App environment")
c.argument('workload_profile_name', options_list=['--workload-profile-name', '-w'], help='The friendly name for the workload profile')

with self.argument_context('containerapp env workload-profile set') as c:
c.argument('workload_profile_type', help="The type of workload profile to add or update. Run 'az containerapp env workload-profile list-supported -l <region>' to check the options for your region.")
c.argument('min_nodes', help="The minimum node count for the workload profile")
c.argument('max_nodes', help="The maximum node count for the workload profile")
3 changes: 3 additions & 0 deletions src/containerapp/azext_containerapp/_up_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ def __init__(
registry_user=None,
registry_pass=None,
env_vars=None,
workload_profile_name=None,
ingress=None,
):

Expand All @@ -291,6 +292,7 @@ def __init__(
self.registry_pass = registry_pass
self.env_vars = env_vars
self.ingress = ingress
self.workload_profile_name = workload_profile_name

self.should_create_acr = False
self.acr: "AzureContainerRegistry" = None
Expand Down Expand Up @@ -320,6 +322,7 @@ def create(self, no_registry=False):
registry_pass=None if no_registry else self.registry_pass,
registry_user=None if no_registry else self.registry_user,
env_vars=self.env_vars,
workload_profile_name=self.workload_profile_name,
ingress=self.ingress,
)

Expand Down
36 changes: 35 additions & 1 deletion src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from knack.log import get_logger
from msrestazure.tools import parse_resource_id, is_valid_resource_id, resource_id

from ._clients import ContainerAppClient, ManagedEnvironmentClient
from ._clients import ContainerAppClient, ManagedEnvironmentClient, WorkloadProfileClient
from ._client_factory import handle_raw_exception, providers_client_factory, cf_resource_groups, log_analytics_client_factory, log_analytics_shared_key_client_factory
from ._constants import (MAXIMUM_CONTAINER_APP_NAME_LENGTH, SHORT_POLLING_INTERVAL_SECS, LONG_POLLING_INTERVAL_SECS,
LOG_ANALYTICS_RP, CONTAINER_APPS_RP, CHECK_CERTIFICATE_NAME_AVAILABILITY_TYPE, ACR_IMAGE_SUFFIX,
Expand Down Expand Up @@ -1565,6 +1565,40 @@ def list_environment_locations(cmd):
return res_locations


# normalizes workload profile type
def get_workload_profile_type(cmd, name, location):
return name.upper()


def get_default_workload_profile(cmd, location):
return "Consumption"


def get_default_workload_profile_name_from_env(cmd, env_def, resource_group):
location = env_def["location"]
api_default = get_default_workload_profile(cmd, location)
env_profiles = WorkloadProfileClient.list(cmd, resource_group, env_def["name"])
if api_default in [p["name"] for p in env_profiles]:
return api_default
return env_profiles[0]["name"]


def get_default_workload_profiles(cmd, location):
profiles = [
{
"workloadProfileType": "Consumption",
"Name": "Consumption"
}
]
return profiles


def ensure_workload_profile_supported(cmd, env_name, env_rg, workload_profile_name, managed_env_info):
profile_names = [p["name"] for p in safe_get(managed_env_info, "properties", "workloadProfiles", default=[])]
if workload_profile_name not in profile_names:
raise ValidationError(f"Not a valid workload profile name: '{workload_profile_name}'. Run 'az containerapp env workload-profile list -n myEnv -g myResourceGroup' to see options.")


def set_ip_restrictions(ip_restrictions, ip_restriction_name, ip_address_range, description, action):
updated = False
for e in ip_restrictions:
Expand Down
7 changes: 7 additions & 0 deletions src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,10 @@ def load_command_table(self, _):

with self.command_group('containerapp compose') as g:
g.custom_command('create', 'create_containerapps_from_compose')

with self.command_group('containerapp env workload-profile', is_preview=True) as g:
g.custom_command('list-supported', 'list_supported_workload_profiles')
g.custom_command('list', 'list_workload_profiles')
g.custom_show_command('show', 'show_workload_profile')
g.custom_command('set', 'set_workload_profile')
g.custom_command('delete', 'delete_workload_profile')
Loading

0 comments on commit 29df418

Please sign in to comment.