test_cloud.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. # -*- coding: utf-8 -*-
  2. '''
  3. :codeauthor: Jayesh Kariya <jayeshk@saltstack.com>
  4. '''
  5. # Import Python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. # Import Salt Testing Libs
  8. from tests.support.mixins import LoaderModuleMockMixin
  9. from tests.support.unit import TestCase
  10. from tests.support.mock import (
  11. MagicMock,
  12. patch)
  13. # Import Salt Libs
  14. import salt.states.cloud as cloud
  15. import salt.utils.cloud
  16. class CloudTestCase(TestCase, LoaderModuleMockMixin):
  17. '''
  18. Test cases for salt.states.cloud
  19. '''
  20. def setup_loader_modules(self):
  21. return {cloud: {}}
  22. # 'present' function tests: 1
  23. def test_present(self):
  24. '''
  25. Test to spin up a single instance on a cloud provider, using salt-cloud.
  26. '''
  27. name = 'mycloud'
  28. cloud_provider = 'my_cloud_provider'
  29. ret = {'name': name,
  30. 'result': True,
  31. 'changes': {},
  32. 'comment': ''}
  33. mock = MagicMock(side_effect=[True, False])
  34. mock_bool = MagicMock(side_effect=[True, False, False])
  35. mock_dict = MagicMock(return_value={'cloud': 'saltcloud'})
  36. with patch.dict(cloud.__salt__, {'cmd.retcode': mock,
  37. 'cloud.has_instance': mock_bool,
  38. 'cloud.create': mock_dict}):
  39. comt = ('onlyif condition is false')
  40. ret.update({'comment': comt})
  41. self.assertDictEqual(cloud.present(name, cloud_provider,
  42. onlyif=False), ret)
  43. self.assertDictEqual(cloud.present(name, cloud_provider, onlyif=''),
  44. ret)
  45. comt = ('unless condition is true')
  46. ret.update({'comment': comt})
  47. self.assertDictEqual(cloud.present(name, cloud_provider,
  48. unless=True), ret)
  49. self.assertDictEqual(cloud.present(name, cloud_provider, unless=''),
  50. ret)
  51. comt = ('Already present instance {0}'.format(name))
  52. ret.update({'comment': comt})
  53. self.assertDictEqual(cloud.present(name, cloud_provider), ret)
  54. with patch.dict(cloud.__opts__, {'test': True}):
  55. comt = ('Instance {0} needs to be created'.format(name))
  56. ret.update({'comment': comt, 'result': None})
  57. self.assertDictEqual(cloud.present(name, cloud_provider), ret)
  58. with patch.dict(cloud.__opts__, {'test': False}):
  59. comt = ('Created instance mycloud using provider '
  60. 'my_cloud_provider and the following options: {}')
  61. ret.update({'comment': comt, 'result': True,
  62. 'changes': {'cloud': 'saltcloud'}})
  63. self.assertDictEqual(cloud.present(name, cloud_provider), ret)
  64. # 'absent' function tests: 1
  65. def test_absent(self):
  66. '''
  67. Test to ensure that no instances with the specified names exist.
  68. '''
  69. name = 'mycloud'
  70. ret = {'name': name,
  71. 'result': True,
  72. 'changes': {},
  73. 'comment': ''}
  74. mock = MagicMock(side_effect=[True, False])
  75. mock_bool = MagicMock(side_effect=[False, True, True])
  76. mock_dict = MagicMock(return_value={'cloud': 'saltcloud'})
  77. with patch.dict(cloud.__salt__, {'cmd.retcode': mock,
  78. 'cloud.has_instance': mock_bool,
  79. 'cloud.destroy': mock_dict}):
  80. comt = ('onlyif condition is false')
  81. ret.update({'comment': comt})
  82. self.assertDictEqual(cloud.absent(name, onlyif=False), ret)
  83. self.assertDictEqual(cloud.absent(name, onlyif=''), ret)
  84. comt = ('unless condition is true')
  85. ret.update({'comment': comt})
  86. self.assertDictEqual(cloud.absent(name, unless=True), ret)
  87. self.assertDictEqual(cloud.absent(name, unless=''), ret)
  88. comt = ('Already absent instance {0}'.format(name))
  89. ret.update({'comment': comt})
  90. self.assertDictEqual(cloud.absent(name), ret)
  91. with patch.dict(cloud.__opts__, {'test': True}):
  92. comt = ('Instance {0} needs to be destroyed'.format(name))
  93. ret.update({'comment': comt, 'result': None})
  94. self.assertDictEqual(cloud.absent(name), ret)
  95. with patch.dict(cloud.__opts__, {'test': False}):
  96. comt = (('Destroyed instance {0}').format(name))
  97. ret.update({'comment': comt, 'result': True,
  98. 'changes': {'cloud': 'saltcloud'}})
  99. self.assertDictEqual(cloud.absent(name), ret)
  100. # 'profile' function tests: 1
  101. def test_profile(self):
  102. '''
  103. Test to create a single instance on a cloud provider,
  104. using a salt-cloud profile.
  105. '''
  106. name = 'mycloud'
  107. profile = 'myprofile'
  108. ret = {'name': name,
  109. 'result': True,
  110. 'changes': {},
  111. 'comment': ''}
  112. mock = MagicMock(side_effect=[True, False])
  113. mock_dict = MagicMock(side_effect=[{'cloud': 'saltcloud'},
  114. {'Not Actioned': True},
  115. {'Not Actioned': True},
  116. {
  117. 'Not Found': True,
  118. 'Not Actioned/Not Running': True
  119. }])
  120. mock_d = MagicMock(return_value={})
  121. with patch.dict(cloud.__salt__, {'cmd.retcode': mock,
  122. 'cloud.profile': mock_d,
  123. 'cloud.action': mock_dict}):
  124. comt = ('onlyif condition is false')
  125. ret.update({'comment': comt})
  126. self.assertDictEqual(cloud.profile(name, profile, onlyif=False),
  127. ret)
  128. self.assertDictEqual(cloud.profile(name, profile, onlyif=''), ret)
  129. comt = ('unless condition is true')
  130. ret.update({'comment': comt})
  131. self.assertDictEqual(cloud.profile(name, profile, unless=True), ret)
  132. self.assertDictEqual(cloud.profile(name, profile, unless=''), ret)
  133. comt = ('Already present instance {0}'.format(name))
  134. ret.update({'comment': comt})
  135. self.assertDictEqual(cloud.profile(name, profile), ret)
  136. with patch.dict(cloud.__opts__, {'test': True}):
  137. comt = ('Instance {0} needs to be created'.format(name))
  138. ret.update({'comment': comt, 'result': None})
  139. self.assertDictEqual(cloud.profile(name, profile), ret)
  140. with patch.dict(cloud.__opts__, {'test': False}):
  141. comt = (('Failed to create instance {0}'
  142. 'using profile {1}').format(name, profile))
  143. ret.update({'comment': comt, 'result': False})
  144. self.assertDictEqual(cloud.profile(name, profile), ret)
  145. with patch.dict(cloud.__opts__, {'test': False}):
  146. comt = (('Failed to create instance {0}'
  147. 'using profile {1}').format(name, profile))
  148. ret.update({'comment': comt, 'result': False})
  149. self.assertDictEqual(cloud.profile(name, profile), ret)
  150. # 'volume_present' function tests: 1
  151. def test_volume_present(self):
  152. '''
  153. Test to check that a block volume exists.
  154. '''
  155. name = 'mycloud'
  156. ret = {'name': name,
  157. 'result': False,
  158. 'changes': {},
  159. 'comment': ''}
  160. mock = MagicMock(return_value=name)
  161. mock_lst = MagicMock(side_effect=[[name], [], []])
  162. with patch.dict(cloud.__salt__, {'cloud.volume_list': mock_lst,
  163. 'cloud.volume_create': mock}):
  164. with patch.object(salt.utils.cloud, 'check_name',
  165. MagicMock(return_value=True)):
  166. comt = ('Invalid characters in name.')
  167. ret.update({'comment': comt})
  168. self.assertDictEqual(cloud.volume_present(name), ret)
  169. comt = ('Volume exists: {0}'.format(name))
  170. ret.update({'comment': comt, 'result': True})
  171. self.assertDictEqual(cloud.volume_present(name), ret)
  172. with patch.dict(cloud.__opts__, {'test': True}):
  173. comt = ('Volume {0} will be created.'.format(name))
  174. ret.update({'comment': comt, 'result': None})
  175. self.assertDictEqual(cloud.volume_present(name), ret)
  176. with patch.dict(cloud.__opts__, {'test': False}):
  177. comt = ('Volume {0} was created'.format(name))
  178. ret.update({'comment': comt, 'result': True,
  179. 'changes': {'old': None, 'new': name}})
  180. self.assertDictEqual(cloud.volume_present(name), ret)
  181. # 'volume_absent' function tests: 1
  182. def test_volume_absent(self):
  183. '''
  184. Test to check that a block volume exists.
  185. '''
  186. name = 'mycloud'
  187. ret = {'name': name,
  188. 'result': False,
  189. 'changes': {},
  190. 'comment': ''}
  191. mock = MagicMock(return_value=False)
  192. mock_lst = MagicMock(side_effect=[[], [name], [name]])
  193. with patch.dict(cloud.__salt__, {'cloud.volume_list': mock_lst,
  194. 'cloud.volume_delete': mock}):
  195. with patch.object(salt.utils.cloud, 'check_name',
  196. MagicMock(return_value=True)):
  197. comt = ('Invalid characters in name.')
  198. ret.update({'comment': comt})
  199. self.assertDictEqual(cloud.volume_absent(name), ret)
  200. comt = ('Volume is absent.')
  201. ret.update({'comment': comt, 'result': True})
  202. self.assertDictEqual(cloud.volume_absent(name), ret)
  203. with patch.dict(cloud.__opts__, {'test': True}):
  204. comt = ('Volume {0} will be deleted.'.format(name))
  205. ret.update({'comment': comt, 'result': None})
  206. self.assertDictEqual(cloud.volume_absent(name), ret)
  207. with patch.dict(cloud.__opts__, {'test': False}):
  208. comt = ('Volume {0} failed to delete.'.format(name))
  209. ret.update({'comment': comt, 'result': False})
  210. self.assertDictEqual(cloud.volume_absent(name), ret)
  211. # 'volume_attached' function tests: 1
  212. def test_volume_attached(self):
  213. '''
  214. Test to check if a block volume is attached.
  215. '''
  216. name = 'mycloud'
  217. server_name = 'mycloud_server'
  218. disk_name = 'trogdor'
  219. ret = {'name': name,
  220. 'result': False,
  221. 'changes': {},
  222. 'comment': ''}
  223. mock = MagicMock(return_value=False)
  224. mock_dict = MagicMock(side_effect=[{name: {'name': disk_name, 'attachments': True}}, {},
  225. {name: {'name': disk_name, 'attachments': False}},
  226. {name: {'name': disk_name, 'attachments': False}},
  227. {name: {'name': disk_name, 'attachments': False}}])
  228. with patch.dict(cloud.__salt__, {'cloud.volume_list': mock_dict,
  229. 'cloud.action': mock}):
  230. with patch.object(salt.utils.cloud, 'check_name',
  231. MagicMock(side_effect=[True, False, True])):
  232. comt = ('Invalid characters in name.')
  233. ret.update({'comment': comt})
  234. self.assertDictEqual(cloud.volume_attached(name, server_name),
  235. ret)
  236. ret.update({'name': server_name})
  237. self.assertDictEqual(cloud.volume_attached(name, server_name),
  238. ret)
  239. comt = ('Volume {0} is already attached: True'.format(disk_name))
  240. ret.update({'comment': comt, 'result': True})
  241. self.assertDictEqual(cloud.volume_attached(name, server_name), ret)
  242. comt = ('Volume {0} does not exist'.format(name))
  243. ret.update({'comment': comt, 'result': False})
  244. self.assertDictEqual(cloud.volume_attached(name, server_name), ret)
  245. comt = ('Server {0} does not exist'.format(server_name))
  246. ret.update({'comment': comt, 'result': False})
  247. self.assertDictEqual(cloud.volume_attached(name, server_name), ret)
  248. mock = MagicMock(return_value=True)
  249. with patch.dict(cloud.__salt__, {'cloud.action': mock,
  250. 'cloud.volume_attach': mock}):
  251. with patch.dict(cloud.__opts__, {'test': True}):
  252. comt = ('Volume {0} will be will be attached.'.format(name))
  253. ret.update({'comment': comt, 'result': None})
  254. self.assertDictEqual(cloud.volume_attached(name,
  255. server_name),
  256. ret)
  257. with patch.dict(cloud.__opts__, {'test': False}):
  258. comt = ('Volume {0} was created'.format(name))
  259. ret.update({'comment': comt, 'result': True,
  260. 'changes': {'new': True,
  261. 'old': {'name': disk_name,
  262. 'attachments': False}}})
  263. self.assertDictEqual(cloud.volume_attached(name,
  264. server_name),
  265. ret)
  266. # 'volume_detached' function tests: 1
  267. def test_volume_detached(self):
  268. '''
  269. Test to check if a block volume is detached.
  270. '''
  271. name = 'mycloud'
  272. server_name = 'mycloud_server'
  273. disk_name = 'trogdor'
  274. ret = {'name': name,
  275. 'result': False,
  276. 'changes': {},
  277. 'comment': ''}
  278. mock = MagicMock(return_value=False)
  279. mock_dict = MagicMock(side_effect=[{name: {'name': disk_name, 'attachments': False}}, {},
  280. {name: {'name': disk_name, 'attachments': True}},
  281. {name: {'name': disk_name, 'attachments': True}},
  282. {name: {'name': disk_name, 'attachments': True}}])
  283. with patch.dict(cloud.__salt__, {'cloud.volume_list': mock_dict,
  284. 'cloud.action': mock}):
  285. with patch.object(salt.utils.cloud, 'check_name',
  286. MagicMock(side_effect=[True, False, True])):
  287. comt = ('Invalid characters in name.')
  288. ret.update({'comment': comt})
  289. self.assertDictEqual(cloud.volume_detached(name, server_name),
  290. ret)
  291. ret.update({'name': server_name})
  292. self.assertDictEqual(cloud.volume_detached(name, server_name),
  293. ret)
  294. comt = ('Volume {0} is not currently attached to anything.'.format(disk_name))
  295. ret.update({'comment': comt, 'result': True})
  296. self.assertDictEqual(cloud.volume_detached(name, server_name), ret)
  297. comt = ('Volume {0} does not exist'.format(name))
  298. ret.update({'comment': comt})
  299. self.assertDictEqual(cloud.volume_detached(name, server_name), ret)
  300. comt = ('Server {0} does not exist'.format(server_name))
  301. ret.update({'comment': comt})
  302. self.assertDictEqual(cloud.volume_detached(name, server_name), ret)
  303. mock = MagicMock(return_value=True)
  304. with patch.dict(cloud.__salt__, {'cloud.action': mock,
  305. 'cloud.volume_detach': mock}):
  306. with patch.dict(cloud.__opts__, {'test': True}):
  307. comt = ('Volume {0} will be will be detached.'.format(name))
  308. ret.update({'comment': comt, 'result': None})
  309. self.assertDictEqual(cloud.volume_detached(name,
  310. server_name),
  311. ret)
  312. with patch.dict(cloud.__opts__, {'test': False}):
  313. comt = ('Volume {0} was created'.format(name))
  314. ret.update({'comment': comt, 'result': True,
  315. 'changes': {'new': True,
  316. 'old': {'name': disk_name,
  317. 'attachments': True}}})
  318. self.assertDictEqual(cloud.volume_detached(name,
  319. server_name),
  320. ret)