| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344 |
- 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.middleware import dispatch
- from cloudbridge.cloud.base.resources import ClientPagedResultList
- from cloudbridge.cloud.base.resources import ServerPagedResultList
- from cloudbridge.cloud.base.services import BaseBucketObjectService
- from cloudbridge.cloud.base.services import BaseBucketService
- from cloudbridge.cloud.base.services import BaseComputeService
- from cloudbridge.cloud.base.services import BaseFloatingIPService
- from cloudbridge.cloud.base.services import BaseGatewayService
- from cloudbridge.cloud.base.services import BaseImageService
- from cloudbridge.cloud.base.services import BaseInstanceService
- from cloudbridge.cloud.base.services import BaseKeyPairService
- from cloudbridge.cloud.base.services import BaseNetworkService
- from cloudbridge.cloud.base.services import BaseNetworkingService
- from cloudbridge.cloud.base.services import BaseRegionService
- from cloudbridge.cloud.base.services import BaseRouterService
- from cloudbridge.cloud.base.services import BaseSecurityService
- from cloudbridge.cloud.base.services import BaseSnapshotService
- from cloudbridge.cloud.base.services import BaseStorageService
- from cloudbridge.cloud.base.services import BaseSubnetService
- from cloudbridge.cloud.base.services import BaseVMFirewallRuleService
- from cloudbridge.cloud.base.services import BaseVMFirewallService
- from cloudbridge.cloud.base.services import BaseVMTypeService
- from cloudbridge.cloud.base.services import BaseVolumeService
- from cloudbridge.cloud.interfaces.exceptions import DuplicateResourceException
- from cloudbridge.cloud.interfaces.exceptions import InvalidParamException
- from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
- from cloudbridge.cloud.interfaces.resources import MachineImage
- from cloudbridge.cloud.interfaces.resources import Network
- from cloudbridge.cloud.interfaces.resources import PlacementZone
- from cloudbridge.cloud.interfaces.resources import Snapshot
- from cloudbridge.cloud.interfaces.resources import TrafficDirection
- from cloudbridge.cloud.interfaces.resources import VMFirewall
- from cloudbridge.cloud.interfaces.resources import VMType
- from cloudbridge.cloud.interfaces.resources import Volume
- from .resources import AzureBucket
- from .resources import AzureBucketObject
- from .resources import AzureFloatingIP
- from .resources import AzureInstance
- from .resources import AzureInternetGateway
- from .resources import AzureKeyPair
- from .resources import AzureLaunchConfig
- from .resources import AzureMachineImage
- from .resources import AzureNetwork
- from .resources import AzureRegion
- from .resources import AzureRouter
- from .resources import AzureSnapshot
- from .resources import AzureSubnet
- from .resources import AzureVMFirewall
- from .resources import AzureVMFirewallRule
- from .resources import AzureVMType
- from .resources import 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)
- self._vm_firewall_rules = AzureVMFirewallRuleService(provider)
- class AzureVMFirewallService(BaseVMFirewallService):
- def __init__(self, provider):
- super(AzureVMFirewallService, self).__init__(provider)
- @dispatch(event="provider.security.vm_firewalls.get",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- def get(self, vm_firewall_id):
- try:
- fws = self.provider.azure_client.get_vm_firewall(vm_firewall_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
- @dispatch(event="provider.security.vm_firewalls.list",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- 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)
- @cb_helpers.deprecated_alias(network_id='network')
- @dispatch(event="provider.security.vm_firewalls.create",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- def create(self, label, network, description=None):
- AzureVMFirewall.assert_valid_resource_label(label)
- name = AzureVMFirewall._generate_name_from_label(label, "cb-fw")
- net = network.id if isinstance(network, Network) else network
- parameters = {"location": self.provider.region_name,
- "tags": {'Label': label,
- 'network_id': net}}
- if description:
- parameters['tags'].update(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
- @dispatch(event="provider.security.vm_firewalls.delete",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- def delete(self, vmf):
- fw_id = vmf.id if isinstance(vmf, AzureVMFirewall) else vmf
- self.provider.azure_client.delete_vm_firewall(fw_id)
- class AzureVMFirewallRuleService(BaseVMFirewallRuleService):
- def __init__(self, provider):
- super(AzureVMFirewallRuleService, self).__init__(provider)
- def list(self, firewall, limit=None, marker=None):
- # Filter out firewall rules with priority < 3500 because values
- # between 3500 and 4096 are assumed to be owned by cloudbridge
- # default rules.
- # pylint:disable=protected-access
- rules = [AzureVMFirewallRule(firewall, rule) for rule
- in firewall._vm_firewall.security_rules
- if rule.priority < 3500]
- return ClientPagedResultList(self._provider, rules,
- limit=limit, marker=marker)
- def create(self, firewall, direction, protocol=None, from_port=None,
- to_port=None, cidr=None, src_dest_fw=None):
- if protocol and from_port and to_port:
- return self._create_rule(direction, protocol, from_port,
- to_port, cidr)
- elif src_dest_fw:
- result = None
- fw = (self._provider.security.vm_firewalls.get(src_dest_fw)
- if isinstance(src_dest_fw, str) else src_dest_fw)
- for rule in fw.rules:
- result = self._create_rule(
- rule.direction, rule.protocol, rule.from_port,
- rule.to_port, rule.cidr)
- return result
- else:
- return None
- def _create_rule(self, firewall, direction, protocol,
- from_port, to_port, cidr):
- # If cidr is None, default values is set as 0.0.0.0/0
- if not cidr:
- cidr = '0.0.0.0/0'
- count = len(firewall._vm_firewall.security_rules) + 1
- rule_name = "cb-rule-" + str(count)
- priority = 1000 + count
- destination_port_range = str(from_port) + "-" + str(to_port)
- source_port_range = '*'
- destination_address_prefix = "*"
- access = "Allow"
- direction = ("Inbound" if direction == TrafficDirection.INBOUND
- else "Outbound")
- parameters = {"priority": priority,
- "protocol": protocol,
- "source_port_range": source_port_range,
- "source_address_prefix": cidr,
- "destination_port_range": destination_port_range,
- "destination_address_prefix": destination_address_prefix,
- "access": access,
- "direction": direction}
- result = self._provider.azure_client. \
- create_vm_firewall_rule(firewall.id,
- rule_name, parameters)
- # pylint:disable=protected-access
- firewall._vm_firewall.security_rules.append(result)
- return AzureVMFirewallRule(firewall, result)
- def delete(self, firewall, rule):
- vm_firewall = firewall.name
- self.provider.azure_client. \
- delete_vm_firewall_rule(rule.id, vm_firewall)
- for i, o in enumerate(firewall._vm_firewall.security_rules):
- if o.id == rule.id:
- del firewall._vm_firewall.security_rules[i]
- break
- class AzureKeyPairService(BaseKeyPairService):
- PARTITION_KEY = '00000000-0000-0000-0000-000000000000'
- def __init__(self, provider):
- super(AzureKeyPairService, self).__init__(provider)
- @dispatch(event="provider.security.key_pairs.get",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- 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.debug("KeyPair %s was not found.", key_pair_id)
- log.debug(error)
- return None
- @dispatch(event="provider.security.key_pairs.list",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- 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)
- @dispatch(event="provider.security.key_pairs.find",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- 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 InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- @dispatch(event="provider.security.key_pairs.create",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- 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
- @dispatch(event="provider.security.key_pairs.delete",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- def delete(self, kp):
- key_pair = kp if isinstance(kp, AzureKeyPair) else self.get(kp)
- if key_pair:
- # pylint:disable=protected-access
- self.provider.azure_client.delete_public_key(key_pair._key_pair)
- 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)
- self._bucket_obj_svc = AzureBucketObjectService(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
- @property
- def _bucket_objects(self):
- return self._bucket_obj_svc
- class AzureVolumeService(BaseVolumeService):
- def __init__(self, provider):
- super(AzureVolumeService, self).__init__(provider)
- @dispatch(event="provider.storage.volumes.get",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def get(self, volume_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
- @dispatch(event="provider.storage.volumes.find",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- obj_list = self
- 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 InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- @dispatch(event="provider.storage.volumes.list",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- 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)
- @dispatch(event="provider.storage.volumes.create",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def create(self, label, size, zone, snapshot=None, description=None):
- AzureVolume.assert_valid_resource_label(label)
- disk_name = AzureVolume._generate_name_from_label(label, "cb-vol")
- 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:
- 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
- },
- '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
- },
- '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
- @dispatch(event="provider.storage.volumes.delete",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def delete(self, volume_id):
- vol_id = (volume_id.id if isinstance(volume_id, AzureVolume)
- else volume_id)
- self.provider.azure_client.delete_disk(vol_id)
- class AzureSnapshotService(BaseSnapshotService):
- def __init__(self, provider):
- super(AzureSnapshotService, self).__init__(provider)
- @dispatch(event="provider.storage.snapshots.get",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def get(self, snapshot_id):
- try:
- snapshot = self.provider.azure_client.get_snapshot(snapshot_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
- @dispatch(event="provider.storage.snapshots.find",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- obj_list = self
- 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 InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- @dispatch(event="provider.storage.snapshots.list",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- snaps = [AzureSnapshot(self.provider, obj)
- for obj in
- self.provider.azure_client.list_snapshots()]
- return ClientPagedResultList(self.provider, snaps, limit, marker)
- @dispatch(event="provider.storage.snapshots.create",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def create(self, label, volume, description=None):
- AzureSnapshot.assert_valid_resource_label(label)
- snapshot_name = AzureSnapshot._generate_name_from_label(label,
- "cb-snap")
- tags = {'Label': label}
- if description:
- tags.update(Description=description)
- volume = (self.provider.storage.volumes.get(volume)
- if isinstance(volume, str) else volume)
- params = {
- 'location': self.provider.azure_client.region_name,
- 'creation_data': {
- 'create_option': DiskCreateOption.copy,
- 'source_uri': volume.resource_id
- },
- 'disk_size_gb': volume.size,
- 'tags': tags
- }
- azure_snap = self.provider.azure_client.create_snapshot(snapshot_name,
- params)
- return AzureSnapshot(self.provider, azure_snap)
- @dispatch(event="provider.storage.snapshots.delete",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def delete(self, snapshot_id):
- snap_id = (snapshot_id.id if isinstance(snapshot_id, AzureSnapshot)
- else snapshot_id)
- self.provider.azure_client.delete_snapshot(snap_id)
- class AzureBucketService(BaseBucketService):
- def __init__(self, provider):
- super(AzureBucketService, self).__init__(provider)
- @dispatch(event="provider.storage.buckets.get",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- 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
- @dispatch(event="provider.storage.buckets.list",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- buckets = [AzureBucket(self.provider, bucket)
- for bucket
- in self.provider.azure_client.list_containers()[0]]
- return ClientPagedResultList(self.provider, buckets,
- limit=limit, marker=marker)
- @dispatch(event="provider.storage.buckets.create",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- 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)
- @dispatch(event="provider.storage.buckets.delete",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- def delete(self, bucket):
- """
- Delete this bucket.
- """
- b_id = bucket.id if isinstance(bucket, AzureBucket) else bucket
- self.provider.azure_client.delete_container(b_id)
- class AzureBucketObjectService(BaseBucketObjectService):
- def __init__(self, provider):
- super(AzureBucketObjectService, self).__init__(provider)
- def get(self, bucket, object_id):
- """
- Retrieve a given object from this bucket.
- """
- try:
- obj = self.provider.azure_client.get_blob(bucket.name,
- object_id)
- return AzureBucketObject(self.provider, bucket, obj)
- except AzureException as azureEx:
- log.exception(azureEx)
- return None
- def list(self, bucket, limit=None, marker=None, prefix=None):
- """
- List all objects within this bucket.
- :rtype: BucketObject
- :return: List of all available BucketObjects within this bucket.
- """
- objects = [AzureBucketObject(self.provider, bucket, obj)
- for obj in
- self.provider.azure_client.list_blobs(
- bucket.name, prefix=prefix)]
- return ClientPagedResultList(self.provider, objects,
- limit=limit, marker=marker)
- def find(self, bucket, **kwargs):
- obj_list = [AzureBucketObject(self.provider, bucket, obj)
- for obj in
- self.provider.azure_client.list_blobs(bucket.name)]
- filters = ['name']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- return ClientPagedResultList(self.provider, list(matches))
- def create(self, bucket, name):
- self.provider.azure_client.create_blob_from_text(
- bucket.name, name, '')
- return self.get(bucket, name)
- 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 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 = ['label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- def list(self, filter_by_owner=True, 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() \
- if not filter_by_owner else []
- 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 AzureInstanceService(BaseInstanceService):
- def __init__(self, provider):
- super(AzureInstanceService, self).__init__(provider)
- 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)
- @dispatch(event="provider.compute.instances.create",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def create(self, label, image, vm_type, subnet, zone,
- 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': {'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)
- @dispatch(event="provider.compute.instances.list",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- 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)
- @dispatch(event="provider.compute.instances.get",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- 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
- @dispatch(event="provider.compute.instances.find",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- obj_list = self
- 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 InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- @dispatch(event="provider.compute.instances.delete",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def delete(self, inst):
- """
- Permanently terminate this instance.
- After deleting the VM. we are deleting the network interface
- associated to the instance, and also removing OS disk and data disks
- where tag with name 'delete_on_terminate' has value True.
- """
- ins = inst if isinstance(inst, AzureInstance) else self.get(inst)
- if not inst:
- return
- # Remove IPs first to avoid a network interface conflict
- for public_ip_id in ins._public_ip_ids:
- ins.remove_floating_ip(public_ip_id)
- self.provider.azure_client.deallocate_vm(ins.id)
- self.provider.azure_client.delete_vm(ins.id)
- for nic_id in ins._nic_ids:
- self.provider.azure_client.delete_nic(nic_id)
- for data_disk in ins._vm.storage_profile.data_disks:
- if data_disk.managed_disk:
- if ins._vm.tags.get('delete_on_terminate',
- 'False') == 'True':
- self.provider.azure_client. \
- delete_disk(data_disk.managed_disk.id)
- if ins._vm.storage_profile.os_disk.managed_disk:
- self.provider.azure_client. \
- delete_disk(ins._vm.storage_profile.os_disk.managed_disk.id)
- 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
- @dispatch(event="provider.compute.vm_types.list",
- priority=BaseVMTypeService.STANDARD_EVENT_PRIORITY)
- 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 AzureRegionService(BaseRegionService):
- def __init__(self, provider):
- super(AzureRegionService, self).__init__(provider)
- @dispatch(event="provider.compute.regions.get",
- priority=BaseRegionService.STANDARD_EVENT_PRIORITY)
- 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
- @dispatch(event="provider.compute.regions.list",
- priority=BaseRegionService.STANDARD_EVENT_PRIORITY)
- 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 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)
- self._gateway_service = AzureGatewayService(self.provider)
- self._floating_ip_service = AzureFloatingIPService(self.provider)
- class AzureNetworkService(BaseNetworkService):
- def __init__(self, provider):
- super(AzureNetworkService, self).__init__(provider)
- @dispatch(event="provider.networking.networks.get",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- 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
- @dispatch(event="provider.networking.networks.list",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- networks = [AzureNetwork(self.provider, network)
- for network in self.provider.azure_client.list_networks()]
- return ClientPagedResultList(self.provider, networks,
- limit=limit, marker=marker)
- @dispatch(event="provider.networking.networks.create",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def create(self, label, cidr_block):
- AzureNetwork.assert_valid_resource_label(label)
- params = {
- 'location': self.provider.azure_client.region_name,
- 'address_space': {
- 'address_prefixes': [cidr_block]
- },
- '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
- @dispatch(event="provider.networking.networks.delete",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def delete(self, net):
- net_id = net.id if isinstance(net, AzureNetwork) else net
- if net_id:
- self.provider.azure_client.delete_network(net_id)
- class AzureSubnetService(BaseSubnetService):
- def __init__(self, provider):
- super(AzureSubnetService, self).__init__(provider)
- 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
- @dispatch(event="provider.networking.subnets.get",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- 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.
- """
- 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
- @dispatch(event="provider.networking.subnets.list",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def list(self, network=None, limit=None, marker=None):
- return ClientPagedResultList(self.provider,
- self._list_subnets(network),
- limit=limit, marker=marker)
- @dispatch(event="provider.networking.subnets.find",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def find(self, network=None, **kwargs):
- obj_list = self._list_subnets(network)
- filters = ['label']
- matches = cb_helpers.generic_find(filters, kwargs, obj_list)
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- @dispatch(event="provider.networking.subnets.create",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def create(self, label, network, cidr_block, zone):
- AzureSubnet.assert_valid_resource_label(label)
- # Although Subnet doesn't support tags in Azure, we use the parent
- # Network's tags to track its subnets' labels
- subnet_name = AzureSubnet._generate_name_from_label(label, "cb-sn")
- network_id = network.id \
- if isinstance(network, Network) else network
- 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
- @dispatch(event="provider.networking.subnets.delete",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def delete(self, subnet):
- sn = subnet if isinstance(subnet, AzureSubnet) else self.get(subnet)
- if sn:
- self.provider.azure_client.delete_subnet(sn.id)
- # Although Subnet doesn't support labels, we use the parent
- # Network's tags to track the subnet's labels, thus that
- # network-level tag must be deleted with the subnet
- net_id = sn.network_id
- az_network = self.provider.azure_client.get_network(net_id)
- az_network.tags.pop(sn.tag_name)
- self._provider.azure_client.update_network_tags(
- az_network.id, az_network)
- class AzureRouterService(BaseRouterService):
- def __init__(self, provider):
- super(AzureRouterService, self).__init__(provider)
- @dispatch(event="provider.networking.routers.get",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- 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
- @dispatch(event="provider.networking.routers.find",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- obj_list = self
- 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 InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, ", ".join(filters)))
- return ClientPagedResultList(self.provider,
- matches if matches else [])
- @dispatch(event="provider.networking.routers.list",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- 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)
- @dispatch(event="provider.networking.routers.create",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def create(self, label, network):
- router_name = AzureRouter._generate_name_from_label(label, "cb-router")
- parameters = {"location": self.provider.region_name,
- "tags": {'Label': label}}
- route = self.provider.azure_client. \
- create_route_table(router_name, parameters)
- return AzureRouter(self.provider, route)
- @dispatch(event="provider.networking.routers.delete",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def delete(self, router):
- r = router if isinstance(router, AzureRouter) else self.get(router)
- if r:
- self.provider.azure_client.delete_route_table(r.name)
- class AzureGatewayService(BaseGatewayService):
- def __init__(self, provider):
- super(AzureGatewayService, self).__init__(provider)
- # Azure doesn't have a notion of a route table or an internet
- # gateway as OS and AWS so create placeholder objects of the
- # AzureInternetGateway here.
- # http://bit.ly/2BqGdVh
- # Singleton returned by the list and get methods
- def _gateway_singleton(self, network):
- return AzureInternetGateway(self._provider, None, network)
- def get_or_create_inet_gateway(self, network):
- return self._gateway_singleton(network)
- def list(self, network, limit=None, marker=None):
- gws = [self._gateway_singleton(network)]
- return ClientPagedResultList(self._provider,
- gws,
- limit=limit, marker=marker)
- def delete(self, network, gateway):
- pass
- class AzureFloatingIPService(BaseFloatingIPService):
- def __init__(self, provider):
- super(AzureFloatingIPService, self).__init__(provider)
- def get(self, gateway, fip_id):
- log.debug("Getting Azure Floating IP container with the id: %s",
- fip_id)
- fip = [fip for fip in self if fip.id == fip_id]
- return fip[0] if fip else None
- def list(self, gateway, limit=None, marker=None):
- floating_ips = [AzureFloatingIP(self.provider, floating_ip,
- gateway.network_id)
- for floating_ip in self.provider.azure_client.
- list_floating_ips()]
- return ClientPagedResultList(self.provider, floating_ips,
- limit=limit, marker=marker)
- def create(self, gateway):
- public_ip_parameters = {
- 'location': self.provider.azure_client.region_name,
- 'public_ip_allocation_method': 'Static'
- }
- public_ip_name = AzureFloatingIP._generate_name_from_label('cb-fip-')
- floating_ip = self.provider.azure_client.\
- create_floating_ip(public_ip_name, public_ip_parameters)
- return AzureFloatingIP(self.provider, floating_ip, gateway.network_id)
- def delete(self, gateway, fip):
- fip_id = fip if isinstance(fip, AzureFloatingIP) else fip
- self._provider.azure_client.delete_floating_ip(fip_id)
|