2
0

services.py 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. """
  2. Services implemented by the OpenStack provider.
  3. """
  4. import logging
  5. from cinderclient.exceptions import NotFound as CinderNotFound
  6. from neutronclient.common.exceptions import NeutronClientException
  7. from neutronclient.common.exceptions import PortNotFoundClient
  8. from novaclient.exceptions import NotFound as NovaNotFound
  9. from openstack.exceptions import HttpException
  10. from openstack.exceptions import NotFoundException
  11. from openstack.exceptions import ResourceNotFound
  12. from swiftclient import ClientException as SwiftClientException
  13. import cloudbridge.cloud.base.helpers as cb_helpers
  14. from cloudbridge.cloud.base.middleware import dispatch
  15. from cloudbridge.cloud.base.resources import BaseLaunchConfig
  16. from cloudbridge.cloud.base.resources import ClientPagedResultList
  17. from cloudbridge.cloud.base.services import BaseBucketObjectService
  18. from cloudbridge.cloud.base.services import BaseBucketService
  19. from cloudbridge.cloud.base.services import BaseComputeService
  20. from cloudbridge.cloud.base.services import BaseFloatingIPService
  21. from cloudbridge.cloud.base.services import BaseGatewayService
  22. from cloudbridge.cloud.base.services import BaseImageService
  23. from cloudbridge.cloud.base.services import BaseInstanceService
  24. from cloudbridge.cloud.base.services import BaseKeyPairService
  25. from cloudbridge.cloud.base.services import BaseNetworkService
  26. from cloudbridge.cloud.base.services import BaseNetworkingService
  27. from cloudbridge.cloud.base.services import BaseRegionService
  28. from cloudbridge.cloud.base.services import BaseRouterService
  29. from cloudbridge.cloud.base.services import BaseSecurityService
  30. from cloudbridge.cloud.base.services import BaseSnapshotService
  31. from cloudbridge.cloud.base.services import BaseStorageService
  32. from cloudbridge.cloud.base.services import BaseSubnetService
  33. from cloudbridge.cloud.base.services import BaseVMFirewallRuleService
  34. from cloudbridge.cloud.base.services import BaseVMFirewallService
  35. from cloudbridge.cloud.base.services import BaseVMTypeService
  36. from cloudbridge.cloud.base.services import BaseVolumeService
  37. from cloudbridge.cloud.interfaces.exceptions \
  38. import DuplicateResourceException
  39. from cloudbridge.cloud.interfaces.exceptions import InvalidParamException
  40. from cloudbridge.cloud.interfaces.exceptions import InvalidValueException
  41. from cloudbridge.cloud.interfaces.resources import KeyPair
  42. from cloudbridge.cloud.interfaces.resources import MachineImage
  43. from cloudbridge.cloud.interfaces.resources import Network
  44. from cloudbridge.cloud.interfaces.resources import PlacementZone
  45. from cloudbridge.cloud.interfaces.resources import Snapshot
  46. from cloudbridge.cloud.interfaces.resources import Subnet
  47. from cloudbridge.cloud.interfaces.resources import TrafficDirection
  48. from cloudbridge.cloud.interfaces.resources import VMFirewall
  49. from cloudbridge.cloud.interfaces.resources import VMType
  50. from cloudbridge.cloud.interfaces.resources import Volume
  51. from . import helpers as oshelpers
  52. from .resources import OpenStackBucket
  53. from .resources import OpenStackBucketObject
  54. from .resources import OpenStackFloatingIP
  55. from .resources import OpenStackInstance
  56. from .resources import OpenStackInternetGateway
  57. from .resources import OpenStackKeyPair
  58. from .resources import OpenStackMachineImage
  59. from .resources import OpenStackNetwork
  60. from .resources import OpenStackRegion
  61. from .resources import OpenStackRouter
  62. from .resources import OpenStackSnapshot
  63. from .resources import OpenStackSubnet
  64. from .resources import OpenStackVMFirewall
  65. from .resources import OpenStackVMFirewallRule
  66. from .resources import OpenStackVMType
  67. from .resources import OpenStackVolume
  68. log = logging.getLogger(__name__)
  69. class OpenStackSecurityService(BaseSecurityService):
  70. def __init__(self, provider):
  71. super(OpenStackSecurityService, self).__init__(provider)
  72. # Initialize provider services
  73. self._key_pairs = OpenStackKeyPairService(provider)
  74. self._vm_firewalls = OpenStackVMFirewallService(provider)
  75. self._vm_firewall_rule_svc = OpenStackVMFirewallRuleService(provider)
  76. @property
  77. def key_pairs(self):
  78. return self._key_pairs
  79. @property
  80. def vm_firewalls(self):
  81. return self._vm_firewalls
  82. @property
  83. def _vm_firewall_rules(self):
  84. return self._vm_firewall_rule_svc
  85. def get_or_create_ec2_credentials(self):
  86. """
  87. A provider specific method than returns the ec2 credentials for the
  88. current user, or creates a new pair if one doesn't exist.
  89. """
  90. keystone = self.provider.keystone
  91. if hasattr(keystone, 'ec2'):
  92. user_id = keystone.session.get_user_id()
  93. user_creds = [cred for cred in keystone.ec2.list(user_id) if
  94. cred.tenant_id == keystone.session.get_project_id()]
  95. if user_creds:
  96. return user_creds[0]
  97. else:
  98. return keystone.ec2.create(
  99. user_id, keystone.session.get_project_id())
  100. return None
  101. def get_ec2_endpoints(self):
  102. """
  103. A provider specific method than returns the ec2 endpoints if
  104. available.
  105. """
  106. keystone = self.provider.keystone
  107. ec2_url = keystone.session.get_endpoint(service_type='ec2')
  108. s3_url = keystone.session.get_endpoint(service_type='s3')
  109. return {'ec2_endpoint': ec2_url,
  110. 's3_endpoint': s3_url}
  111. class OpenStackKeyPairService(BaseKeyPairService):
  112. def __init__(self, provider):
  113. super(OpenStackKeyPairService, self).__init__(provider)
  114. @dispatch(event="provider.security.key_pairs.get",
  115. priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
  116. def get(self, key_pair_id):
  117. """
  118. Returns a KeyPair given its id.
  119. """
  120. log.debug("Returning KeyPair with the id %s", key_pair_id)
  121. try:
  122. return OpenStackKeyPair(
  123. self.provider, self.provider.nova.keypairs.get(key_pair_id))
  124. except NovaNotFound:
  125. log.debug("KeyPair %s was not found.", key_pair_id)
  126. return None
  127. @dispatch(event="provider.security.key_pairs.list",
  128. priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
  129. def list(self, limit=None, marker=None):
  130. """
  131. List all key pairs associated with this account.
  132. :rtype: ``list`` of :class:`.KeyPair`
  133. :return: list of KeyPair objects
  134. """
  135. keypairs = self.provider.nova.keypairs.list()
  136. results = [OpenStackKeyPair(self.provider, kp)
  137. for kp in keypairs]
  138. log.debug("Listing all key pairs associated with OpenStack "
  139. "Account: %s", results)
  140. return ClientPagedResultList(self.provider, results,
  141. limit=limit, marker=marker)
  142. @dispatch(event="provider.security.key_pairs.find",
  143. priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
  144. def find(self, **kwargs):
  145. name = kwargs.pop('name', None)
  146. # All kwargs should have been popped at this time.
  147. if len(kwargs) > 0:
  148. raise InvalidParamException(
  149. "Unrecognised parameters for search: %s. Supported "
  150. "attributes: %s" % (kwargs, 'name'))
  151. keypairs = self.provider.nova.keypairs.findall(name=name)
  152. results = [OpenStackKeyPair(self.provider, kp)
  153. for kp in keypairs]
  154. log.debug("Searching for %s in: %s", name, keypairs)
  155. return ClientPagedResultList(self.provider, results)
  156. @dispatch(event="provider.security.key_pairs.create",
  157. priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
  158. def create(self, name, public_key_material=None):
  159. OpenStackKeyPair.assert_valid_resource_name(name)
  160. existing_kp = self.find(name=name)
  161. if existing_kp:
  162. raise DuplicateResourceException(
  163. 'Keypair already exists with name {0}'.format(name))
  164. private_key = None
  165. if not public_key_material:
  166. public_key_material, private_key = cb_helpers.generate_key_pair()
  167. kp = self.provider.nova.keypairs.create(name,
  168. public_key=public_key_material)
  169. cb_kp = OpenStackKeyPair(self.provider, kp)
  170. cb_kp.material = private_key
  171. return cb_kp
  172. @dispatch(event="provider.security.key_pairs.delete",
  173. priority=BaseKeyPairService.STANDARD_EVENT_PRIORITY)
  174. def delete(self, key_pair):
  175. keypair = (key_pair if isinstance(key_pair, OpenStackKeyPair)
  176. else self.get(key_pair))
  177. if keypair:
  178. # pylint:disable=protected-access
  179. keypair._key_pair.delete()
  180. class OpenStackVMFirewallService(BaseVMFirewallService):
  181. def __init__(self, provider):
  182. super(OpenStackVMFirewallService, self).__init__(provider)
  183. @dispatch(event="provider.security.vm_firewalls.get",
  184. priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
  185. def get(self, vm_firewall_id):
  186. try:
  187. return OpenStackVMFirewall(
  188. self.provider,
  189. self.provider.os_conn.network
  190. .get_security_group(vm_firewall_id))
  191. except (ResourceNotFound, NotFoundException):
  192. log.debug("Firewall %s not found.", vm_firewall_id)
  193. return None
  194. @dispatch(event="provider.security.vm_firewalls.list",
  195. priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
  196. def list(self, limit=None, marker=None):
  197. firewalls = [
  198. OpenStackVMFirewall(self.provider, fw)
  199. for fw in self.provider.os_conn.network.security_groups()]
  200. return ClientPagedResultList(self.provider, firewalls,
  201. limit=limit, marker=marker)
  202. @cb_helpers.deprecated_alias(network_id='network')
  203. @dispatch(event="provider.security.vm_firewalls.create",
  204. priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
  205. def create(self, label, network, description=None):
  206. OpenStackVMFirewall.assert_valid_resource_label(label)
  207. net_id = network.id if isinstance(network, Network) else network
  208. # We generally simulate a network being associated with a firewall
  209. # by storing the supplied value in the firewall description field that
  210. # is not modifiable after creation; however, because of some networking
  211. # specificity in Nectar, we must also allow an empty network id value.
  212. if not net_id:
  213. net_id = ""
  214. if not description:
  215. description = ""
  216. description += " [{}{}]".format(OpenStackVMFirewall._network_id_tag,
  217. net_id)
  218. sg = self.provider.os_conn.network.create_security_group(
  219. name=label, description=description)
  220. if sg:
  221. return OpenStackVMFirewall(self.provider, sg)
  222. return None
  223. @dispatch(event="provider.security.vm_firewalls.delete",
  224. priority=BaseVMFirewallService.STANDARD_EVENT_PRIORITY)
  225. def delete(self, vm_firewall):
  226. fw = (vm_firewall if isinstance(vm_firewall, OpenStackVMFirewall)
  227. else self.get(vm_firewall))
  228. if fw:
  229. # pylint:disable=protected-access
  230. fw._vm_firewall.delete(self.provider.os_conn.session)
  231. class OpenStackVMFirewallRuleService(BaseVMFirewallRuleService):
  232. def __init__(self, provider):
  233. super(OpenStackVMFirewallRuleService, self).__init__(provider)
  234. @dispatch(event="provider.security.vm_firewall_rules.list",
  235. priority=BaseVMFirewallRuleService.STANDARD_EVENT_PRIORITY)
  236. def list(self, firewall, limit=None, marker=None):
  237. # pylint:disable=protected-access
  238. rules = [OpenStackVMFirewallRule(firewall, r)
  239. for r in firewall._vm_firewall.security_group_rules]
  240. return ClientPagedResultList(self.provider, rules,
  241. limit=limit, marker=marker)
  242. @dispatch(event="provider.security.vm_firewall_rules.create",
  243. priority=BaseVMFirewallRuleService.STANDARD_EVENT_PRIORITY)
  244. def create(self, firewall, direction, protocol=None, from_port=None,
  245. to_port=None, cidr=None, src_dest_fw=None):
  246. src_dest_fw_id = (src_dest_fw.id if isinstance(src_dest_fw,
  247. OpenStackVMFirewall)
  248. else src_dest_fw)
  249. try:
  250. if direction == TrafficDirection.INBOUND:
  251. os_direction = 'ingress'
  252. elif direction == TrafficDirection.OUTBOUND:
  253. os_direction = 'egress'
  254. else:
  255. raise InvalidValueException("direction", direction)
  256. # pylint:disable=protected-access
  257. rule = self.provider.os_conn.network.create_security_group_rule(
  258. security_group_id=firewall.id,
  259. direction=os_direction,
  260. port_range_max=to_port,
  261. port_range_min=from_port,
  262. protocol=protocol,
  263. remote_ip_prefix=cidr,
  264. remote_group_id=src_dest_fw_id)
  265. firewall.refresh()
  266. return OpenStackVMFirewallRule(firewall, rule.to_dict())
  267. except HttpException as e:
  268. firewall.refresh()
  269. # 409=Conflict, raised for duplicate rule
  270. if e.status_code == 409:
  271. existing = self.find(firewall, direction=direction,
  272. protocol=protocol, from_port=from_port,
  273. to_port=to_port, cidr=cidr,
  274. src_dest_fw_id=src_dest_fw_id)
  275. return existing[0]
  276. else:
  277. raise e
  278. @dispatch(event="provider.security.vm_firewall_rules.delete",
  279. priority=BaseVMFirewallRuleService.STANDARD_EVENT_PRIORITY)
  280. def delete(self, firewall, rule):
  281. rule_id = (rule.id if isinstance(rule, OpenStackVMFirewallRule)
  282. else rule)
  283. self.provider.os_conn.network.delete_security_group_rule(rule_id)
  284. firewall.refresh()
  285. class OpenStackStorageService(BaseStorageService):
  286. def __init__(self, provider):
  287. super(OpenStackStorageService, self).__init__(provider)
  288. # Initialize provider services
  289. self._volume_svc = OpenStackVolumeService(self.provider)
  290. self._snapshot_svc = OpenStackSnapshotService(self.provider)
  291. self._bucket_svc = OpenStackBucketService(self.provider)
  292. self._bucket_obj_svc = OpenStackBucketObjectService(self.provider)
  293. @property
  294. def volumes(self):
  295. return self._volume_svc
  296. @property
  297. def snapshots(self):
  298. return self._snapshot_svc
  299. @property
  300. def buckets(self):
  301. return self._bucket_svc
  302. @property
  303. def _bucket_objects(self):
  304. return self._bucket_obj_svc
  305. class OpenStackVolumeService(BaseVolumeService):
  306. def __init__(self, provider):
  307. super(OpenStackVolumeService, self).__init__(provider)
  308. @dispatch(event="provider.storage.volumes.get",
  309. priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
  310. def get(self, volume_id):
  311. try:
  312. return OpenStackVolume(
  313. self.provider, self.provider.cinder.volumes.get(volume_id))
  314. except CinderNotFound:
  315. log.debug("Volume %s was not found.", volume_id)
  316. return None
  317. @dispatch(event="provider.storage.volumes.find",
  318. priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
  319. def find(self, **kwargs):
  320. label = kwargs.pop('label', None)
  321. # All kwargs should have been popped at this time.
  322. if len(kwargs) > 0:
  323. raise InvalidParamException(
  324. "Unrecognised parameters for search: %s. Supported "
  325. "attributes: %s" % (kwargs, 'label'))
  326. log.debug("Searching for an OpenStack Volume with the label %s", label)
  327. search_opts = {'name': label}
  328. cb_vols = [
  329. OpenStackVolume(self.provider, vol)
  330. for vol in self.provider.cinder.volumes.list(
  331. search_opts=search_opts,
  332. limit=oshelpers.os_result_limit(self.provider),
  333. marker=None)]
  334. return oshelpers.to_server_paged_list(self.provider, cb_vols)
  335. @dispatch(event="provider.storage.volumes.list",
  336. priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
  337. def list(self, limit=None, marker=None):
  338. cb_vols = [
  339. OpenStackVolume(self.provider, vol)
  340. for vol in self.provider.cinder.volumes.list(
  341. limit=oshelpers.os_result_limit(self.provider, limit),
  342. marker=marker)]
  343. return oshelpers.to_server_paged_list(self.provider, cb_vols, limit)
  344. @dispatch(event="provider.storage.volumes.create",
  345. priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
  346. def create(self, label, size, zone, snapshot=None, description=None):
  347. OpenStackVolume.assert_valid_resource_label(label)
  348. zone_id = zone.id if isinstance(zone, PlacementZone) else zone
  349. snapshot_id = snapshot.id if isinstance(
  350. snapshot, OpenStackSnapshot) and snapshot else snapshot
  351. os_vol = self.provider.cinder.volumes.create(
  352. size, name=label, description=description,
  353. availability_zone=zone_id, snapshot_id=snapshot_id)
  354. return OpenStackVolume(self.provider, os_vol)
  355. @dispatch(event="provider.storage.volumes.delete",
  356. priority=BaseVolumeService.STANDARD_EVENT_PRIORITY)
  357. def delete(self, volume):
  358. volume = (volume if isinstance(volume, OpenStackVolume)
  359. else self.get(volume))
  360. if volume:
  361. # pylint:disable=protected-access
  362. volume._volume.delete()
  363. class OpenStackSnapshotService(BaseSnapshotService):
  364. def __init__(self, provider):
  365. super(OpenStackSnapshotService, self).__init__(provider)
  366. @dispatch(event="provider.storage.snapshots.get",
  367. priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
  368. def get(self, snapshot_id):
  369. try:
  370. return OpenStackSnapshot(
  371. self.provider,
  372. self.provider.cinder.volume_snapshots.get(snapshot_id))
  373. except CinderNotFound:
  374. log.debug("Snapshot %s was not found.", snapshot_id)
  375. return None
  376. @dispatch(event="provider.storage.snapshots.find",
  377. priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
  378. def find(self, **kwargs):
  379. label = kwargs.pop('label', None)
  380. # All kwargs should have been popped at this time.
  381. if len(kwargs) > 0:
  382. raise InvalidParamException(
  383. "Unrecognised parameters for search: %s. Supported "
  384. "attributes: %s" % (kwargs, 'label'))
  385. search_opts = {'name': label, # TODO: Cinder is ignoring name
  386. 'limit': oshelpers.os_result_limit(self.provider),
  387. 'marker': None}
  388. log.debug("Searching for an OpenStack snapshot with the following "
  389. "params: %s", search_opts)
  390. cb_snaps = [
  391. OpenStackSnapshot(self.provider, snap) for
  392. snap in self.provider.cinder.volume_snapshots.list(search_opts)
  393. if snap.name == label]
  394. return oshelpers.to_server_paged_list(self.provider, cb_snaps)
  395. @dispatch(event="provider.storage.snapshots.list",
  396. priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
  397. def list(self, limit=None, marker=None):
  398. cb_snaps = [
  399. OpenStackSnapshot(self.provider, snap) for
  400. snap in self.provider.cinder.volume_snapshots.list(
  401. search_opts={'limit': oshelpers.os_result_limit(self.provider,
  402. limit),
  403. 'marker': marker})]
  404. return oshelpers.to_server_paged_list(self.provider, cb_snaps, limit)
  405. @dispatch(event="provider.storage.snapshots.create",
  406. priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
  407. def create(self, label, volume, description=None):
  408. OpenStackSnapshot.assert_valid_resource_label(label)
  409. volume_id = (volume.id if isinstance(volume, OpenStackVolume)
  410. else volume)
  411. os_snap = self.provider.cinder.volume_snapshots.create(
  412. volume_id, name=label,
  413. description=description)
  414. return OpenStackSnapshot(self.provider, os_snap)
  415. @dispatch(event="provider.storage.snapshots.delete",
  416. priority=BaseSnapshotService.STANDARD_EVENT_PRIORITY)
  417. def delete(self, snapshot):
  418. s = (snapshot if isinstance(snapshot, OpenStackSnapshot) else
  419. self.get(snapshot))
  420. if s:
  421. # pylint:disable=protected-access
  422. s._snapshot.delete()
  423. class OpenStackBucketService(BaseBucketService):
  424. def __init__(self, provider):
  425. super(OpenStackBucketService, self).__init__(provider)
  426. @dispatch(event="provider.storage.buckets.get",
  427. priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
  428. def get(self, bucket_id):
  429. """
  430. Returns a bucket given its ID. Returns ``None`` if the bucket
  431. does not exist.
  432. """
  433. _, container_list = self.provider.swift.get_account(
  434. prefix=bucket_id)
  435. if container_list:
  436. return OpenStackBucket(self.provider,
  437. next((c for c in container_list
  438. if c['name'] == bucket_id), None))
  439. else:
  440. log.debug("Bucket %s was not found.", bucket_id)
  441. return None
  442. @dispatch(event="provider.storage.buckets.find",
  443. priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
  444. def find(self, **kwargs):
  445. name = kwargs.pop('name', None)
  446. # All kwargs should have been popped at this time.
  447. if len(kwargs) > 0:
  448. raise InvalidParamException(
  449. "Unrecognised parameters for search: %s. Supported "
  450. "attributes: %s" % (kwargs, 'name'))
  451. _, container_list = self.provider.swift.get_account()
  452. cb_buckets = [OpenStackBucket(self.provider, c)
  453. for c in container_list
  454. if name in c.get("name")]
  455. return oshelpers.to_server_paged_list(self.provider, cb_buckets)
  456. @dispatch(event="provider.storage.buckets.list",
  457. priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
  458. def list(self, limit=None, marker=None):
  459. _, container_list = self.provider.swift.get_account(
  460. limit=oshelpers.os_result_limit(self.provider, limit),
  461. marker=marker)
  462. cb_buckets = [OpenStackBucket(self.provider, c)
  463. for c in container_list]
  464. return oshelpers.to_server_paged_list(self.provider, cb_buckets, limit)
  465. @dispatch(event="provider.storage.buckets.create",
  466. priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
  467. def create(self, name, location=None):
  468. OpenStackBucket.assert_valid_resource_name(name)
  469. location = location or self.provider.region_name
  470. try:
  471. self.provider.swift.head_container(name)
  472. raise DuplicateResourceException(
  473. 'Bucket already exists with name {0}'.format(name))
  474. except SwiftClientException:
  475. self.provider.swift.put_container(name)
  476. return self.get(name)
  477. @dispatch(event="provider.storage.buckets.delete",
  478. priority=BaseBucketService.STANDARD_EVENT_PRIORITY)
  479. def delete(self, bucket):
  480. b_id = bucket.id if isinstance(bucket, OpenStackBucket) else bucket
  481. self.provider.swift.delete_container(b_id)
  482. class OpenStackBucketObjectService(BaseBucketObjectService):
  483. def __init__(self, provider):
  484. super(OpenStackBucketObjectService, self).__init__(provider)
  485. def get(self, bucket, name):
  486. """
  487. Retrieve a given object from this bucket.
  488. """
  489. # Swift always returns a reference for the container first,
  490. # followed by a list containing references to objects.
  491. _, object_list = self.provider.swift.get_container(
  492. bucket.name, prefix=name)
  493. # Loop through list of objects looking for an exact name vs. a prefix
  494. for obj in object_list:
  495. if obj.get('name') == name:
  496. return OpenStackBucketObject(self.provider,
  497. bucket,
  498. obj)
  499. return None
  500. def list(self, bucket, limit=None, marker=None, prefix=None):
  501. """
  502. List all objects within this bucket.
  503. :rtype: BucketObject
  504. :return: List of all available BucketObjects within this bucket.
  505. """
  506. _, object_list = self.provider.swift.get_container(
  507. bucket.name,
  508. limit=oshelpers.os_result_limit(self.provider, limit),
  509. marker=marker, prefix=prefix)
  510. cb_objects = [OpenStackBucketObject(
  511. self.provider, bucket, obj) for obj in object_list]
  512. return oshelpers.to_server_paged_list(
  513. self.provider,
  514. cb_objects,
  515. limit)
  516. def find(self, bucket, **kwargs):
  517. _, obj_list = self.provider.swift.get_container(bucket.name)
  518. cb_objs = [OpenStackBucketObject(self.provider, bucket, obj)
  519. for obj in obj_list]
  520. filters = ['name']
  521. matches = cb_helpers.generic_find(filters, kwargs, cb_objs)
  522. return ClientPagedResultList(self.provider, list(matches))
  523. def create(self, bucket, object_name):
  524. self.provider.swift.put_object(bucket.name, object_name, None)
  525. return self.get(bucket, object_name)
  526. class OpenStackComputeService(BaseComputeService):
  527. def __init__(self, provider):
  528. super(OpenStackComputeService, self).__init__(provider)
  529. self._vm_type_svc = OpenStackVMTypeService(self.provider)
  530. self._instance_svc = OpenStackInstanceService(self.provider)
  531. self._region_svc = OpenStackRegionService(self.provider)
  532. self._images_svc = OpenStackImageService(self.provider)
  533. @property
  534. def images(self):
  535. return self._images_svc
  536. @property
  537. def vm_types(self):
  538. return self._vm_type_svc
  539. @property
  540. def instances(self):
  541. return self._instance_svc
  542. @property
  543. def regions(self):
  544. return self._region_svc
  545. class OpenStackImageService(BaseImageService):
  546. def __init__(self, provider):
  547. super(OpenStackImageService, self).__init__(provider)
  548. def get(self, image_id):
  549. """
  550. Returns an Image given its id
  551. """
  552. log.debug("Getting OpenStack Image with the id: %s", image_id)
  553. try:
  554. return OpenStackMachineImage(
  555. self.provider, self.provider.os_conn.image.get_image(image_id))
  556. except (NotFoundException, ResourceNotFound):
  557. log.debug("Image %s not found", image_id)
  558. return None
  559. def find(self, **kwargs):
  560. filters = ['label']
  561. obj_list = self
  562. return cb_helpers.generic_find(filters, kwargs, obj_list)
  563. def list(self, filter_by_owner=True, limit=None, marker=None):
  564. """
  565. List all images.
  566. """
  567. project_id = None
  568. if filter_by_owner:
  569. project_id = self.provider.os_conn.session.get_project_id()
  570. os_images = self.provider.os_conn.image.images(
  571. owner=project_id,
  572. limit=oshelpers.os_result_limit(self.provider, limit),
  573. marker=marker)
  574. cb_images = [
  575. OpenStackMachineImage(self.provider, img)
  576. for img in os_images]
  577. return oshelpers.to_server_paged_list(self.provider, cb_images, limit)
  578. class OpenStackInstanceService(BaseInstanceService):
  579. def __init__(self, provider):
  580. super(OpenStackInstanceService, self).__init__(provider)
  581. def _to_block_device_mapping(self, launch_config):
  582. """
  583. Extracts block device mapping information
  584. from a launch config and constructs a BlockDeviceMappingV2
  585. object.
  586. """
  587. bdm = []
  588. for device in launch_config.block_devices:
  589. bdm_dict = dict()
  590. if device.is_volume:
  591. bdm_dict['destination_type'] = 'volume'
  592. if device.is_root:
  593. bdm_dict['device_name'] = '/dev/sda'
  594. bdm_dict['boot_index'] = 0
  595. if isinstance(device.source, Snapshot):
  596. bdm_dict['source_type'] = 'snapshot'
  597. bdm_dict['uuid'] = device.source.id
  598. elif isinstance(device.source, Volume):
  599. bdm_dict['source_type'] = 'volume'
  600. bdm_dict['uuid'] = device.source.id
  601. elif isinstance(device.source, MachineImage):
  602. bdm_dict['source_type'] = 'image'
  603. bdm_dict['uuid'] = device.source.id
  604. else:
  605. bdm_dict['source_type'] = 'blank'
  606. if device.delete_on_terminate is not None:
  607. bdm_dict[
  608. 'delete_on_termination'] = device.delete_on_terminate
  609. if device.size:
  610. bdm_dict['volume_size'] = device.size
  611. else:
  612. bdm_dict['destination_type'] = 'local'
  613. bdm_dict['source_type'] = 'blank'
  614. bdm_dict['delete_on_termination'] = True
  615. bdm.append(bdm_dict)
  616. return bdm
  617. def _has_root_device(self, launch_config):
  618. if not launch_config:
  619. return False
  620. for device in launch_config.block_devices:
  621. if device.is_root:
  622. return True
  623. return False
  624. def create_launch_config(self):
  625. return BaseLaunchConfig(self.provider)
  626. @dispatch(event="provider.compute.instances.create",
  627. priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
  628. def create(self, label, image, vm_type, subnet, zone,
  629. key_pair=None, vm_firewalls=None, user_data=None,
  630. launch_config=None, **kwargs):
  631. OpenStackInstance.assert_valid_resource_label(label)
  632. image_id = image.id if isinstance(image, MachineImage) else image
  633. vm_size = vm_type.id if \
  634. isinstance(vm_type, VMType) else \
  635. self.provider.compute.vm_types.find(
  636. name=vm_type)[0].id
  637. if isinstance(subnet, Subnet):
  638. subnet_id = subnet.id
  639. net_id = subnet.network_id
  640. else:
  641. subnet_id = subnet
  642. net_id = (self.provider.networking.subnets
  643. .get(subnet_id).network_id
  644. if subnet_id else None)
  645. zone_id = zone.id if isinstance(zone, PlacementZone) else zone
  646. key_pair_name = key_pair.name if \
  647. isinstance(key_pair, KeyPair) else key_pair
  648. bdm = None
  649. if launch_config:
  650. bdm = self._to_block_device_mapping(launch_config)
  651. # Security groups must be passed in as a list of IDs and attached to a
  652. # port if a port is being created. Otherwise, the security groups must
  653. # be passed in as a list of names to the servers.create() call.
  654. # OpenStack will respect the port's security groups first and then
  655. # fall-back to the named security groups.
  656. sg_name_list = []
  657. nics = None
  658. if subnet_id:
  659. log.debug("Creating network port for %s in subnet: %s",
  660. label, subnet_id)
  661. sg_list = []
  662. if vm_firewalls:
  663. if isinstance(vm_firewalls, list) and \
  664. isinstance(vm_firewalls[0], VMFirewall):
  665. sg_list = vm_firewalls
  666. else:
  667. sg_list = (self.provider.security.vm_firewalls
  668. .find(label=sg) for sg in vm_firewalls)
  669. sg_list = (sg[0] for sg in sg_list if sg)
  670. sg_id_list = [sg.id for sg in sg_list]
  671. port_def = {
  672. "port": {
  673. "admin_state_up": True,
  674. "name": OpenStackInstance._generate_name_from_label(
  675. label, 'cb-port'),
  676. "network_id": net_id,
  677. "fixed_ips": [{"subnet_id": subnet_id}],
  678. "security_groups": sg_id_list
  679. }
  680. }
  681. port_id = self.provider.neutron.create_port(port_def)['port']['id']
  682. nics = [{'net-id': net_id, 'port-id': port_id}]
  683. else:
  684. if vm_firewalls:
  685. if isinstance(vm_firewalls, list) and \
  686. isinstance(vm_firewalls[0], VMFirewall):
  687. sg_name_list = [sg.name for sg in vm_firewalls]
  688. else:
  689. sg_list = (self.provider.security.vm_firewalls.get(sg)
  690. for sg in vm_firewalls)
  691. sg_name_list = (sg[0].name for sg in sg_list if sg)
  692. log.debug("Launching in subnet %s", subnet_id)
  693. os_instance = self.provider.nova.servers.create(
  694. label,
  695. None if self._has_root_device(launch_config) else image_id,
  696. vm_size,
  697. min_count=1,
  698. max_count=1,
  699. availability_zone=zone_id,
  700. key_name=key_pair_name,
  701. security_groups=sg_name_list,
  702. userdata=str(user_data) or None,
  703. block_device_mapping_v2=bdm,
  704. nics=nics)
  705. return OpenStackInstance(self.provider, os_instance)
  706. @dispatch(event="provider.compute.instances.find",
  707. priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
  708. def find(self, **kwargs):
  709. label = kwargs.pop('label', None)
  710. # All kwargs should have been popped at this time.
  711. if len(kwargs) > 0:
  712. raise InvalidParamException(
  713. "Unrecognised parameters for search: %s. Supported "
  714. "attributes: %s" % (kwargs, 'label'))
  715. search_opts = {'name': label}
  716. cb_insts = [
  717. OpenStackInstance(self.provider, inst)
  718. for inst in self.provider.nova.servers.list(
  719. search_opts=search_opts,
  720. limit=oshelpers.os_result_limit(self.provider),
  721. marker=None)]
  722. return oshelpers.to_server_paged_list(self.provider, cb_insts)
  723. @dispatch(event="provider.compute.instances.list",
  724. priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
  725. def list(self, limit=None, marker=None):
  726. """
  727. List all instances.
  728. """
  729. cb_insts = [
  730. OpenStackInstance(self.provider, inst)
  731. for inst in self.provider.nova.servers.list(
  732. limit=oshelpers.os_result_limit(self.provider, limit),
  733. marker=marker)]
  734. return oshelpers.to_server_paged_list(self.provider, cb_insts, limit)
  735. @dispatch(event="provider.compute.instances.get",
  736. priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
  737. def get(self, instance_id):
  738. """
  739. Returns an instance given its id.
  740. """
  741. try:
  742. os_instance = self.provider.nova.servers.get(instance_id)
  743. return OpenStackInstance(self.provider, os_instance)
  744. except NovaNotFound:
  745. log.debug("Instance %s was not found.", instance_id)
  746. return None
  747. @dispatch(event="provider.compute.instances.delete",
  748. priority=BaseInstanceService.STANDARD_EVENT_PRIORITY)
  749. def delete(self, instance):
  750. ins = (instance if isinstance(instance, OpenStackInstance) else
  751. self.get(instance))
  752. if ins:
  753. # pylint:disable=protected-access
  754. os_instance = ins._os_instance
  755. # delete the port we created when launching
  756. # Assumption: it's the first interface in the list
  757. iface_list = os_instance.interface_list()
  758. if iface_list:
  759. self.provider.neutron.delete_port(iface_list[0].port_id)
  760. os_instance.delete()
  761. class OpenStackVMTypeService(BaseVMTypeService):
  762. def __init__(self, provider):
  763. super(OpenStackVMTypeService, self).__init__(provider)
  764. @dispatch(event="provider.compute.vm_types.list",
  765. priority=BaseVMTypeService.STANDARD_EVENT_PRIORITY)
  766. def list(self, limit=None, marker=None):
  767. cb_itypes = [
  768. OpenStackVMType(self.provider, obj)
  769. for obj in self.provider.nova.flavors.list(
  770. limit=oshelpers.os_result_limit(self.provider, limit),
  771. marker=marker)]
  772. return oshelpers.to_server_paged_list(self.provider, cb_itypes, limit)
  773. class OpenStackRegionService(BaseRegionService):
  774. def __init__(self, provider):
  775. super(OpenStackRegionService, self).__init__(provider)
  776. @dispatch(event="provider.compute.regions.get",
  777. priority=BaseRegionService.STANDARD_EVENT_PRIORITY)
  778. def get(self, region_id):
  779. log.debug("Getting OpenStack Region with the id: %s", region_id)
  780. region = (r for r in self if r.id == region_id)
  781. return next(region, None)
  782. @dispatch(event="provider.compute.regions.list",
  783. priority=BaseRegionService.STANDARD_EVENT_PRIORITY)
  784. def list(self, limit=None, marker=None):
  785. # pylint:disable=protected-access
  786. if self.provider._keystone_version == 3:
  787. os_regions = [OpenStackRegion(self.provider, region)
  788. for region in self.provider.keystone.regions.list()]
  789. return ClientPagedResultList(self.provider, os_regions,
  790. limit=limit, marker=marker)
  791. else:
  792. # Keystone v3 onwards supports directly listing regions
  793. # but for v2, this convoluted method is necessary.
  794. regions = (
  795. endpoint.get('region') or endpoint.get('region_id')
  796. for svc in self.provider.keystone.service_catalog.get_data()
  797. for endpoint in svc.get('endpoints', [])
  798. )
  799. regions = set(region for region in regions if region)
  800. os_regions = [OpenStackRegion(self.provider, region)
  801. for region in regions]
  802. return ClientPagedResultList(self.provider, os_regions,
  803. limit=limit, marker=marker)
  804. @property
  805. def current(self):
  806. nova_region = self.provider.nova.client.region_name
  807. return self.get(nova_region) if nova_region else None
  808. class OpenStackNetworkingService(BaseNetworkingService):
  809. def __init__(self, provider):
  810. super(OpenStackNetworkingService, self).__init__(provider)
  811. self._network_service = OpenStackNetworkService(self.provider)
  812. self._subnet_service = OpenStackSubnetService(self.provider)
  813. self._router_service = OpenStackRouterService(self.provider)
  814. self._gateway_service = OpenStackGatewayService(self.provider)
  815. self._floating_ip_service = OpenStackFloatingIPService(self.provider)
  816. @property
  817. def networks(self):
  818. return self._network_service
  819. @property
  820. def subnets(self):
  821. return self._subnet_service
  822. @property
  823. def routers(self):
  824. return self._router_service
  825. @property
  826. def _gateways(self):
  827. return self._gateway_service
  828. @property
  829. def _floating_ips(self):
  830. return self._floating_ip_service
  831. class OpenStackNetworkService(BaseNetworkService):
  832. def __init__(self, provider):
  833. super(OpenStackNetworkService, self).__init__(provider)
  834. @dispatch(event="provider.networking.networks.get",
  835. priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
  836. def get(self, network_id):
  837. network = (n for n in self if n.id == network_id)
  838. return next(network, None)
  839. @dispatch(event="provider.networking.networks.list",
  840. priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
  841. def list(self, limit=None, marker=None):
  842. networks = [OpenStackNetwork(self.provider, network)
  843. for network in self.provider.neutron.list_networks()
  844. .get('networks') if network]
  845. return ClientPagedResultList(self.provider, networks,
  846. limit=limit, marker=marker)
  847. @dispatch(event="provider.networking.networks.find",
  848. priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
  849. def find(self, **kwargs):
  850. label = kwargs.pop('label', None)
  851. # All kwargs should have been popped at this time.
  852. if len(kwargs) > 0:
  853. raise InvalidParamException(
  854. "Unrecognised parameters for search: %s. Supported "
  855. "attributes: %s" % (kwargs, 'label'))
  856. log.debug("Searching for OpenStack Network with label: %s", label)
  857. networks = [OpenStackNetwork(self.provider, network)
  858. for network in self.provider.neutron.list_networks(
  859. name=label)
  860. .get('networks') if network]
  861. return ClientPagedResultList(self.provider, networks)
  862. @dispatch(event="provider.networking.networks.create",
  863. priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
  864. def create(self, label, cidr_block):
  865. OpenStackNetwork.assert_valid_resource_label(label)
  866. net_info = {'name': label or ""}
  867. network = self.provider.neutron.create_network({'network': net_info})
  868. cb_net = OpenStackNetwork(self.provider, network.get('network'))
  869. if label:
  870. cb_net.label = label
  871. return cb_net
  872. @dispatch(event="provider.networking.networks.delete",
  873. priority=BaseNetworkService.STANDARD_EVENT_PRIORITY)
  874. def delete(self, network):
  875. network = (network if isinstance(network, OpenStackNetwork) else
  876. self.get(network))
  877. if not network:
  878. return
  879. if not network.external and network.id in str(
  880. self.provider.neutron.list_networks()):
  881. # If there are ports associated with the network, it won't delete
  882. ports = self.provider.neutron.list_ports(
  883. network_id=network.id).get('ports', [])
  884. for port in ports:
  885. try:
  886. self.provider.neutron.delete_port(port.get('id'))
  887. except PortNotFoundClient:
  888. # Ports could have already been deleted if instances
  889. # are terminated etc. so exceptions can be safely ignored
  890. pass
  891. self.provider.neutron.delete_network(network.id)
  892. class OpenStackSubnetService(BaseSubnetService):
  893. def __init__(self, provider):
  894. super(OpenStackSubnetService, self).__init__(provider)
  895. @dispatch(event="provider.networking.subnets.get",
  896. priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
  897. def get(self, subnet_id):
  898. subnet = (s for s in self if s.id == subnet_id)
  899. return next(subnet, None)
  900. @dispatch(event="provider.networking.subnets.list",
  901. priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
  902. def list(self, network=None, limit=None, marker=None):
  903. if network:
  904. network_id = (network.id if isinstance(network, OpenStackNetwork)
  905. else network)
  906. subnets = [subnet for subnet in self if network_id ==
  907. subnet.network_id]
  908. else:
  909. subnets = [OpenStackSubnet(self.provider, subnet) for subnet in
  910. self.provider.neutron.list_subnets().get('subnets', [])]
  911. return ClientPagedResultList(self.provider, subnets,
  912. limit=limit, marker=marker)
  913. @dispatch(event="provider.networking.subnets.create",
  914. priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
  915. def create(self, label, network, cidr_block, zone):
  916. """zone param is ignored."""
  917. OpenStackSubnet.assert_valid_resource_label(label)
  918. network_id = (network.id if isinstance(network, OpenStackNetwork)
  919. else network)
  920. subnet_info = {'name': label, 'network_id': network_id,
  921. 'cidr': cidr_block, 'ip_version': 4}
  922. subnet = (self.provider.neutron.create_subnet({'subnet': subnet_info})
  923. .get('subnet'))
  924. cb_subnet = OpenStackSubnet(self.provider, subnet)
  925. return cb_subnet
  926. @dispatch(event="provider.networking.subnets.delete",
  927. priority=BaseSubnetService.STANDARD_EVENT_PRIORITY)
  928. def delete(self, subnet):
  929. sn_id = subnet.id if isinstance(subnet, OpenStackSubnet) else subnet
  930. self.provider.neutron.delete_subnet(sn_id)
  931. def get_or_create_default(self, zone):
  932. """
  933. Subnet zone is not supported by OpenStack and is thus ignored.
  934. """
  935. try:
  936. sn = self.find(label=OpenStackSubnet.CB_DEFAULT_SUBNET_LABEL)
  937. if sn:
  938. return sn[0]
  939. # No default subnet look for default network, then create subnet
  940. net = self.provider.networking.networks.get_or_create_default()
  941. sn = self.provider.networking.subnets.create(
  942. label=OpenStackSubnet.CB_DEFAULT_SUBNET_LABEL,
  943. cidr_block=OpenStackSubnet.CB_DEFAULT_SUBNET_IPV4RANGE,
  944. network=net, zone=zone)
  945. router = self.provider.networking.routers.get_or_create_default(
  946. net)
  947. router.attach_subnet(sn)
  948. gateway = net.gateways.get_or_create()
  949. router.attach_gateway(gateway)
  950. return sn
  951. except NeutronClientException:
  952. return None
  953. class OpenStackRouterService(BaseRouterService):
  954. def __init__(self, provider):
  955. super(OpenStackRouterService, self).__init__(provider)
  956. @dispatch(event="provider.networking.routers.get",
  957. priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
  958. def get(self, router_id):
  959. log.debug("Getting OpenStack Router with the id: %s", router_id)
  960. router = self.provider.os_conn.get_router(router_id)
  961. return OpenStackRouter(self.provider, router) if router else None
  962. @dispatch(event="provider.networking.routers.list",
  963. priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
  964. def list(self, limit=None, marker=None):
  965. routers = self.provider.os_conn.list_routers()
  966. os_routers = [OpenStackRouter(self.provider, r) for r in routers]
  967. return ClientPagedResultList(self.provider, os_routers, limit=limit,
  968. marker=marker)
  969. @dispatch(event="provider.networking.routers.find",
  970. priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
  971. def find(self, **kwargs):
  972. obj_list = self
  973. filters = ['label']
  974. matches = cb_helpers.generic_find(filters, kwargs, obj_list)
  975. return ClientPagedResultList(self._provider, list(matches))
  976. @dispatch(event="provider.networking.routers.create",
  977. priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
  978. def create(self, label, network):
  979. """Parameter ``network`` is not used by OpenStack."""
  980. router = self.provider.os_conn.create_router(name=label)
  981. return OpenStackRouter(self.provider, router)
  982. @dispatch(event="provider.networking.routers.delete",
  983. priority=BaseRouterService.STANDARD_EVENT_PRIORITY)
  984. def delete(self, router):
  985. r_id = router.id if isinstance(router, OpenStackRouter) else router
  986. self.provider.os_conn.delete_router(r_id)
  987. class OpenStackGatewayService(BaseGatewayService):
  988. """For OpenStack, an internet gateway is a just an 'external' network."""
  989. def __init__(self, provider):
  990. super(OpenStackGatewayService, self).__init__(provider)
  991. def _check_fip_connectivity(self, network, external_net):
  992. # Due to current limitations in OpenStack:
  993. # https://bugs.launchpad.net/neutron/+bug/1743480, it's not
  994. # possible to differentiate between floating ip networks and provider
  995. # external networks. Therefore, we systematically step through
  996. # all available networks and perform an assignment test to infer valid
  997. # floating ip nets.
  998. dummy_router = self._provider.networking.routers.create(
  999. label='cb-conn-test-router', network=network)
  1000. with cb_helpers.cleanup_action(lambda: dummy_router.delete()):
  1001. try:
  1002. dummy_router.attach_gateway(external_net)
  1003. return True
  1004. except Exception:
  1005. return False
  1006. @dispatch(event="provider.networking.gateways.get_or_create",
  1007. priority=BaseGatewayService.STANDARD_EVENT_PRIORITY)
  1008. def get_or_create(self, network):
  1009. """For OS, inet gtw is any net that has `external` property set."""
  1010. external_nets = (n for n in self._provider.networking.networks
  1011. if n.external)
  1012. for net in external_nets:
  1013. if self._check_fip_connectivity(network, net):
  1014. return OpenStackInternetGateway(self._provider, net)
  1015. return None
  1016. @dispatch(event="provider.networking.gateways.delete",
  1017. priority=BaseGatewayService.STANDARD_EVENT_PRIORITY)
  1018. def delete(self, network, gateway):
  1019. pass
  1020. @dispatch(event="provider.networking.gateways.list",
  1021. priority=BaseGatewayService.STANDARD_EVENT_PRIORITY)
  1022. def list(self, network, limit=None, marker=None):
  1023. log.debug("OpenStack listing of all current internet gateways")
  1024. igl = [OpenStackInternetGateway(self._provider, n)
  1025. for n in self._provider.networking.networks
  1026. if n.external and self._check_fip_connectivity(network, n)]
  1027. return ClientPagedResultList(self._provider, igl, limit=limit,
  1028. marker=marker)
  1029. class OpenStackFloatingIPService(BaseFloatingIPService):
  1030. def __init__(self, provider):
  1031. super(OpenStackFloatingIPService, self).__init__(provider)
  1032. @dispatch(event="provider.networking.floating_ips.get",
  1033. priority=BaseFloatingIPService.STANDARD_EVENT_PRIORITY)
  1034. def get(self, gateway, fip_id):
  1035. try:
  1036. return OpenStackFloatingIP(
  1037. self.provider,
  1038. self.provider.os_conn.network.get_ip(fip_id))
  1039. except (ResourceNotFound, NotFoundException):
  1040. log.debug("Floating IP %s not found.", fip_id)
  1041. return None
  1042. @dispatch(event="provider.networking.floating_ips.list",
  1043. priority=BaseFloatingIPService.STANDARD_EVENT_PRIORITY)
  1044. def list(self, gateway, limit=None, marker=None):
  1045. fips = [OpenStackFloatingIP(self.provider, fip)
  1046. for fip in self.provider.os_conn.network.ips(
  1047. floating_network_id=gateway.id
  1048. )]
  1049. return ClientPagedResultList(self.provider, fips,
  1050. limit=limit, marker=marker)
  1051. @dispatch(event="provider.networking.floating_ips.create",
  1052. priority=BaseFloatingIPService.STANDARD_EVENT_PRIORITY)
  1053. def create(self, gateway):
  1054. return OpenStackFloatingIP(
  1055. self.provider, self.provider.os_conn.network.create_ip(
  1056. floating_network_id=gateway.id))
  1057. @dispatch(event="provider.networking.floating_ips.delete",
  1058. priority=BaseFloatingIPService.STANDARD_EVENT_PRIORITY)
  1059. def delete(self, gateway, fip):
  1060. if isinstance(fip, OpenStackFloatingIP):
  1061. # pylint:disable=protected-access
  1062. os_ip = fip._ip
  1063. else:
  1064. try:
  1065. os_ip = self.provider.os_conn.network.get_ip(fip)
  1066. except (ResourceNotFound, NotFoundException):
  1067. log.debug("Floating IP %s not found.", fip)
  1068. return True
  1069. os_ip.delete(self._provider.os_conn.session)