services.py 58 KB

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