| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116 |
- import base64
- import logging
- import uuid
- from azure.common import AzureException
- from azure.mgmt.compute.models import DiskCreateOption
- from msrestazure.azure_exceptions import CloudError
- import cloudbridge.cloud.base.helpers as cb_helpers
- from cloudbridge.cloud.base.resources import ClientPagedResultList, \
- ServerPagedResultList
- from cloudbridge.cloud.base.services import BaseBucketService, \
- BaseComputeService, \
- BaseImageService, BaseInstanceService, BaseKeyPairService, \
- BaseNetworkService, BaseNetworkingService, BaseRegionService, \
- BaseRouterService, BaseSecurityService, BaseSnapshotService, \
- BaseStorageService, BaseSubnetService, BaseVMFirewallService, \
- BaseVMTypeService, BaseVolumeService
- from cloudbridge.cloud.interfaces.exceptions import \
- DuplicateResourceException, InvalidValueException
- from cloudbridge.cloud.interfaces.resources import MachineImage, \
- Network, PlacementZone, Snapshot, Subnet, VMFirewall, VMType, Volume
- from .resources import AzureBucket, \
- AzureInstance, AzureKeyPair, \
- AzureLaunchConfig, AzureMachineImage, AzureNetwork, \
- AzureRegion, AzureRouter, AzureSnapshot, AzureSubnet, \
- AzureVMFirewall, AzureVMType, AzureVolume
- log = logging.getLogger(__name__)
- class AzureSecurityService(BaseSecurityService):
- def __init__(self, provider):
- super(AzureSecurityService, self).__init__(provider)
- # Initialize provider services
- self._key_pairs = AzureKeyPairService(provider)
- self._vm_firewalls = AzureVMFirewallService(provider)
- @property
- def key_pairs(self):
- return self._key_pairs
- @property
- def vm_firewalls(self):
- return self._vm_firewalls
- class AzureVMFirewallService(BaseVMFirewallService):
- def __init__(self, provider):
- super(AzureVMFirewallService, self).__init__(provider)
- def get(self, fw_id):
- try:
- fws = self.provider.azure_client.get_vm_firewall(fw_id)
- return AzureVMFirewall(self.provider, fws)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def list(self, limit=None, marker=None):
- fws = [AzureVMFirewall(self.provider, fw)
- for fw in self.provider.azure_client.list_vm_firewall()]
- return ClientPagedResultList(self.provider, fws, limit, marker)
- def create(self, label=None, description=None, network_id=None):
- name = AzureVMFirewall._generate_name_from_label(label, "cb-fw")
- parameters = {"location": self.provider.region_name}
- if label:
- AzureVMFirewall.assert_valid_resource_label(label)
- parameters.update({'tags': {'Label': label}})
- if description:
- tags = parameters.get('tags')
- if tags:
- tags.update(Description=description)
- else:
- parameters.update({'tags': {'Description': description}})
- fw = self.provider.azure_client.create_vm_firewall(name,
- parameters)
- # Add default rules to negate azure default rules.
- # See: https://github.com/CloudVE/cloudbridge/issues/106
- # pylint:disable=protected-access
- for rule in fw.default_security_rules:
- rule_name = "cb-override-" + rule.name
- # Transpose rules to priority 4001 onwards, because
- # only 0-4096 are allowed for custom rules
- rule.priority = rule.priority - 61440
- rule.access = "Deny"
- self.provider.azure_client.create_vm_firewall_rule(
- fw.id, rule_name, rule)
- # Add a new custom rule allowing all outbound traffic to the internet
- parameters = {"priority": 3000,
- "protocol": "*",
- "source_port_range": "*",
- "source_address_prefix": "*",
- "destination_port_range": "*",
- "destination_address_prefix": "Internet",
- "access": "Allow",
- "direction": "Outbound"}
- result = self.provider.azure_client.create_vm_firewall_rule(
- fw.id, "cb-default-internet-outbound", parameters)
- fw.security_rules.append(result)
- cb_fw = AzureVMFirewall(self.provider, fw)
- return cb_fw
- def find(self, **kwargs):
- obj_list = self
- filters = ['label', 'name']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def delete(self, group_id):
- self.provider.azure_client.delete_vm_firewall(group_id)
- class AzureKeyPairService(BaseKeyPairService):
- PARTITION_KEY = '00000000-0000-0000-0000-000000000000'
- def __init__(self, provider):
- super(AzureKeyPairService, self).__init__(provider)
- def get(self, key_pair_id):
- try:
- key_pair = self.provider.azure_client.\
- get_public_key(key_pair_id)
- if key_pair:
- return AzureKeyPair(self.provider, key_pair)
- return None
- except AzureException as error:
- log.exception(error)
- return None
- def list(self, limit=None, marker=None):
- key_pairs, resume_marker = self.provider.azure_client.list_public_keys(
- AzureKeyPairService.PARTITION_KEY, marker=marker,
- limit=limit or self.provider.config.default_result_limit)
- results = [AzureKeyPair(self.provider, key_pair)
- for key_pair in key_pairs]
- return ServerPagedResultList(is_truncated=resume_marker,
- marker=resume_marker,
- supports_total=False,
- data=results)
- def find(self, **kwargs):
- obj_list = self
- filters = ['name']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def create(self, name, public_key_material=None):
- AzureKeyPair.assert_valid_resource_name(name)
- key_pair = self.get(name)
- if key_pair:
- raise DuplicateResourceException(
- 'Keypair already exists with name {0}'.format(name))
- private_key = None
- if not public_key_material:
- public_key_material, private_key = cb_helpers.generate_key_pair()
- entity = {
- 'PartitionKey': AzureKeyPairService.PARTITION_KEY,
- 'RowKey': str(uuid.uuid4()),
- 'Name': name,
- 'Key': public_key_material
- }
- self.provider.azure_client.create_public_key(entity)
- key_pair = self.get(name)
- key_pair.material = private_key
- return key_pair
- class AzureBucketService(BaseBucketService):
- def __init__(self, provider):
- super(AzureBucketService, self).__init__(provider)
- def get(self, bucket_id):
- """
- Returns a bucket given its ID. Returns ``None`` if the bucket
- does not exist.
- """
- try:
- bucket = self.provider.azure_client.get_container(bucket_id)
- return AzureBucket(self.provider, bucket)
- except AzureException as error:
- log.exception(error)
- return None
- def find(self, **kwargs):
- obj_list = self
- filters = ['name']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def list(self, limit=None, marker=None):
- """
- List all containers.
- """
- buckets = [AzureBucket(self.provider, bucket)
- for bucket in self.provider.azure_client.list_containers()]
- return ClientPagedResultList(self.provider, buckets,
- limit=limit, marker=marker)
- def create(self, name, location=None):
- """
- Create a new bucket.
- """
- AzureBucket.assert_valid_resource_name(name)
- bucket = self.provider.azure_client.create_container(name)
- return AzureBucket(self.provider, bucket)
- class AzureStorageService(BaseStorageService):
- def __init__(self, provider):
- super(AzureStorageService, self).__init__(provider)
- # Initialize provider services
- self._volume_svc = AzureVolumeService(self.provider)
- self._snapshot_svc = AzureSnapshotService(self.provider)
- self._bucket_svc = AzureBucketService(self.provider)
- @property
- def volumes(self):
- return self._volume_svc
- @property
- def snapshots(self):
- return self._snapshot_svc
- @property
- def buckets(self):
- return self._bucket_svc
- class AzureVolumeService(BaseVolumeService):
- def __init__(self, provider):
- super(AzureVolumeService, self).__init__(provider)
- def get(self, volume_id):
- """
- Returns a volume given its id.
- """
- try:
- volume = self.provider.azure_client.get_disk(volume_id)
- return AzureVolume(self.provider, volume)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def find(self, **kwargs):
- obj_list = self
- filters = ['name', 'label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def list(self, limit=None, marker=None):
- """
- List all volumes.
- """
- azure_vols = self.provider.azure_client.list_disks()
- cb_vols = [AzureVolume(self.provider, vol) for vol in azure_vols]
- return ClientPagedResultList(self.provider, cb_vols,
- limit=limit, marker=marker)
- def create(self, size, zone=None, label=None, description=None,
- snapshot=None):
- """
- Creates a new volume.
- """
- disk_name = AzureVolume._generate_name_from_label(label, "cb-vol")
- if label:
- AzureVolume.assert_valid_resource_label(label)
- tags = {'Label': label}
- zone_id = zone.id if isinstance(zone, PlacementZone) else zone
- snapshot = (self.provider.storage.snapshots.get(snapshot)
- if snapshot and isinstance(snapshot, str) else snapshot)
- if description:
- if not tags:
- tags = {}
- tags.update(Description=description)
- if snapshot:
- params = {
- 'location':
- zone_id or self.provider.azure_client.region_name,
- 'creation_data': {
- 'create_option': DiskCreateOption.copy,
- 'source_uri': snapshot.resource_id
- }
- }
- if tags:
- params.update(tags=tags)
- disk = self.provider.azure_client.create_snapshot_disk(disk_name,
- params)
- else:
- params = {
- 'location':
- zone_id or self.provider.region_name,
- 'disk_size_gb': size,
- 'creation_data': {
- 'create_option': DiskCreateOption.empty
- }
- }
- if tags:
- params.update(tags=tags)
- disk = self.provider.azure_client.create_empty_disk(disk_name,
- params)
- azure_vol = self.provider.azure_client.get_disk(disk.id)
- cb_vol = AzureVolume(self.provider, azure_vol)
- return cb_vol
- class AzureSnapshotService(BaseSnapshotService):
- def __init__(self, provider):
- super(AzureSnapshotService, self).__init__(provider)
- def get(self, ss_id):
- """
- Returns a snapshot given its id.
- """
- try:
- snapshot = self.provider.azure_client.get_snapshot(ss_id)
- return AzureSnapshot(self.provider, snapshot)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def find(self, **kwargs):
- obj_list = self
- filters = ['name', 'label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def list(self, limit=None, marker=None):
- """
- List all snapshots.
- """
- snaps = [AzureSnapshot(self.provider, obj)
- for obj in
- self.provider.azure_client.list_snapshots()]
- return ClientPagedResultList(self.provider, snaps, limit, marker)
- def create(self, volume, label=None, description=None):
- """
- Creates a new snapshot of a given volume.
- """
- volume = (self.provider.storage.volumes.get(volume)
- if isinstance(volume, str) else volume)
- snapshot_name = AzureSnapshot._generate_name_from_label(label,
- "cb-snap")
- if label:
- AzureSnapshot.assert_valid_resource_label(label)
- tags = {'Label': label}
- if description:
- if not tags:
- tags = {}
- tags.update(Description=description)
- params = {
- 'location': self.provider.azure_client.region_name,
- 'creation_data': {
- 'create_option': DiskCreateOption.copy,
- 'source_uri': volume.resource_id
- },
- 'disk_size_gb': volume.size
- }
- if tags:
- params.update(tags=tags)
- azure_snap = self.provider.azure_client.create_snapshot(snapshot_name,
- params)
- return AzureSnapshot(self.provider, azure_snap)
- class AzureComputeService(BaseComputeService):
- def __init__(self, provider):
- super(AzureComputeService, self).__init__(provider)
- self._vm_type_svc = AzureVMTypeService(self.provider)
- self._instance_svc = AzureInstanceService(self.provider)
- self._region_svc = AzureRegionService(self.provider)
- self._images_svc = AzureImageService(self.provider)
- @property
- def images(self):
- return self._images_svc
- @property
- def vm_types(self):
- return self._vm_type_svc
- @property
- def instances(self):
- return self._instance_svc
- @property
- def regions(self):
- return self._region_svc
- class AzureInstanceService(BaseInstanceService):
- def __init__(self, provider):
- super(AzureInstanceService, self).__init__(provider)
- def create(self, image, vm_type, label, subnet=None, zone=None,
- key_pair=None, vm_firewalls=None, user_data=None,
- launch_config=None, **kwargs):
- AzureInstance.assert_valid_resource_label(label)
- instance_name = AzureInstance._generate_name_from_label(label,
- "cb-ins")
- image = (image if isinstance(image, AzureMachineImage) else
- self.provider.compute.images.get(image))
- if not isinstance(image, AzureMachineImage):
- raise Exception("Provided image %s is not a valid azure image"
- % image)
- instance_size = vm_type.id if \
- isinstance(vm_type, VMType) else vm_type
- if not subnet:
- # Azure has only a single zone per region; use the current one
- zone = self.provider.compute.regions.get(
- self.provider.region_name).zones[0]
- subnet = self.provider.networking.subnets.get_or_create_default(
- zone)
- else:
- subnet = (self.provider.networking.subnets.get(subnet)
- if isinstance(subnet, str) else subnet)
- zone_id = zone.id if isinstance(zone, PlacementZone) else zone
- subnet_id, zone_id, vm_firewall_id = \
- self._resolve_launch_options(instance_name,
- subnet, zone_id, vm_firewalls)
- storage_profile = self._create_storage_profile(image, launch_config,
- instance_name, zone_id)
- nic_params = {
- 'location': self.provider.region_name,
- 'ip_configurations': [{
- 'name': instance_name + '_ip_config',
- 'private_ip_allocation_method': 'Dynamic',
- 'subnet': {
- 'id': subnet_id
- }
- }]
- }
- if vm_firewall_id:
- nic_params['network_security_group'] = {
- 'id': vm_firewall_id
- }
- nic_info = self.provider.azure_client.create_nic(
- instance_name + '_nic',
- nic_params
- )
- # #! indicates shell script
- ud = '#cloud-config\n' + user_data \
- if user_data and not user_data.startswith('#!')\
- and not user_data.startswith('#cloud-config') else user_data
- # Key_pair is mandatory in azure and it should not be None.
- temp_key_pair = None
- if key_pair:
- key_pair = (key_pair if isinstance(key_pair, AzureKeyPair)
- else self.provider.security.key_pairs.get(key_pair))
- else:
- # Create a temporary keypair if none is provided to keep Azure
- # happy, but the private key will be discarded, so it'll be all
- # but useless. However, this will allow an instance to be launched
- # without specifying a keypair, so users may still be able to login
- # if they have a preinstalled keypair/password baked into the image
- temp_kp_name = "".join(["cb-default-kp-",
- str(uuid.uuid5(uuid.NAMESPACE_OID,
- instance_name))[-6:]])
- key_pair = self.provider.security.key_pairs.create(
- name=temp_kp_name)
- temp_key_pair = key_pair
- params = {
- 'location': zone_id or self.provider.region_name,
- 'os_profile': {
- 'admin_username': self.provider.vm_default_user_name,
- 'computer_name': instance_name,
- 'linux_configuration': {
- "disable_password_authentication": True,
- "ssh": {
- "public_keys": [{
- "path":
- "/home/{}/.ssh/authorized_keys".format(
- self.provider.vm_default_user_name),
- "key_data": key_pair._key_pair.Key
- }]
- }
- }
- },
- 'hardware_profile': {
- 'vm_size': instance_size
- },
- 'network_profile': {
- 'network_interfaces': [{
- 'id': nic_info.id
- }]
- },
- 'storage_profile': storage_profile,
- 'tags': {}
- }
- if label:
- params['tags'].update(Label=label)
- for disk_def in storage_profile.get('data_disks', []):
- params['tags'] = dict(disk_def.get('tags', {}), **params['tags'])
- if user_data:
- custom_data = base64.b64encode(bytes(ud, 'utf-8'))
- params['os_profile']['custom_data'] = str(custom_data, 'utf-8')
- if not temp_key_pair:
- params['tags'].update(Key_Pair=key_pair.id)
- try:
- vm = self.provider.azure_client.create_vm(instance_name, params)
- except Exception as e:
- # If VM creation fails, attempt to clean up intermediary resources
- self.provider.azure_client.delete_nic(nic_info.id)
- for disk_def in storage_profile.get('data_disks', []):
- if disk_def.get('tags', {}).get('delete_on_terminate'):
- disk_id = disk_def.get('managed_disk', {}).get('id')
- if disk_id:
- vol = self.provider.storage.volumes.get(disk_id)
- vol.delete()
- raise e
- finally:
- if temp_key_pair:
- temp_key_pair.delete()
- return AzureInstance(self.provider, vm)
- def _resolve_launch_options(self, inst_name, subnet=None, zone_id=None,
- vm_firewalls=None):
- if subnet:
- # subnet's zone takes precedence
- zone_id = subnet.zone.id
- vm_firewall_id = None
- if isinstance(vm_firewalls, list) and len(vm_firewalls) > 0:
- if isinstance(vm_firewalls[0], VMFirewall):
- vm_firewalls_ids = [fw.id for fw in vm_firewalls]
- vm_firewall_id = vm_firewalls[0].resource_id
- else:
- vm_firewalls_ids = vm_firewalls
- vm_firewall = self.provider.security.\
- vm_firewalls.get(vm_firewalls[0])
- vm_firewall_id = vm_firewall.resource_id
- if len(vm_firewalls) > 1:
- new_fw = self.provider.security.vm_firewalls.\
- create(label='{0}-fw'.format(inst_name),
- description='Merge vm firewall {0}'.
- format(','.join(vm_firewalls_ids)))
- for fw in vm_firewalls:
- new_fw.add_rule(src_dest_fw=fw)
- vm_firewall_id = new_fw.resource_id
- return subnet.resource_id, zone_id, vm_firewall_id
- def _create_storage_profile(self, image, launch_config, instance_name,
- zone_id):
- if image.is_gallery_image:
- reference = image._image.as_dict()
- image_ref = {
- 'publisher': reference['publisher'],
- 'offer': reference['offer'],
- 'sku': reference['sku'],
- 'version': reference['version']
- }
- else:
- image_ref = {
- 'id': image.resource_id
- }
- storage_profile = {
- 'image_reference': image_ref,
- "os_disk": {
- "name": instance_name + '_os_disk',
- "create_option": DiskCreateOption.from_image
- },
- }
- if launch_config:
- data_disks, root_disk_size = self._process_block_device_mappings(
- launch_config, instance_name, zone_id)
- if data_disks:
- storage_profile['data_disks'] = data_disks
- if root_disk_size:
- storage_profile['os_disk']['disk_size_gb'] = root_disk_size
- return storage_profile
- def _process_block_device_mappings(self, launch_config,
- vm_name, zone=None):
- """
- Processes block device mapping information
- and returns a Data disk dictionary list. If new volumes
- are requested (source is None and destination is VOLUME), they will be
- created and the relevant volume ids included in the mapping.
- """
- data_disks = []
- root_disk_size = None
- def append_disk(disk_def, device_no, delete_on_terminate):
- # In azure, there is no option to specify terminate disks
- # (similar to AWS delete_on_terminate) on VM delete.
- # This method uses the azure tags functionality to store
- # the delete_on_terminate option when the virtual machine
- # is deleted, we parse the tags and delete accordingly
- disk_def['lun'] = device_no
- disk_def['tags'] = {
- 'delete_on_terminate': delete_on_terminate
- }
- data_disks.append(disk_def)
- for device_no, device in enumerate(launch_config.block_devices):
- if device.is_volume:
- if device.is_root:
- root_disk_size = device.size
- else:
- # In azure, os disk automatically created,
- # we are ignoring the root disk, if specified
- if isinstance(device.source, Snapshot):
- snapshot_vol = device.source.create_volume()
- disk_def = {
- # pylint:disable=protected-access
- 'name': snapshot_vol._volume.name,
- 'create_option': DiskCreateOption.attach,
- 'managed_disk': {
- 'id': snapshot_vol.id
- }
- }
- elif isinstance(device.source, Volume):
- disk_def = {
- # pylint:disable=protected-access
- 'name': device.source._volume.name,
- 'create_option': DiskCreateOption.attach,
- 'managed_disk': {
- 'id': device.source.id
- }
- }
- elif isinstance(device.source, MachineImage):
- disk_def = {
- # pylint:disable=protected-access
- 'name': device.source._volume.name,
- 'create_option': DiskCreateOption.from_image,
- 'source_resource_id': device.source.id
- }
- else:
- disk_def = {
- # pylint:disable=protected-access
- 'create_option': DiskCreateOption.empty,
- 'disk_size_gb': device.size
- }
- append_disk(disk_def, device_no,
- device.delete_on_terminate)
- else: # device is ephemeral
- # in azure we cannot add the ephemeral disks explicitly
- pass
- return data_disks, root_disk_size
- def create_launch_config(self):
- return AzureLaunchConfig(self.provider)
- def list(self, limit=None, marker=None):
- """
- List all instances.
- """
- instances = [AzureInstance(self.provider, inst)
- for inst in self.provider.azure_client.list_vm()]
- return ClientPagedResultList(self.provider, instances,
- limit=limit, marker=marker)
- def get(self, instance_id):
- """
- Returns an instance given its id. Returns None
- if the object does not exist.
- """
- try:
- vm = self.provider.azure_client.get_vm(instance_id)
- return AzureInstance(self.provider, vm)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def find(self, **kwargs):
- obj_list = self
- filters = ['name', 'label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- class AzureImageService(BaseImageService):
- def __init__(self, provider):
- super(AzureImageService, self).__init__(provider)
- def get(self, image_id):
- """
- Returns an Image given its id
- """
- try:
- image = self.provider.azure_client.get_image(image_id)
- return AzureMachineImage(self.provider, image)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def find(self, **kwargs):
- obj_list = self
- filters = ['name', 'label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def list(self, limit=None, marker=None):
- """
- List all images.
- """
- azure_images = self.provider.azure_client.list_images()
- azure_gallery_refs = self.provider.azure_client.list_gallery_refs()
- cb_images = [AzureMachineImage(self.provider, img)
- for img in azure_images + azure_gallery_refs]
- return ClientPagedResultList(self.provider, cb_images,
- limit=limit, marker=marker)
- class AzureVMTypeService(BaseVMTypeService):
- def __init__(self, provider):
- super(AzureVMTypeService, self).__init__(provider)
- @property
- def instance_data(self):
- """
- Fetch info about the available instances.
- """
- r = self.provider.azure_client.list_vm_types()
- return r
- def list(self, limit=None, marker=None):
- vm_types = [AzureVMType(self.provider, vm_type)
- for vm_type in self.instance_data]
- return ClientPagedResultList(self.provider, vm_types,
- limit=limit, marker=marker)
- class AzureNetworkingService(BaseNetworkingService):
- def __init__(self, provider):
- super(AzureNetworkingService, self).__init__(provider)
- self._network_service = AzureNetworkService(self.provider)
- self._subnet_service = AzureSubnetService(self.provider)
- self._router_service = AzureRouterService(self.provider)
- @property
- def networks(self):
- return self._network_service
- @property
- def subnets(self):
- return self._subnet_service
- @property
- def routers(self):
- return self._router_service
- class AzureNetworkService(BaseNetworkService):
- def __init__(self, provider):
- super(AzureNetworkService, self).__init__(provider)
- def get(self, network_id):
- try:
- network = self.provider.azure_client.get_network(network_id)
- return AzureNetwork(self.provider, network)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def list(self, limit=None, marker=None):
- """
- List all networks.
- """
- networks = [AzureNetwork(self.provider, network)
- for network in self.provider.azure_client.list_networks()]
- return ClientPagedResultList(self.provider, networks,
- limit=limit, marker=marker)
- def find(self, **kwargs):
- obj_list = self
- filters = ['name', 'label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def create(self, cidr_block, label=None):
- AzureNetwork.assert_valid_resource_label(label)
- params = {
- 'location': self.provider.azure_client.region_name,
- 'address_space': {
- 'address_prefixes': [cidr_block]
- }
- }
- if label:
- params.update(tags={'Label': label})
- network_name = AzureNetwork._generate_name_from_label(label, 'cb-net')
- az_network = self.provider.azure_client.create_network(network_name,
- params)
- cb_network = AzureNetwork(self.provider, az_network)
- return cb_network
- def delete(self, network_id):
- """
- Delete an existing network.
- """
- self.provider.azure_client.delete_network(network_id)
- class AzureRegionService(BaseRegionService):
- def __init__(self, provider):
- super(AzureRegionService, self).__init__(provider)
- def get(self, region_id):
- region = None
- for azureRegion in self.provider.azure_client.list_locations():
- if azureRegion.name == region_id:
- region = AzureRegion(self.provider, azureRegion)
- break
- return region
- def list(self, limit=None, marker=None):
- regions = [AzureRegion(self.provider, region)
- for region in self.provider.azure_client.list_locations()]
- return ClientPagedResultList(self.provider, regions,
- limit=limit, marker=marker)
- @property
- def current(self):
- return self.get(self.provider.region_name)
- class AzureSubnetService(BaseSubnetService):
- def __init__(self, provider):
- super(AzureSubnetService, self).__init__(provider)
- def get(self, subnet_id):
- """
- Azure does not provide an api to get the subnet directly by id.
- It also requires the network id.
- To make it consistent across the providers the following code
- gets the specific code from the subnet list.
- :param subnet_id:
- :return:
- """
- try:
- azure_subnet = self.provider.azure_client.get_subnet(subnet_id)
- return AzureSubnet(self.provider,
- azure_subnet) if azure_subnet else None
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def list(self, network=None, limit=None, marker=None):
- """
- List subnets
- """
- return ClientPagedResultList(self.provider,
- self._list_subnets(network),
- limit=limit, marker=marker)
- def _list_subnets(self, network=None):
- result_list = []
- if network:
- network_id = network.id \
- if isinstance(network, Network) else network
- result_list = self.provider.azure_client.list_subnets(network_id)
- else:
- for net in self.provider.networking.networks:
- try:
- result_list.extend(self.provider.azure_client.list_subnets(
- net.id
- ))
- except CloudError as cloud_error:
- if "NotFound" in cloud_error.error.error:
- log.exception(cloud_error)
- else:
- raise cloud_error
- subnets = [AzureSubnet(self.provider, subnet)
- for subnet in result_list]
- return subnets
- def find(self, network=None, **kwargs):
- obj_list = self._list_subnets(network)
- filters = ['label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def create(self, network, cidr_block, label=None, **kwargs):
- """
- Create subnet
- """
- network_id = network.id \
- if isinstance(network, Network) else network
- # Although Subnet doesn't support labels, we use the parent Network's
- # tags to track the subnet's labels
- AzureSubnet.assert_valid_resource_label(label)
- subnet_name = AzureSubnet._generate_name_from_label(label, "cb-sn")
- subnet_info = self.provider.azure_client\
- .create_subnet(
- network_id,
- subnet_name,
- {
- 'address_prefix': cidr_block
- }
- )
- subnet = AzureSubnet(self.provider, subnet_info)
- subnet.label = label
- return subnet
- def get_or_create_default(self, zone):
- default_cidr = '10.0.1.0/24'
- # No provider-default Subnet exists, look for a library-default one
- matches = self.find(label=AzureSubnet.CB_DEFAULT_SUBNET_LABEL)
- if matches:
- return matches[0]
- # No provider-default Subnet exists, try to create it (net + subnets)
- networks = self.provider.networking.networks.find(
- label=AzureNetwork.CB_DEFAULT_NETWORK_LABEL)
- if networks:
- network = networks[0]
- else:
- network = self.provider.networking.networks.create(
- '10.0.0.0/16', label=AzureNetwork.CB_DEFAULT_NETWORK_LABEL)
- subnet = self.create(network, default_cidr,
- label=AzureSubnet.CB_DEFAULT_SUBNET_LABEL)
- return subnet
- def delete(self, subnet):
- subnet_id = subnet.id if isinstance(subnet, Subnet) else subnet
- self.provider.azure_client.delete_subnet(subnet_id)
- class AzureRouterService(BaseRouterService):
- def __init__(self, provider):
- super(AzureRouterService, self).__init__(provider)
- def get(self, router_id):
- try:
- route = self.provider.azure_client.get_route_table(router_id)
- return AzureRouter(self.provider, route)
- except (CloudError, InvalidValueException) as cloud_error:
- # Azure raises the cloud error if the resource not available
- log.exception(cloud_error)
- return None
- def find(self, **kwargs):
- obj_list = self
- filters = ['name', 'label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise TypeError("Unrecognised parameters for search: %s."
- " Supported attributes: %s" % (kwargs,
- ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def list(self, limit=None, marker=None):
- routes = [AzureRouter(self.provider, route)
- for route in
- self.provider.azure_client.list_route_tables()]
- return ClientPagedResultList(self.provider,
- routes,
- limit=limit, marker=marker)
- def create(self, network, label=None):
- router_name = AzureRouter._generate_name_from_label(label, "cb-router")
- parameters = {"location": self.provider.region_name}
- if label:
- AzureRouter.assert_valid_resource_label(label)
- parameters.update(tags={'Label': label})
- route = self.provider.azure_client. \
- create_route_table(router_name, parameters)
- return AzureRouter(self.provider, route)
|