Skip to content

Commit

Permalink
Merged.
Browse files Browse the repository at this point in the history
  • Loading branch information
Haroon Feisal committed Apr 22, 2022
2 parents bfcace8 + 0ba7185 commit 39dad3d
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 34 deletions.
2 changes: 1 addition & 1 deletion src/containerapp/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Release History
===============

0.4.0
0.3.2
++++++
* Create or update a container app and all associated resources (container app environment, ACR, Github Actions, resource group, etc.) with 'az containerapp up'
* Open an ssh-like shell in a Container App with 'az containerapp exec'
Expand Down
4 changes: 4 additions & 0 deletions src/containerapp/azext_containerapp/.flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
ignore =
W503 # line break before binary operator, not compliant with PEP 8
E203 # whitespace before ':', not compliant with PEP 8
6 changes: 3 additions & 3 deletions src/containerapp/azext_containerapp/_clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ def list_replicas(cls, cmd, resource_group_name, container_app_name, revision_na
resource_group_name,
container_app_name,
revision_name,
PREVIEW_API_VERSION)
STABLE_API_VERSION)

r = send_raw_request(cmd.cli_ctx, "GET", request_url)
j = r.json()
Expand Down Expand Up @@ -395,7 +395,7 @@ def get_replica(cls, cmd, resource_group_name, container_app_name, revision_name
container_app_name,
revision_name,
replica_name,
PREVIEW_API_VERSION)
STABLE_API_VERSION)

r = send_raw_request(cmd.cli_ctx, "GET", request_url)
return r.json()
Expand All @@ -410,7 +410,7 @@ def get_auth_token(cls, cmd, resource_group_name, name):
sub_id,
resource_group_name,
name,
PREVIEW_API_VERSION)
STABLE_API_VERSION)

r = send_raw_request(cmd.cli_ctx, "POST", request_url)
return r.json()
Expand Down
10 changes: 5 additions & 5 deletions src/containerapp/azext_containerapp/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@

helps['containerapp exec'] = """
type: command
short-summary: Open an SSH-like interactive shell within a container app replica (pod)
short-summary: Open an SSH-like interactive shell within a container app replica
examples:
- name: exec into a container app
text: |
Expand Down Expand Up @@ -132,7 +132,7 @@

helps['containerapp logs show'] = """
type: command
short-summary: Show past logs and/or print logs in real time (with the --follow parameter). Note that the logs are only taken from one revision, replica (pod), and container.
short-summary: Show past logs and/or print logs in real time (with the --follow parameter). Note that the logs are only taken from one revision, replica, and container.
examples:
- name: Fetch the past 20 lines of logs from an app and return
text: |
Expand All @@ -148,12 +148,12 @@
# Replica Commands
helps['containerapp replica'] = """
type: group
short-summary: Manage container app replicas (pods)
short-summary: Manage container app replicas
"""

helps['containerapp replica list'] = """
type: command
short-summary: List a container app revision's replicas (pods)
short-summary: List a container app revision's replica
examples:
- name: List a container app's replicas in the latest revision
text: |
Expand All @@ -165,7 +165,7 @@

helps['containerapp replica show'] = """
type: command
short-summary: Show a container app replica (pod)
short-summary: Show a container app replica
examples:
- name: Show a replica from the latest revision
text: |
Expand Down
8 changes: 3 additions & 5 deletions src/containerapp/azext_containerapp/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def load_arguments(self, _):

with self.argument_context('containerapp exec') as c:
c.argument('container', help="The name of the container to ssh into")
c.argument('replica', help="The name of the replica (pod) to ssh into. List replicas with 'az containerapp replica list'. A replica may not exist if there is not traffic to your app.")
c.argument('replica', help="The name of the replica to ssh into. List replicas with 'az containerapp replica list'. A replica may not exist if there is not traffic to your app.")
c.argument('revision', help="The name of the container app revision to ssh into. Defaults to the latest revision.")
c.argument('startup_command', options_list=["--command"], help="The startup command (bash, zsh, sh, etc.).")
c.argument('name', name_type, id_part=None, help="The name of the Containerapp.")
Expand All @@ -44,21 +44,20 @@ def load_arguments(self, _):
c.argument('tail', help="The number of past logs to print (0-300)", type=int, default=20)
c.argument('container', help="The name of the container")
c.argument('output_format', options_list=["--format"], help="Log output format", arg_type=get_enum_type(["json", "text"]), default="json")
c.argument('replica', help="The name of the replica (pod). List replicas with 'az containerapp replica list'. A replica may not exist if there is not traffic to your app.")
c.argument('replica', help="The name of the replica. List replicas with 'az containerapp replica list'. A replica may not exist if there is not traffic to your app.")
c.argument('revision', help="The name of the container app revision. Defaults to the latest revision.")
c.argument('name', name_type, id_part=None, help="The name of the Containerapp.")
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)

# Replica
with self.argument_context('containerapp replica') as c:
c.argument('replica', help="The name of the replica (pod). ")
c.argument('replica', help="The name of the replica. ")
c.argument('revision', help="The name of the container app revision. Defaults to the latest revision.")
c.argument('name', name_type, id_part=None, help="The name of the Containerapp.")
c.argument('resource_group_name', arg_type=resource_group_name_type, id_part=None)

# Container
with self.argument_context('containerapp', arg_group='Container') as c:
# c.argument('image', type=str, options_list=['--image', '-i'], help="Container image, e.g. publisher/image-name:tag.")
c.argument('container_name', type=str, help="Name of the container.")
c.argument('cpu', type=float, validator=validate_cpu, help="Required CPU in cores from 0.25 - 2.0, e.g. 0.5")
c.argument('memory', type=str, validator=validate_memory, help="Required memory from 0.5 - 4.0 ending with \"Gi\", e.g. 1.0Gi")
Expand Down Expand Up @@ -225,7 +224,6 @@ def load_arguments(self, _):
c.argument('name', configured_default='name', id_part=None)
c.argument('managed_env', configured_default='managed_env')
c.argument('registry_server', configured_default='registry_server')
c.argument('dryrun', help="Show summary of the operation instead of executing it.")
c.argument('source', type=str, help='Local directory path to upload to Azure container registry.')
c.argument('image', type=str, 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.')
Expand Down
42 changes: 29 additions & 13 deletions src/containerapp/azext_containerapp/_up_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
MutuallyExclusiveArgumentError)
from azure.cli.core.commands.client_factory import get_subscription_id
from azure.cli.command_modules.appservice._create_util import check_resource_group_exists
from azure.cli.command_modules.acr.custom import acr_show
from azure.cli.core.commands.client_factory import get_mgmt_service_client
from azure.mgmt.containerregistry import ContainerRegistryManagementClient
from knack.log import get_logger

from msrestazure.tools import parse_resource_id, is_valid_resource_id, resource_id
Expand Down Expand Up @@ -381,16 +384,19 @@ def _get_env_and_group_from_log_analytics(cmd, resource_group_name, env:'Contain

def _get_acr_from_image(cmd, app):
if app.image is not None and "azurecr.io" in app.image:
app.registry_server = app.image.split('/')[0] # TODO what if this conflicts with registry_server param?
parsed = urlparse(app.image)
registry_name = (parsed.netloc if parsed.scheme else parsed.path).split('.')[0]
if app.registry_user is None or app.registry_pass is None:
logger.info('No credential was provided to access Azure Container Registry. Trying to look up...')
app.registry_server = app.image.split('/')[0] # TODO what if this conflicts with registry_server param?
parsed = urlparse(app.image)
registry_name = (parsed.netloc if parsed.scheme else parsed.path).split('.')[0]
try:
app.registry_user, app.registry_pass, registry_rg = _get_acr_cred(cmd.cli_ctx, registry_name)
app.acr = AzureContainerRegistry(registry_name, ResourceGroup(cmd, registry_rg, None, None))
except Exception as ex:
raise RequiredArgumentMissingError('Failed to retrieve credentials for container registry. Please provide the registry username and password') from ex
try:
app.registry_user, app.registry_pass, registry_rg = _get_acr_cred(cmd.cli_ctx, registry_name)
app.acr = AzureContainerRegistry(registry_name, ResourceGroup(cmd, registry_rg, None, None))
except Exception as ex:
raise RequiredArgumentMissingError('Failed to retrieve credentials for container registry. Please provide the registry username and password') from ex
else:
acr_rg = _get_acr_rg(app)
app.acr = AzureContainerRegistry(name=registry_name, resource_group=ResourceGroup(app.cmd, acr_rg, None, None))


def _get_registry_from_app(app):
Expand All @@ -400,28 +406,36 @@ def _get_registry_from_app(app):
app.registry_server = containerapp_def["properties"]["configuration"]["registries"][0]["server"]


def _get_acr_rg(app):
registry_name = app.registry_server[:app.registry_server.rindex(".azurecr.io")]
client = get_mgmt_service_client(app.cmd.cli_ctx, ContainerRegistryManagementClient).registries
return parse_resource_id(acr_show(app.cmd, client, registry_name).id)["resource_group"]

def _get_registry_details(cmd, app: 'ContainerApp'):
registry_rg = None
registry_name = None
if app.registry_server:
if "azurecr.io" not in app.registry_server:
raise ValidationError("Cannot supply non-Azure registry when using --source.")
parsed = urlparse(app.registry_server)
registry_name = (parsed.netloc if parsed.scheme else parsed.path).split('.')[0]
if app.registry_user is None or app.registry_pass is None:
logger.info('No credential was provided to access Azure Container Registry. Trying to look up...')
parsed = urlparse(app.registry_server)
registry_name = (parsed.netloc if parsed.scheme else parsed.path).split('.')[0]
try:
app.registry_user, app.registry_pass, registry_rg = _get_acr_cred(cmd.cli_ctx, registry_name)
except Exception as ex:
raise RequiredArgumentMissingError('Failed to retrieve credentials for container registry. Please provide the registry username and password') from ex
else:
registry_rg = _get_acr_rg(app)
else:
registry_rg = app.resource_group.name
user = get_profile_username()
registry_name = app.name.replace('-','')
registry_name = registry_name + str(hash((registry_rg, user, app.name))).replace("-", "")[:10]
registry_name = f"ca{registry_name}acr"
registry_name = app.name.replace('-','').lower()
registry_name = registry_name + str(hash((registry_rg, user, app.name))).replace("-", "").replace(".", "")[:10] # cap at 15 characters total
registry_name = f"ca{registry_name}acr" # ACR names must start + end in a letter
app.registry_server = registry_name + ".azurecr.io"
app.should_create_acr = True

app.acr = AzureContainerRegistry(registry_name, ResourceGroup(cmd, registry_rg, None, None))


Expand All @@ -437,6 +451,7 @@ def _set_up_defaults(cmd, name, resource_group_name, logs_customer_id, location,
# get ACR details from --image, if possible
_get_acr_from_image(cmd, app)


def _create_github_action(app:'ContainerApp',
env:'ContainerAppEnvironment',
service_principal_client_id, service_principal_client_secret, service_principal_tenant_id,
Expand Down Expand Up @@ -469,6 +484,7 @@ def _create_github_action(app:'ContainerApp',
image=app.image,
context_path=context_path)


def up_output(app):
url = safe_get(ContainerAppClient.show(app.cmd, app.resource_group.name, app.name), "properties",
"configuration",
Expand Down
6 changes: 3 additions & 3 deletions src/containerapp/azext_containerapp/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def is_int(s):
return False


def await_github_action(cmd, token, repo, branch, name, resource_group_name, timeout=300):
def await_github_action(cmd, token, repo, branch, name, resource_group_name, timeout_secs=300):
from .custom import show_github_action
from github import Github
from time import sleep
Expand Down Expand Up @@ -187,7 +187,7 @@ def await_github_action(cmd, token, repo, branch, name, resource_group_name, tim
sleep(1)
animation.tick()

if (datetime.utcnow() - start).seconds >= timeout:
if (datetime.utcnow() - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to start.")

animation.flush()
Expand All @@ -202,7 +202,7 @@ def await_github_action(cmd, token, repo, branch, name, resource_group_name, tim
animation.tick()
status = [wf.status for wf in workflow.get_runs() if wf.id == run_id][0]
animation.flush()
if (datetime.utcnow() - start).seconds >= timeout:
if (datetime.utcnow() - start).seconds >= timeout_secs:
raise CLIInternalError("Timed out while waiting for the Github action to start.")

if status != "completed":
Expand Down
7 changes: 4 additions & 3 deletions src/containerapp/azext_containerapp/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,7 @@ def create_or_update_github_action(cmd,
registry_name = (parsed.netloc if parsed.scheme else parsed.path).split('.')[0]

try:
registry_username, registry_password = _get_acr_cred(cmd.cli_ctx, registry_name)
registry_username, registry_password, _ = _get_acr_cred(cmd.cli_ctx, registry_name)
except Exception as ex:
raise RequiredArgumentMissingError('Failed to retrieve credentials for container registry. Please provide the registry username and password') from ex

Expand Down Expand Up @@ -1725,7 +1725,6 @@ def set_secrets(cmd, name, resource_group_name, secrets,
# yaml=None,
no_wait=False):
_validate_subscription_registered(cmd, "Microsoft.App")

# if not yaml and not secrets:
# raise RequiredArgumentMissingError('Usage error: --secrets is required if not using --yaml')

Expand Down Expand Up @@ -2008,7 +2007,7 @@ def containerapp_up(cmd,
service_principal_tenant_id=None):
from ._up_utils import (_validate_up_args, _reformat_image, _get_dockerfile_content, _get_ingress_and_target_port,
ResourceGroup, ContainerAppEnvironment, ContainerApp, _get_registry_from_app,
_get_registry_details, _create_github_action, _set_up_defaults, up_output)
_get_registry_details, _create_github_action, _set_up_defaults, up_output, AzureContainerRegistry)

dockerfile="Dockerfile" # for now the dockerfile name must be "Dockerfile" (until GH actions API is updated)

Expand Down Expand Up @@ -2042,6 +2041,8 @@ def containerapp_up(cmd,
env.create_if_needed(name)
app.create_acr_if_needed()



if source:
app.run_acr_build(dockerfile, source, False)

Expand Down
2 changes: 1 addition & 1 deletion src/containerapp/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# TODO: Confirm this is the right version number you want and it matches your
# HISTORY.rst entry.

VERSION = '0.4.0'
VERSION = '0.3.2'


# The full list of classifiers is available at
Expand Down

0 comments on commit 39dad3d

Please sign in to comment.