test_compute_service.py 11 KB

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