test_block_store_service.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import time
  2. import six
  3. from cloudbridge.cloud.factory import ProviderList
  4. from cloudbridge.cloud.interfaces import SnapshotState
  5. from cloudbridge.cloud.interfaces import VolumeState
  6. from cloudbridge.cloud.interfaces.provider import TestMockHelperMixin
  7. from cloudbridge.cloud.interfaces.resources import AttachmentInfo
  8. from cloudbridge.cloud.interfaces.resources import Snapshot
  9. from cloudbridge.cloud.interfaces.resources import Volume
  10. from test import helpers
  11. from test.helpers import ProviderTestBase
  12. from test.helpers import standard_interface_tests as sit
  13. class CloudBlockStoreServiceTestCase(ProviderTestBase):
  14. _multiprocess_can_split_ = True
  15. @helpers.skipIfNoService(['storage.volumes'])
  16. def test_crud_volume(self):
  17. def create_vol(label):
  18. return self.provider.storage.volumes.create(
  19. label, 1,
  20. helpers.get_provider_test_data(self.provider, "placement"))
  21. def cleanup_vol(vol):
  22. if vol:
  23. vol.delete()
  24. vol.wait_for([VolumeState.DELETED, VolumeState.UNKNOWN],
  25. terminal_states=[VolumeState.ERROR])
  26. vol.refresh()
  27. self.assertTrue(
  28. vol.state == VolumeState.UNKNOWN,
  29. "Volume.state must be unknown when refreshing after a "
  30. "delete but got %s"
  31. % vol.state)
  32. sit.check_crud(self, self.provider.storage.volumes, Volume,
  33. "cb-createvol", create_vol, cleanup_vol)
  34. @helpers.skipIfNoService(['storage.volumes'])
  35. def test_attach_detach_volume(self):
  36. label = "cb-attachvol-{0}".format(helpers.get_uuid())
  37. # Declare these variables and late binding will allow
  38. # the cleanup method access to the most current values
  39. test_instance = None
  40. with helpers.cleanup_action(lambda: helpers.cleanup_test_resources(
  41. test_instance)):
  42. subnet = helpers.get_or_create_default_subnet(
  43. self.provider)
  44. test_instance = helpers.get_test_instance(
  45. self.provider, label, subnet=subnet)
  46. test_vol = self.provider.storage.volumes.create(
  47. label, 1, test_instance.zone_id)
  48. with helpers.cleanup_action(lambda: test_vol.delete()):
  49. test_vol.wait_till_ready()
  50. test_vol.attach(test_instance, '/dev/sda2')
  51. test_vol.wait_for(
  52. [VolumeState.IN_USE],
  53. terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
  54. test_vol.detach()
  55. test_vol.wait_for(
  56. [VolumeState.AVAILABLE],
  57. terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
  58. @helpers.skipIfNoService(['storage.volumes'])
  59. def test_volume_properties(self):
  60. label = "cb-volprops-{0}".format(helpers.get_uuid())
  61. vol_desc = 'newvoldesc1'
  62. # Declare these variables and late binding will allow
  63. # the cleanup method access to the most current values
  64. test_instance = None
  65. with helpers.cleanup_action(lambda: helpers.cleanup_test_resources(
  66. test_instance)):
  67. subnet = helpers.get_or_create_default_subnet(
  68. self.provider)
  69. test_instance = helpers.get_test_instance(
  70. self.provider, label, subnet=subnet)
  71. test_vol = self.provider.storage.volumes.create(
  72. label, 1, test_instance.zone_id, description=vol_desc)
  73. with helpers.cleanup_action(lambda: test_vol.delete()):
  74. test_vol.wait_till_ready()
  75. self.assertTrue(
  76. isinstance(test_vol.size, six.integer_types) and
  77. test_vol.size >= 0,
  78. "Volume.size must be a positive number, but got %s"
  79. % test_vol.size)
  80. self.assertTrue(
  81. test_vol.description is None or
  82. isinstance(test_vol.description, six.string_types),
  83. "Volume.description must be None or a string. Got: %s"
  84. % test_vol.description)
  85. self.assertIsNone(test_vol.source)
  86. self.assertIsNone(test_vol.source)
  87. self.assertIsNotNone(test_vol.create_time)
  88. self.assertIsNotNone(test_vol.zone_id)
  89. self.assertIsNone(test_vol.attachments)
  90. test_vol.attach(test_instance, '/dev/sda2')
  91. test_vol.wait_for(
  92. [VolumeState.IN_USE],
  93. terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
  94. self.assertIsNotNone(test_vol.attachments)
  95. self.assertIsInstance(test_vol.attachments, AttachmentInfo)
  96. self.assertEqual(test_vol.attachments.volume, test_vol)
  97. self.assertEqual(test_vol.attachments.instance_id,
  98. test_instance.id)
  99. if (self.provider.PROVIDER_ID != 'azure' and
  100. self.provider.PROVIDER_ID != 'gce'):
  101. self.assertEqual(test_vol.attachments.device,
  102. "/dev/sda2")
  103. test_vol.detach()
  104. test_vol.label = 'newvolname1'
  105. test_vol.wait_for(
  106. [VolumeState.AVAILABLE],
  107. terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
  108. self.assertEqual(test_vol.label, 'newvolname1')
  109. self.assertEqual(test_vol.description, vol_desc)
  110. self.assertIsNone(test_vol.attachments)
  111. test_vol.wait_for(
  112. [VolumeState.AVAILABLE],
  113. terminal_states=[VolumeState.ERROR, VolumeState.DELETED])
  114. @helpers.skipIfNoService(['storage.snapshots'])
  115. def test_crud_snapshot(self):
  116. # Create a new volume, create a snapshot of the volume, and check
  117. # whether list_snapshots properly detects the new snapshot.
  118. # Delete everything afterwards.
  119. label = "cb-crudsnap-{0}".format(helpers.get_uuid())
  120. test_vol = self.provider.storage.volumes.create(
  121. label, 1,
  122. helpers.get_provider_test_data(self.provider, "placement"))
  123. with helpers.cleanup_action(lambda: test_vol.delete()):
  124. test_vol.wait_till_ready()
  125. def create_snap(label):
  126. return test_vol.create_snapshot(label=label,
  127. description=label)
  128. def cleanup_snap(snap):
  129. if snap:
  130. snap.delete()
  131. snap.wait_for([SnapshotState.UNKNOWN],
  132. terminal_states=[SnapshotState.ERROR])
  133. snap.refresh()
  134. self.assertTrue(
  135. snap.state == SnapshotState.UNKNOWN,
  136. "Snapshot.state must be unknown when refreshing after "
  137. "a delete but got %s"
  138. % snap.state)
  139. sit.check_crud(self, self.provider.storage.snapshots, Snapshot,
  140. "cb-snap", create_snap, cleanup_snap)
  141. # Test creation of a snap via SnapshotService
  142. def create_snap2(label):
  143. return self.provider.storage.snapshots.create(
  144. label=label, volume=test_vol, description=label)
  145. if (self.provider.PROVIDER_ID == ProviderList.AWS and
  146. not isinstance(self.provider, TestMockHelperMixin)):
  147. time.sleep(15) # Or get SnapshotCreationPerVolumeRateExceeded
  148. sit.check_crud(self, self.provider.storage.snapshots, Snapshot,
  149. "cb-snaptwo", create_snap2, cleanup_snap)
  150. @helpers.skipIfNoService(['storage.snapshots'])
  151. def test_snapshot_properties(self):
  152. label = "cb-snapprop-{0}".format(helpers.get_uuid())
  153. test_vol = self.provider.storage.volumes.create(
  154. label, 1,
  155. helpers.get_provider_test_data(self.provider, "placement"))
  156. with helpers.cleanup_action(lambda: test_vol.delete()):
  157. test_vol.wait_till_ready()
  158. snap_label = "cb-snap-{0}".format(label)
  159. test_snap = test_vol.create_snapshot(label=snap_label,
  160. description=snap_label)
  161. def cleanup_snap(snap):
  162. if snap:
  163. snap.delete()
  164. snap.wait_for([SnapshotState.UNKNOWN],
  165. terminal_states=[SnapshotState.ERROR])
  166. with helpers.cleanup_action(lambda: cleanup_snap(test_snap)):
  167. test_snap.wait_till_ready()
  168. self.assertTrue(isinstance(test_vol.size, six.integer_types))
  169. self.assertEqual(
  170. test_snap.size, test_vol.size,
  171. "Snapshot.size must match original volume's size: %s"
  172. " but is: %s" % (test_vol.size, test_snap.size))
  173. self.assertTrue(
  174. test_vol.description is None or
  175. isinstance(test_vol.description, six.string_types),
  176. "Snapshot.description must be None or a string. Got: %s"
  177. % test_vol.description)
  178. self.assertEqual(test_vol.id, test_snap.volume_id)
  179. self.assertIsNotNone(test_vol.create_time)
  180. test_snap.label = 'snapnewname1'
  181. test_snap.description = 'snapnewdescription1'
  182. test_snap.refresh()
  183. self.assertEqual(test_snap.label, 'snapnewname1')
  184. self.assertEqual(test_snap.description, 'snapnewdescription1')
  185. # Test volume creation from a snapshot (via VolumeService)
  186. sv_label = "cb-snapvol-{0}".format(test_snap.name)
  187. snap_vol = self.provider.storage.volumes.create(
  188. sv_label, 1,
  189. helpers.get_provider_test_data(self.provider, "placement"),
  190. snapshot=test_snap)
  191. with helpers.cleanup_action(lambda: snap_vol.delete()):
  192. snap_vol.wait_till_ready()
  193. # Test volume creation from a snapshot (via Snapshot)
  194. snap_vol2 = test_snap.create_volume(
  195. helpers.get_provider_test_data(self.provider, "placement"))
  196. with helpers.cleanup_action(lambda: snap_vol2.delete()):
  197. snap_vol2.wait_till_ready()