resources.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. """
  2. DataTypes used by this provider
  3. """
  4. from cloudbridge.providers.base import BaseInstance
  5. from cloudbridge.providers.base import BaseKeyPair
  6. from cloudbridge.providers.base import BaseMachineImage
  7. from cloudbridge.providers.base import BaseSecurityGroup
  8. from cloudbridge.providers.base import BaseSnapshot
  9. from cloudbridge.providers.base import BaseVolume
  10. from cloudbridge.providers.interfaces import InstanceState
  11. from cloudbridge.providers.interfaces import InstanceType
  12. from cloudbridge.providers.interfaces import MachineImageState
  13. from cloudbridge.providers.interfaces import PlacementZone
  14. from cloudbridge.providers.interfaces import Region
  15. from cloudbridge.providers.interfaces import SnapshotState
  16. from cloudbridge.providers.interfaces import VolumeState
  17. class OpenStackMachineImage(BaseMachineImage):
  18. # ref: http://docs.openstack.org/developer/glance/statuses.html
  19. IMAGE_STATE_MAP = {
  20. 'QUEUED': MachineImageState.PENDING,
  21. 'SAVING': MachineImageState.PENDING,
  22. 'ACTIVE': MachineImageState.AVAILABLE,
  23. 'KILLED': MachineImageState.ERROR,
  24. 'DELETED': MachineImageState.ERROR,
  25. 'PENDING_DELETE': MachineImageState.ERROR
  26. }
  27. def __init__(self, provider, os_image):
  28. self.provider = provider
  29. if isinstance(os_image, OpenStackMachineImage):
  30. self._os_image = os_image._os_image
  31. else:
  32. self._os_image = os_image
  33. @property
  34. def image_id(self):
  35. """
  36. Get the image identifier.
  37. :rtype: ``str``
  38. :return: ID for this instance as returned by the cloud middleware.
  39. """
  40. return self._os_image.id
  41. @property
  42. def name(self):
  43. """
  44. Get the image name.
  45. :rtype: ``str``
  46. :return: Name for this image as returned by the cloud middleware.
  47. """
  48. return self._os_image.name
  49. @property
  50. def description(self):
  51. """
  52. Get the image description.
  53. :rtype: ``str``
  54. :return: Description for this image as returned by the cloud middleware
  55. """
  56. return self._os_image.description
  57. def delete(self):
  58. """
  59. Delete this image
  60. """
  61. self._os_image.delete()
  62. @property
  63. def state(self):
  64. return OpenStackMachineImage.IMAGE_STATE_MAP.get(
  65. self._os_image.status, MachineImageState.UNKNOWN)
  66. def refresh(self):
  67. """
  68. Refreshes the state of this instance by re-querying the cloud provider
  69. for its latest state.
  70. """
  71. image = self.provider.images.get_image(self.image_id)
  72. if image:
  73. self._os_image = image._os_image
  74. else:
  75. # The image no longer exists and cannot be refreshed.
  76. # set the status to unknown
  77. self._os_image.status = 'unknown'
  78. class OpenStackPlacementZone(PlacementZone):
  79. def __init__(self, provider, zone):
  80. self.provider = provider
  81. if isinstance(zone, OpenStackPlacementZone):
  82. self._os_zone = zone._os_zone
  83. else:
  84. self._os_zone = zone
  85. @property
  86. def name(self):
  87. """
  88. Get the zone name.
  89. :rtype: ``str``
  90. :return: Name for this zone as returned by the cloud middleware.
  91. """
  92. # return self._os_zone.zoneName
  93. return self._os_zone
  94. @property
  95. def region(self):
  96. """
  97. Get the region that this zone belongs to.
  98. :rtype: ``str``
  99. :return: Name of this zone's region as returned by the cloud middleware
  100. """
  101. return self._os_zone.region_name
  102. class OpenStackInstanceType(InstanceType):
  103. def __init__(self, os_flavor):
  104. self.os_flavor = os_flavor
  105. @property
  106. def id(self):
  107. return self.os_flavor.id
  108. @property
  109. def name(self):
  110. return self.os_flavor.name
  111. def __repr__(self):
  112. return "<CB-OSInstanceType: {0}={1}>".format(self.id, self.name)
  113. class OpenStackInstance(BaseInstance):
  114. # ref: http://docs.openstack.org/developer/nova/v2/2.0_server_concepts.html
  115. # and http://developer.openstack.org/api-ref-compute-v2.html
  116. INSTANCE_STATE_MAP = {
  117. 'ACTIVE': InstanceState.RUNNING,
  118. 'BUILD': InstanceState.PENDING,
  119. 'DELETED': InstanceState.TERMINATED,
  120. 'ERROR': InstanceState.ERROR,
  121. 'HARD_REBOOT': InstanceState.REBOOTING,
  122. 'PASSWORD': InstanceState.PENDING,
  123. 'PAUSED': InstanceState.STOPPED,
  124. 'REBOOT': InstanceState.REBOOTING,
  125. 'REBUILD': InstanceState.CONFIGURING,
  126. 'RESCUE': InstanceState.CONFIGURING,
  127. 'RESIZE': InstanceState.CONFIGURING,
  128. 'REVERT_RESIZE': InstanceState.CONFIGURING,
  129. 'SOFT_DELETED': InstanceState.STOPPED,
  130. 'STOPPED': InstanceState.STOPPED,
  131. 'SUSPENDED': InstanceState.STOPPED,
  132. 'SHUTOFF': InstanceState.STOPPED,
  133. 'UNKNOWN': InstanceState.UNKNOWN,
  134. 'VERIFY_RESIZE': InstanceState.CONFIGURING
  135. }
  136. def __init__(self, provider, os_instance):
  137. self.provider = provider
  138. self._os_instance = os_instance
  139. @property
  140. def instance_id(self):
  141. """
  142. Get the instance identifier.
  143. """
  144. return self._os_instance.id
  145. @property
  146. def name(self):
  147. """
  148. Get the instance name.
  149. """
  150. return self._os_instance.name
  151. @name.setter
  152. def name(self, value):
  153. """
  154. Set the instance name.
  155. """
  156. self._os_instance.name = value
  157. self._os_instance.update()
  158. @property
  159. def public_ips(self):
  160. """
  161. Get all the public IP addresses for this instance.
  162. """
  163. return self._os_instance.networks['public']
  164. @property
  165. def private_ips(self):
  166. """
  167. Get all the private IP addresses for this instance.
  168. """
  169. return self._os_instance.networks['private']
  170. @property
  171. def instance_type(self):
  172. """
  173. Get the instance type.
  174. """
  175. return OpenStackInstanceType(self._os_instance.flavor)
  176. def reboot(self):
  177. """
  178. Reboot this instance (using the cloud middleware API).
  179. """
  180. self._os_instance.reboot()
  181. def terminate(self):
  182. """
  183. Permanently terminate this instance.
  184. """
  185. self._os_instance.delete()
  186. @property
  187. def image_id(self):
  188. """
  189. Get the image ID for this instance.
  190. """
  191. return self._os_instance.image_id
  192. @property
  193. def placement_zone(self):
  194. """
  195. Get the placement zone where this instance is running.
  196. """
  197. return OpenStackPlacementZone(
  198. self.provider,
  199. getattr(self._os_instance, 'OS-EXT-AZ:availability_zone', None))
  200. @property
  201. def mac_address(self):
  202. """
  203. Get the MAC address for this instance.
  204. """
  205. raise NotImplementedError(
  206. 'mac_address not implemented by this provider')
  207. @property
  208. def security_group_ids(self):
  209. """
  210. Get the security group IDs associated with this instance.
  211. """
  212. return [BaseSecurityGroup(group.id, group.name, group.description)
  213. for group in self._os_instance.security_groups]
  214. @property
  215. def key_pair_name(self):
  216. """
  217. Get the name of the key pair associated with this instance.
  218. """
  219. return BaseKeyPair(self._os_instance.key_name)
  220. def create_image(self, name):
  221. """
  222. Create a new image based on this instance.
  223. """
  224. image_id = self._os_instance.create_image(name)
  225. return OpenStackMachineImage(
  226. self.provider, self.provider.images.get_image(image_id))
  227. @property
  228. def state(self):
  229. return OpenStackInstance.INSTANCE_STATE_MAP.get(
  230. self._os_instance.status, InstanceState.UNKNOWN)
  231. def refresh(self):
  232. """
  233. Refreshes the state of this instance by re-querying the cloud provider
  234. for its latest state.
  235. """
  236. instance = self.provider.compute.get_instance(
  237. self.instance_id)
  238. if instance:
  239. self._os_instance = instance._os_instance
  240. else:
  241. # The instance no longer exists and cannot be refreshed.
  242. # set the status to unknown
  243. self._os_instance.status = 'unknown'
  244. def __repr__(self):
  245. return "<CB-OSInstance: {0}({1})>".format(self.name, self.instance_id)
  246. class OpenStackRegion(Region):
  247. def __init__(self, provider, os_region):
  248. self.provider = provider
  249. self._os_region = os_region
  250. @property
  251. def name(self):
  252. return self._os_region.zoneName
  253. def __repr__(self):
  254. return "<CB-OSRegion: {0}>".format(self.name)
  255. class OpenStackVolume(BaseVolume):
  256. # Ref: http://developer.openstack.org/api-ref-blockstorage-v2.html
  257. VOLUME_STATE_MAP = {
  258. 'creating': VolumeState.CREATING,
  259. 'available': VolumeState.AVAILABLE,
  260. 'attaching': VolumeState.CONFIGURING,
  261. 'in-use': VolumeState.IN_USE,
  262. 'deleting': VolumeState.CONFIGURING,
  263. 'error': VolumeState.ERROR,
  264. 'error_deleting': VolumeState.ERROR,
  265. 'backing-up': VolumeState.CONFIGURING,
  266. 'restoring-backup': VolumeState.CONFIGURING,
  267. 'error_restoring': VolumeState.ERROR,
  268. 'error_extending': VolumeState.ERROR
  269. }
  270. def __init__(self, provider, volume):
  271. self.provider = provider
  272. self._volume = volume
  273. @property
  274. def volume_id(self):
  275. return self._volume.id
  276. @property
  277. def name(self):
  278. """
  279. Get the volume name.
  280. """
  281. return self._volume.name
  282. @name.setter
  283. def name(self, value):
  284. """
  285. Set the volume name.
  286. """
  287. self._volume.name = value
  288. self._volume.update()
  289. def attach(self, instance, device):
  290. """
  291. Attach this volume to an instance.
  292. """
  293. instance_id = instance.instance_id if isinstance(
  294. instance,
  295. OpenStackInstance) else instance
  296. self._volume.attach(instance_id, device)
  297. def detach(self, force=False):
  298. """
  299. Detach this volume from an instance.
  300. """
  301. self._volume.detach()
  302. def create_snapshot(self, name, description=None):
  303. """
  304. Create a snapshot of this Volume.
  305. """
  306. return self.provider.block_store.snapshots.create_snapshot(
  307. name, self, description=description)
  308. def delete(self):
  309. """
  310. Delete this volume.
  311. """
  312. self._volume.delete()
  313. @property
  314. def state(self):
  315. return OpenStackVolume.VOLUME_STATE_MAP.get(
  316. self._volume.status, VolumeState.UNKNOWN)
  317. def refresh(self):
  318. """
  319. Refreshes the state of this volume by re-querying the cloud provider
  320. for its latest state.
  321. """
  322. vol = self.provider.block_store.volumes.get_volume(
  323. self.volume_id)
  324. if vol:
  325. self._volume = vol._volume
  326. else:
  327. # The volume no longer exists and cannot be refreshed.
  328. # set the status to unknown
  329. self._volume.status = 'unknown'
  330. def __repr__(self):
  331. return "<CB-OSVolume: {0} ({1})>".format(self.volume_id, self.name)
  332. class OpenStackSnapshot(BaseSnapshot):
  333. # Ref: http://developer.openstack.org/api-ref-blockstorage-v2.html
  334. SNAPSHOT_STATE_MAP = {
  335. 'creating': SnapshotState.PENDING,
  336. 'available': SnapshotState.AVAILABLE,
  337. 'deleting': SnapshotState.CONFIGURING,
  338. 'error': SnapshotState.ERROR,
  339. 'error_deleting': SnapshotState.ERROR
  340. }
  341. def __init__(self, provider, snapshot):
  342. self.provider = provider
  343. self._snapshot = snapshot
  344. @property
  345. def snapshot_id(self):
  346. return self._snapshot.id
  347. @property
  348. def name(self):
  349. """
  350. Get the snapshot name.
  351. """
  352. return self._snapshot.name
  353. @name.setter
  354. def name(self, value):
  355. """
  356. Set the snapshot name.
  357. """
  358. self._snapshot.add_tag('Name', value)
  359. self._snapshot.update()
  360. @property
  361. def state(self):
  362. return OpenStackSnapshot.SNAPSHOT_STATE_MAP.get(
  363. self._snapshot.status, SnapshotState.UNKNOWN)
  364. def refresh(self):
  365. """
  366. Refreshes the state of this snapshot by re-querying the cloud provider
  367. for its latest state.
  368. """
  369. snap = self.provider.block_store.snapshots.get_snapshot(
  370. self.snapshot_id)
  371. if snap:
  372. self._snapshot = snap._snapshot
  373. else:
  374. # The snapshot no longer exists and cannot be refreshed.
  375. # set the status to unknown
  376. self._snapshot.status = 'unknown'
  377. def delete(self):
  378. """
  379. Delete this snapshot.
  380. """
  381. self._snapshot.delete()
  382. def __repr__(self):
  383. return "<CB-OSSnapshot: {0} ({1}>".format(self.snapshot_id, self.name)