diff --git a/src/containerapp/azext_containerapp/_clients.py b/src/containerapp/azext_containerapp/_clients.py index 0034b61bd85..9c779257250 100644 --- a/src/containerapp/azext_containerapp/_clients.py +++ b/src/containerapp/azext_containerapp/_clients.py @@ -103,7 +103,7 @@ def create_or_update(cls, cmd, resource_group_name, name, container_app_envelope @classmethod def update(cls, cmd, resource_group_name, name, container_app_envelope, no_wait=False): management_hostname = cmd.cli_ctx.cloud.endpoints.resource_manager - api_version = PREVIEW_API_VERSION + api_version = STABLE_API_VERSION sub_id = get_subscription_id(cmd.cli_ctx) url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/containerApps/{}?api-version={}" request_url = url_fmt.format( @@ -117,7 +117,7 @@ def update(cls, cmd, resource_group_name, name, container_app_envelope, no_wait= if no_wait: return r.json() - elif r.status_code == 201: + elif r.status_code == 202: url_fmt = "{}/subscriptions/{}/resourceGroups/{}/providers/Microsoft.App/containerApps/{}?api-version={}" request_url = url_fmt.format( management_hostname.strip('/'), diff --git a/src/containerapp/azext_containerapp/_up_utils.py b/src/containerapp/azext_containerapp/_up_utils.py index 44f6665158c..dfeae4135fd 100644 --- a/src/containerapp/azext_containerapp/_up_utils.py +++ b/src/containerapp/azext_containerapp/_up_utils.py @@ -29,7 +29,7 @@ _get_default_containerapps_location, safe_get, is_int, create_service_principal_for_rbac, repo_url_to_name, get_container_app_if_exists) -from .custom import (create_managed_environment, create_containerapp, list_containerapp, +from .custom import (create_managed_environment, containerapp_up_logic, list_containerapp, list_managed_environments, create_or_update_github_action) logger = get_logger(__name__) @@ -219,7 +219,7 @@ def create(self, no_registry=False): else: logger.warning(f"Creating Containerapp {self.name} in resource group {self.resource_group.name}") - return create_containerapp(cmd=self.cmd, + return containerapp_up_logic(cmd=self.cmd, name=self.name, resource_group_name=self.resource_group.name, image=self.image, @@ -229,8 +229,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, - ingress=self.ingress, - disable_warnings=True) + ingress=self.ingress) def create_acr_if_needed(self): if self.should_create_acr: @@ -252,7 +251,7 @@ def create_acr(self): self.registry_user, self.registry_pass, _ = _get_acr_cred(self.cmd.cli_ctx, registry_name) - def run_acr_build(self, dockerfile, source): + def run_acr_build(self, dockerfile, source, quiet=False): image_name = self.image if self.image is not None else self.name from datetime import datetime now = datetime.now() @@ -260,7 +259,7 @@ def run_acr_build(self, dockerfile, source): image_name += ":{}".format(str(now).replace(' ', '').replace('-', '').replace('.', '').replace(':', '')) self.image = self.registry_server + '/' + image_name - queue_acr_build(self.cmd, self.acr.resource_group.name, self.acr.name, image_name, source, dockerfile, quiet=True) + queue_acr_build(self.cmd, self.acr.resource_group.name, self.acr.name, image_name, source, dockerfile, quiet) def _create_service_principal(cmd, resource_group_name, env_resource_group_name): logger.warning("No valid service principal provided. Creating a new service principal...") @@ -492,13 +491,8 @@ def up_output(app): "ingress", "fqdn") if url and not url.startswith("http"): url = f"http://{url}" - if url: - output = (f"\nYour container app ({app.name}) has been created a deployed! Congrats! \n\n" - f"Browse to your container app at: {url} \n\n" - f"Stream logs for your container with: az containerapp logs -n {app.name} -g {app.resource_group.name} \n\n" - f"See full output using: az containerapp show -n {app.name} -g {app.resource_group.name} \n") - else: - output = (f"\nYour container app ({app.name}) has been created a deployed! Congrats! \n\n" - f"Stream logs for your container with: az containerapp logs -n {app.name} -g {app.resource_group.name} \n\n" - f"See full output using: az containerapp show -n {app.name} -g {app.resource_group.name} \n") - return output + + logger.warning(f"\nYour container app ({app.name}) has been created a deployed! Congrats! \n") + url and logger.warning(f"Browse to your container app at: {url} \n") + logger.warning(f"Stream logs for your container with: az containerapp logs -n {app.name} -g {app.resource_group.name} \n") + logger.warning(f"See full output using: az containerapp show -n {app.name} -g {app.resource_group.name} \n") diff --git a/src/containerapp/azext_containerapp/custom.py b/src/containerapp/azext_containerapp/custom.py index a3515ca44df..6649c86f0ef 100644 --- a/src/containerapp/azext_containerapp/custom.py +++ b/src/containerapp/azext_containerapp/custom.py @@ -2016,6 +2016,10 @@ def containerapp_up(cmd, image = _reformat_image(source, repo, image) token = None if not repo else get_github_access_token(cmd, ["admin:repo_hook", "repo", "workflow"], token) + if image and "mcr.microsoft.com/azuredocs/containerapps-helloworld:latest" in image.lower(): + ingress = "external" if not ingress else ingress + target_port = 80 if not target_port else target_port + dockerfile_content = _get_dockerfile_content(repo, branch, token, source, context_path, dockerfile) ingress, target_port = _get_ingress_and_target_port(ingress, target_port, dockerfile_content) @@ -2025,6 +2029,10 @@ def containerapp_up(cmd, _set_up_defaults(cmd, name, resource_group_name, logs_customer_id, location, resource_group, env, app) + if app.check_exists(): + if app.get()["properties"]["provisioningState"] == "InProgress": + raise ValidationError("Containerapp has an existing provisioning in progress. Please wait until provisioning has completed and rerun the command.") + if source or repo: registry_server = _get_registry_from_app(app) # if the app exists, get the registry _get_registry_details(cmd, app) # fetch ACR creds from arguments registry arguments @@ -2036,7 +2044,7 @@ def containerapp_up(cmd, if source: - app.run_acr_build(dockerfile, source) + app.run_acr_build(dockerfile, source, False) app.create(no_registry=bool(repo)) if repo: @@ -2046,4 +2054,130 @@ def containerapp_up(cmd, if browse: open_containerapp_in_browser(cmd, app.name, app.resource_group.name) - print(up_output(app)) + up_output(app) + + +def containerapp_up_logic(cmd, resource_group_name, name, managed_env, image, env_vars, ingress, target_port, registry_server, registry_user, registry_pass): + containerapp_def = None + try: + containerapp_def = ContainerAppClient.show(cmd=cmd, resource_group_name=resource_group_name, name=name) + except: + pass + + try: + location = ManagedEnvironmentClient.show(cmd, resource_group_name, managed_env.split('/')[-1])["location"] + except: + pass + + ca_exists = False + if containerapp_def: + ca_exists = True + + if not ca_exists: + containerapp_def = None + containerapp_def = ContainerAppModel + containerapp_def["location"] = location + containerapp_def["properties"]["managedEnvironmentId"] = managed_env + containerapp_def["properties"]["configuration"] = ConfigurationModel + else: + # check provisioning state here instead of secrets so no error + _get_existing_secrets(cmd, resource_group_name, name, containerapp_def) + + + container = ContainerModel + container["image"] = image + container["name"] = name + + + if env_vars: + container["env"] = parse_env_var_flags(env_vars) + + + external_ingress = None + if ingress is not None: + if ingress.lower() == "internal": + external_ingress = False + elif ingress.lower() == "external": + external_ingress = True + + + ingress_def = None + if target_port is not None and ingress is not None: + ingress_def = IngressModel + ingress_def["external"] = external_ingress + ingress_def["targetPort"] = target_port + containerapp_def["properties"]["configuration"]["ingress"] = ingress_def + + + # handle multi-container case + if ca_exists: + existing_containers = containerapp_def["properties"]["template"]["containers"] + if len(existing_containers) == 0: + # No idea how this would ever happen, failed provisioning maybe? + containerapp_def["properties"]["template"] = TemplateModel + containerapp_def["properties"]["template"]["containers"] = [container] + if len(existing_containers) == 1: + # Assume they want it updated + existing_containers[0] = container + if len(existing_containers) > 1: + # Assume they want to update, if not existing just add it + existing_containers = [x for x in existing_containers if x['name'].lower() == name.lower()] + if len(existing_containers) == 1: + existing_containers[0] = container + else: + existing_containers.append(container) + containerapp_def["properties"]["template"]["containers"] = existing_containers + else: + containerapp_def["properties"]["template"] = TemplateModel + containerapp_def["properties"]["template"]["containers"] = [container] + + + registries_def = None + registry = None + + + if "secrets" not in containerapp_def["properties"]["configuration"] or containerapp_def["properties"]["configuration"]["secrets"] == None: + containerapp_def["properties"]["configuration"]["secrets"] = [] + + + if "registries" not in containerapp_def["properties"]["configuration"] or containerapp_def["properties"]["configuration"]["registries"] == None: + containerapp_def["properties"]["configuration"]["registries"] = [] + + + registries_def = containerapp_def["properties"]["configuration"]["registries"] + + if registry_server: + # Check if updating existing registry + updating_existing_registry = False + for r in registries_def: + if r['server'].lower() == registry_server.lower(): + updating_existing_registry = True + if registry_user: + r["username"] = registry_user + if registry_pass: + r["passwordSecretRef"] = store_as_secret_and_return_secret_ref( + containerapp_def["properties"]["configuration"]["secrets"], + r["username"], + r["server"], + registry_pass, + update_existing_secret=True) + + + # If not updating existing registry, add as new registry + if not updating_existing_registry: + registry = RegistryCredentialsModel + registry["server"] = registry_server + registry["username"] = registry_user + registry["passwordSecretRef"] = store_as_secret_and_return_secret_ref( + containerapp_def["properties"]["configuration"]["secrets"], + registry_user, + registry_server, + registry_pass, + update_existing_secret=True) + + registries_def.append(registry) + + if ca_exists: + return ContainerAppClient.update(cmd, resource_group_name, name, containerapp_def) + else: + return ContainerAppClient.create_or_update(cmd, resource_group_name, name, containerapp_def) \ No newline at end of file