diff --git a/src/image-copy/HISTORY.rst b/src/image-copy/HISTORY.rst new file mode 100644 index 00000000000..d87de66e3db --- /dev/null +++ b/src/image-copy/HISTORY.rst @@ -0,0 +1,9 @@ +.. :changelog: + +Release History +=============== + +0.2.4 +++++++ +* Fix copying an image originally created from a blob (create a snapshot with the source storage account id) + diff --git a/src/image-copy/azext_imagecopy/__init__.py b/src/image-copy/azext_imagecopy/__init__.py index edbd1cea20f..17850ce9f20 100644 --- a/src/image-copy/azext_imagecopy/__init__.py +++ b/src/image-copy/azext_imagecopy/__init__.py @@ -4,6 +4,7 @@ # -------------------------------------------------------------------------------------------- from azure.cli.core import AzCommandsLoader +from azure.cli.core.commands.parameters import tags_type import azext_imagecopy._help # pylint: disable=unused-import @@ -51,6 +52,7 @@ def load_arguments(self, _): help='Resource Group name where temporary storage account will be created.') c.argument('export_as_snapshot', options_list=['--export-as-snapshot'], action='store_true', default=False, help='Include this switch to export the copies as snapshots instead of images.') + c.argument('tags', tags_type) COMMAND_LOADER_CLS = ImageCopyCommandsLoader diff --git a/src/image-copy/azext_imagecopy/cli_utils.py b/src/image-copy/azext_imagecopy/cli_utils.py index 0cb38083194..ce5ae42cdfd 100644 --- a/src/image-copy/azext_imagecopy/cli_utils.py +++ b/src/image-copy/azext_imagecopy/cli_utils.py @@ -69,3 +69,21 @@ def prepare_cli_command(cmd, output_as_json=True, tags=None, subscription=None): full_cmd += tags.split() return full_cmd + + +def get_storage_account_id_from_blob_path(cmd, blob_path, resource_group, subscription_id=None): + from msrestazure.tools import resource_id + from azure.cli.core.commands.client_factory import get_subscription_id + + logger.debug('Getting storage account id for blob: %s', blob_path) + + storage_account_name = blob_path.split('.')[0].split('/')[-1] + + if not subscription_id: + subscription_id = get_subscription_id(cmd.cli_ctx) + + storage_account_id = resource_id( + subscription=subscription_id, resource_group=resource_group, + namespace='Microsoft.Storage', type='storageAccounts', name=storage_account_name) + + return storage_account_id diff --git a/src/image-copy/azext_imagecopy/create_target.py b/src/image-copy/azext_imagecopy/create_target.py index 4d9cf6d465e..89897a94229 100644 --- a/src/image-copy/azext_imagecopy/create_target.py +++ b/src/image-copy/azext_imagecopy/create_target.py @@ -9,10 +9,7 @@ from knack.util import CLIError from knack.log import get_logger -from msrestazure.tools import resource_id -from azure.cli.core.commands.client_factory import get_subscription_id - -from azext_imagecopy.cli_utils import run_cli_command, prepare_cli_command +from azext_imagecopy.cli_utils import run_cli_command, prepare_cli_command, get_storage_account_id_from_blob_path logger = get_logger(__name__) @@ -116,14 +113,10 @@ def create_target_image(cmd, location, transient_resource_group_name, source_typ else: snapshot_resource_group_name = transient_resource_group_name - storage_account_name = target_blob_path.split('.')[0].split('/')[-1] - if target_subscription: - subscription_id = target_subscription - else: - subscription_id = get_subscription_id(cmd.cli_ctx) - source_storage_account_id = resource_id( - subscription=subscription_id, resource_group=transient_resource_group_name, - namespace='Microsoft.Storage', type='storageAccounts', name=storage_account_name) + source_storage_account_id = get_storage_account_id_from_blob_path(cmd, + target_blob_path, + transient_resource_group_name, + target_subscription) cli_cmd = prepare_cli_command(['snapshot', 'create', '--resource-group', snapshot_resource_group_name, @@ -153,7 +146,6 @@ def create_target_image(cmd, location, transient_resource_group_name, source_typ '--resource-group', target_resource_group_name, '--name', target_image_name, '--location', location, - '--source', target_blob_path, '--os-type', source_os_type, '--source', target_snapshot_id], tags=tags, diff --git a/src/image-copy/azext_imagecopy/custom.py b/src/image-copy/azext_imagecopy/custom.py index 6cb1556e9f3..223bb8956fc 100644 --- a/src/image-copy/azext_imagecopy/custom.py +++ b/src/image-copy/azext_imagecopy/custom.py @@ -8,7 +8,7 @@ from knack.util import CLIError from knack.log import get_logger -from azext_imagecopy.cli_utils import run_cli_command, prepare_cli_command +from azext_imagecopy.cli_utils import run_cli_command, prepare_cli_command, get_storage_account_id_from_blob_path from azext_imagecopy.create_target import create_target_image logger = get_logger(__name__) @@ -75,10 +75,21 @@ def imagecopy(cmd, source_resource_group_name, source_object_name, target_locati # TODO: skip creating another snapshot when the source is a snapshot logger.warning("Creating source snapshot") source_os_disk_snapshot_name = source_object_name + '_os_disk_snapshot' - cli_cmd = prepare_cli_command(['snapshot', 'create', - '--name', source_os_disk_snapshot_name, - '--resource-group', source_resource_group_name, - '--source', source_os_disk_id]) + + if source_os_disk_type == "BLOB": + source_storage_account_id = get_storage_account_id_from_blob_path(cmd, + source_os_disk_id, + source_resource_group_name) + cli_cmd = prepare_cli_command(['snapshot', 'create', + '--name', source_os_disk_snapshot_name, + '--resource-group', source_resource_group_name, + '--source', source_os_disk_id, + '--source-storage-account-id', source_storage_account_id]) + else: + cli_cmd = prepare_cli_command(['snapshot', 'create', + '--name', source_os_disk_snapshot_name, + '--resource-group', source_resource_group_name, + '--source', source_os_disk_id]) run_cli_command(cli_cmd) diff --git a/src/image-copy/setup.py b/src/image-copy/setup.py index 6c8b909b997..498cb7edb81 100644 --- a/src/image-copy/setup.py +++ b/src/image-copy/setup.py @@ -8,19 +8,17 @@ from codecs import open from setuptools import setup, find_packages -VERSION = "0.2.3" +VERSION = "0.2.4" CLASSIFIERS = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'License :: OSI Approved :: MIT License', ]