From a4c81ae3537e58e2d85ca90844f33949a27e5b99 Mon Sep 17 00:00:00 2001 From: snehapar9 <108305436+snehapar9@users.noreply.github.com> Date: Wed, 10 May 2023 15:09:05 -0700 Subject: [PATCH] Remove patch list + make managed env optional (#3) * Adding patch list * Added patch list command * Revert thumbprint arg * Fix bugs * Integrated with Harry * Fixed bug * Fixed command usage text * Made managed env optional * Fixed identation * Fixed identation * Made env optional * Remove patch list --------- Co-authored-by: harrli Co-authored-by: Harry Li <110055355+harryli0108@users.noreply.github.com> --- src/containerapp/azext_containerapp/_help.py | 20 ++------- .../azext_containerapp/_params.py | 11 ++--- src/containerapp/azext_containerapp/_utils.py | 4 -- .../azext_containerapp/commands.py | 5 +-- src/containerapp/azext_containerapp/custom.py | 45 +++++++++++-------- 5 files changed, 35 insertions(+), 50 deletions(-) diff --git a/src/containerapp/azext_containerapp/_help.py b/src/containerapp/azext_containerapp/_help.py index 92f583e4f92..27cdcbfcb14 100644 --- a/src/containerapp/azext_containerapp/_help.py +++ b/src/containerapp/azext_containerapp/_help.py @@ -1272,26 +1272,14 @@ --compose-file-path "path/to/docker-compose.yml" """ -helps['containerapp patch list'] = """ +helps['containerapp patch'] = """ type: command - short-summary: List patchable and unpatchable container apps. - examples: - - name: List patchable container apps. - text: | - az containerapp list -g MyResourceGroup --environment MyContainerappEnv - - name: List patchable and non-patchable container apps. - text: | - az containerapp list -g MyResourceGroup --environment MyContainerappEnv --show-all -""" - -helps['containerapp patch run'] = """ - type: command - short-summary: List and choose container apps to be patched. + short-summary: List and select container apps to be patched. exmaples: - - name: Patch a container app. + - name: Show containerapps that can be patched and apply patch. text: | az containerapp patch -g MyResourceGroup --environment MyContainerappEnv - - name: Patch a container app and show scan results of all container apps. + - name: Show patchable and unpatchable containerapps and apply patch. text: | az containerapp patch -g MyResourceGroup --environment MyContainerappEnv --show-all """ \ No newline at end of file diff --git a/src/containerapp/azext_containerapp/_params.py b/src/containerapp/azext_containerapp/_params.py index dcd6b8bf744..6833161c505 100644 --- a/src/containerapp/azext_containerapp/_params.py +++ b/src/containerapp/azext_containerapp/_params.py @@ -415,12 +415,7 @@ 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 list') as c: + 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'], help='Name or resource id of the Container App environment.') - c.argument('show_all', options_list=['--show-all'],help='Show all patchable and non-patchable containerapps') - - with self.argument_context('containerapp patch run') 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'], help='Name or resource id of the Container App environment.') - c.argument('show_all', options_list=['--show-all'],help='Show all patchable and non-patchable containerapps') \ No newline at end of file + 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') \ No newline at end of file diff --git a/src/containerapp/azext_containerapp/_utils.py b/src/containerapp/azext_containerapp/_utils.py index cadc1074304..b58135b1783 100644 --- a/src/containerapp/azext_containerapp/_utils.py +++ b/src/containerapp/azext_containerapp/_utils.py @@ -1722,7 +1722,6 @@ def format_location(location=None): return location.lower().replace(" ", "").replace("(", "").replace(")", "") return location - def is_docker_running(): # check to see if docker is running client = None @@ -1776,7 +1775,6 @@ def get_pack_exec_path(): return "" - def patchableCheck(repoTagSplit: str, oryxBuilderRunImgTags, bom): tagProp = parseOryxMarinerTag(repoTagSplit) if tagProp is None: @@ -1839,7 +1837,6 @@ def patchableCheck(repoTagSplit: str, oryxBuilderRunImgTags, bom): } return result - def getCurrentMarinerTags() -> list(OryxMarinerRunImgTagProperty): r = requests.get("https://mcr.microsoft.com/v2/oryx/builder/tags/list") tags = r.json() @@ -1870,7 +1867,6 @@ def getCurrentMarinerTags() -> list(OryxMarinerRunImgTagProperty): tagList[framework] = {majorMinorVer: {support: {marinerVer: [tagObj]}}} return tagList - def parseOryxMarinerTag(tag: str) -> OryxMarinerRunImgTagProperty: tagSplit = tag.split("-") if tagSplit[0] == "run" and tagSplit[1] == "dotnet": diff --git a/src/containerapp/azext_containerapp/commands.py b/src/containerapp/azext_containerapp/commands.py index 4ed96005fd1..2fb296cbb58 100644 --- a/src/containerapp/azext_containerapp/commands.py +++ b/src/containerapp/azext_containerapp/commands.py @@ -53,6 +53,7 @@ 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 @@ -199,7 +200,3 @@ 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') - g.custom_command('run', 'patch_run') diff --git a/src/containerapp/azext_containerapp/custom.py b/src/containerapp/azext_containerapp/custom.py index 7b92c944932..2943faf731a 100644 --- a/src/containerapp/azext_containerapp/custom.py +++ b/src/containerapp/azext_containerapp/custom.py @@ -4301,16 +4301,26 @@ def delete_workload_profile(cmd, resource_group_name, env_name, workload_profile except Exception as e: handle_raw_exception(e) -def patch_list(cmd, resource_group_name, managed_env, show_all=False): - caList = list_containerapp(cmd, resource_group_name, managed_env) + +def patch_list(cmd, resource_group_name, managed_env=None, show_all=False): + if(managed_env): + caList = list_containerapp(cmd, resource_group_name, managed_env) + else: + envList = list_managed_environments(cmd, resource_group_name) + envNames = [] + for env in envList: + envNames.append(env["name"]) + caList = [] + for envName in envNames: + caList+= list_containerapp(cmd,resource_group_name, envName) imgs = [] if caList: for ca in caList: + managedEnvName = ca["properties"]["managedEnvironmentId"].split('/')[-1] containers = ca["properties"]["template"]["containers"] for container in containers: - result = dict(imageName=container["image"], targetContainerName=container["name"], targetContainerAppName=ca["name"], revisionMode=ca["properties"]["configuration"]["activeRevisionsMode"]) - imgs.append(result) - + result = dict(imageName=container["image"], targetContainerName=container["name"], targetContainerAppName=ca["name"], targetContainerAppEnvironmentName = managedEnvName, revisionMode=ca["properties"]["configuration"]["activeRevisionsMode"]) + imgs.append(result) # Get the BOM of the images results = [] boms = [] @@ -4319,7 +4329,7 @@ def patch_list(cmd, resource_group_name, managed_env, show_all=False): # for img in imgs: if (img["imageName"].find("run-dotnet") != -1) and (img["imageName"].find("cbl-mariner") != -1): - bom = { "remote_info": { "run_images": [{ "name": "mcr.microsoft.com/oryx/builder:" + img["imageName"].split(":")[-1] }] }, "image_name": img["imageName"], "targetContainerName": img["targetContainerName"], "targetContainerAppName": img["targetContainerAppName"], "revisionMode": img["revisionMode"] } + bom = { "remote_info": { "run_images": [{ "name": "mcr.microsoft.com/oryx/builder:" + img["imageName"].split(":")[-1] }] }, "image_name": img["imageName"], "targetContainerName": img["targetContainerName"], "targetContainerAppName": img["targetContainerAppName"], "targetContainerAppEnvironmentName": img["targetContainerAppEnvironmentName"], "revisionMode": img["revisionMode"] } else: subprocess.run("pack inspect-image " + img["imageName"] + " --output json > ./bom.json 2>&1", shell=True) with open("./bom.json", "rb") as f: @@ -4329,11 +4339,11 @@ def patch_list(cmd, resource_group_name, managed_env, show_all=False): bom = dict(remote_info=401, image_name=img["imageName"]) else: bom = json.loads(lines) - bom.update({ "targetContainerName": img["targetContainerName"], "targetContainerAppName": img["targetContainerAppName"], "revisionMode": img["revisionMode"] }) + bom.update({ "targetContainerName": img["targetContainerName"], "targetContainerAppName": img["targetContainerAppName"], "targetContainerAppEnvironmentName":img["targetContainerAppEnvironmentName"],"revisionMode": img["revisionMode"] }) + boms.append(bom) # # For testing - # with open("./bom.json", "rb") as f: # lines = f.read() # # if lines.find(b"status code 401 Unauthorized") == -1 or lines.find(b"unable to find image") == -1: @@ -4352,13 +4362,12 @@ def patch_list(cmd, resource_group_name, managed_env, show_all=False): # Start checking if the images are based on Mariner for bom in boms: if bom["remote_info"] == 401: - results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=None, newRunImage=None, id=None, reason=failedReason)) + results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName=bom["targetContainerAppEnvironmentName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=None, newRunImage=None, id=None, reason=failedReason)) else: # devide run-images into different parts by "/" runImagesProps = bom["remote_info"]["run_images"] if runImagesProps is None: - - results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=None, newRunImage=None, id=None, reason=notBasedMarinerReason)) + results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"],targetContainerAppEnvironmentName=bom["targetContainerAppEnvironmentName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=None, newRunImage=None, id=None, reason=notBasedMarinerReason)) else: for runImagesProp in runImagesProps: # result = None @@ -4373,21 +4382,22 @@ def patch_list(cmd, resource_group_name, managed_env, show_all=False): else: results[checkResult["id"]] = checkResult else: - results["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=bom["remote_info"]["run_images"]["name"], newRunImage=None, id=None, reason=failedReason)) + 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["NotPatchable"].append(dict(targetContainerName=bom["targetContainerName"], targetContainerAppName=bom["targetContainerAppName"], revisionMode=bom["revisionMode"], targetImageName=bom["image_name"], oldRunImage=bom["remote_info"]["run_images"]["name"], newRunImage=None, id=None, reason=mcrCheckReason)) + 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 = {k: v for k, v in results.items() if k != "NotPatchable"} return results -def patch_run(cmd, resource_group_name, managed_env, show_all=False): +def patch_run(cmd, resource_group_name, 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"]: print("No patchable image found.") if not show_all: - print("Use --show-all to show all the images' patchable check.") + print("Use --show-all to show all the patchable and unpatchable images.") return else: patchable_check_results_json = json.dumps(patchable_check_results, indent=4) @@ -4410,7 +4420,7 @@ def patch_apply(cmd, patchCheckList, method, resource_group_name): patchCheckList[key]["newRunImage"], patchCheckList[key]["revisionMode"])) elif m == "n": - print("No patch applied.") + print("No patch applied."); return else: if method in patchCheckList.keys(): results.append(patch_cli_call(cmd, @@ -4421,7 +4431,7 @@ def patch_apply(cmd, patchCheckList, method, resource_group_name): patchCheckList[method]["newRunImage"], patchCheckList[method]["revisionMode"])) else: - print("Invalid patch method or id.") + print("Invalid patch method or id."); return return results def patch_cli_call(cmd, resource_group, container_app_name, container_name, target_image_name, new_run_image, revision_mode): @@ -4450,4 +4460,3 @@ def patch_cli_call(cmd, resource_group, container_app_name, container_name, targ except Exception: print("Error: Failed to create new revision with the container app.") raise -