Skip to content

Commit

Permalink
[Deployment Manager] Add `az deploymentmanager rollout/service/servic…
Browse files Browse the repository at this point in the history
…e-topology/service-unit/step list` commands (#11757)

* DeploymentManager 2019-11-preview update

* Modify tests, update history.rst

* Fix pylint and style errors

* Styling fixes

* Fixing fileInput close for test automation pass

* Incorporate feedback

* Incorporated feedback + Re-record tests after merge

* Fix styling errors

* Incorporated feedback

* Incorporated feedback

* Fix cli styling errors

* rearrange history

Co-authored-by: Zunli Hu <zuh@microsoft.com>
  • Loading branch information
deveshguha and Juliehzl authored Jan 30, 2020
1 parent a92152c commit f8fcf6f
Show file tree
Hide file tree
Showing 17 changed files with 2,150 additions and 934 deletions.
6 changes: 6 additions & 0 deletions src/azure-cli/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ Release History
* Add new commands group 'cdn endpoint rule' to manage rules
* Update azure-mgmt-cdn version to 4.0.0 to use api version 2019-04-15

**Deployment Manager**

* Add list operation for all resources.
* Enhance step resource for new step type.
* Update azure-mgmt-deploymentmanager package to use version 0.2.0.

**IoT**

* Deprecated 'IoT hub Job' commands.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@
az deploymentmanager artifact-source show -g rg1 -n contosoServiceArtifactSource
"""

helps['deploymentmanager artifact-source list'] = """
type: command
short-summary: List all artifact sources in a resource group.
examples:
- name: List artifact sources in the given resource group.
text: >
az deploymentmanager artifact-source list -g rg1
"""

helps['deploymentmanager artifact-source update'] = """
type: command
short-summary: Updates an artifact source.
Expand Down Expand Up @@ -85,6 +94,15 @@
az deploymentmanager rollout show -g rg1 -n contosoServiceRollout --retry-attempt 1
"""

helps['deploymentmanager rollout list'] = """
type: command
short-summary: List all rollouts in a resource group
examples:
- name: List all rollouts in the resource group
text: >
az deploymentmanager rollout list -g rg1
"""

helps['deploymentmanager rollout stop'] = """
type: command
short-summary: Stop the rollout.
Expand Down Expand Up @@ -126,6 +144,15 @@
az deploymentmanager service show -g rg1 --service-topology-name contosoServiceTopology -n contosoService1
"""

helps['deploymentmanager service list'] = """
type: command
short-summary: List all services in a service topology.
examples:
- name: List all the services under the given service topology.
text: >
az deploymentmanager service list -g rg1 --service-topology-name contosoServiceTopology
"""

helps['deploymentmanager service update'] = """
type: command
short-summary: Updates the service.
Expand Down Expand Up @@ -167,6 +194,15 @@
az deploymentmanager service-topology show -g rg1 -n contosoServiceTopology
"""

helps['deploymentmanager service-topology list'] = """
type: command
short-summary: List all service topologies in a resource group.
examples:
- name: List all the service topologies in the resource group.
text: >
az deploymentmanager service-topology list -g rg1
"""

helps['deploymentmanager service-topology update'] = """
type: command
short-summary: Updates the service topology.
Expand Down Expand Up @@ -217,6 +253,15 @@
az deploymentmanager service-unit show -g rg1 --service-topology-name contosoServiceTopology --service-name contosoService1 -n ContosoService1Storage
"""

helps['deploymentmanager service-unit list'] = """
type: command
short-summary: List all service units in a service.
examples:
- name: List the service units in the given service topology and service.
text: >
az deploymentmanager service-unit list -g rg1 --service-topology-name contosoServiceTopology --service-name contosoService1
"""

helps['deploymentmanager service-unit update'] = """
type: command
short-summary: Updates the service unit.
Expand All @@ -239,9 +284,12 @@
type: command
short-summary: Creates the step.
examples:
- name: Creates a step.
- name: Creates a wait step.
text: >
az deploymentmanager step create -g rg1 -l location -n contosoServiceWaitStep --duration PT30M
- name: Creates a health check step from a JSON file. The step information is read from the file.
text: >
az deploymentmanager step create -g rg1 --step healthcheck_step.json
"""

helps['deploymentmanager step show'] = """
Expand All @@ -253,6 +301,15 @@
az deploymentmanager step show -g rg1 -n contosoServiceWaitStep
"""

helps['deploymentmanager step list'] = """
type: command
short-summary: List all steps in a resource group.
examples:
- name: List available steps in the given resource group.
text: >
az deploymentmanager step list -g rg1
"""

helps['deploymentmanager step update'] = """
type: command
short-summary: Updates the step.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,24 +119,27 @@ def load_arguments(self, _):

duration_type = CLIArgumentType(options_list='--duration', help='The duration of the wait step in ISO 8601 format.')
step_name_type = CLIArgumentType(options_list=['--step-name', '--name', '-n'], help='The name of the step', completer=get_resource_name_completion_list('Microsoft.DeploymentManager/steps'))
step_type = CLIArgumentType(options_list='--step', help='The step object, specify either the path to a json file or provide a json string that forms the step resource. The json is expected to be of the same format as the output of the relevant `az deploymentmanager step show` command')

with self.argument_context('deploymentmanager step') as c:
c.argument('resource_group_name', resource_group_name_type)
c.argument('location', get_location_type(self.cli_ctx), required=True)
c.argument('location', get_location_type(self.cli_ctx))
c.argument('step_name', step_name_type)
c.argument('duration', duration_type)
c.argument('tags', tags_type)

with self.argument_context('deploymentmanager step create') as c:
c.argument('resource_group_name', resource_group_name_type)
c.argument('location', get_location_type(self.cli_ctx), required=True)
c.argument('location', get_location_type(self.cli_ctx))
c.argument('step_name', step_name_type)
c.argument('step', step_type)
c.argument('duration', duration_type)
c.argument('tags', tags_type)

with self.argument_context('deploymentmanager step update') as c:
c.argument('resource_group_name', resource_group_name_type)
c.argument('step_name', step_name_type)
c.argument('step', step_type)
c.argument('duration', duration_type)
c.argument('tags', tags_type)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def load_command_table(self, _):
g.custom_command('create', 'cli_artifact_source_create')
g.command('delete', 'delete', confirmation="There might be rollouts referencing the artifact source. Do you want to delete?")
g.command('show', 'get')
g.command('list', 'list')
g.generic_update_command(
'update',
setter_arg_name='artifact_source_info',
Expand All @@ -51,6 +52,7 @@ def load_command_table(self, _):
g.custom_command('create', 'cli_service_topology_create')
g.command('delete', 'delete')
g.command('show', 'get')
g.command('list', 'list')
g.generic_update_command(
'update',
setter_arg_name='service_topology_info',
Expand All @@ -61,6 +63,7 @@ def load_command_table(self, _):
g.custom_command('create', 'cli_service_create')
g.command('delete', 'delete')
g.command('show', 'get')
g.command('list', 'list')
g.generic_update_command(
'update',
setter_arg_name='service_info',
Expand All @@ -71,6 +74,7 @@ def load_command_table(self, _):
g.custom_command('create', 'cli_service_unit_create')
g.command('delete', 'delete')
g.command('show', 'get')
g.command('list', 'list')
g.generic_update_command(
'update',
setter_arg_name='service_unit_info',
Expand All @@ -81,6 +85,7 @@ def load_command_table(self, _):
g.custom_command('create', 'cli_step_create')
g.command('delete', 'delete')
g.command('show', 'get')
g.command('list', 'list')
g.generic_update_command(
'update',
setter_arg_name='step_info',
Expand All @@ -89,6 +94,7 @@ def load_command_table(self, _):

with self.command_group('deploymentmanager rollout', rollouts) as g:
g.command('show', 'get')
g.command('list', 'list')
g.command('stop', 'cancel', confirmation="Do you want to cancel the rollout?")
g.custom_command(
'restart',
Expand Down
111 changes: 95 additions & 16 deletions src/azure-cli/azure/cli/command_modules/deploymentmanager/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import json
import os
from knack.log import get_logger
from knack.util import CLIError

from azure.cli.core.util import get_file_json, shell_safe_json_parse

from azure.cli.command_modules.deploymentmanager._client_factory import (
cf_artifact_sources,
cf_service_topologies,
Expand Down Expand Up @@ -271,39 +275,72 @@ def cli_service_unit_update(
def cli_step_create(
cmd,
resource_group_name,
step_name,
duration,
step_name=None,
step=None,
duration=None,
location=None,
tags=None):

waitStepProperties = WaitStepProperties(
attributes=WaitStepAttributes(duration=duration))
if step is None and duration is None:
raise CLIError('usage error: specify either step or duration. \
If step is specified, it can either be a wait step or health check step.')

if location is None:
location = get_location_from_resource_group(cmd.cli_ctx, resource_group_name)

step = StepResource(
properties=waitStepProperties,
location=location,
tags=tags)
if step is not None and duration is not None:
raise CLIError('usage error: specify only one of step or duration. \
If step is specified, it can either be a wait step or health check step.')

client = cf_steps(cmd.cli_ctx)
if step is not None:
step_resource = get_step_from_json(client, step)
step_name = step_resource.name

elif duration is not None:
if step_name is None:
raise CLIError('usage error: step name is not specified.')

waitStepProperties = WaitStepProperties(attributes=WaitStepAttributes(duration=duration))

if location is None:
if resource_group_name is not None:
location = get_location_from_resource_group(cmd.cli_ctx, resource_group_name)

step_resource = StepResource(
properties=waitStepProperties,
location=location,
tags=tags)

return client.create_or_update(
resource_group_name=resource_group_name,
step_name=step_name,
step_info=step)
step_info=step_resource)


def cli_step_update(
cmd,
instance,
duration,
step=None,
duration=None,
tags=None):

instance.properties.attributes.duration = duration
if (step is None and duration is None):
raise CLIError('usage error: specify either step or duration. \
If step is specified, it can either be a wait step or health check step.')

if tags is not None:
instance.tags = tags
if (step is not None and duration is not None):
raise CLIError('usage error: specify only one of step or duration. \
If step is specified, it can either be a wait step or health check step.')

if duration is not None:
instance.properties.attributes.duration = duration

# only update tags if updating duration property. If updating step from a file, read everything from file.
if tags is not None:
instance.tags = tags

elif step is not None:
client = cf_steps(cmd.cli_ctx)
step_resource = get_step_from_json(client, step)
instance = step_resource

return instance

Expand All @@ -327,3 +364,45 @@ def get_location_from_resource_group(cli_ctx, resource_group_name):
client = get_mgmt_service_client(cli_ctx, ResourceType.MGMT_RESOURCE_RESOURCES)
group = client.resource_groups.get(resource_group_name)
return group.location


def get_step_from_json(client, health_check_step):
return get_object_from_json(client, health_check_step, 'StepResource')


def get_or_read_json(json_or_file):
json_obj = None
if is_json(json_or_file):
json_obj = shell_safe_json_parse(json_or_file)
elif os.path.exists(json_or_file):
json_obj = get_file_json(json_or_file)
if json_obj is None:
raise ValueError(
"""
The variable passed should be in valid JSON format and be supplied by az deploymentmanager step CLI command.
Make sure that you use output of relevant 'az deploymentmanager step show' command and the --out is 'json'
""")
return json_obj


def get_object_from_json(client, json_or_file, class_name):
# Determine if input is json or file
json_obj = get_or_read_json(json_or_file)

# Deserialize json to object
param = client._deserialize(class_name, json_obj) # pylint: disable=protected-access
if param is None:
raise ValueError(
"""
The variable passed should be in valid JSON format and be supplied by az deploymentmanager step CLI command.
Make sure that you use output of relevant 'az deploymentmanager step show' commands and the --out is 'json'
""")
return param


def is_json(content):
try:
json.loads(content)
except ValueError:
return False
return True
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"Identity": {
"type": "userAssigned",
"identityIds": [
"/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourcegroups/cliadmxy32gy/providers/Microsoft.ManagedIdentity/userAssignedIdentities/cliadmxy32gyIdentity"
"__USER_ASSIGNED_IDENTITY__"
]
},
"properties": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"Identity": {
"type": "userAssigned",
"identityIds": [
"/subscriptions/0b1f6471-1bf0-4dda-aec3-cb9272f09590/resourcegroups/cliadmxy32gy/providers/Microsoft.ManagedIdentity/userAssignedIdentities/cliadmxy32gyIdentity"
"__USER_ASSIGNED_IDENTITY__"
]
},
"properties": {
Expand Down
Loading

0 comments on commit f8fcf6f

Please sign in to comment.