services.py 49 KB

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