services.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. """
  2. Services implemented by the OpenStack provider.
  3. """
  4. import fnmatch
  5. import re
  6. from cinderclient.exceptions import NotFound as CinderNotFound
  7. from novaclient.exceptions import NotFound as NovaNotFound
  8. from cloudbridge.cloud.base.resources import BaseLaunchConfig
  9. from cloudbridge.cloud.base.resources import ClientPagedResultList
  10. from cloudbridge.cloud.base.services import BaseBlockStoreService
  11. from cloudbridge.cloud.base.services import BaseComputeService
  12. from cloudbridge.cloud.base.services import BaseImageService
  13. from cloudbridge.cloud.base.services import BaseInstanceService
  14. from cloudbridge.cloud.base.services import BaseInstanceTypesService
  15. from cloudbridge.cloud.base.services import BaseKeyPairService
  16. from cloudbridge.cloud.base.services import BaseNetworkService
  17. from cloudbridge.cloud.base.services import BaseObjectStoreService
  18. from cloudbridge.cloud.base.services import BaseRegionService
  19. from cloudbridge.cloud.base.services import BaseSecurityGroupService
  20. from cloudbridge.cloud.base.services import BaseSecurityService
  21. from cloudbridge.cloud.base.services import BaseSnapshotService
  22. from cloudbridge.cloud.base.services import BaseSubnetService
  23. from cloudbridge.cloud.base.services import BaseVolumeService
  24. from cloudbridge.cloud.interfaces.resources import InstanceType
  25. from cloudbridge.cloud.interfaces.resources import KeyPair
  26. from cloudbridge.cloud.interfaces.resources import MachineImage
  27. from cloudbridge.cloud.interfaces.resources import PlacementZone
  28. from cloudbridge.cloud.interfaces.resources import SecurityGroup
  29. from cloudbridge.cloud.interfaces.resources import Snapshot
  30. from cloudbridge.cloud.interfaces.resources import Volume
  31. from cloudbridge.cloud.providers.openstack import helpers as oshelpers
  32. from .resources import OpenStackBucket
  33. from .resources import OpenStackInstance
  34. from .resources import OpenStackInstanceType
  35. from .resources import OpenStackKeyPair
  36. from .resources import OpenStackMachineImage
  37. from .resources import OpenStackNetwork
  38. from .resources import OpenStackRegion
  39. from .resources import OpenStackSecurityGroup
  40. from .resources import OpenStackSnapshot
  41. from .resources import OpenStackSubnet
  42. from .resources import OpenStackVolume
  43. class OpenStackSecurityService(BaseSecurityService):
  44. def __init__(self, provider):
  45. super(OpenStackSecurityService, self).__init__(provider)
  46. # Initialize provider services
  47. self._key_pairs = OpenStackKeyPairService(provider)
  48. self._security_groups = OpenStackSecurityGroupService(provider)
  49. @property
  50. def key_pairs(self):
  51. """
  52. Provides access to key pairs for this provider.
  53. :rtype: ``object`` of :class:`.KeyPairService`
  54. :return: a KeyPairService object
  55. """
  56. return self._key_pairs
  57. @property
  58. def security_groups(self):
  59. """
  60. Provides access to security groups for this provider.
  61. :rtype: ``object`` of :class:`.SecurityGroupService`
  62. :return: a SecurityGroupService object
  63. """
  64. return self._security_groups
  65. class OpenStackKeyPairService(BaseKeyPairService):
  66. def __init__(self, provider):
  67. super(OpenStackKeyPairService, self).__init__(provider)
  68. def get(self, key_pair_id):
  69. """
  70. Returns a KeyPair given its id.
  71. """
  72. try:
  73. return OpenStackKeyPair(
  74. self.provider, self.provider.nova.keypairs.get(key_pair_id))
  75. except NovaNotFound:
  76. return None
  77. def list(self, limit=None, marker=None):
  78. """
  79. List all key pairs associated with this account.
  80. :rtype: ``list`` of :class:`.KeyPair`
  81. :return: list of KeyPair objects
  82. """
  83. keypairs = self.provider.nova.keypairs.list()
  84. results = [OpenStackKeyPair(self.provider, kp)
  85. for kp in keypairs]
  86. return ClientPagedResultList(self.provider, results,
  87. limit=limit, marker=marker)
  88. def find(self, name, limit=None, marker=None):
  89. """
  90. Searches for a key pair by a given list of attributes.
  91. """
  92. keypairs = self.provider.nova.keypairs.findall(name=name)
  93. results = [OpenStackKeyPair(self.provider, kp)
  94. for kp in keypairs]
  95. return ClientPagedResultList(self.provider, results,
  96. limit=limit, marker=marker)
  97. def create(self, name):
  98. """
  99. Create a new key pair or return an existing one by the same name.
  100. :type name: str
  101. :param name: The name of the key pair to be created.
  102. :rtype: ``object`` of :class:`.KeyPair`
  103. :return: A key pair instance or ``None`` if one was not be created.
  104. """
  105. kp = self.get(name)
  106. if kp:
  107. return kp
  108. kp = self.provider.nova.keypairs.create(name)
  109. return OpenStackKeyPair(self.provider, kp)
  110. class OpenStackSecurityGroupService(BaseSecurityGroupService):
  111. def __init__(self, provider):
  112. super(OpenStackSecurityGroupService, self).__init__(provider)
  113. def get(self, sg_id):
  114. """
  115. Returns a SecurityGroup given its id.
  116. """
  117. try:
  118. return OpenStackSecurityGroup(
  119. self.provider, self.provider.nova.security_groups.get(sg_id))
  120. except NovaNotFound:
  121. return None
  122. def list(self, limit=None, marker=None):
  123. """
  124. List all security groups associated with this account.
  125. :rtype: ``list`` of :class:`.SecurityGroup`
  126. :return: list of SecurityGroup objects
  127. """
  128. sgs = [OpenStackSecurityGroup(self.provider, sg)
  129. for sg in self.provider.nova.security_groups.list()]
  130. return ClientPagedResultList(self.provider, sgs,
  131. limit=limit, marker=marker)
  132. def create(self, name, description):
  133. """
  134. Create a new security group under the current account.
  135. :type name: str
  136. :param name: The name of the new security group.
  137. :type description: str
  138. :param description: The description of the new security group.
  139. :rtype: ``object`` of :class:`.SecurityGroup`
  140. :return: a SecurityGroup object
  141. """
  142. sg = self.provider.nova.security_groups.create(name, description)
  143. if sg:
  144. return OpenStackSecurityGroup(self.provider, sg)
  145. return None
  146. def find(self, name, limit=None, marker=None):
  147. """
  148. Get all security groups associated with your account.
  149. """
  150. sgs = self.provider.nova.security_groups.findall(name=name)
  151. results = [OpenStackSecurityGroup(self.provider, sg)
  152. for sg in sgs]
  153. return ClientPagedResultList(self.provider, results,
  154. limit=limit, marker=marker)
  155. def delete(self, group_id):
  156. """
  157. Delete an existing SecurityGroup.
  158. :type group_id: str
  159. :param group_id: The security group ID to be deleted.
  160. :rtype: ``bool``
  161. :return: ``True`` if the security group does not exist, ``False``
  162. otherwise. Note that this implies that the group may not have
  163. been deleted by this method but instead has not existed in
  164. the first place.
  165. """
  166. sg = self.get(group_id)
  167. if sg:
  168. sg.delete()
  169. return True
  170. class OpenStackImageService(BaseImageService):
  171. def __init__(self, provider):
  172. super(OpenStackImageService, self).__init__(provider)
  173. def get(self, image_id):
  174. """
  175. Returns an Image given its id
  176. """
  177. try:
  178. return OpenStackMachineImage(
  179. self.provider, self.provider.nova.images.get(image_id))
  180. except NovaNotFound:
  181. return None
  182. def find(self, name, limit=None, marker=None):
  183. """
  184. Searches for an image by a given list of attributes
  185. """
  186. regex = fnmatch.translate(name)
  187. cb_images = [
  188. OpenStackMachineImage(self.provider, img)
  189. for img in self
  190. if img.name and re.search(regex, img.name)]
  191. return oshelpers.to_server_paged_list(self.provider, cb_images, limit)
  192. def list(self, limit=None, marker=None):
  193. """
  194. List all images.
  195. """
  196. if marker is None:
  197. os_images = self.provider.nova.images.list(
  198. limit=oshelpers.os_result_limit(self.provider, limit))
  199. else:
  200. os_images = self.provider.nova.images.list(
  201. limit=oshelpers.os_result_limit(self.provider, limit),
  202. marker=marker)
  203. cb_images = [
  204. OpenStackMachineImage(self.provider, img)
  205. for img in os_images]
  206. return oshelpers.to_server_paged_list(self.provider, cb_images, limit)
  207. class OpenStackInstanceTypesService(BaseInstanceTypesService):
  208. def __init__(self, provider):
  209. super(OpenStackInstanceTypesService, self).__init__(provider)
  210. def list(self, limit=None, marker=None):
  211. cb_itypes = [
  212. OpenStackInstanceType(self.provider, obj)
  213. for obj in self.provider.nova.flavors.list(
  214. limit=oshelpers.os_result_limit(self.provider, limit),
  215. marker=marker)]
  216. return oshelpers.to_server_paged_list(self.provider, cb_itypes, limit)
  217. class OpenStackBlockStoreService(BaseBlockStoreService):
  218. def __init__(self, provider):
  219. super(OpenStackBlockStoreService, self).__init__(provider)
  220. # Initialize provider services
  221. self._volume_svc = OpenStackVolumeService(self.provider)
  222. self._snapshot_svc = OpenStackSnapshotService(self.provider)
  223. @property
  224. def volumes(self):
  225. return self._volume_svc
  226. @property
  227. def snapshots(self):
  228. return self._snapshot_svc
  229. class OpenStackVolumeService(BaseVolumeService):
  230. def __init__(self, provider):
  231. super(OpenStackVolumeService, self).__init__(provider)
  232. def get(self, volume_id):
  233. """
  234. Returns a volume given its id.
  235. """
  236. try:
  237. return OpenStackVolume(
  238. self.provider, self.provider.cinder.volumes.get(volume_id))
  239. except CinderNotFound:
  240. return None
  241. def find(self, name, limit=None, marker=None):
  242. """
  243. Searches for a volume by a given list of attributes.
  244. """
  245. search_opts = {'name': name}
  246. cb_vols = [
  247. OpenStackVolume(self.provider, vol)
  248. for vol in self.provider.cinder.volumes.list(
  249. search_opts=search_opts,
  250. limit=oshelpers.os_result_limit(self.provider, limit),
  251. marker=marker)]
  252. return oshelpers.to_server_paged_list(self.provider, cb_vols, limit)
  253. def list(self, limit=None, marker=None):
  254. """
  255. List all volumes.
  256. """
  257. cb_vols = [
  258. OpenStackVolume(self.provider, vol)
  259. for vol in self.provider.cinder.volumes.list(
  260. limit=oshelpers.os_result_limit(self.provider, limit),
  261. marker=marker)]
  262. return oshelpers.to_server_paged_list(self.provider, cb_vols, limit)
  263. def create(self, name, size, zone, snapshot=None, description=None):
  264. """
  265. Creates a new volume.
  266. """
  267. zone_id = zone.id if isinstance(zone, PlacementZone) else zone
  268. snapshot_id = snapshot.id if isinstance(
  269. snapshot, OpenStackSnapshot) and snapshot else snapshot
  270. os_vol = self.provider.cinder.volumes.create(
  271. size, name=name, description=description,
  272. availability_zone=zone_id, snapshot_id=snapshot_id)
  273. return OpenStackVolume(self.provider, os_vol)
  274. class OpenStackSnapshotService(BaseSnapshotService):
  275. def __init__(self, provider):
  276. super(OpenStackSnapshotService, self).__init__(provider)
  277. def get(self, snapshot_id):
  278. """
  279. Returns a snapshot given its id.
  280. """
  281. try:
  282. return OpenStackSnapshot(
  283. self.provider,
  284. self.provider.cinder.volume_snapshots.get(snapshot_id))
  285. except CinderNotFound:
  286. return None
  287. def find(self, name, limit=None, marker=None):
  288. """
  289. Searches for a volume by a given list of attributes.
  290. """
  291. search_opts = {'name': name, # TODO: Cinder is ignoring name
  292. 'limit': oshelpers.os_result_limit(self.provider,
  293. limit),
  294. 'marker': marker}
  295. cb_snaps = [
  296. OpenStackSnapshot(self.provider, snap) for
  297. snap in self.provider.cinder.volume_snapshots.list(search_opts)
  298. if snap.name == name]
  299. return oshelpers.to_server_paged_list(self.provider, cb_snaps, limit)
  300. def list(self, limit=None, marker=None):
  301. """
  302. List all snapshot.
  303. """
  304. cb_snaps = [
  305. OpenStackSnapshot(self.provider, snap) for
  306. snap in self.provider.cinder.volume_snapshots.list(
  307. search_opts={'limit': oshelpers.os_result_limit(self.provider,
  308. limit),
  309. 'marker': marker})]
  310. return oshelpers.to_server_paged_list(self.provider, cb_snaps, limit)
  311. def create(self, name, volume, description=None):
  312. """
  313. Creates a new snapshot of a given volume.
  314. """
  315. volume_id = (volume.id if isinstance(volume, OpenStackVolume)
  316. else volume)
  317. os_snap = self.provider.cinder.volume_snapshots.create(
  318. volume_id, name=name,
  319. description=description)
  320. return OpenStackSnapshot(self.provider, os_snap)
  321. class OpenStackObjectStoreService(BaseObjectStoreService):
  322. def __init__(self, provider):
  323. super(OpenStackObjectStoreService, self).__init__(provider)
  324. def get(self, bucket_id):
  325. """
  326. Returns a bucket given its ID. Returns ``None`` if the bucket
  327. does not exist.
  328. """
  329. _, container_list = self.provider.swift.get_account(
  330. prefix=bucket_id)
  331. if container_list:
  332. return OpenStackBucket(self.provider, container_list[0])
  333. else:
  334. return None
  335. def find(self, name, limit=None, marker=None):
  336. """
  337. Searches for a bucket by a given list of attributes.
  338. """
  339. _, container_list = self.provider.swift.get_account(
  340. limit=oshelpers.os_result_limit(self.provider, limit),
  341. marker=marker)
  342. cb_buckets = [OpenStackBucket(self.provider, c)
  343. for c in container_list
  344. if name in c.get("name")]
  345. return oshelpers.to_server_paged_list(self.provider, cb_buckets, limit)
  346. def list(self, limit=None, marker=None):
  347. """
  348. List all containers.
  349. """
  350. _, container_list = self.provider.swift.get_account(
  351. limit=oshelpers.os_result_limit(self.provider, limit),
  352. marker=marker)
  353. cb_buckets = [OpenStackBucket(self.provider, c)
  354. for c in container_list]
  355. return oshelpers.to_server_paged_list(self.provider, cb_buckets, limit)
  356. def create(self, name, location=None):
  357. """
  358. Create a new bucket.
  359. """
  360. self.provider.swift.put_container(name)
  361. return self.get(name)
  362. class OpenStackRegionService(BaseRegionService):
  363. def __init__(self, provider):
  364. super(OpenStackRegionService, self).__init__(provider)
  365. def get(self, region_id):
  366. region = (r for r in self.list() if r.id == region_id)
  367. return next(region, None)
  368. def list(self, limit=None, marker=None):
  369. # TODO: KeyStone V3 onwards will support directly listing regions
  370. # but for now, this convoluted method is necessary
  371. regions = (
  372. endpoint.get('region') or endpoint.get('region_id')
  373. for svc in self.provider.keystone.service_catalog.get_data()
  374. for endpoint in svc.get('endpoints', [])
  375. )
  376. regions = set(region for region in regions if region)
  377. os_regions = [OpenStackRegion(self.provider, region)
  378. for region in regions]
  379. return ClientPagedResultList(self.provider, os_regions,
  380. limit=limit, marker=marker)
  381. class OpenStackComputeService(BaseComputeService):
  382. def __init__(self, provider):
  383. super(OpenStackComputeService, self).__init__(provider)
  384. self._instance_type_svc = OpenStackInstanceTypesService(self.provider)
  385. self._instance_svc = OpenStackInstanceService(self.provider)
  386. self._region_svc = OpenStackRegionService(self.provider)
  387. self._images_svc = OpenStackImageService(self.provider)
  388. @property
  389. def images(self):
  390. return self._images_svc
  391. @property
  392. def instance_types(self):
  393. return self._instance_type_svc
  394. @property
  395. def instances(self):
  396. return self._instance_svc
  397. @property
  398. def regions(self):
  399. return self._region_svc
  400. class OpenStackInstanceService(BaseInstanceService):
  401. def __init__(self, provider):
  402. super(OpenStackInstanceService, self).__init__(provider)
  403. def create(self, name, image, instance_type, zone=None,
  404. key_pair=None, security_groups=None, user_data=None,
  405. launch_config=None,
  406. **kwargs):
  407. """
  408. Creates a new virtual machine instance.
  409. """
  410. image_id = image.id if isinstance(image, MachineImage) else image
  411. instance_size = instance_type.id if \
  412. isinstance(instance_type, InstanceType) else \
  413. self.provider.compute.instance_types.find(
  414. name=instance_type)[0].id
  415. zone_id = zone.id if isinstance(zone, PlacementZone) else zone
  416. key_pair_name = key_pair.name if \
  417. isinstance(key_pair, KeyPair) else key_pair
  418. if security_groups:
  419. if isinstance(security_groups, list) and \
  420. isinstance(security_groups[0], SecurityGroup):
  421. security_groups_list = [sg.name for sg in security_groups]
  422. else:
  423. security_groups_list = security_groups
  424. else:
  425. security_groups_list = None
  426. if launch_config:
  427. bdm = self._to_block_device_mapping(launch_config)
  428. nics = self._format_nics(launch_config)
  429. else:
  430. bdm = nics = None
  431. os_instance = self.provider.nova.servers.create(
  432. name,
  433. None if self._has_root_device(launch_config) else image_id,
  434. instance_size,
  435. min_count=1,
  436. max_count=1,
  437. availability_zone=zone_id,
  438. key_name=key_pair_name,
  439. security_groups=security_groups_list,
  440. userdata=user_data,
  441. block_device_mapping_v2=bdm,
  442. nics=nics)
  443. return OpenStackInstance(self.provider, os_instance)
  444. def _to_block_device_mapping(self, launch_config):
  445. """
  446. Extracts block device mapping information
  447. from a launch config and constructs a BlockDeviceMappingV2
  448. object.
  449. """
  450. bdm = []
  451. for device in launch_config.block_devices:
  452. bdm_dict = dict()
  453. if device.is_volume:
  454. bdm_dict['destination_type'] = 'volume'
  455. if device.is_root:
  456. bdm_dict['device_name'] = '/dev/sda'
  457. bdm_dict['boot_index'] = 0
  458. if isinstance(device.source, Snapshot):
  459. bdm_dict['source_type'] = 'snapshot'
  460. bdm_dict['uuid'] = device.source.id
  461. elif isinstance(device.source, Volume):
  462. bdm_dict['source_type'] = 'volume'
  463. bdm_dict['uuid'] = device.source.id
  464. elif isinstance(device.source, MachineImage):
  465. bdm_dict['source_type'] = 'image'
  466. bdm_dict['uuid'] = device.source.id
  467. else:
  468. bdm_dict['source_type'] = 'blank'
  469. if device.delete_on_terminate is not None:
  470. bdm_dict[
  471. 'delete_on_termination'] = device.delete_on_terminate
  472. if device.size:
  473. bdm_dict['volume_size'] = device.size
  474. else:
  475. bdm_dict['destination_type'] = 'local'
  476. bdm_dict['source_type'] = 'blank'
  477. bdm_dict['delete_on_termination'] = True
  478. bdm.append(bdm_dict)
  479. return bdm
  480. def _has_root_device(self, launch_config):
  481. if not launch_config:
  482. return False
  483. for device in launch_config.block_devices:
  484. if device.is_root:
  485. return True
  486. return False
  487. def _format_nics(self, launch_config):
  488. """
  489. Format network IDs for the API call.
  490. """
  491. nics = []
  492. for net_id in launch_config.network_interfaces:
  493. nics.append({'net-id': net_id})
  494. return nics
  495. def create_launch_config(self):
  496. return BaseLaunchConfig(self.provider)
  497. def find(self, name, limit=None, marker=None):
  498. """
  499. Searches for an instance by a given list of attributes.
  500. """
  501. search_opts = {'name': name}
  502. cb_insts = [
  503. OpenStackInstance(self.provider, inst)
  504. for inst in self.provider.nova.servers.list(
  505. search_opts=search_opts,
  506. limit=oshelpers.os_result_limit(self.provider, limit),
  507. marker=marker)]
  508. return oshelpers.to_server_paged_list(self.provider, cb_insts, limit)
  509. def list(self, limit=None, marker=None):
  510. """
  511. List all instances.
  512. """
  513. cb_insts = [
  514. OpenStackInstance(self.provider, inst)
  515. for inst in self.provider.nova.servers.list(
  516. limit=oshelpers.os_result_limit(self.provider, limit),
  517. marker=marker)]
  518. return oshelpers.to_server_paged_list(self.provider, cb_insts, limit)
  519. def get(self, instance_id):
  520. """
  521. Returns an instance given its id.
  522. """
  523. try:
  524. os_instance = self.provider.nova.servers.get(instance_id)
  525. return OpenStackInstance(self.provider, os_instance)
  526. except NovaNotFound:
  527. return None
  528. class OpenStackNetworkService(BaseNetworkService):
  529. def __init__(self, provider):
  530. super(OpenStackNetworkService, self).__init__(provider)
  531. self._subnet_svc = OpenStackSubnetService(self.provider)
  532. def get(self, network_id):
  533. network = (n for n in self.list() if n.id == network_id)
  534. return next(network, None)
  535. def list(self, limit=None, marker=None):
  536. networks = [OpenStackNetwork(self.provider, network)
  537. for network in self.provider.neutron.list_networks()
  538. .get('networks', [])]
  539. return ClientPagedResultList(self.provider, networks,
  540. limit=limit, marker=marker)
  541. def create(self, name=''):
  542. net_info = {'name': name}
  543. network = self.provider.neutron.create_network({'network': net_info})
  544. return OpenStackNetwork(self.provider, network.get('network'))
  545. @property
  546. def subnets(self):
  547. return self._subnet_svc
  548. class OpenStackSubnetService(BaseSubnetService):
  549. def __init__(self, provider):
  550. super(OpenStackSubnetService, self).__init__(provider)
  551. def get(self, subnet_id):
  552. subnet = (s for s in self.list() if s.id == subnet_id)
  553. return next(subnet, None)
  554. def list(self, network=None):
  555. if network:
  556. network_id = (network.id if isinstance(network, OpenStackNetwork)
  557. else network)
  558. subnets = self.list()
  559. return [subnet for subnet in subnets if network_id in
  560. subnet.network_id]
  561. subnets = self.provider.neutron.list_subnets().get('subnets', [])
  562. return [OpenStackSubnet(self.provider, subnet) for subnet in subnets]
  563. def create(self, network, cidr_block, name=''):
  564. network_id = (network.id if isinstance(network, OpenStackNetwork)
  565. else network)
  566. subnet_info = {'name': name, 'network_id': network_id,
  567. 'cidr': cidr_block, 'ip_version': 4}
  568. subnet = (self.provider.neutron.create_subnet({'subnet': subnet_info})
  569. .get('subnet'))
  570. return OpenStackSubnet(self.provider, subnet)
  571. def delete(self, subnet):
  572. subnet_id = (subnet.id if isinstance(subnet, OpenStackSubnet)
  573. else subnet)
  574. self.provider.neutron.delete_subnet(subnet_id)
  575. # Adhear to the interface docs
  576. if subnet_id not in self.list():
  577. return True
  578. return False