Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image-Copy: better resource names, allow tags & image name override #151

Merged
merged 7 commits into from
Apr 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/image-copy/azext_imagecopy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ def load_arguments(self, _):
help='Number of parallel copy operations')
c.argument('cleanup', options_list=['--cleanup'], action='store_true', default=False,
help='Include this switch to delete temporary resources upon completion')
c.argument('target_name', options_list=['--target-name'],
help='Name of the final image that will be created')


COMMAND_LOADER_CLS = ImageCopyCommandsLoader
9 changes: 7 additions & 2 deletions src/image-copy/azext_imagecopy/cli_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from knack.log import get_logger
logger = get_logger(__name__)

EXTENSION_TAG_STRING = 'created_by=image-copy-extension'


# pylint: disable=inconsistent-return-statements
def run_cli_command(cmd, return_as_json=False):
Expand All @@ -36,7 +38,7 @@ def run_cli_command(cmd, return_as_json=False):
raise


def prepare_cli_command(cmd, output_as_json=True):
def prepare_cli_command(cmd, output_as_json=True, tags=None):
full_cmd = [sys.executable, '-m', 'azure.cli'] + cmd

if output_as_json:
Expand All @@ -46,6 +48,9 @@ def prepare_cli_command(cmd, output_as_json=True):

# tag newly created resources, containers don't have tags
if 'create' in cmd and ('container' not in cmd):
full_cmd += ['--tags', 'created_by=image-copy-extension']
full_cmd += ['--tags', EXTENSION_TAG_STRING]

if tags is not None:
full_cmd += tags.split()

return full_cmd
27 changes: 15 additions & 12 deletions src/image-copy/azext_imagecopy/create_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@
from knack.log import get_logger
logger = get_logger(__name__)

PROGRESS_LINE_LENGTH = 40
STORAGE_ACCOUNT_NAME_LENGTH = 24


# pylint: disable=too-many-locals
def create_target_image(location, transient_resource_group_name, source_type, source_object_name,
source_os_disk_snapshot_name, source_os_disk_snapshot_url, source_os_type,
target_resource_group_name, azure_pool_frequency):
target_resource_group_name, azure_pool_frequency, tags, target_name):

subscription_id = get_subscription_id()

subscription_hash = hashlib.sha1(
subscription_id.encode("UTF-8")).hexdigest()
unique_subscription_string = subscription_hash[:7]
unique_subscription_string = subscription_hash[:(
STORAGE_ACCOUNT_NAME_LENGTH - len(location))]

# create the target storage account
logger.warn(
Expand Down Expand Up @@ -92,7 +93,7 @@ def create_target_image(location, transient_resource_group_name, source_type, so
wait_for_blob_copy_operation(blob_name, target_container_name,
target_storage_account_name, azure_pool_frequency, location)
msg = "{0} - Copy time: {1}".format(
location, datetime.datetime.now() - start_datetime).ljust(PROGRESS_LINE_LENGTH)
location, datetime.datetime.now() - start_datetime)
logger.warn(msg)

# Create the snapshot in the target region from the copied blob
Expand All @@ -112,19 +113,22 @@ def create_target_image(location, transient_resource_group_name, source_type, so

# Create the final image
logger.warn("%s - Creating final image", location)
target_image_name = source_object_name
if source_type != 'image':
target_image_name += '-image'
target_image_name += '-' + location
if target_name is None:
target_image_name = source_object_name
if source_type != 'image':
target_image_name += '-image'
target_image_name += '-' + location
else:
target_image_name = target_name

cli_cmd = prepare_cli_command(['image', 'create',
'--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])

'--source', target_snapshot_id], tags=tags)
logger.warn("command: %s", cli_cmd)
run_cli_command(cli_cmd)


Expand All @@ -147,8 +151,7 @@ def wait_for_blob_copy_operation(blob_name, target_container_name, target_storag

if current_progress != prev_progress:
msg = "{0} - Copy progress: {1}%"\
.format(location, str(current_progress))\
.ljust(PROGRESS_LINE_LENGTH) # need to justify since messages overide each other
.format(location, str(current_progress))
logger.warn(msg)

prev_progress = current_progress
Expand Down
15 changes: 13 additions & 2 deletions src/image-copy/azext_imagecopy/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
from azext_imagecopy.cli_utils import run_cli_command, prepare_cli_command
from azext_imagecopy.create_target import create_target_image

from knack.util import CLIError
from knack.log import get_logger
logger = get_logger(__name__)


# pylint: disable=too-many-statements
def imagecopy(source_resource_group_name, source_object_name, target_location,
target_resource_group_name, source_type='image', cleanup='false', parallel_degree=-1):
target_resource_group_name, source_type='image', cleanup='false',
parallel_degree=-1, tags=None, target_name=None):

# get the os disk id from source vm/image
logger.warn("Getting os disk id of the source vm/image")
Expand All @@ -24,6 +26,14 @@ def imagecopy(source_resource_group_name, source_object_name, target_location,

json_cmd_output = run_cli_command(cli_cmd, return_as_json=True)

if 'id' not in json_cmd_output['storageProfile']['osDisk']['managedDisk']:
logger.error(
"It looks like the source resource isn't backed by a managed OS disk. Quitting...")
raise CLIError('Source with no Managed OS disk')

if json_cmd_output['storageProfile']['dataDisks']:
logger.warn("Data disks in the source detected, but are ignored by this extension!")

source_os_disk_id = json_cmd_output['storageProfile']['osDisk']['managedDisk']['id']
source_os_type = json_cmd_output['storageProfile']['osDisk']['osType']
logger.debug("source_os_disk_id: %s. source_os_type: %s",
Expand Down Expand Up @@ -80,7 +90,8 @@ def imagecopy(source_resource_group_name, source_object_name, target_location,
location = location.strip()
tasks.append((location, transient_resource_group_name, source_type,
source_object_name, source_os_disk_snapshot_name, source_os_disk_snapshot_url,
source_os_type, target_resource_group_name, azure_pool_frequency))
source_os_type, target_resource_group_name, azure_pool_frequency,
tags, target_name))

logger.warn("Starting async process for all locations")

Expand Down
6 changes: 3 additions & 3 deletions src/image-copy/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from codecs import open
from setuptools import setup, find_packages

VERSION = "0.0.5"
VERSION = "0.0.6"

CLASSIFIERS = [
'Development Status :: 4 - Beta',
Expand All @@ -29,8 +29,8 @@
setup(
name='image-copy-extension',
version=VERSION,
description='An Azure CLI Extension that copies images from region to region.',
long_description='An Azure CLI Extension that copies images from region to region.',
description='Support for copying managed vm images between regions',
long_description='Support for copying managed vm images between regions',
license='MIT',
author='Tamir Kamara',
author_email='tamir.kamara@microsoft.com',
Expand Down