| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199 |
- """
- Services implemented by the OpenStack provider.
- """
- import logging
- from cinderclient.exceptions import NotFound as CinderNotFound
- from neutronclient.common.exceptions import NeutronClientException
- from neutronclient.common.exceptions import PortNotFoundClient
- from novaclient.exceptions import NotFound as NovaNotFound
- from openstack.exceptions import HttpException
- from openstack.exceptions import NotFoundException
- from openstack.exceptions import ResourceNotFound
- from swiftclient import ClientException as SwiftClientException
- import cloudbridge.cloud.base.helpers as cb_helpers
- from cloudbridge.cloud.base.middleware import dispatch
- from cloudbridge.cloud.base.resources import BaseLaunchConfig
- from cloudbridge.cloud.base.resources import ClientPagedResultList
- 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 KeyPair
- 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 Subnet
- 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 . import helpers as oshelpers
- from .resources import OpenStackBucket
- from .resources import OpenStackBucketObject
- from .resources import OpenStackFloatingIP
- from .resources import OpenStackInstance
- from .resources import OpenStackInternetGateway
- from .resources import OpenStackKeyPair
- from .resources import OpenStackMachineImage
- from .resources import OpenStackNetwork
- from .resources import OpenStackRegion
- from .resources import OpenStackRouter
- from .resources import OpenStackSnapshot
- from .resources import OpenStackSubnet
- from .resources import OpenStackVMFirewall
- from .resources import OpenStackVMFirewallRule
- from .resources import OpenStackVMType
- from .resources import OpenStackVolume
- log = logging.getLogger(__name__)
- class OpenStackSecurityService(BaseSecurityService):
- def __init__(self, provider):
- super(OpenStackSecurityService, self).__init__(provider)
- # Initialize provider services
- self._key_pairs = OpenStackKeyPairService(provider)
- self._vm_firewalls = OpenStackVMFirewallService(provider)
- self._vm_firewall_rules = OpenStackVMFirewallRuleService(provider)
- def get_or_create_ec2_credentials(self):
- """
- A provider specific method than returns the ec2 credentials for the
- current user, or creates a new pair if one doesn't exist.
- """
- keystone = self.provider.keystone
- if hasattr(keystone, 'ec2'):
- user_id = keystone.session.get_user_id()
- user_creds = [cred for cred in keystone.ec2.list(user_id) if
- cred.tenant_id == keystone.session.get_project_id()]
- if user_creds:
- return user_creds[0]
- else:
- return keystone.ec2.create(
- user_id, keystone.session.get_project_id())
- return None
- def get_ec2_endpoints(self):
- """
- A provider specific method than returns the ec2 endpoints if
- available.
- """
- keystone = self.provider.keystone
- ec2_url = keystone.session.get_endpoint(service_type='ec2')
- s3_url = keystone.session.get_endpoint(service_type='s3')
- return {'ec2_endpoint': ec2_url,
- 's3_endpoint': s3_url}
- class OpenStackKeyPairService(BaseKeyPairService):
- def __init__(self, provider):
- super(OpenStackKeyPairService, self).__init__(provider)
- @dispatch(event="provider.security.key_pairs.get",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- def get(self, key_pair_id):
- """
- Returns a KeyPair given its id.
- """
- log.debug("Returning KeyPair with the id %s", key_pair_id)
- try:
- return OpenStackKeyPair(
- self.provider, self.provider.nova.keypairs.get(key_pair_id))
- except NovaNotFound:
- log.debug("KeyPair %s was not found.", key_pair_id)
- return None
- @dispatch(event="provider.security.key_pairs.list",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- """
- List all key pairs associated with this account.
- :rtype: ``list`` of :class:`.KeyPair`
- :return: list of KeyPair objects
- """
- keypairs = self.provider.nova.keypairs.list()
- results = [OpenStackKeyPair(self.provider, kp)
- for kp in keypairs]
- log.debug("Listing all key pairs associated with OpenStack "
- "Account: %s", results)
- return ClientPagedResultList(self.provider, results,
- limit=limit, marker=marker)
- @dispatch(event="provider.security.key_pairs.find",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- name = kwargs.pop('name', None)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, 'name'))
- keypairs = self.provider.nova.keypairs.findall(name=name)
- results = [OpenStackKeyPair(self.provider, kp)
- for kp in keypairs]
- log.debug("Searching for %s in: %s", name, keypairs)
- return ClientPagedResultList(self.provider, results)
- @dispatch(event="provider.security.key_pairs.create",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- def create(self, name, public_key_material=None):
- OpenStackKeyPair.assert_valid_resource_name(name)
- existing_kp = self.find(name=name)
- if existing_kp:
- 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()
- kp = self.provider.nova.keypairs.create(name,
- public_key=public_key_material)
- cb_kp = OpenStackKeyPair(self.provider, kp)
- cb_kp.material = private_key
- return cb_kp
- @dispatch(event="provider.security.key_pairs.delete",
- priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
- def delete(self, kp):
- keypair = kp if isinstance(kp, OpenStackKeyPair) else self.get(kp)
- if keypair:
- # pylint:disable=protected-access
- keypair._key_pair.delete()
- class OpenStackVMFirewallService(BaseVMFirewallService):
- def __init__(self, provider):
- super(OpenStackVMFirewallService, self).__init__(provider)
- @dispatch(event="provider.security.vm_firewalls.get",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- def get(self, vm_firewall_id):
- try:
- return OpenStackVMFirewall(
- self.provider,
- self.provider.os_conn.network
- .get_security_group(vm_firewall_id))
- except (ResourceNotFound, NotFoundException):
- log.debug("Firewall %s not found.", vm_firewall_id)
- return None
- @dispatch(event="provider.security.vm_firewalls.list",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- firewalls = [
- OpenStackVMFirewall(self.provider, fw)
- for fw in self.provider.os_conn.network.security_groups()]
- return ClientPagedResultList(self.provider, firewalls,
- limit=limit, marker=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):
- OpenStackVMFirewall.assert_valid_resource_label(label)
- net = network.id if isinstance(network, Network) else network
- # We generally simulate a network being associated with a firewall
- # by storing the supplied value in the firewall description field that
- # is not modifiable after creation; however, because of some networking
- # specificity in Nectar, we must also allow an empty network id value.
- if not net:
- net = ""
- if not description:
- description = ""
- description += " [{}{}]".format(OpenStackVMFirewall._network_id_tag,
- net)
- sg = self.provider.os_conn.network.create_security_group(
- name=label, description=description)
- if sg:
- return OpenStackVMFirewall(self.provider, sg)
- return None
- @dispatch(event="provider.security.vm_firewalls.delete",
- priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
- def delete(self, vmf):
- fw = vmf if isinstance(vmf, OpenStackVMFirewall) else self.get(vmf)
- if fw:
- # pylint:disable=protected-access
- fw._vm_firewall.delete(self.provider.os_conn.session)
- class OpenStackVMFirewallRuleService(BaseVMFirewallRuleService):
- def __init__(self, provider, firewall):
- super(OpenStackVMFirewallRuleService, self).__init__(provider)
- def list(self, firewall, limit=None, marker=None):
- # pylint:disable=protected-access
- rules = [OpenStackVMFirewallRule(firewall, r)
- for r in firewall._vm_firewall.security_group_rules]
- 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):
- src_dest_fw_id = (src_dest_fw.id if isinstance(src_dest_fw,
- OpenStackVMFirewall)
- else src_dest_fw)
- try:
- if direction == TrafficDirection.INBOUND:
- os_direction = 'ingress'
- elif direction == TrafficDirection.OUTBOUND:
- os_direction = 'egress'
- else:
- raise InvalidValueException("direction", direction)
- # pylint:disable=protected-access
- rule = self.provider.os_conn.network.create_security_group_rule(
- security_group_id=firewall.id,
- direction=os_direction,
- port_range_max=to_port,
- port_range_min=from_port,
- protocol=protocol,
- remote_ip_prefix=cidr,
- remote_group_id=src_dest_fw_id)
- firewall.refresh()
- return OpenStackVMFirewallRule(firewall, rule.to_dict())
- except HttpException as e:
- firewall.refresh()
- # 409=Conflict, raised for duplicate rule
- if e.status_code == 409:
- existing = self.find(direction=direction, protocol=protocol,
- from_port=from_port, to_port=to_port,
- cidr=cidr, src_dest_fw_id=src_dest_fw_id)
- return existing[0]
- else:
- raise e
- def delete(self, firewall, rule):
- self.provider.os_conn.network.delete_security_group_rule(rule.id)
- firewall.refresh()
- class OpenStackStorageService(BaseStorageService):
- def __init__(self, provider):
- super(OpenStackStorageService, self).__init__(provider)
- # Initialize provider services
- self._volume_svc = OpenStackVolumeService(self.provider)
- self._snapshot_svc = OpenStackSnapshotService(self.provider)
- self._bucket_svc = OpenStackBucketService(self.provider)
- self._bucket_obj_svc = OpenStackBucketObjectService(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 OpenStackVolumeService(BaseVolumeService):
- def __init__(self, provider):
- super(OpenStackVolumeService, self).__init__(provider)
- @dispatch(event="provider.storage.volumes.get",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def get(self, volume_id):
- try:
- return OpenStackVolume(
- self.provider, self.provider.cinder.volumes.get(volume_id))
- except CinderNotFound:
- log.debug("Volume %s was not found.", volume_id)
- return None
- @dispatch(event="provider.storage.volumes.find",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- label = kwargs.pop('label', None)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, 'label'))
- log.debug("Searching for an OpenStack Volume with the label %s", label)
- search_opts = {'name': label}
- cb_vols = [
- OpenStackVolume(self.provider, vol)
- for vol in self.provider.cinder.volumes.list(
- search_opts=search_opts,
- limit=oshelpers.os_result_limit(self.provider),
- marker=None)]
- return oshelpers.to_server_paged_list(self.provider, cb_vols)
- @dispatch(event="provider.storage.volumes.list",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- cb_vols = [
- OpenStackVolume(self.provider, vol)
- for vol in self.provider.cinder.volumes.list(
- limit=oshelpers.os_result_limit(self.provider, limit),
- marker=marker)]
- return oshelpers.to_server_paged_list(self.provider, cb_vols, limit)
- @dispatch(event="provider.storage.volumes.create",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def create(self, label, size, zone, snapshot=None, description=None):
- OpenStackVolume.assert_valid_resource_label(label)
- zone_id = zone.id if isinstance(zone, PlacementZone) else zone
- snapshot_id = snapshot.id if isinstance(
- snapshot, OpenStackSnapshot) and snapshot else snapshot
- os_vol = self.provider.cinder.volumes.create(
- size, name=label, description=description,
- availability_zone=zone_id, snapshot_id=snapshot_id)
- return OpenStackVolume(self.provider, os_vol)
- @dispatch(event="provider.storage.volumes.delete",
- priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
- def delete(self, vol):
- volume = vol if isinstance(vol, OpenStackVolume) else self.get(vol)
- if volume:
- # pylint:disable=protected-access
- volume._volume.delete()
- class OpenStackSnapshotService(BaseSnapshotService):
- def __init__(self, provider):
- super(OpenStackSnapshotService, self).__init__(provider)
- @dispatch(event="provider.storage.snapshots.get",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def get(self, snapshot_id):
- try:
- return OpenStackSnapshot(
- self.provider,
- self.provider.cinder.volume_snapshots.get(snapshot_id))
- except CinderNotFound:
- log.debug("Snapshot %s was not found.", snapshot_id)
- return None
- @dispatch(event="provider.storage.snapshots.find",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- label = kwargs.pop('label', None)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, 'label'))
- search_opts = {'name': label, # TODO: Cinder is ignoring name
- 'limit': oshelpers.os_result_limit(self.provider),
- 'marker': None}
- log.debug("Searching for an OpenStack snapshot with the following "
- "params: %s", search_opts)
- cb_snaps = [
- OpenStackSnapshot(self.provider, snap) for
- snap in self.provider.cinder.volume_snapshots.list(search_opts)
- if snap.name == label]
- return oshelpers.to_server_paged_list(self.provider, cb_snaps)
- @dispatch(event="provider.storage.snapshots.list",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- cb_snaps = [
- OpenStackSnapshot(self.provider, snap) for
- snap in self.provider.cinder.volume_snapshots.list(
- search_opts={'limit': oshelpers.os_result_limit(self.provider,
- limit),
- 'marker': marker})]
- return oshelpers.to_server_paged_list(self.provider, cb_snaps, limit)
- @dispatch(event="provider.storage.snapshots.create",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def create(self, label, volume, description=None):
- OpenStackSnapshot.assert_valid_resource_label(label)
- volume_id = (volume.id if isinstance(volume, OpenStackVolume)
- else volume)
- os_snap = self.provider.cinder.volume_snapshots.create(
- volume_id, name=label,
- description=description)
- return OpenStackSnapshot(self.provider, os_snap)
- @dispatch(event="provider.storage.snapshots.delete",
- priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
- def delete(self, snap):
- s = snap if isinstance(snap, OpenStackSnapshot) else self.get(snap)
- if s:
- # pylint:disable=protected-access
- s._snapshot.delete()
- class OpenStackBucketService(BaseBucketService):
- def __init__(self, provider):
- super(OpenStackBucketService, 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.
- """
- _, container_list = self.provider.swift.get_account(
- prefix=bucket_id)
- if container_list:
- return OpenStackBucket(self.provider,
- next((c for c in container_list
- if c['name'] == bucket_id), None))
- else:
- log.debug("Bucket %s was not found.", bucket_id)
- return None
- @dispatch(event="provider.storage.buckets.find",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- name = kwargs.pop('name', None)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, 'name'))
- _, container_list = self.provider.swift.get_account()
- cb_buckets = [OpenStackBucket(self.provider, c)
- for c in container_list
- if name in c.get("name")]
- return oshelpers.to_server_paged_list(self.provider, cb_buckets)
- @dispatch(event="provider.storage.buckets.list",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- _, container_list = self.provider.swift.get_account(
- limit=oshelpers.os_result_limit(self.provider, limit),
- marker=marker)
- cb_buckets = [OpenStackBucket(self.provider, c)
- for c in container_list]
- return oshelpers.to_server_paged_list(self.provider, cb_buckets, limit)
- @dispatch(event="provider.storage.buckets.create",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- def create(self, name, location=None):
- OpenStackBucket.assert_valid_resource_name(name)
- location = location or self.provider.region_name
- try:
- self.provider.swift.head_container(name)
- raise DuplicateResourceException(
- 'Bucket already exists with name {0}'.format(name))
- except SwiftClientException:
- self.provider.swift.put_container(name)
- return self.get(name)
- @dispatch(event="provider.storage.buckets.delete",
- priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
- def delete(self, bucket):
- b_id = bucket.id if isinstance(bucket, OpenStackBucket) else bucket
- self.provider.swift.delete_container(b_id)
- class OpenStackBucketObjectService(BaseBucketObjectService):
- def __init__(self, provider):
- super(OpenStackBucketObjectService, self).__init__(provider)
- def get(self, bucket, name):
- """
- Retrieve a given object from this bucket.
- """
- # Swift always returns a reference for the container first,
- # followed by a list containing references to objects.
- _, object_list = self.provider.swift.get_container(
- bucket.name, prefix=name)
- # Loop through list of objects looking for an exact name vs. a prefix
- for obj in object_list:
- if obj.get('name') == name:
- return OpenStackBucketObject(self.provider,
- bucket,
- obj)
- 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.
- """
- _, object_list = self.provider.swift.get_container(
- bucket.name,
- limit=oshelpers.os_result_limit(self.provider, limit),
- marker=marker, prefix=prefix)
- cb_objects = [OpenStackBucketObject(
- self.provider, bucket, obj) for obj in object_list]
- return oshelpers.to_server_paged_list(
- self.provider,
- cb_objects,
- limit)
- def find(self, bucket, **kwargs):
- _, obj_list = self.provider.swift.get_container(bucket.name)
- cb_objs = [OpenStackBucketObject(self.provider, bucket, obj)
- for obj in obj_list]
- filters = ['name']
- matches = cb_helpers.generic_find(filters, kwargs, cb_objs)
- return ClientPagedResultList(self.provider, list(matches))
- def create(self, bucket, object_name):
- self.provider.swift.put_object(bucket.name, object_name, None)
- return self.get(bucket, object_name)
- class OpenStackComputeService(BaseComputeService):
- def __init__(self, provider):
- super(OpenStackComputeService, self).__init__(provider)
- self._vm_type_svc = OpenStackVMTypeService(self.provider)
- self._instance_svc = OpenStackInstanceService(self.provider)
- self._region_svc = OpenStackRegionService(self.provider)
- self._images_svc = OpenStackImageService(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 OpenStackImageService(BaseImageService):
- def __init__(self, provider):
- super(OpenStackImageService, self).__init__(provider)
- def get(self, image_id):
- """
- Returns an Image given its id
- """
- log.debug("Getting OpenStack Image with the id: %s", image_id)
- try:
- return OpenStackMachineImage(
- self.provider, self.provider.os_conn.image.get_image(image_id))
- except (NotFoundException, ResourceNotFound):
- log.debug("Image %s not found", image_id)
- return None
- def find(self, **kwargs):
- filters = ['label']
- obj_list = self
- return cb_helpers.generic_find(filters, kwargs, obj_list)
- def list(self, filter_by_owner=True, limit=None, marker=None):
- """
- List all images.
- """
- project_id = None
- if filter_by_owner:
- project_id = self.provider.os_conn.session.get_project_id()
- os_images = self.provider.os_conn.image.images(
- owner=project_id,
- limit=oshelpers.os_result_limit(self.provider, limit),
- marker=marker)
- cb_images = [
- OpenStackMachineImage(self.provider, img)
- for img in os_images]
- return oshelpers.to_server_paged_list(self.provider, cb_images, limit)
- class OpenStackInstanceService(BaseInstanceService):
- def __init__(self, provider):
- super(OpenStackInstanceService, self).__init__(provider)
- def _to_block_device_mapping(self, launch_config):
- """
- Extracts block device mapping information
- from a launch config and constructs a BlockDeviceMappingV2
- object.
- """
- bdm = []
- for device in launch_config.block_devices:
- bdm_dict = dict()
- if device.is_volume:
- bdm_dict['destination_type'] = 'volume'
- if device.is_root:
- bdm_dict['device_name'] = '/dev/sda'
- bdm_dict['boot_index'] = 0
- if isinstance(device.source, Snapshot):
- bdm_dict['source_type'] = 'snapshot'
- bdm_dict['uuid'] = device.source.id
- elif isinstance(device.source, Volume):
- bdm_dict['source_type'] = 'volume'
- bdm_dict['uuid'] = device.source.id
- elif isinstance(device.source, MachineImage):
- bdm_dict['source_type'] = 'image'
- bdm_dict['uuid'] = device.source.id
- else:
- bdm_dict['source_type'] = 'blank'
- if device.delete_on_terminate is not None:
- bdm_dict[
- 'delete_on_termination'] = device.delete_on_terminate
- if device.size:
- bdm_dict['volume_size'] = device.size
- else:
- bdm_dict['destination_type'] = 'local'
- bdm_dict['source_type'] = 'blank'
- bdm_dict['delete_on_termination'] = True
- bdm.append(bdm_dict)
- return bdm
- def _has_root_device(self, launch_config):
- if not launch_config:
- return False
- for device in launch_config.block_devices:
- if device.is_root:
- return True
- return False
- def create_launch_config(self):
- return BaseLaunchConfig(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):
- OpenStackInstance.assert_valid_resource_label(label)
- image_id = image.id if isinstance(image, MachineImage) else image
- vm_size = vm_type.id if \
- isinstance(vm_type, VMType) else \
- self.provider.compute.vm_types.find(
- name=vm_type)[0].id
- if isinstance(subnet, Subnet):
- subnet_id = subnet.id
- net_id = subnet.network_id
- else:
- subnet_id = subnet
- net_id = (self.provider.networking.subnets
- .get(subnet_id).network_id
- if subnet_id else None)
- zone_id = zone.id if isinstance(zone, PlacementZone) else zone
- key_pair_name = key_pair.name if \
- isinstance(key_pair, KeyPair) else key_pair
- bdm = None
- if launch_config:
- bdm = self._to_block_device_mapping(launch_config)
- # Security groups must be passed in as a list of IDs and attached to a
- # port if a port is being created. Otherwise, the security groups must
- # be passed in as a list of names to the servers.create() call.
- # OpenStack will respect the port's security groups first and then
- # fall-back to the named security groups.
- sg_name_list = []
- nics = None
- if subnet_id:
- log.debug("Creating network port for %s in subnet: %s",
- label, subnet_id)
- sg_list = []
- if vm_firewalls:
- if isinstance(vm_firewalls, list) and \
- isinstance(vm_firewalls[0], VMFirewall):
- sg_list = vm_firewalls
- else:
- sg_list = (self.provider.security.vm_firewalls
- .find(label=sg) for sg in vm_firewalls)
- sg_list = (sg[0] for sg in sg_list if sg)
- sg_id_list = [sg.id for sg in sg_list]
- port_def = {
- "port": {
- "admin_state_up": True,
- "name": OpenStackInstance._generate_name_from_label(
- label, 'cb-port'),
- "network_id": net_id,
- "fixed_ips": [{"subnet_id": subnet_id}],
- "security_groups": sg_id_list
- }
- }
- port_id = self.provider.neutron.create_port(port_def)['port']['id']
- nics = [{'net-id': net_id, 'port-id': port_id}]
- else:
- if vm_firewalls:
- if isinstance(vm_firewalls, list) and \
- isinstance(vm_firewalls[0], VMFirewall):
- sg_name_list = [sg.name for sg in vm_firewalls]
- else:
- sg_list = (self.provider.security.vm_firewalls.get(sg)
- for sg in vm_firewalls)
- sg_name_list = (sg[0].name for sg in sg_list if sg)
- log.debug("Launching in subnet %s", subnet_id)
- os_instance = self.provider.nova.servers.create(
- label,
- None if self._has_root_device(launch_config) else image_id,
- vm_size,
- min_count=1,
- max_count=1,
- availability_zone=zone_id,
- key_name=key_pair_name,
- security_groups=sg_name_list,
- userdata=str(user_data) or None,
- block_device_mapping_v2=bdm,
- nics=nics)
- return OpenStackInstance(self.provider, os_instance)
- @dispatch(event="provider.compute.instances.find",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- label = kwargs.pop('label', None)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, 'label'))
- search_opts = {'name': label}
- cb_insts = [
- OpenStackInstance(self.provider, inst)
- for inst in self.provider.nova.servers.list(
- search_opts=search_opts,
- limit=oshelpers.os_result_limit(self.provider),
- marker=None)]
- return oshelpers.to_server_paged_list(self.provider, cb_insts)
- @dispatch(event="provider.compute.instances.list",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- """
- List all instances.
- """
- cb_insts = [
- OpenStackInstance(self.provider, inst)
- for inst in self.provider.nova.servers.list(
- limit=oshelpers.os_result_limit(self.provider, limit),
- marker=marker)]
- return oshelpers.to_server_paged_list(self.provider, cb_insts, limit)
- @dispatch(event="provider.compute.instances.get",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def get(self, instance_id):
- """
- Returns an instance given its id.
- """
- try:
- os_instance = self.provider.nova.servers.get(instance_id)
- return OpenStackInstance(self.provider, os_instance)
- except NovaNotFound:
- log.debug("Instance %s was not found.", instance_id)
- return None
- @dispatch(event="provider.compute.instances.delete",
- priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
- def delete(self, inst):
- ins = inst if isinstance(inst, OpenStackInstance) else self.get(inst)
- if ins:
- # pylint:disable=protected-access
- os_instance = ins._os_instance
- # delete the port we created when launching
- # Assumption: it's the first interface in the list
- iface_list = os_instance.interface_list()
- if iface_list:
- self.provider.neutron.delete_port(iface_list[0].port_id)
- os_instance.delete()
- class OpenStackVMTypeService(BaseVMTypeService):
- def __init__(self, provider):
- super(OpenStackVMTypeService, self).__init__(provider)
- @dispatch(event="provider.compute.vm_types.list",
- priority=BaseVMTypeService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- cb_itypes = [
- OpenStackVMType(self.provider, obj)
- for obj in self.provider.nova.flavors.list(
- limit=oshelpers.os_result_limit(self.provider, limit),
- marker=marker)]
- return oshelpers.to_server_paged_list(self.provider, cb_itypes, limit)
- class OpenStackRegionService(BaseRegionService):
- def __init__(self, provider):
- super(OpenStackRegionService, self).__init__(provider)
- @dispatch(event="provider.compute.regions.get",
- priority=BaseRegionService.STANDARD_EVENT_PRIORITY)
- def get(self, region_id):
- log.debug("Getting OpenStack Region with the id: %s", region_id)
- region = (r for r in self if r.id == region_id)
- return next(region, None)
- @dispatch(event="provider.compute.regions.list",
- priority=BaseRegionService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- # pylint:disable=protected-access
- if self.provider._keystone_version == 3:
- os_regions = [OpenStackRegion(self.provider, region)
- for region in self.provider.keystone.regions.list()]
- return ClientPagedResultList(self.provider, os_regions,
- limit=limit, marker=marker)
- else:
- # Keystone v3 onwards supports directly listing regions
- # but for v2, this convoluted method is necessary.
- regions = (
- endpoint.get('region') or endpoint.get('region_id')
- for svc in self.provider.keystone.service_catalog.get_data()
- for endpoint in svc.get('endpoints', [])
- )
- regions = set(region for region in regions if region)
- os_regions = [OpenStackRegion(self.provider, region)
- for region in regions]
- return ClientPagedResultList(self.provider, os_regions,
- limit=limit, marker=marker)
- @property
- def current(self):
- nova_region = self.provider.nova.client.region_name
- return self.get(nova_region) if nova_region else None
- class OpenStackNetworkingService(BaseNetworkingService):
- def __init__(self, provider):
- super(OpenStackNetworkingService, self).__init__(provider)
- self._network_service = OpenStackNetworkService(self.provider)
- self._subnet_service = OpenStackSubnetService(self.provider)
- self._router_service = OpenStackRouterService(self.provider)
- self._gateway_service = OpenStackGatewayService(self.provider)
- self._floating_ip_service = OpenStackFloatingIPService(self.provider)
- class OpenStackNetworkService(BaseNetworkService):
- def __init__(self, provider):
- super(OpenStackNetworkService, self).__init__(provider)
- @dispatch(event="provider.networking.networks.get",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def get(self, network_id):
- network = (n for n in self if n.id == network_id)
- return next(network, None)
- @dispatch(event="provider.networking.networks.list",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- networks = [OpenStackNetwork(self.provider, network)
- for network in self.provider.neutron.list_networks()
- .get('networks') if network]
- return ClientPagedResultList(self.provider, networks,
- limit=limit, marker=marker)
- @dispatch(event="provider.networking.networks.find",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def find(self, **kwargs):
- label = kwargs.pop('label', None)
- # All kwargs should have been popped at this time.
- if len(kwargs) > 0:
- raise InvalidParamException(
- "Unrecognised parameters for search: %s. Supported "
- "attributes: %s" % (kwargs, 'label'))
- log.debug("Searching for OpenStack Network with label: %s", label)
- networks = [OpenStackNetwork(self.provider, network)
- for network in self.provider.neutron.list_networks(
- name=label)
- .get('networks') if network]
- return ClientPagedResultList(self.provider, networks)
- @dispatch(event="provider.networking.networks.create",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def create(self, label, cidr_block):
- OpenStackNetwork.assert_valid_resource_label(label)
- net_info = {'name': label or ""}
- network = self.provider.neutron.create_network({'network': net_info})
- cb_net = OpenStackNetwork(self.provider, network.get('network'))
- if label:
- cb_net.label = label
- return cb_net
- @dispatch(event="provider.networking.networks.delete",
- priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
- def delete(self, net):
- network = net if isinstance(net, OpenStackNetwork) else self.get(net)
- if not network:
- return
- if not network.external and network.id in str(
- self.provider.neutron.list_networks()):
- # If there are ports associated with the network, it won't delete
- ports = self.provider.neutron.list_ports(
- network_id=network.id).get('ports', [])
- for port in ports:
- try:
- self.provider.neutron.delete_port(port.get('id'))
- except PortNotFoundClient:
- # Ports could have already been deleted if instances
- # are terminated etc. so exceptions can be safely ignored
- pass
- self.provider.neutron.delete_network(network.id)
- class OpenStackSubnetService(BaseSubnetService):
- def __init__(self, provider):
- super(OpenStackSubnetService, self).__init__(provider)
- @dispatch(event="provider.networking.subnets.get",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def get(self, subnet_id):
- subnet = (s for s in self if s.id == subnet_id)
- return next(subnet, None)
- @dispatch(event="provider.networking.subnets.list",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def list(self, network=None, limit=None, marker=None):
- if network:
- network_id = (network.id if isinstance(network, OpenStackNetwork)
- else network)
- subnets = [subnet for subnet in self if network_id ==
- subnet.network_id]
- else:
- subnets = [OpenStackSubnet(self.provider, subnet) for subnet in
- self.provider.neutron.list_subnets().get('subnets', [])]
- return ClientPagedResultList(self.provider, subnets,
- limit=limit, marker=marker)
- @dispatch(event="provider.networking.subnets.create",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def create(self, label, network, cidr_block, zone):
- """zone param is ignored."""
- OpenStackSubnet.assert_valid_resource_label(label)
- network_id = (network.id if isinstance(network, OpenStackNetwork)
- else network)
- subnet_info = {'name': label, 'network_id': network_id,
- 'cidr': cidr_block, 'ip_version': 4}
- subnet = (self.provider.neutron.create_subnet({'subnet': subnet_info})
- .get('subnet'))
- cb_subnet = OpenStackSubnet(self.provider, subnet)
- return cb_subnet
- @dispatch(event="provider.networking.subnets.delete",
- priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
- def delete(self, subnet):
- sn_id = subnet.id if isinstance(subnet, OpenStackSubnet) else subnet
- self.provider.neutron.delete_subnet(sn_id)
- def get_or_create_default(self, zone):
- """
- Subnet zone is not supported by OpenStack and is thus ignored.
- """
- try:
- sn = self.find(label=OpenStackSubnet.CB_DEFAULT_SUBNET_LABEL)
- if sn:
- return sn[0]
- # No default subnet look for default network, then create subnet
- net = self.provider.networking.networks.get_or_create_default()
- sn = self.provider.networking.subnets.create(
- label=OpenStackSubnet.CB_DEFAULT_SUBNET_LABEL,
- cidr_block=OpenStackSubnet.CB_DEFAULT_SUBNET_IPV4RANGE,
- network=net, zone=zone)
- router = self.provider.networking.routers.get_or_create_default(
- net)
- router.attach_subnet(sn)
- gateway = net.gateways.get_or_create_inet_gateway()
- router.attach_gateway(gateway)
- return sn
- except NeutronClientException:
- return None
- class OpenStackRouterService(BaseRouterService):
- def __init__(self, provider):
- super(OpenStackRouterService, self).__init__(provider)
- @dispatch(event="provider.networking.routers.get",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def get(self, router_id):
- log.debug("Getting OpenStack Router with the id: %s", router_id)
- router = self.provider.os_conn.get_router(router_id)
- return OpenStackRouter(self.provider, router) if router else None
- @dispatch(event="provider.networking.routers.list",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def list(self, limit=None, marker=None):
- routers = self.provider.os_conn.list_routers()
- os_routers = [OpenStackRouter(self.provider, r) for r in routers]
- return ClientPagedResultList(self.provider, os_routers, limit=limit,
- marker=marker)
- @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)
- return ClientPagedResultList(self._provider, list(matches))
- @dispatch(event="provider.networking.routers.create",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def create(self, label, network):
- """Parameter ``network`` is not used by OpenStack."""
- router = self.provider.os_conn.create_router(name=label)
- return OpenStackRouter(self.provider, router)
- @dispatch(event="provider.networking.routers.delete",
- priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
- def delete(self, router):
- r_id = router.id if isinstance(router, OpenStackRouter) else router
- self.provider.os_conn.delete_router(r_id)
- class OpenStackGatewayService(BaseGatewayService):
- """For OpenStack, an internet gateway is a just an 'external' network."""
- def __init__(self, provider):
- super(OpenStackGatewayService, self).__init__(provider)
- def _check_fip_connectivity(self, network, external_net):
- # Due to current limitations in OpenStack:
- # https://bugs.launchpad.net/neutron/+bug/1743480, it's not
- # possible to differentiate between floating ip networks and provider
- # external networks. Therefore, we systematically step through
- # all available networks and perform an assignment test to infer valid
- # floating ip nets.
- dummy_router = self._provider.networking.routers.create(
- label='cb-conn-test-router', network=network)
- with cb_helpers.cleanup_action(lambda: dummy_router.delete()):
- try:
- dummy_router.attach_gateway(external_net)
- return True
- except Exception:
- return False
- def get_or_create_inet_gateway(self, network):
- """For OS, inet gtw is any net that has `external` property set."""
- external_nets = (n for n in self._provider.networking.networks
- if n.external)
- for net in external_nets:
- if self._check_fip_connectivity(net):
- return OpenStackInternetGateway(self._provider, net)
- return None
- def delete(self, network, gateway):
- log.debug("Deleting OpenStack Gateway: %s", gateway)
- gateway.delete()
- def list(self, network, limit=None, marker=None):
- log.debug("OpenStack listing of all current internet gateways")
- igl = [OpenStackInternetGateway(self._provider, n)
- for n in self._provider.networking.networks
- if n.external and self._check_fip_connectivity(n)]
- return ClientPagedResultList(self._provider, igl, limit=limit,
- marker=marker)
- class OpenStackFloatingIPService(BaseFloatingIPService):
- def __init__(self, provider, gateway):
- super(OpenStackFloatingIPService, self).__init__(provider, gateway)
- def get(self, gateway, fip_id):
- try:
- return OpenStackFloatingIP(
- self.provider, self.provider.os_conn.network.get_ip(fip_id))
- except (ResourceNotFound, NotFoundException):
- log.debug("Floating IP %s not found.", fip_id)
- return None
- def list(self, gateway, limit=None, marker=None):
- fips = [OpenStackFloatingIP(self.provider, fip)
- for fip in self.provider.os_conn.network.ips(
- floating_network_id=gateway.id
- )]
- return ClientPagedResultList(self.provider, fips,
- limit=limit, marker=marker)
- def create(self, gateway):
- return OpenStackFloatingIP(
- self.provider, self.provider.os_conn.network.create_ip(
- floating_network_id=gateway.id))
- def delete(self, gateway, fip):
- if isinstance(fip, OpenStackFloatingIP):
- os_ip = fip._ip
- else:
- try:
- os_ip = self.provider.os_conn.network.get_ip(fip)
- except (ResourceNotFound, NotFoundException):
- log.debug("Floating IP %s not found.", fip)
- return True
- os_ip.delete(self._provider.os_conn.session)
|