Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bbaee5f
Adding patch list
harryli0108 May 4, 2023
5419d8e
Added patch list command
snehapar9 May 4, 2023
9f425d8
Revert thumbprint arg
snehapar9 May 4, 2023
1d8078a
Fix bugs
harryli0108 May 4, 2023
9af1fc8
Merge branch 'snehapar/patch-list' into patchList
snehapar9 May 4, 2023
04f21ed
Merge pull request #1 from harryli0108/patchList
snehapar9 May 4, 2023
1821286
Integrated with Harry
snehapar9 May 4, 2023
e373062
Fixed bug
snehapar9 May 5, 2023
eae2a49
Fixed command usage text
snehapar9 May 5, 2023
44371f1
Made managed env optional
snehapar9 May 8, 2023
9ba04df
Fixed identation
snehapar9 May 8, 2023
fd55c59
Fixed identation
snehapar9 May 8, 2023
3a5f808
Merge branch 'snehapar/test-branch' into test
harryli0108 May 8, 2023
4ee1946
Merge branch 'snehapar/test-branch' into test
harryli0108 May 8, 2023
ee786b5
Merge pull request #2 from harryli0108/test
snehapar9 May 8, 2023
01ec69a
Made env optional
snehapar9 May 9, 2023
f00eba5
Merge pull request #3 from harryli0108/main
snehapar9 May 9, 2023
6a17a94
Merge branch 'snehapar/patch-list' into snehapar/test-branch
snehapar9 May 9, 2023
cfb5fe2
Remove patch list
snehapar9 May 10, 2023
eca488e
Update help text for patch list and patch run
snehapar9 May 10, 2023
f75be55
Modified help text
snehapar9 May 11, 2023
d6aa33d
Merge branch 'main' into snehapar/test-branch
snehapar9 May 11, 2023
d1f890b
Made resouce group optional
snehapar9 May 11, 2023
e20e7de
Merge branch 'snehapar/test-branch' of https://github.com/snehapar9/a…
snehapar9 May 11, 2023
9b3e381
Added custom telemetry
snehapar9 May 11, 2023
398f7ce
Fixed linting errors
snehapar9 May 11, 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
24 changes: 21 additions & 3 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -1272,14 +1272,32 @@
--compose-file-path "path/to/docker-compose.yml"
"""

#Patch commands
helps['containerapp patch'] = """
type: group
short-summary: Patch Azure Container Apps.
"""

helps['containerapp patch list'] = """
type: command
short-summary: List Container Apps to be patched.Patching is only available for the apps built using the source to cloud feature.
exmaples:
- name: List Container Apps that can be patched.
text: |
az containerapp patch -g MyResourceGroup --environment MyContainerappEnv
- name: List patchable and unpatchable Container Apps.
text: |
az containerapp patch -g MyResourceGroup --environment MyContainerappEnv --show-all
"""

helps['containerapp patch run'] = """
type: command
short-summary: List and select container apps to be patched.
short-summary: List and select Container Apps to be patched.Patching is only available for the apps built using the source to cloud feature.
exmaples:
- name: Show containerapps that can be patched and apply patch.
- name: List Container Apps that can be patched and apply patch.
text: |
az containerapp patch -g MyResourceGroup --environment MyContainerappEnv
- name: Show patchable and unpatchable containerapps and apply patch.
- name: List patchable and unpatchable Container Apps and apply patch.
text: |
az containerapp patch -g MyResourceGroup --environment MyContainerappEnv --show-all
"""
14 changes: 10 additions & 4 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,13 @@ def load_arguments(self, _):
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")

with self.argument_context('containerapp patch') as c:
c.argument('resource_group_name', options_list=['--rg','-g'], configured_default='resource_group_name', id_part=None)
c.argument('environment', options_list=['--environment', '-e'], help='Name or resource id of the Container App environment.')
c.argument('show_all', options_list=['--show-all'],help='Show all patchable and unpatchable containerapps')
with self.argument_context('containerapp patch list') as c:
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('managed_env',options_list=['--environment','-e'],help='Name or resource id of the Container App environment.')
c.argument('show_all', options_list=['--show-all'],help='Show all patchable and unpatchable Container Apps')

with self.argument_context('containerapp patch run') as c:
c.argument('resource_group_name', arg_type=resource_group_name_type)
c.argument('managed_env',validator=validate_managed_env_name_or_id, options_list=['--environment', '-e'], help='Name or resource id of the Container App environment.')
c.argument('show_all', options_list=['--show-all'],help='Show all patchable and unpatchable Container Apps')

1 change: 1 addition & 0 deletions src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1781,6 +1781,7 @@ def patchableCheck(repoTagSplit: str, oryxBuilderRunImgTags, bom):
result = {
"targetContainerAppName": bom["targetContainerAppName"],
"targetContainerName": bom["targetContainerName"],
"targetContainerAppEnvironmentName": bom["targetContainerAppEnvironmentName"],
"revisionMode": bom["revisionMode"],
"targetImageName": bom["image_name"],
"oldRunImage": repoTagSplit,
Expand Down
6 changes: 5 additions & 1 deletion src/containerapp/azext_containerapp/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ def load_command_table(self, _):
g.custom_command('exec', 'containerapp_ssh', validator=validate_ssh)
g.custom_command('up', 'containerapp_up', supports_no_wait=False, exception_handler=ex_handler_factory())
g.custom_command('browse', 'open_containerapp_in_browser')
g.custom_command('patch','patch_run', isPreview=True)

with self.command_group('containerapp replica') as g:
g.custom_show_command('show', 'get_replica') # TODO implement the table transformer
Expand Down Expand Up @@ -200,3 +199,8 @@ def load_command_table(self, _):
g.custom_show_command('show', 'show_workload_profile')
g.custom_command('set', 'set_workload_profile')
g.custom_command('delete', 'delete_workload_profile')

with self.command_group('containerapp patch', is_preview=True) as g:
g.custom_command('list','patch_list',is_preview=True)
g.custom_command('run','patch_run',is_preview=True)

54 changes: 30 additions & 24 deletions src/containerapp/azext_containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import requests
import json
import subprocess
from azure.cli.core import telemetry as telemetry_core

from azure.cli.core.azclierror import (
RequiredArgumentMissingError,
Expand All @@ -30,6 +31,7 @@
from msrestazure.tools import parse_resource_id, is_valid_resource_id
from msrest.exceptions import DeserializationError


from ._client_factory import handle_raw_exception, handle_non_404_exception
from ._clients import ManagedEnvironmentClient, ContainerAppClient, GitHubActionClient, DaprComponentClient, StorageClient, AuthClient, WorkloadProfileClient
from ._github_oauth import get_github_access_token
Expand Down Expand Up @@ -4133,7 +4135,7 @@ def show_auth_config(cmd, resource_group_name, name):
return auth_settings

# Compose

def create_containerapps_from_compose(cmd, # pylint: disable=R0914
resource_group_name,
managed_env,
Expand Down Expand Up @@ -4303,7 +4305,7 @@ def delete_workload_profile(cmd, resource_group_name, env_name, workload_profile


def patch_list(cmd, resource_group_name, managed_env=None, show_all=False):
if(managed_env):
if managed_env:
caList = list_containerapp(cmd, resource_group_name, managed_env)
else:
envList = list_managed_environments(cmd, resource_group_name)
Expand All @@ -4320,7 +4322,7 @@ def patch_list(cmd, resource_group_name, managed_env=None, show_all=False):
containers = ca["properties"]["template"]["containers"]
for container in containers:
result = dict(imageName=container["image"], targetContainerName=container["name"], targetContainerAppName=ca["name"], targetContainerAppEnvironmentName = managedEnvName, revisionMode=ca["properties"]["configuration"]["activeRevisionsMode"])
imgs.append(result)
imgs.append(result)
# Get the BOM of the images
results = []
boms = []
Expand Down Expand Up @@ -4371,7 +4373,7 @@ def patch_list(cmd, resource_group_name, managed_env=None, show_all=False):
else:
for runImagesProp in runImagesProps:
# result = None
if (runImagesProp["name"].find("mcr.microsoft.com/oryx/builder") != -1):
if runImagesProp["name"].find("mcr.microsoft.com/oryx/builder") != -1:
runImagesProp = runImagesProp["name"].split(":")
runImagesTag = runImagesProp[1]
# Based on Mariners
Expand All @@ -4381,17 +4383,19 @@ def patch_list(cmd, resource_group_name, managed_env=None, show_all=False):
results["NotPatchable"].append(checkResult)
else:
results[checkResult["id"]] = checkResult
else:
results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName=bom["targetContainerAppEnvironmentName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=bom["remote_info"]["run_images"]["name"], newRunImage=None, id=None, reason=failedReason))
results.append(dict(targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName=bom["targetContainerAppEnvironmentName"], oldRunImage=bom["remote_info"]["run_images"], newRunImage=None, id=None, reason=failedReason))
else:
results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName = bom["targetContainerAppEnvironmentName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=bom["remote_info"]["run_images"]["name"], newRunImage=None, id=None, reason=failedReason))
results.append(dict(targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName = bom["targetContainerAppEnvironmentName"], oldRunImage=bom["remote_info"]["run_images"], newRunImage=None, id=None, reason=failedReason))
else:
# Not based on image from mcr.microsoft.com/dotnet
results.append(dict(targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName=bom["targetContainerAppEnvironmentName"], oldRunImage=bom["remote_info"]["run_images"], newRunImage=None, id=None, reason=mcrCheckReason))
if show_all == False :
results.append(dict(targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName=bom["targetContainerAppEnvironmentName"], oldRunImage=bom["remote_info"]["run_images"], newRunImage=None, id=None, reason=mcrCheckReason))
if not show_all == False :
results = {k: v for k, v in results.items() if k != "NotPatchable"}
if not results :
print("No Container App available to patch at this time.");return
return results

def patch_run(cmd, resource_group_name, managed_env=None, show_all=False):
def patch_run(cmd, resource_group_name=None, managed_env=None, show_all=False):
patchable_check_results = patch_list(cmd, resource_group_name, managed_env, show_all=show_all)
patchable_result_key_list = list(patchable_check_results.keys())
if len(patchable_result_key_list) == 0 or patchable_result_key_list == ["NotPatchable"]:
Expand All @@ -4403,6 +4407,8 @@ def patch_run(cmd, resource_group_name, managed_env=None, show_all=False):
patchable_check_results_json = json.dumps(patchable_check_results, indent=4)
print(patchable_check_results_json)
user_input=input("Do you want to apply all the patch or specify by id? (y/n/id)\n")
if user_input == "y":
telemetry_core.add_extension_event('patch-run')
return patch_apply(cmd, patchable_check_results, user_input, resource_group_name)

def patch_apply(cmd, patchCheckList, method, resource_group_name):
Expand All @@ -4412,23 +4418,23 @@ def patch_apply(cmd, patchCheckList, method, resource_group_name):
for key in patchCheckList.keys():
if key != "NotPatchable":
if patchCheckList[key]["newRunImage"]:
results.append(patch_cli_call(cmd,
results.append(patch_cli_call(cmd,
resource_group_name,
patchCheckList[key]["targetContainerAppName"],
patchCheckList[key]["targetContainerName"],
patchCheckList[key]["targetImageName"],
patchCheckList[key]["newRunImage"],
patchCheckList[key]["targetContainerAppName"],
patchCheckList[key]["targetContainerName"],
patchCheckList[key]["targetImageName"],
patchCheckList[key]["newRunImage"],
patchCheckList[key]["revisionMode"]))
elif m == "n":
print("No patch applied."); return
else:
if method in patchCheckList.keys():
results.append(patch_cli_call(cmd,
results.append(patch_cli_call(cmd,
resource_group_name,
patchCheckList[method]["targetContainerAppName"],
patchCheckList[method]["targetContainerName"],
patchCheckList[method]["targetImageName"],
patchCheckList[method]["newRunImage"],
patchCheckList[method]["targetContainerAppName"],
patchCheckList[method]["targetContainerName"],
patchCheckList[method]["targetImageName"],
patchCheckList[method]["newRunImage"],
patchCheckList[method]["revisionMode"]))
else:
print("Invalid patch method or id."); return
Expand All @@ -4447,10 +4453,10 @@ def patch_cli_call(cmd, resource_group, container_app_name, container_name, targ
raise
try:
print("Patching container app: " + container_app_name + " container: " + container_name + " with image: " + new_target_image_name)
update_info_json = update_containerapp(cmd,
name=container_app_name,
resource_group_name=resource_group,
container_name=container_name,
update_info_json = update_containerapp(cmd,
name=container_app_name,
resource_group_name=resource_group,
container_name=container_name,
image=new_target_image_name)
print("Container app revision created successfully.")
## TODO: activate revision, fix the error when running the following two lines
Expand Down