test_compute_service.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import uuid
  2. import unittest
  3. import ipaddress
  4. import six
  5. from cloudbridge.cloud.interfaces \
  6. import InvalidConfigurationException
  7. from cloudbridge.cloud.interfaces import InstanceState
  8. from cloudbridge.cloud.interfaces.resources import InstanceType
  9. from cloudbridge.cloud.interfaces.resources import WaitStateException
  10. from test.helpers import ProviderTestBase
  11. import test.helpers as helpers
  12. @unittest.skip("Skipping Compute tests")
  13. class CloudComputeServiceTestCase(ProviderTestBase):
  14. def __init__(self, methodName, provider):
  15. super(CloudComputeServiceTestCase, self).__init__(
  16. methodName=methodName, provider=provider)
  17. def test_crud_instance(self):
  18. name = "CBInstCrud-{0}-{1}".format(
  19. self.provider.name,
  20. uuid.uuid4())
  21. net, _ = helpers.create_test_network(self.provider, name)
  22. inst = helpers.get_test_instance(self.provider, name, network=net)
  23. with helpers.cleanup_action(lambda: helpers.cleanup_test_resources(
  24. inst, net)):
  25. all_instances = self.provider.compute.instances.list()
  26. list_instances = [i for i in all_instances if i.name == name]
  27. self.assertTrue(
  28. len(list_instances) == 1,
  29. "List instances does not return the expected instance %s" %
  30. name)
  31. # check iteration
  32. iter_instances = [i for i in self.provider.compute.instances
  33. if i.name == name]
  34. self.assertTrue(
  35. len(iter_instances) == 1,
  36. "Iter instances does not return the expected instance %s" %
  37. name)
  38. # check find
  39. find_instances = self.provider.compute.instances.find(name=name)
  40. self.assertTrue(
  41. len(find_instances) == 1,
  42. "Find instances does not return the expected instance %s" %
  43. name)
  44. # check non-existent find
  45. find_instances = self.provider.compute.instances.find(
  46. name="non_existent")
  47. self.assertTrue(
  48. len(find_instances) == 0,
  49. "Find() for a non-existent image returned %s" % find_instances)
  50. get_inst = self.provider.compute.instances.get(
  51. inst.id)
  52. self.assertTrue(
  53. list_instances[0] ==
  54. get_inst == inst,
  55. "Objects returned by list: {0} and get: {1} are not as "
  56. " expected: {2}" .format(list_instances[0].id,
  57. get_inst.id,
  58. inst.id))
  59. self.assertTrue(
  60. list_instances[0].name ==
  61. get_inst.name == inst.name,
  62. "Names returned by list: {0} and get: {1} are not as "
  63. " expected: {2}" .format(list_instances[0].name,
  64. get_inst.name,
  65. inst.name))
  66. deleted_inst = self.provider.compute.instances.get(
  67. inst.id)
  68. self.assertTrue(
  69. deleted_inst is None or deleted_inst.state in (
  70. InstanceState.TERMINATED,
  71. InstanceState.UNKNOWN),
  72. "Instance %s should have been deleted but still exists." %
  73. name)
  74. def _is_valid_ip(self, address):
  75. try:
  76. ipaddress.ip_address(address)
  77. except ValueError:
  78. return False
  79. return True
  80. def test_instance_properties(self):
  81. name = "CBInstProps-{0}-{1}".format(
  82. self.provider.name,
  83. uuid.uuid4())
  84. net, _ = helpers.create_test_network(self.provider, name)
  85. kp = self.provider.security.key_pairs.create(name=name)
  86. sg = self.provider.security.security_groups.create(
  87. name=name, description=name, network_id=net.id)
  88. test_instance = helpers.get_test_instance(self.provider,
  89. name, key_pair=kp,
  90. security_groups=[sg],
  91. network=net)
  92. with helpers.cleanup_action(lambda: helpers.cleanup_test_resources(
  93. test_instance, net, sg, kp)):
  94. self.assertTrue(
  95. test_instance.id in repr(test_instance),
  96. "repr(obj) should contain the object id so that the object"
  97. " can be reconstructed, but does not. eval(repr(obj)) == obj")
  98. self.assertEqual(
  99. test_instance.name, name,
  100. "Instance name {0} is not equal to the expected name"
  101. " {1}".format(test_instance.name, name))
  102. image_id = helpers.get_provider_test_data(self.provider, "image")
  103. self.assertEqual(test_instance.image_id, image_id,
  104. "Image id {0} is not equal to the expected id"
  105. " {1}".format(test_instance.image_id, image_id))
  106. self.assertIsInstance(test_instance.zone_id,
  107. six.string_types)
  108. # FIXME: Moto is not returning the instance's placement zone
  109. # find_zone = [zone for zone in
  110. # self.provider.compute.regions.current.zones
  111. # if zone.id == test_instance.zone_id]
  112. # self.assertEqual(len(find_zone), 1,
  113. # "Instance's placement zone could not be "
  114. # " found in zones list")
  115. self.assertEqual(
  116. test_instance.image_id,
  117. helpers.get_provider_test_data(self.provider, "image"))
  118. self.assertIsInstance(test_instance.public_ips, list)
  119. self.assertIsInstance(test_instance.private_ips, list)
  120. self.assertEqual(
  121. test_instance.key_pair_name,
  122. kp.name)
  123. self.assertIsInstance(test_instance.security_groups, list)
  124. self.assertEqual(
  125. test_instance.security_groups[0],
  126. sg)
  127. self.assertIsInstance(test_instance.security_group_ids, list)
  128. self.assertEqual(
  129. test_instance.security_group_ids[0],
  130. sg.id)
  131. # Must have either a public or a private ip
  132. ip_private = test_instance.private_ips[0] \
  133. if test_instance.private_ips else None
  134. ip_address = test_instance.public_ips[0] \
  135. if test_instance.public_ips and test_instance.public_ips[0] \
  136. else ip_private
  137. self.assertIsNotNone(
  138. ip_address,
  139. "Instance must have either a public IP or a private IP")
  140. self.assertTrue(
  141. self._is_valid_ip(ip_address),
  142. "Instance must have a valid IP address")
  143. self.assertIsInstance(test_instance.instance_type_id,
  144. six.string_types)
  145. itype = self.provider.compute.instance_types.get(
  146. test_instance.instance_type_id)
  147. self.assertEqual(
  148. itype, test_instance.instance_type,
  149. "Instance type {0} does not match expected type {1}".format(
  150. itype.name, test_instance.instance_type))
  151. self.assertIsInstance(itype, InstanceType)
  152. expected_type = helpers.get_provider_test_data(self.provider,
  153. 'instance_type')
  154. self.assertEqual(
  155. itype.name, expected_type,
  156. "Instance type {0} does not match expected type {1}".format(
  157. itype.name, expected_type))
  158. def test_block_device_mapping_launch_config(self):
  159. lc = self.provider.compute.instances.create_launch_config()
  160. # specifying an invalid size should raise
  161. # an exception
  162. with self.assertRaises(InvalidConfigurationException):
  163. lc.add_volume_device(size=-1)
  164. # Attempting to add a blank volume without specifying a size
  165. # should raise an exception
  166. with self.assertRaises(InvalidConfigurationException):
  167. lc.add_volume_device(source=None)
  168. # block_devices should be empty so far
  169. self.assertListEqual(
  170. lc.block_devices, [], "No block devices should have been"
  171. " added to mappings list since the configuration was"
  172. " invalid")
  173. # Add a new volume
  174. lc.add_volume_device(size=1, delete_on_terminate=True)
  175. # Override root volume size
  176. image_id = helpers.get_provider_test_data(self.provider, "image")
  177. img = self.provider.compute.images.get(image_id)
  178. lc.add_volume_device(
  179. is_root=True,
  180. source=img,
  181. # TODO: This should be greater than the ami size or tests will fail
  182. # on actual infrastructure. Needs an image.size method
  183. size=2,
  184. delete_on_terminate=True)
  185. # Attempting to add more than one root volume should raise an
  186. # exception.
  187. with self.assertRaises(InvalidConfigurationException):
  188. lc.add_volume_device(size=1, is_root=True)
  189. # Attempting to add an incorrect source should raise an exception
  190. with self.assertRaises(InvalidConfigurationException):
  191. lc.add_volume_device(
  192. source="invalid_source",
  193. delete_on_terminate=True)
  194. # Add all available ephemeral devices
  195. instance_type_name = helpers.get_provider_test_data(
  196. self.provider,
  197. "instance_type")
  198. inst_type = self.provider.compute.instance_types.find(
  199. name=instance_type_name)[0]
  200. for _ in range(inst_type.num_ephemeral_disks):
  201. lc.add_ephemeral_device()
  202. # block_devices should be populated
  203. self.assertTrue(
  204. len(lc.block_devices) == 2 + inst_type.num_ephemeral_disks,
  205. "Expected %d total block devices bit found %d" %
  206. (2 + inst_type.num_ephemeral_disks, len(lc.block_devices)))
  207. def test_block_device_mapping_attachments(self):
  208. name = "CBInstBlkAttch-{0}-{1}".format(
  209. self.provider.name,
  210. uuid.uuid4())
  211. # test_vol = self.provider.block_store.volumes.create(
  212. # name,
  213. # 1,
  214. # helpers.get_provider_test_data(self.provider, "placement"))
  215. # with helpers.cleanup_action(lambda: test_vol.delete()):
  216. # test_vol.wait_till_ready()
  217. # test_snap = test_vol.create_snapshot(name=name,
  218. # description=name)
  219. #
  220. # def cleanup_snap(snap):
  221. # snap.delete()
  222. # snap.wait_for(
  223. # [SnapshotState.UNKNOWN],
  224. # terminal_states=[SnapshotState.ERROR])
  225. #
  226. # with helpers.cleanup_action(lambda: cleanup_snap(test_snap)):
  227. # test_snap.wait_till_ready()
  228. lc = self.provider.compute.instances.create_launch_config()
  229. # Add a new blank volume
  230. # lc.add_volume_device(size=1, delete_on_terminate=True)
  231. # Attach an existing volume
  232. # lc.add_volume_device(size=1, source=test_vol,
  233. # delete_on_terminate=True)
  234. # Add a new volume based on a snapshot
  235. # lc.add_volume_device(size=1, source=test_snap,
  236. # delete_on_terminate=True)
  237. # Override root volume size
  238. image_id = helpers.get_provider_test_data(
  239. self.provider,
  240. "image")
  241. img = self.provider.compute.images.get(image_id)
  242. lc.add_volume_device(
  243. is_root=True,
  244. source=img,
  245. # TODO: This should be greater than the ami size or tests
  246. # will fail on actual infrastructure. Needs an image.size
  247. # method
  248. size=2,
  249. delete_on_terminate=True)
  250. # Add all available ephemeral devices
  251. instance_type_name = helpers.get_provider_test_data(
  252. self.provider,
  253. "instance_type")
  254. inst_type = self.provider.compute.instance_types.find(
  255. name=instance_type_name)[0]
  256. for _ in range(inst_type.num_ephemeral_disks):
  257. lc.add_ephemeral_device()
  258. net, _ = helpers.create_test_network(self.provider, name)
  259. lc.add_network_interface(net.id)
  260. inst = helpers.create_test_instance(
  261. self.provider,
  262. name,
  263. zone=helpers.get_provider_test_data(
  264. self.provider,
  265. 'placement'),
  266. launch_config=lc)
  267. def cleanup(instance, net):
  268. instance.terminate()
  269. instance.wait_for(
  270. [InstanceState.TERMINATED, InstanceState.UNKNOWN],
  271. terminal_states=[InstanceState.ERROR])
  272. helpers.delete_test_network(net)
  273. with helpers.cleanup_action(lambda: cleanup(inst, net)):
  274. try:
  275. inst.wait_till_ready()
  276. except WaitStateException as e:
  277. self.fail("The block device mapped launch did not "
  278. " complete successfully: %s" % e)
  279. # TODO: Check instance attachments and make sure they
  280. # correspond to requested mappings