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

Containerapp - add workload profile support and bump version to 11-01-preview #6081

Merged
merged 54 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
9c8bd59
bump version
StrawnSC Aug 25, 2022
9b4a3d9
Updated to preview api version and reran all tests. (#147)
runefa Aug 25, 2022
ea2ba6f
initial premium sku implementation
StrawnSC Sep 19, 2022
c5a69fe
bump version
StrawnSC Sep 14, 2022
df599b0
Custom Domains on Managed Environments (#152)
runefa Sep 15, 2022
084911d
add/update premium sku features -- updates for api changes, up/contai…
StrawnSC Sep 20, 2022
ea75e99
workaround for updating workload profiles
StrawnSC Sep 23, 2022
82635b8
start testing; handle logging differently in update
StrawnSC Sep 23, 2022
458ed64
private preview
StrawnSC Sep 27, 2022
eebf24c
automatically add WP to environment if needed
StrawnSC Sep 28, 2022
1878ca7
unhardcode premium sku
StrawnSC Oct 4, 2022
123e994
wlp changes
Feb 23, 2023
2211c4d
fix auto lowercase
Feb 23, 2023
44e642a
change version
Feb 24, 2023
2921f5c
change version
Feb 24, 2023
031c47a
merge conflicts
Feb 24, 2023
ff44316
fix wlp commands
Feb 24, 2023
0fdc036
fix enable wlp
Feb 24, 2023
220c69b
change log analytics
Feb 24, 2023
6706ca6
wlp updates
Feb 24, 2023
36777f2
wlp commands
Feb 24, 2023
55cd9e2
fix lowercase issues
Feb 24, 2023
e992f09
v1.0.4 add name and change type
Mar 9, 2023
b0c3c77
reset to v1.0.3
Mar 9, 2023
d1cc669
v1.0.3 fix optional workload profile name
Mar 9, 2023
af36351
update to 1.0.5, create containerapp with friendly name
Mar 13, 2023
e4b33b7
fix param names for 1.0.5
Mar 13, 2023
a840e67
change put to patch for update managed env
Mar 14, 2023
3df2f76
1.0.6, fix update container app and make wlp type optional
Mar 20, 2023
2b0694e
fix merge conflicts from main
Mar 21, 2023
11abb64
fix other conflicts
Mar 21, 2023
9b8b417
switch to 11-01-preview
Mar 21, 2023
2e6e2f9
fix failing test scenario
Mar 22, 2023
e0570b4
fix conflicts
Mar 27, 2023
a09c9dc
update workload profile tests
Mar 28, 2023
4773fc2
add help for wlp commands
Mar 28, 2023
0841e52
cleanup some comments
Mar 28, 2023
354936a
fix styling
Mar 28, 2023
d350d9b
fix polling
Mar 28, 2023
346f3d3
fix unintended rebasing change
Mar 28, 2023
2c50727
fix merge conflicts
Mar 28, 2023
0397d1e
fix tests and add help params
Mar 29, 2023
d89943f
fix lint
Mar 29, 2023
33d358e
revert appLogsConfiguration in create_managedenvironment and fix pylint
Greedygre Mar 29, 2023
962d988
remove useless file and fix liner
Greedygre Mar 29, 2023
0929bae
fix
Greedygre Mar 29, 2023
55e808b
fix tags patch bug
Greedygre Mar 29, 2023
2ba1682
re run test
Greedygre Mar 29, 2023
6e47ec3
change enable-workload-profiles
Mar 29, 2023
10d1f25
remove usless test yml file
Greedygre Mar 31, 2023
307b433
revert poll change
Greedygre Mar 31, 2023
777fd0d
add preview flag
Greedygre Mar 31, 2023
3ca2270
fix preview
Greedygre Mar 31, 2023
4c7d7dc
Merge pull request #1 from Greedygre/xinyu/fix_preview_flag
Greedygre Mar 31, 2023
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
35 changes: 35 additions & 0 deletions containerapp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

location: eastus
type: Microsoft.App/containerApps
tags:
tagname: value
properties:
environmentId: /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.App/managedEnvironments/env000002
configuration:
activeRevisionsMode: Multiple
ingress:
external: true
allowInsecure: false
targetPort: 80
traffic:
- latestRevision: true
weight: 100
transport: Auto
template:
revisionSuffix: myrevision
containers:
- image: nginx
name: nginx
env:
- name: HTTP_PORT
value: 80
command:
- npm
- start
resources:
cpu: 0.5
memory: 1Gi
scale:
minReplicas: 1
maxReplicas: 3

10 changes: 10 additions & 0 deletions src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ Upcoming
* '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
40 changes: 36 additions & 4 deletions 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 All @@ -42,7 +42,7 @@ def flush(self):
sys.stderr.write("\r\033[K")


def poll(cmd, request_url, poll_if_status): # pylint: disable=inconsistent-return-statements
def poll(cmd, request_url, poll_if_status: list): # pylint: disable=inconsistent-return-statements
try:
start = time.time()
end = time.time() + POLLING_TIMEOUT
Expand All @@ -69,7 +69,7 @@ def poll(cmd, request_url, poll_if_status): # pylint: disable=inconsistent-retu

delete_statuses = ["scheduledfordelete", "cancelled"]

if poll_if_status not in delete_statuses: # Catch "not found" errors if polling for delete
if poll_if_status[0] not in delete_statuses: # Catch "not found" errors if polling for delete
raise e


Expand Down Expand Up @@ -555,7 +555,7 @@ def update(cls, cmd, resource_group_name, name, managed_environment_envelope, no
else:
raise AzureResponseError(f"Invalid operation URL: '{operation_url}'")

return r.json()
return
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def delete(cls, cmd, resource_group_name, name, no_wait=False):
Expand Down Expand Up @@ -858,6 +858,38 @@ def get_auth_token(cls, cmd, resource_group_name, name):
r = send_raw_request(cmd.cli_ctx, "POST", request_url)
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={}"
# url_fmt = "{}/subscriptions/{}/resourcegroups/{}/providers/Microsoft.App/managedEnvironments/{}/getWorkloadProfileStates?api-version={}"
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved
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
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
20 changes: 20 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.", )

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')

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('enableWorkloadProfiles', options_list=["--enableWorkloadProfiles", "-w"], help="Allow this environment to have workload profiles --infrastructure-subnet-resource-id/-s is required for workload profiles to be enabled")
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved

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')

with self.argument_context('containerapp revision label') as c:
c.argument('name', id_part=None)
Expand Down Expand Up @@ -310,6 +319,8 @@ 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 +402,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
35 changes: 34 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 @@ -1564,6 +1564,39 @@ 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):
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved
return "Consumption"


def get_default_workload_profile_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]:
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved
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):
from .custom import update_managed_environment

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
Expand Down
23 changes: 23 additions & 0 deletions src/containerapp/azext_containerapp/aaz/latest/app/__cmd_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# --------------------------------------------------------------------------------------------
p-bouchon marked this conversation as resolved.
Show resolved Hide resolved
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: skip-file
# flake8: noqa

from azure.cli.core.aaz import *


@register_command_group(
"app",
)
class __CMDGroup(AAZCommandGroup):
"""az container app
"""
pass


__all__ = ["__CMDGroup"]
12 changes: 12 additions & 0 deletions src/containerapp/azext_containerapp/aaz/latest/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
#
# Code generated by aaz-dev-tools
# --------------------------------------------------------------------------------------------

# pylint: skip-file
# flake8: noqa

from .__cmd_group import *
from ._managed_environment_list import *
Loading