test_libcloud_compute.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: :email:`Anthony Shaw <anthonyshaw@apache.org>`
  4. '''
  5. # Import Python Libs
  6. from __future__ import absolute_import, unicode_literals, print_function
  7. import logging
  8. from salt.utils.versions import LooseVersion as _LooseVersion
  9. # Import Salt Testing Libs
  10. from tests.support.mixins import LoaderModuleMockMixin
  11. from tests.support.unit import TestCase, skipIf
  12. from tests.support.mock import (
  13. patch,
  14. MagicMock,
  15. )
  16. import salt.modules.libcloud_compute as libcloud_compute
  17. REQUIRED_LIBCLOUD_VERSION = '2.0.0'
  18. try:
  19. import libcloud
  20. from libcloud.compute.base import (
  21. BaseDriver, Node,
  22. NodeSize, NodeState, NodeLocation,
  23. StorageVolume, StorageVolumeState,
  24. VolumeSnapshot, NodeImage, KeyPair)
  25. if hasattr(libcloud, '__version__') and _LooseVersion(libcloud.__version__) < _LooseVersion(REQUIRED_LIBCLOUD_VERSION):
  26. raise ImportError()
  27. logging.getLogger('libcloud').setLevel(logging.CRITICAL)
  28. HAS_LIBCLOUD = True
  29. except ImportError:
  30. HAS_LIBCLOUD = False
  31. if HAS_LIBCLOUD:
  32. class MockComputeDriver(BaseDriver):
  33. def __init__(self): # pylint: disable=W0231
  34. self._TEST_SIZE = NodeSize(
  35. id='test_id', name='test_size',
  36. ram=4096, disk=10240, bandwidth=100000, price=0,
  37. driver=self)
  38. self._TEST_NODE = Node(
  39. id='test_id', name='test_node',
  40. state=NodeState.RUNNING, public_ips=['1.2.3.4'],
  41. private_ips=['2.3.4.5'], driver=self,
  42. size=self._TEST_SIZE, extra={
  43. 'ex_key': 'ex_value'
  44. })
  45. self._TEST_LOCATION = NodeLocation(
  46. id='test_location',
  47. name='location1',
  48. country='Australia',
  49. driver=self)
  50. self._TEST_VOLUME = StorageVolume(
  51. id='vol1',
  52. name='vol_name',
  53. size=40960,
  54. driver=self,
  55. state=StorageVolumeState.AVAILABLE,
  56. extra={
  57. 'ex_key': 'ex_value'
  58. }
  59. )
  60. self._TEST_VOLUME_SNAPSHOT = VolumeSnapshot(
  61. id='snap1',
  62. size=80960,
  63. driver=self
  64. )
  65. self._TEST_IMAGE = NodeImage(
  66. id='image1',
  67. name='test_image',
  68. extra={
  69. 'ex_key': 'ex_value'
  70. },
  71. driver=self
  72. )
  73. self._TEST_KEY_PAIR = KeyPair(
  74. name='test_key',
  75. fingerprint='abc123',
  76. public_key='pub123',
  77. private_key='priv123',
  78. driver=self,
  79. extra={
  80. 'ex_key': 'ex_value'
  81. }
  82. )
  83. def list_nodes(self):
  84. return [self._TEST_NODE]
  85. def list_sizes(self, location=None):
  86. if location:
  87. assert location.id == 'test_location'
  88. return [self._TEST_SIZE]
  89. def list_locations(self):
  90. return [self._TEST_LOCATION]
  91. def reboot_node(self, node):
  92. assert node.id == 'test_id'
  93. return True
  94. def destroy_node(self, node):
  95. assert node.id == 'test_id'
  96. return True
  97. def list_volumes(self):
  98. return [self._TEST_VOLUME]
  99. def list_volume_snapshots(self, volume):
  100. assert volume.id == 'vol1'
  101. return [self._TEST_VOLUME_SNAPSHOT]
  102. def create_volume(self, size, name, location=None, snapshot=None):
  103. assert size == 9000
  104. assert name == 'test_new_volume'
  105. if location:
  106. assert location.country == 'Australia'
  107. return self._TEST_VOLUME
  108. def create_volume_snapshot(self, volume, name=None):
  109. assert volume.id == 'vol1'
  110. if name:
  111. assert name == 'test_snapshot'
  112. return self._TEST_VOLUME_SNAPSHOT
  113. def attach_volume(self, node, volume, device=None):
  114. assert node.id == 'test_id'
  115. assert volume.id == 'vol1'
  116. if device:
  117. assert device == '/dev/sdc'
  118. return True
  119. def detach_volume(self, volume):
  120. assert volume.id == 'vol1'
  121. return True
  122. def destroy_volume(self, volume):
  123. assert volume.id == 'vol1'
  124. return True
  125. def destroy_volume_snapshot(self, snapshot):
  126. assert snapshot.id == 'snap1'
  127. return True
  128. def list_images(self, location=None):
  129. if location:
  130. assert location.id == 'test_location'
  131. return [self._TEST_IMAGE]
  132. def create_image(self, node, name, description=None):
  133. assert node.id == 'test_id'
  134. return self._TEST_IMAGE
  135. def delete_image(self, node_image):
  136. return True
  137. def get_image(self, image_id):
  138. assert image_id == 'image1'
  139. return self._TEST_IMAGE
  140. def copy_image(self, source_region, node_image, name, description=None):
  141. assert source_region == 'us-east1'
  142. assert node_image.id == 'image1'
  143. assert name == 'copy_test'
  144. return self._TEST_IMAGE
  145. def list_key_pairs(self):
  146. return [self._TEST_KEY_PAIR]
  147. def get_key_pair(self, name):
  148. assert name == 'test_key'
  149. return self._TEST_KEY_PAIR
  150. def create_key_pair(self, name):
  151. assert name == 'test_key'
  152. return self._TEST_KEY_PAIR
  153. def import_key_pair_from_string(self, name, key_material):
  154. assert name == 'test_key'
  155. assert key_material == 'test_key_value'
  156. return self._TEST_KEY_PAIR
  157. def import_key_pair_from_file(self, name, key_file_path):
  158. assert name == 'test_key'
  159. assert key_file_path == '/path/to/key'
  160. return self._TEST_KEY_PAIR
  161. def delete_key_pair(self, key_pair):
  162. assert key_pair.name == 'test_key'
  163. return True
  164. else:
  165. MockComputeDriver = object
  166. @skipIf(not HAS_LIBCLOUD, 'No libcloud installed')
  167. @patch('salt.modules.libcloud_compute._get_driver',
  168. MagicMock(return_value=MockComputeDriver()))
  169. class LibcloudComputeModuleTestCase(TestCase, LoaderModuleMockMixin):
  170. def setup_loader_modules(self):
  171. module_globals = {
  172. '__salt__': {
  173. 'config.option': MagicMock(return_value={
  174. 'test': {
  175. 'driver': 'test',
  176. 'key': '2orgk34kgk34g'
  177. }
  178. })
  179. }
  180. }
  181. if libcloud_compute.HAS_LIBCLOUD is False:
  182. module_globals['sys.modules'] = {'libcloud': MagicMock()}
  183. return {libcloud_compute: module_globals}
  184. def test_module_creation(self):
  185. client = libcloud_compute._get_driver('test')
  186. self.assertFalse(client is None)
  187. def test_init(self):
  188. with patch('salt.utils.compat.pack_dunder', return_value=False) as dunder:
  189. libcloud_compute.__init__(None)
  190. dunder.assert_called_with('salt.modules.libcloud_compute')
  191. def _validate_node(self, node):
  192. self.assertEqual(node['name'], 'test_node')
  193. self.assertEqual(node['id'], 'test_id')
  194. self.assertEqual(node['private_ips'], ['2.3.4.5'])
  195. self.assertEqual(node['public_ips'], ['1.2.3.4'])
  196. self.assertEqual(node['size']['name'], 'test_size')
  197. def _validate_size(self, size):
  198. self.assertEqual(size['id'], 'test_id')
  199. self.assertEqual(size['name'], 'test_size')
  200. self.assertEqual(size['ram'], 4096)
  201. def _validate_location(self, location):
  202. self.assertEqual(location['id'], 'test_location')
  203. self.assertEqual(location['name'], 'location1')
  204. self.assertEqual(location['country'], 'Australia')
  205. def _validate_volume(self, volume):
  206. self.assertEqual(volume['id'], 'vol1')
  207. self.assertEqual(volume['name'], 'vol_name')
  208. self.assertEqual(volume['size'], 40960)
  209. self.assertEqual(volume['state'], 'available')
  210. self.assertEqual(volume['extra'], {'ex_key': 'ex_value'})
  211. def _validate_volume_snapshot(self, volume):
  212. self.assertEqual(volume['id'], 'snap1')
  213. self.assertEqual(volume['size'], 80960)
  214. def _validate_image(self, image):
  215. self.assertEqual(image['id'], 'image1')
  216. self.assertEqual(image['name'], 'test_image')
  217. self.assertEqual(image['extra'], {'ex_key': 'ex_value'})
  218. def _validate_key_pair(self, key):
  219. self.assertEqual(key['name'], 'test_key')
  220. self.assertEqual(key['fingerprint'], 'abc123')
  221. self.assertEqual(key['extra'], {'ex_key': 'ex_value'})
  222. def test_list_nodes(self):
  223. nodes = libcloud_compute.list_nodes('test')
  224. self.assertEqual(len(nodes), 1)
  225. self._validate_node(nodes[0])
  226. def test_list_sizes(self):
  227. sizes = libcloud_compute.list_sizes('test')
  228. self.assertEqual(len(sizes), 1)
  229. self._validate_size(sizes[0])
  230. def test_list_sizes_location(self):
  231. sizes = libcloud_compute.list_sizes('test', location_id='test_location')
  232. self.assertEqual(len(sizes), 1)
  233. self._validate_size(sizes[0])
  234. def test_list_locations(self):
  235. locations = libcloud_compute.list_locations('test')
  236. self.assertEqual(len(locations), 1)
  237. self._validate_location(locations[0])
  238. def test_reboot_node(self):
  239. result = libcloud_compute.reboot_node('test_id', 'test')
  240. self.assertTrue(result)
  241. def test_reboot_node_invalid(self):
  242. with self.assertRaises(ValueError):
  243. libcloud_compute.reboot_node('foo_node', 'test')
  244. def test_destroy_node(self):
  245. result = libcloud_compute.destroy_node('test_id', 'test')
  246. self.assertTrue(result)
  247. def test_destroy_node_invalid(self):
  248. with self.assertRaises(ValueError):
  249. libcloud_compute.destroy_node('foo_node', 'test')
  250. def test_list_volumes(self):
  251. volumes = libcloud_compute.list_volumes('test')
  252. self.assertEqual(len(volumes), 1)
  253. self._validate_volume(volumes[0])
  254. def test_list_volume_snapshots(self):
  255. volumes = libcloud_compute.list_volume_snapshots('vol1', 'test')
  256. self.assertEqual(len(volumes), 1)
  257. self._validate_volume_snapshot(volumes[0])
  258. def test_create_volume(self):
  259. volume = libcloud_compute.create_volume(9000, 'test_new_volume', 'test')
  260. self._validate_volume(volume)
  261. def test_create_volume_in_location(self):
  262. volume = libcloud_compute.create_volume(9000, 'test_new_volume', 'test', location_id='test_location')
  263. self._validate_volume(volume)
  264. def test_create_volume_snapshot(self):
  265. snapshot = libcloud_compute.create_volume_snapshot('vol1', 'test')
  266. self._validate_volume_snapshot(snapshot)
  267. def test_create_volume_snapshot_named(self):
  268. snapshot = libcloud_compute.create_volume_snapshot('vol1', 'test', name='test_snapshot')
  269. self._validate_volume_snapshot(snapshot)
  270. def test_attach_volume(self):
  271. result = libcloud_compute.attach_volume('test_id', 'vol1', 'test')
  272. self.assertTrue(result)
  273. def test_detatch_volume(self):
  274. result = libcloud_compute.detach_volume('vol1', 'test')
  275. self.assertTrue(result)
  276. def test_destroy_volume(self):
  277. result = libcloud_compute.destroy_volume('vol1', 'test')
  278. self.assertTrue(result)
  279. def test_destroy_volume_snapshot(self):
  280. result = libcloud_compute.destroy_volume_snapshot('vol1', 'snap1', 'test')
  281. self.assertTrue(result)
  282. def test_list_images(self):
  283. images = libcloud_compute.list_images('test')
  284. self.assertEqual(len(images), 1)
  285. self._validate_image(images[0])
  286. def test_list_images_in_location(self):
  287. images = libcloud_compute.list_images('test', location_id='test_location')
  288. self.assertEqual(len(images), 1)
  289. self._validate_image(images[0])
  290. def test_create_image(self):
  291. image = libcloud_compute.create_image('test_id', 'new_image', 'test')
  292. self._validate_image(image)
  293. def test_delete_image(self):
  294. result = libcloud_compute.delete_image('image1', 'test')
  295. self.assertTrue(result)
  296. def test_get_image(self):
  297. image = libcloud_compute.get_image('image1', 'test')
  298. self._validate_image(image)
  299. def test_copy_image(self):
  300. new_image = libcloud_compute.copy_image('us-east1', 'image1', 'copy_test', 'test')
  301. self._validate_image(new_image)
  302. def test_list_key_pairs(self):
  303. keys = libcloud_compute.list_key_pairs('test')
  304. self.assertEqual(len(keys), 1)
  305. self._validate_key_pair(keys[0])
  306. def test_get_key_pair(self):
  307. key = libcloud_compute.get_key_pair('test_key', 'test')
  308. self._validate_key_pair(key)
  309. def test_create_key_pair(self):
  310. key = libcloud_compute.create_key_pair('test_key', 'test')
  311. self._validate_key_pair(key)
  312. def test_import_key_string(self):
  313. key = libcloud_compute.import_key_pair('test_key', 'test_key_value', 'test')
  314. self._validate_key_pair(key)
  315. def test_import_key_file(self):
  316. key = libcloud_compute.import_key_pair('test_key', '/path/to/key', 'test', key_type='FILE')
  317. self._validate_key_pair(key)
  318. def test_delete_key_pair(self):
  319. result = libcloud_compute.delete_key_pair('test_key', 'test')
  320. self.assertTrue(result)