From 0018963d51499deaf14badddd0d55f70d7e1987b Mon Sep 17 00:00:00 2001 From: Nicholas King Date: Tue, 24 Apr 2018 17:20:34 -0700 Subject: [PATCH 1/3] First draft of webapps snapshot commands --- src/index.json | 4 ++-- src/webapp/azext_webapp/__init__.py | 16 ++++++++++++- src/webapp/azext_webapp/_help.py | 23 +++++++++++++++++++ src/webapp/azext_webapp/custom.py | 35 ++++++++++++++++++++++++++++- src/webapp/setup.py | 2 +- 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/index.json b/src/index.json index e5eb9faac72..8c864cb912f 100644 --- a/src/index.json +++ b/src/index.json @@ -281,7 +281,7 @@ ], "webapp": [ { - "filename": "webapp-0.2.1-py2.py3-none-any.whl", + "filename": "webapp-0.2.2-py2.py3-none-any.whl", "sha256Digest": "fe3b28cc9cb2272a36c395ed6279b2a9f925b16877962bf2448a3fa56819bfa4", "downloadUrl": "https://github.com/panchagnula/azure-cli-extensions/raw/sisirap-extensions-whl/dist/webapp-0.2.1-py2.py3-none-any.whl", "metadata": { @@ -322,7 +322,7 @@ "metadata_version": "2.0", "name": "webapp", "summary": "An Azure CLI Extension to manage appservice resources", - "version": "0.2.1" + "version": "0.2.2" } } ], diff --git a/src/webapp/azext_webapp/__init__.py b/src/webapp/azext_webapp/__init__.py index 5acbe9846b3..1bc405a1852 100644 --- a/src/webapp/azext_webapp/__init__.py +++ b/src/webapp/azext_webapp/__init__.py @@ -23,6 +23,8 @@ def __init__(self, cli_ctx=None): def load_command_table(self, _): with self.command_group('webapp') as g: g.custom_command('up', 'create_deploy_webapp') + g.custom_command('config snapshot list', 'list_webapp_snapshots') + g.custom_command('config snapshot restore', 'restore_webapp_snapshot') return self.command_table def load_arguments(self, _): @@ -31,6 +33,18 @@ def load_arguments(self, _): c.argument('dryrun', help="shows summary of the create and deploy operation instead of executing it", default=False, action='store_true') - + with self.argument_context('webapp config snapshot list') as c: + c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of resource group.') + c.argument('name', options_list=['--webapp-name', '-n'], help='Name of the webapp.') + c.argument('slot', options_list=['--slot', '-s'], help='Name of the webapp slot.') + with self.argument_context('webapp config snapshot restore') as c: + c.argument('resource_group', options_list=['--resource-group', '-g'], help='Name of resource group to restore to.') + c.argument('name', options_list=['--webapp-name', '-n'], help='Name of the webapp to restore to.') + c.argument('time', options_list=['--time', '-t'], help='Timestamp of the snapshot to restore.') + c.argument('slot', options_list=['--slot', '-s'], help='Name of the webapp slot to restore to.') + c.argument('restore_config', options_list=['--restore-config'], help='Restore the previous configuration along with web app content.') + c.argument('source_resource_group', options_list=['--source-resource-group'], help='Name of the resource group to retrieve snapshot from.') + c.argument('source_name', options_list=['--source-webapp-name'], help='Name of the webapp to retrieve snapshot from.') + c.argument('source_slot', options_list=['--source-slot'], help='Name of the webapp slot to retrieve snapshot from.') COMMAND_LOADER_CLS = WebappExtCommandLoader diff --git a/src/webapp/azext_webapp/_help.py b/src/webapp/azext_webapp/_help.py index 2aa436e7cd7..afe748b63d2 100644 --- a/src/webapp/azext_webapp/_help.py +++ b/src/webapp/azext_webapp/_help.py @@ -16,3 +16,26 @@ az webapp up -n MyUniqueAppName --dryrun \n az webapp up -n MyUniqueAppName -l locationName """ + +helps['webapp config snapshot list'] = """ + type: command + short-summary: List the snapshots available for a web app. + Snapshots are automatically managed backups of web app content and configuration. + examples: + - name: List the snapshots available for a web app named MyApp. + text: > + az webapp config snapshot list -g Default-Web-WestUS -n MyApp +""" + +helps['webapp config snapshot restore'] = """ + type: command + short-summary: Restore a snapshot to a web app. + A snapshot from a different web app or slot can be restored by specifying the source. + examples: + - name: Overwrite a web app with its own snapshot. + text: > + az webapp config snapshot restore -g Default-Web-WestUS -n MyApp -t 2018-04-25T00:09:20.8736381Z + - name: Overwrite a web app's staging slot with a snapshot from its production slot. + text: > + az webapp config snapshot restore -g Default-Web-WestUS -n MyApp -s staging -t 2018-04-25T00:09:20.8736381Z --source-resource-group Default-Web-WestUS --source-name MyApp --restore-config +""" \ No newline at end of file diff --git a/src/webapp/azext_webapp/custom.py b/src/webapp/azext_webapp/custom.py index 34be7f65cfd..22ab600159e 100644 --- a/src/webapp/azext_webapp/custom.py +++ b/src/webapp/azext_webapp/custom.py @@ -5,8 +5,11 @@ from __future__ import print_function from knack.log import get_logger +from knack.util import CLIError -from azure.mgmt.web.models import (AppServicePlan, SkuDescription) +from azure.mgmt.web.models import (AppServicePlan, SkuDescription, SnapshotRecoveryRequest, SnapshotRecoveryTarget) + +from azure.cli.core.commands.client_factory import get_subscription_id from azure.cli.command_modules.appservice.custom import ( enable_zip_deploy, @@ -178,3 +181,33 @@ def create_deploy_webapp(cmd, name, location=None, dryrun=False): create_json.update({'app_url': url}) logger.warning("All done.") return create_json + +def list_webapp_snapshots(cmd, resource_group, name, slot=None): + client = web_client_factory(cmd.cli_ctx) + if slot is None: + return client.web_apps.list_snapshots(resource_group, name) + else: + return client.web_apps.list_snapshots_slot(resource_group, name, slot) + +def restore_webapp_snapshot(cmd, resource_group, name, time, slot=None, restore_config=False, source_resource_group=None, source_name=None, source_slot=None): + client = web_client_factory(cmd.cli_ctx) + + if all([source_resource_group, source_name]): + sub_id = get_subscription_id(cmd.cli_ctx) + target_id = "/subscriptions/" + sub_id + "/resourceGroups/" + resource_group + "/providers/Microsoft.Web/sites/" + name + if slot: + target_id = target_id + "/slots/" + slot + target = SnapshotRecoveryTarget(id=target_id) + request = SnapshotRecoveryRequest(False, snapshot_time=time, recovery_target=target, recover_configuration=restore_config) + if source_slot: + return client.web_apps.recover_slot(source_resource_group, source_name, request, source_slot) + else: + return client.web_apps.recover(source_resource_group, source_name, request) + elif any([source_resource_group, source_name]): + raise CLIError('usage error: source-resource_group and source-name must both be specified if one is used') + else: + request = SnapshotRecoveryRequest(True, snapshot_time=time, recover_configuration=restore_config) + if slot: + return client.web_apps.recover_slot(resource_group, name, request, slot) + else: + return client.web_apps.recover(resource_group, name, request) \ No newline at end of file diff --git a/src/webapp/setup.py b/src/webapp/setup.py index 6dc1e9a56f9..a5c94a56fb2 100644 --- a/src/webapp/setup.py +++ b/src/webapp/setup.py @@ -8,7 +8,7 @@ from codecs import open from setuptools import setup, find_packages -VERSION = "0.2.1" +VERSION = "0.2.2" CLASSIFIERS = [ 'Development Status :: 4 - Beta', From e31c8a4ec6093d5c39c8a8702dbe8c0bdae7bad8 Mon Sep 17 00:00:00 2001 From: Nicholas King Date: Wed, 25 Apr 2018 12:39:40 -0700 Subject: [PATCH 2/3] Fixes for linter errors --- src/index.json | 4 ++-- src/webapp/azext_webapp/__init__.py | 1 + src/webapp/azext_webapp/_help.py | 4 ++-- src/webapp/azext_webapp/custom.py | 6 ++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/index.json b/src/index.json index 8c864cb912f..df6fe2b78af 100644 --- a/src/index.json +++ b/src/index.json @@ -282,8 +282,8 @@ "webapp": [ { "filename": "webapp-0.2.2-py2.py3-none-any.whl", - "sha256Digest": "fe3b28cc9cb2272a36c395ed6279b2a9f925b16877962bf2448a3fa56819bfa4", - "downloadUrl": "https://github.com/panchagnula/azure-cli-extensions/raw/sisirap-extensions-whl/dist/webapp-0.2.1-py2.py3-none-any.whl", + "sha256Digest": "1787bea76770e13d72d6a0d29fd5af50788051ca12ca64f010ee6fa7657fe5df", + "downloadUrl": "https://github.com/panchagnula/azure-cli-extensions/raw/sisirap-extensions-whl/dist/webapp-0.2.2-py2.py3-none-any.whl", "metadata": { "azext.isPreview": true, "azext.minCliCoreVersion": "2.0.24", diff --git a/src/webapp/azext_webapp/__init__.py b/src/webapp/azext_webapp/__init__.py index 1bc405a1852..468d7885dc6 100644 --- a/src/webapp/azext_webapp/__init__.py +++ b/src/webapp/azext_webapp/__init__.py @@ -47,4 +47,5 @@ def load_arguments(self, _): c.argument('source_name', options_list=['--source-webapp-name'], help='Name of the webapp to retrieve snapshot from.') c.argument('source_slot', options_list=['--source-slot'], help='Name of the webapp slot to retrieve snapshot from.') + COMMAND_LOADER_CLS = WebappExtCommandLoader diff --git a/src/webapp/azext_webapp/_help.py b/src/webapp/azext_webapp/_help.py index afe748b63d2..0d3a1d3e571 100644 --- a/src/webapp/azext_webapp/_help.py +++ b/src/webapp/azext_webapp/_help.py @@ -24,7 +24,7 @@ examples: - name: List the snapshots available for a web app named MyApp. text: > - az webapp config snapshot list -g Default-Web-WestUS -n MyApp + az webapp config snapshot list -g Default-Web-WestUS -n MyApp """ helps['webapp config snapshot restore'] = """ @@ -38,4 +38,4 @@ - name: Overwrite a web app's staging slot with a snapshot from its production slot. text: > az webapp config snapshot restore -g Default-Web-WestUS -n MyApp -s staging -t 2018-04-25T00:09:20.8736381Z --source-resource-group Default-Web-WestUS --source-name MyApp --restore-config -""" \ No newline at end of file +""" diff --git a/src/webapp/azext_webapp/custom.py b/src/webapp/azext_webapp/custom.py index 22ab600159e..9311fcb1e90 100644 --- a/src/webapp/azext_webapp/custom.py +++ b/src/webapp/azext_webapp/custom.py @@ -182,6 +182,7 @@ def create_deploy_webapp(cmd, name, location=None, dryrun=False): logger.warning("All done.") return create_json + def list_webapp_snapshots(cmd, resource_group, name, slot=None): client = web_client_factory(cmd.cli_ctx) if slot is None: @@ -189,9 +190,10 @@ def list_webapp_snapshots(cmd, resource_group, name, slot=None): else: return client.web_apps.list_snapshots_slot(resource_group, name, slot) + def restore_webapp_snapshot(cmd, resource_group, name, time, slot=None, restore_config=False, source_resource_group=None, source_name=None, source_slot=None): client = web_client_factory(cmd.cli_ctx) - + if all([source_resource_group, source_name]): sub_id = get_subscription_id(cmd.cli_ctx) target_id = "/subscriptions/" + sub_id + "/resourceGroups/" + resource_group + "/providers/Microsoft.Web/sites/" + name @@ -210,4 +212,4 @@ def restore_webapp_snapshot(cmd, resource_group, name, time, slot=None, restore_ if slot: return client.web_apps.recover_slot(resource_group, name, request, slot) else: - return client.web_apps.recover(resource_group, name, request) \ No newline at end of file + return client.web_apps.recover(resource_group, name, request) From 82ce24771b9686e750e8f746b5a91f3f62fa90d7 Mon Sep 17 00:00:00 2001 From: Nicholas King Date: Thu, 26 Apr 2018 16:46:58 -0700 Subject: [PATCH 3/3] Fix parameter typos in CLI error message when --source-name and --source-resource-group aren't used together --- src/index.json | 2 +- src/webapp/azext_webapp/custom.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.json b/src/index.json index df6fe2b78af..4f1536d0ff7 100644 --- a/src/index.json +++ b/src/index.json @@ -282,7 +282,7 @@ "webapp": [ { "filename": "webapp-0.2.2-py2.py3-none-any.whl", - "sha256Digest": "1787bea76770e13d72d6a0d29fd5af50788051ca12ca64f010ee6fa7657fe5df", + "sha256Digest": "db8bdba11e6814ceeff37063d0e7548dab42f9e33a64b4c4a5b7ffea0bc93884", "downloadUrl": "https://github.com/panchagnula/azure-cli-extensions/raw/sisirap-extensions-whl/dist/webapp-0.2.2-py2.py3-none-any.whl", "metadata": { "azext.isPreview": true, diff --git a/src/webapp/azext_webapp/custom.py b/src/webapp/azext_webapp/custom.py index 9311fcb1e90..3f076cbe59b 100644 --- a/src/webapp/azext_webapp/custom.py +++ b/src/webapp/azext_webapp/custom.py @@ -206,7 +206,7 @@ def restore_webapp_snapshot(cmd, resource_group, name, time, slot=None, restore_ else: return client.web_apps.recover(source_resource_group, source_name, request) elif any([source_resource_group, source_name]): - raise CLIError('usage error: source-resource_group and source-name must both be specified if one is used') + raise CLIError('usage error: --source-resource-group and --source-name must both be specified if one is used') else: request = SnapshotRecoveryRequest(True, snapshot_time=time, recover_configuration=restore_config) if slot: