Updates to work with "patches vm" commands and VM create command.

This commit is contained in:
Travis Prescott 2016-05-05 14:54:38 -07:00
Родитель cb30be5d75
Коммит ac5f3a8a74
7 изменённых файлов: 183 добавлений и 200 удалений

Просмотреть файл

@ -151,6 +151,9 @@
<Compile Include="command_modules\azure-cli-vm\azure\cli\command_modules\vm\custom.py" />
<Compile Include="command_modules\azure-cli-vm\azure\cli\command_modules\vm\tests\test_vm_image.py" />
<Compile Include="command_modules\azure-cli-vm\azure\cli\command_modules\vm\tests\__init__.py" />
<Compile Include="command_modules\azure-cli-vm\azure\cli\command_modules\vm\_actions.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="command_modules\azure-cli-vm\azure\cli\command_modules\vm\_validators.py">
<SubType>Code</SubType>
</Compile>

Просмотреть файл

@ -37,11 +37,8 @@ def _get_member(obj, path):
def _make_func(client_factory, member_path, return_type_or_func, unbound_func, extra_parameters):
def call_client(args):
client = client_factory(**args)
for p in extra_parameters or []:
param_name = p['name'].split()[0]
param_name = re.sub('--', '', param_name)
param_name = re.sub('-', '_', param_name)
args.pop(param_name)
for param in extra_parameters.keys() if extra_parameters else []:
args.pop(param)
ops_instance = _get_member(client, member_path)
try:
@ -156,8 +153,8 @@ def build_operation(command_name,
# append any 'extra' args needed (for example to obtain a client) that aren't required
# by the SDK.
if extra_parameters:
for arg in extra_parameters:
options.append(arg.copy())
for arg in extra_parameters.keys():
options.append(extra_parameters[arg].copy())
command_table[func] = {
'name': ' '.join([command_name, op.opname]),

Просмотреть файл

@ -244,9 +244,9 @@ PARAMETER_ALIASES.update({
# SUPPLEMENTAL (EXTRA) PARAMETER SETS
STORAGE_DATA_CLIENT_ARGS = [
PARAMETER_ALIASES['account_name'],
PARAMETER_ALIASES['account_key'],
PARAMETER_ALIASES['connection_string'],
PARAMETER_ALIASES['sas_token']
]
STORAGE_DATA_CLIENT_ARGS = {
'account_name': PARAMETER_ALIASES['account_name'],
'account_key': PARAMETER_ALIASES['account_key'],
'connection_string': PARAMETER_ALIASES['connection_string'],
'sas_token': PARAMETER_ALIASES['sas_token']
}

Просмотреть файл

@ -0,0 +1,29 @@
import argparse
import os
import re
class VMImageFieldAction(argparse.Action): #pylint: disable=too-few-public-methods
def __call__(self, parser, namespace, values, option_string=None):
image = values
match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', image)
if image.lower().endswith('.vhd'):
namespace.os_disk_uri = image
elif match:
namespace.os_type = 'Custom'
namespace.os_publisher = match.group(1)
namespace.os_offer = match.group(2)
namespace.os_sku = match.group(3)
namespace.os_version = match.group(4)
else:
namespace.os_type = image
class VMSSHFieldAction(argparse.Action): #pylint: disable=too-few-public-methods
def __call__(self, parser, namespace, values, option_string=None):
ssh_value = values
if os.path.exists(ssh_value):
with open(ssh_value, 'r') as f:
namespace.ssh_key_value = f.read()
else:
namespace.ssh_key_value = ssh_value

Просмотреть файл

@ -1,10 +1,14 @@
import argparse
from azure.mgmt.compute import ComputeManagementClient, ComputeManagementClientConfiguration
from azure.mgmt.compute.models import VirtualHardDisk
from azure.cli.commands import (COMMON_PARAMETERS as GLOBAL_COMMON_PARAMETERS, extend_parameter)
from azure.cli.commands import COMMON_PARAMETERS as GLOBAL_COMMON_PARAMETERS, extend_parameter
from azure.cli.commands._command_creation import get_mgmt_service_client
from azure.cli._locale import L
from azure.cli.command_modules.vm._validators import MinMaxValue
from azure.cli.command_modules.vm._actions import VMImageFieldAction, VMSSHFieldAction
from azure.cli._help_files import helps
from azure.cli._locale import L
# FACTORIES
@ -17,19 +21,16 @@ PARAMETER_ALIASES = GLOBAL_COMMON_PARAMETERS.copy()
PARAMETER_ALIASES.update({
'diskname': {
'name': '--name -n',
'dest': 'name',
'help': L('Disk name'),
},
'disksize': {
'name': '--disksize',
'dest': 'disksize',
'help': L('Size of disk (Gb)'),
'type': MinMaxValue(1, 1023),
'default': 1023
},
'lun': {
'name': '--lun',
'dest': 'lun',
'help': L('0-based logical unit number (LUN). Max value depends on the Virtual ' + \
'Machine size'),
'type': int,
@ -38,4 +39,95 @@ PARAMETER_ALIASES.update({
'name': '--vhd',
'type': VirtualHardDisk
},
'vm_name': {
'name': '--vm-name',
'dest': 'vm_name',
'help': 'Name of Virtual Machine to update',
}
})
VM_CREATE_PARAMETER_ALIASES = {
'name': {
'name': '--name -n'
},
'os_disk_uri': {
'name': '--os-disk-uri',
'help': argparse.SUPPRESS
},
'os_offer': {
'name': '--os_offer',
'help': argparse.SUPPRESS
},
'os_publisher': {
'name': '--os-publisher',
'help': argparse.SUPPRESS
},
'os_sku': {
'name': '--os-sku',
'help': argparse.SUPPRESS
},
'os_type': {
'name': '--os-type',
'help': argparse.SUPPRESS
},
'os_version': {
'name': '--os-version',
'help': argparse.SUPPRESS
},
}
# EXTRA PARAMETER SETS
VM_CREATE_EXTRA_PARAMETERS = {
'image': {
'name': '--image',
'help': 'The OS image. Supported values: Common OS (e.g. Win2012R2Datacenter), ' + \
'URN (e.g. "publisher:offer:sku:version"), or existing VHD URI.',
'action': VMImageFieldAction
},
'ssh_key_value': {
'name': '--ssh-key-value',
'action': VMSSHFieldAction
}
}
VM_PATCH_EXTRA_PARAMETERS = {
'resource_group_name':
extend_parameter(PARAMETER_ALIASES['resource_group_name'], required=True),
'vm_name':
extend_parameter(PARAMETER_ALIASES['vm_name'], required=True)
}
# HELP PARAMETERS
helps['vm create'] = """
type: command
short-summary: Create an Azure Virtual Machine
long-summary: See https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-quick-create-cli/ for an end-to-end tutorial
parameters:
- name: --image
type: string
required: false
short-summary: OS image
long-summary: |
Common OS types: CentOS, CoreOS, Debian, openSUSE, RHEL, SLES, UbuntuLTS,
Win2012R2Datacenter, Win2012Datacenter, Win2008R2SP1
Example URN: canonical:Ubuntu_Snappy_Core:15.04:2016.0318.1949
Example URI: http://<storageAccount>.blob.core.windows.net/vhds/osdiskimage.vhd
populator-commands:
- az vm image list
- az vm image show
examples:
- name: Create a simple Windows Server VM with private IP address
text: >
az vm create --image Win2012R2Datacenter --admin-username myadmin --admin-password Admin_001
-l "West US" -g myvms --name myvm001
- name: Create a Linux VM with SSH key authentication, add a public DNS entry and add to an existing Virtual Network and Availability Set.
text: >
az vm create --image canonical:Ubuntu_Snappy_Core:15.04:2016.0318.1949
--admin-username myadmin --admin-password Admin_001 --authentication-type sshkey
--virtual-network-type existing --virtual-network-name myvnet --subnet-name default
--availability-set-type existing --availability-set-id myavailset
--public-ip-address-type new --dns-name-for-public-ip myGloballyUniqueVmDnsName
-l "West US" -g myvms --name myvm18o --ssh-key-value "<ssh-rsa-key or key-file-path>"
"""

Просмотреть файл

@ -10,57 +10,32 @@ except ImportError:
from azure.mgmt.compute.models import DataDisk
from azure.mgmt.compute.models.compute_management_client_enums import DiskCreateOptionTypes
from azure.cli._locale import L
from azure.cli.commands import CommandTable, LongRunningOperation, RESOURCE_GROUP_ARG_NAME
from azure.cli.commands._command_creation import get_mgmt_service_client
from ._params import PARAMETER_ALIASES, _compute_client_factory
from ._params import PARAMETER_ALIASES, VM_PATCH_EXTRA_PARAMETERS, _compute_client_factory
command_table = CommandTable()
def vm_getter(args):
''' Retreive a VM based on the `args` passed in.
'''
client = _compute_client_factory(**args)
result = client.virtual_machines.get(args.get(RESOURCE_GROUP_ARG_NAME), args.get('vm_name'))
return result
def _vm_get(**kwargs):
'''Retrieves a VM if a resource group and vm name are supplied.'''
vm_name = kwargs.get('vm_name')
resource_group_name = kwargs.get('resource_group_name')
client = _compute_client_factory()
return client.virtual_machines.get(resource_group_name, vm_name) \
if resource_group_name and vm_name else None
def vm_setter(args, instance, start_msg, end_msg):
'''Update the given Virtual Machine instance
'''
def _vm_set(instance, start_msg, end_msg):
'''Update the given Virtual Machine instance'''
instance.resources = None # Issue: https://github.com/Azure/autorest/issues/934
client = _compute_client_factory(**args)
client = _compute_client_factory()
parsed_id = _parse_rg_name(instance.id)
poller = client.virtual_machines.create_or_update(
resource_group_name=args.get(RESOURCE_GROUP_ARG_NAME),
vm_name=args.get('vm_name'),
resource_group_name=parsed_id[0],
vm_name=parsed_id[1],
parameters=instance)
return LongRunningOperation(start_msg, end_msg)(poller)
def patches_vm(start_msg, finish_msg):
'''Decorator indicating that the decorated function modifies an existing Virtual Machine
in Azure.
It automatically adds arguments required to identify the Virtual Machine to be patched and
handles the actual put call to the compute service, leaving the decorated function to only
have to worry about the modifications it has to do.
'''
def wrapped(func):
def invoke(args):
instance = vm_getter(args)
func(args, instance)
vm_setter(args, instance, start_msg, finish_msg)
# All Virtual Machines are identified with a resource group name/name pair, so
# we add these parameters to all commands
command_table[invoke]['arguments'].append(PARAMETER_ALIASES['resource_group_name'])
command_table[invoke]['arguments'].append({
'name': '--vm-name -n',
'dest': 'vm_name',
'help': 'Name of Virtual Machine to update',
'required': True
})
return invoke
return wrapped
def _load_images_from_aliases_doc(publisher, offer, sku):
target_url = ('https://raw.githubusercontent.com/Azure/azure-rest-api-specs/'
'master/arm-compute/quickstart-templates/aliases.json')
@ -134,7 +109,8 @@ def _create_image_instance(publisher, offer, sku, version):
'offer': offer,
'sku': sku,
'version': version
}
}
#
# Composite convenience commands for the CLI
#
@ -150,23 +126,17 @@ def _parse_rg_name(strid):
class ConvenienceVmCommands(object): # pylint: disable=too-few-public-methods
def __init__(self, **_):
pass
def __init__(self, **kwargs):
self.vm = _vm_get(**kwargs)
def list(self, resource_group_name):
''' List Virtual Machines. '''
ccf = _compute_client_factory()
vm_list = ccf.virtual_machines.list(resource_group_name=resource_group_name) \
if group else ccf.virtual_machines.list_all()
if resource_group_name else ccf.virtual_machines.list_all()
return list(vm_list)
def list_vm_images(self,
image_location=None,
publisher=None,
offer=None,
sku=None,
all=False):
def list_vm_images(self, image_location=None, publisher=None, offer=None, sku=None, all=False): # pylint: disable=redefined-builtin
'''vm image list
:param str location:Image location
:param str publisher:Image publisher name
@ -247,34 +217,31 @@ class ConvenienceVmCommands(object): # pylint: disable=too-few-public-methods
return result
#@command_table.command('vm disk attach-new',
@patches_vm('Attaching disk', 'Disk attached')
def attach_new_disk(self, lun, diskname, vhd, disksize=1023, **kwargs):
def attach_new_disk(self, lun, diskname, vhd, disksize=1023, **kwargs):
''' Attach a new disk to an existing Virtual Machine'''
disk = DataDisk(lun=lun, vhd=vhd, name=kwargs.get('name'),
disk = DataDisk(lun=lun, vhd=vhd, name=diskname,
create_option=DiskCreateOptionTypes.empty,
disk_size_gb=disksize)
kwargs.get('instance').storage_profile.data_disks.append(disk)
self.vm.storage_profile.data_disks.append(disk)
_vm_set(self.vm, 'Attaching disk', 'Disk attached')
#@command_table.command('vm disk attach-existing',
@patches_vm('Attaching disk', 'Disk attached')
def attach_existing_disk(self, lun, diskname, vhd, disksize=1023, **kwargs):
''' Attach an existing disk to an existing Virtual Machine '''
# TODO: figure out size of existing disk instead of making the default value 1023
disk = DataDisk(lun=lun, vhd=vhd, name=kwargs.get('name'),
disk = DataDisk(lun=lun, vhd=vhd, name=diskname,
create_option=DiskCreateOptionTypes.attach,
disk_size_gb=disksize)
kwargs.get('instance').storage_profile.data_disks.append(disk)
self.vm.storage_profile.data_disks.append(disk)
_vm_set(self.vm, 'Attaching disk', 'Disk attached')
#@command_table.command('vm disk detach')
@patches_vm('Detaching disk', 'Disk detached')
def detach_disk(self, diskname, **kwargs):
''' Detach a disk from a Virtual Machine '''
# Issue: https://github.com/Azure/autorest/issues/934
instance = kwargs.get('instance')
instance.resources = None
self.vm.resources = None
try:
disk = next(d for d in instance.storage_profile.data_disks
disk = next(d for d in self.vm.storage_profile.data_disks
if d.name == kwargs.get('name'))
instance.storage_profile.data_disks.remove(disk)
self.vm.storage_profile.data_disks.remove(disk)
except StopIteration:
raise RuntimeError("No disk with the name '%s' found" % args.get('name'))
raise RuntimeError("No disk with the name '{}' found".format(diskname))
_vm_set(self.vm, 'Detaching disk', 'Disk detached')

Просмотреть файл

@ -1,7 +1,3 @@
import argparse
import os
import re
from azure.mgmt.compute.operations import (AvailabilitySetsOperations,
VirtualMachineExtensionImagesOperations,
VirtualMachineExtensionsOperations,
@ -15,14 +11,14 @@ from azure.mgmt.compute.operations import (AvailabilitySetsOperations,
from azure.cli.commands._auto_command import build_operation, AutoCommandDefinition
from azure.cli.commands._command_creation import get_mgmt_service_client
from azure.cli.commands import CommandTable, LongRunningOperation
from azure.cli._locale import L
from azure.cli.command_modules.vm.mgmt.lib import (VMCreationClient as VMClient,
VMCreationClientConfiguration
as VMClientConfig)
from azure.cli.command_modules.vm.mgmt.lib.operations import VMOperations
from azure.cli._help_files import helps
from azure.cli._locale import L
from ._params import PARAMETER_ALIASES, _compute_client_factory
from ._params import (PARAMETER_ALIASES, VM_CREATE_EXTRA_PARAMETERS, VM_CREATE_PARAMETER_ALIASES,
VM_PATCH_EXTRA_PARAMETERS, _compute_client_factory)
from .custom import ConvenienceVmCommands
command_table = CommandTable()
@ -62,7 +58,7 @@ build_operation(
AutoCommandDefinition(ConvenienceVmCommands.attach_existing_disk, 'Object', 'attach-existing'),
AutoCommandDefinition(ConvenienceVmCommands.detach_disk, 'Object', 'detach'),
],
command_table, PARAMETER_ALIASES)
command_table, PARAMETER_ALIASES, VM_PATCH_EXTRA_PARAMETERS)
build_operation(
'vm extension', 'virtual_machine_extensions', _compute_client_factory,
@ -86,7 +82,7 @@ build_operation(
command_table, PARAMETER_ALIASES)
build_operation(
'vm usage', 'usage',_compute_client_factory,
'vm usage', 'usage', _compute_client_factory,
[
AutoCommandDefinition(UsageOperations.list, '[Usage]'),
],
@ -161,116 +157,15 @@ build_operation(
],
command_table, PARAMETER_ALIASES)
vm_param_aliases = {
'name': {
'name': '--name -n'
},
'os_disk_uri': {
'name': '--os-disk-uri',
'help': argparse.SUPPRESS
},
'os_offer': {
'name': '--os_offer',
'help': argparse.SUPPRESS
},
'os_publisher': {
'name': '--os-publisher',
'help': argparse.SUPPRESS
},
'os_sku': {
'name': '--os-sku',
'help': argparse.SUPPRESS
},
'os_type': {
'name': '--os-type',
'help': argparse.SUPPRESS
},
'os_version': {
'name': '--os-version',
'help': argparse.SUPPRESS
},
}
class VMImageFieldAction(argparse.Action): #pylint: disable=too-few-public-methods
def __call__(self, parser, namespace, values, option_string=None):
image = values
match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', image)
if image.lower().endswith('.vhd'):
namespace.os_disk_uri = image
elif match:
namespace.os_type = 'Custom'
namespace.os_publisher = match.group(1)
namespace.os_offer = match.group(2)
namespace.os_sku = match.group(3)
namespace.os_version = match.group(4)
else:
namespace.os_type = image
class VMSSHFieldAction(argparse.Action): #pylint: disable=too-few-public-methods
def __call__(self, parser, namespace, values, option_string=None):
ssh_value = values
if os.path.exists(ssh_value):
with open(ssh_value, 'r') as f:
namespace.ssh_key_value = f.read()
else:
namespace.ssh_key_value = ssh_value
extra_parameters = [
{
'name': '--image',
'help': 'The OS image. Supported values: Common OS (e.g. Win2012R2Datacenter), URN (e.g. "publisher:offer:sku:version"), or existing VHD URI.',
'action': VMImageFieldAction
},
{
'name': '--ssh-key-value',
'action': VMSSHFieldAction
}
]
helps['vm create'] = """
type: command
short-summary: Create an Azure Virtual Machine
long-summary: See https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-quick-create-cli/ for an end-to-end tutorial
parameters:
- name: --image
type: string
required: false
short-summary: OS image
long-summary: |
Common OS types: CentOS, CoreOS, Debian, openSUSE, RHEL, SLES, UbuntuLTS,
Win2012R2Datacenter, Win2012Datacenter, Win2008R2SP1
Example URN: canonical:Ubuntu_Snappy_Core:15.04:2016.0318.1949
Example URI: http://<storageAccount>.blob.core.windows.net/vhds/osdiskimage.vhd
populator-commands:
- az vm image list
- az vm image show
examples:
- name: Create a simple Windows Server VM with private IP address
text: >
az vm create --image Win2012R2Datacenter --admin-username myadmin --admin-password Admin_001
-l "West US" -g myvms --name myvm001
- name: Create a Linux VM with SSH key authentication, add a public DNS entry and add to an existing Virtual Network and Availability Set.
text: >
az vm create --image canonical:Ubuntu_Snappy_Core:15.04:2016.0318.1949
--admin-username myadmin --admin-password Admin_001 --authentication-type sshkey
--virtual-network-type existing --virtual-network-name myvnet --subnet-name default
--availability-set-type existing --availability-set-id myavailset
--public-ip-address-type new --dns-name-for-public-ip myGloballyUniqueVmDnsName
-l "West US" -g myvms --name myvm18o --ssh-key-value "<ssh-rsa-key or key-file-path>"
"""
build_operation(
'vm', 'vm', lambda _: get_mgmt_service_client(VMClient, VMClientConfig),
'vm', 'vm', lambda **_: get_mgmt_service_client(VMClient, VMClientConfig),
[
AutoCommandDefinition(VMOperations.create_or_update,
LongRunningOperation(L('Creating virtual machine'), L('Virtual machine created')),
'create')
AutoCommandDefinition(
VMOperations.create_or_update,
LongRunningOperation(L('Creating virtual machine'), L('Virtual machine created')),
'create')
],
command_table,
vm_param_aliases,
extra_parameters)
command_table, VM_CREATE_PARAMETER_ALIASES, VM_CREATE_EXTRA_PARAMETERS)
build_operation(
'vm image', None, ConvenienceVmCommands,