unittest: tests for boot from volume and stop/start instances
This commit is contained in:
		| @@ -63,6 +63,7 @@ class CloudTestCase(test.TestCase): | ||||
|         self.compute = self.start_service('compute') | ||||
|         self.scheduter = self.start_service('scheduler') | ||||
|         self.network = self.start_service('network') | ||||
|         self.volume = self.start_service('volume') | ||||
|         self.image_service = utils.import_object(FLAGS.image_service) | ||||
|  | ||||
|         self.manager = manager.AuthManager() | ||||
| @@ -85,6 +86,7 @@ class CloudTestCase(test.TestCase): | ||||
|         db.network_disassociate(self.context, network_ref['id']) | ||||
|         self.manager.delete_project(self.project) | ||||
|         self.manager.delete_user(self.user) | ||||
|         self.volume.kill() | ||||
|         self.compute.kill() | ||||
|         self.network.kill() | ||||
|         super(CloudTestCase, self).tearDown() | ||||
| @@ -364,15 +366,22 @@ class CloudTestCase(test.TestCase): | ||||
|         self.assertRaises(exception.ImageNotFound, deregister_image, | ||||
|                           self.context, 'ami-bad001') | ||||
|  | ||||
|     def test_console_output(self): | ||||
|         instance_type = FLAGS.default_instance_type | ||||
|         max_count = 1 | ||||
|         kwargs = {'image_id': 'ami-1', | ||||
|                   'instance_type': instance_type, | ||||
|                   'max_count': max_count} | ||||
|     def _run_instance(self, **kwargs): | ||||
|         rv = self.cloud.run_instances(self.context, **kwargs) | ||||
|         greenthread.sleep(0.3) | ||||
|         instance_id = rv['instancesSet'][0]['instanceId'] | ||||
|         return instance_id | ||||
|  | ||||
|     def _run_instance_wait(self, **kwargs): | ||||
|         ec2_instance_id = self._run_instance(**kwargs) | ||||
|         self._wait_for_running(ec2_instance_id) | ||||
|         return ec2_instance_id | ||||
|  | ||||
|     def test_console_output(self): | ||||
|         instance_id = self._run_instance( | ||||
|             image_id='ami-1', | ||||
|             instance_type=FLAGS.default_instance_type, | ||||
|             max_count=1) | ||||
|         output = self.cloud.get_console_output(context=self.context, | ||||
|                                                instance_id=[instance_id]) | ||||
|         self.assertEquals(b64decode(output['output']), 'FAKE CONSOLE?OUTPUT') | ||||
| @@ -383,10 +392,7 @@ class CloudTestCase(test.TestCase): | ||||
|         greenthread.sleep(0.3) | ||||
|  | ||||
|     def test_ajax_console(self): | ||||
|         kwargs = {'image_id': 'ami-1'} | ||||
|         rv = self.cloud.run_instances(self.context, **kwargs) | ||||
|         instance_id = rv['instancesSet'][0]['instanceId'] | ||||
|         greenthread.sleep(0.3) | ||||
|         instance_id = self._run_instance(image_id='ami-1') | ||||
|         output = self.cloud.get_ajax_console(context=self.context, | ||||
|                                              instance_id=[instance_id]) | ||||
|         self.assertEquals(output['url'], | ||||
| @@ -470,3 +476,299 @@ class CloudTestCase(test.TestCase): | ||||
|         vol = db.volume_get(self.context, vol['id']) | ||||
|         self.assertEqual(None, vol['mountpoint']) | ||||
|         db.volume_destroy(self.context, vol['id']) | ||||
|  | ||||
|     def _restart_compute_service(self, periodic_interval=None): | ||||
|         """restart compute service. NOTE: fake driver forgets all instances.""" | ||||
|         self.compute.kill() | ||||
|         if periodic_interval: | ||||
|             self.compute = self.start_service( | ||||
|                 'compute', periodic_interval=periodic_interval) | ||||
|         else: | ||||
|             self.compute = self.start_service('compute') | ||||
|  | ||||
|     def _wait_for_state(self, ctxt, instance_id, predicate): | ||||
|         """Wait for an stopping instance to be a given state""" | ||||
|         id = ec2utils.ec2_id_to_id(instance_id) | ||||
|         while True: | ||||
|             info = self.cloud.compute_api.get(context=ctxt, instance_id=id) | ||||
|             LOG.debug(info) | ||||
|             if predicate(info): | ||||
|                 break | ||||
|             greenthread.sleep(1) | ||||
|  | ||||
|     def _wait_for_running(self, instance_id): | ||||
|         def is_running(info): | ||||
|             return info['state_description'] == 'running' | ||||
|         self._wait_for_state(self.context, instance_id, is_running) | ||||
|  | ||||
|     def _wait_for_stopped(self, instance_id): | ||||
|         def is_stopped(info): | ||||
|             return info['state_description'] == 'stopped' | ||||
|         self._wait_for_state(self.context, instance_id, is_stopped) | ||||
|  | ||||
|     def _wait_for_terminate(self, instance_id): | ||||
|         def is_deleted(info): | ||||
|             return info['deleted'] | ||||
|         elevated = self.context.elevated(read_deleted=True) | ||||
|         self._wait_for_state(elevated, instance_id, is_deleted) | ||||
|  | ||||
|     def test_stop_start_instance(self): | ||||
|         """Makes sure stop/start instnace works""" | ||||
|         # enforce periodic tasks run in short time to avoid wait for 60s. | ||||
|         self._restart_compute_service(periodic_interval=0.3) | ||||
|  | ||||
|         kwargs = {'image_id': 'ami-1', | ||||
|                   'instance_type': FLAGS.default_instance_type, | ||||
|                   'max_count': 1,} | ||||
|         instance_id = self._run_instance_wait(**kwargs) | ||||
|  | ||||
|         # a running instance can't be started. It is just ignored. | ||||
|         result = self.cloud.start_instances(self.context, [instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|         self.assertTrue(result) | ||||
|  | ||||
|         result = self.cloud.stop_instances(self.context, [instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|         self.assertTrue(result) | ||||
|         self._wait_for_stopped(instance_id) | ||||
|          | ||||
|         result = self.cloud.start_instances(self.context, [instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|         self.assertTrue(result) | ||||
|         self._wait_for_running(instance_id) | ||||
|  | ||||
|         result = self.cloud.stop_instances(self.context, [instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|         self.assertTrue(result) | ||||
|         self._wait_for_stopped(instance_id) | ||||
|          | ||||
|         result = self.cloud.terminate_instances(self.context, [instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|         self.assertTrue(result) | ||||
|          | ||||
|         self._restart_compute_service() | ||||
|  | ||||
|     def _volume_create(self): | ||||
|         kwargs = {'status': 'available', | ||||
|                   'host': self.volume.host, | ||||
|                   'size': 1, | ||||
|                   'attach_status': 'detached',} | ||||
|         return db.volume_create(self.context, kwargs) | ||||
|  | ||||
|     def _assert_volume_attached(self, vol, instance_id, mountpoint): | ||||
|         self.assertEqual(vol['instance_id'], instance_id) | ||||
|         self.assertEqual(vol['mountpoint'], mountpoint) | ||||
|         self.assertEqual(vol['status'], "in-use") | ||||
|         self.assertEqual(vol['attach_status'], "attached") | ||||
|          | ||||
|     def _assert_volume_detached(self, vol): | ||||
|         self.assertEqual(vol['instance_id'], None) | ||||
|         self.assertEqual(vol['mountpoint'], None) | ||||
|         self.assertEqual(vol['status'], "available") | ||||
|         self.assertEqual(vol['attach_status'], "detached") | ||||
|  | ||||
|     def test_stop_start_with_volume(self): | ||||
|         """Make sure run instance with block device mapping works""" | ||||
|  | ||||
|         # enforce periodic tasks run in short time to avoid wait for 60s. | ||||
|         self._restart_compute_service(periodic_interval=0.3) | ||||
|  | ||||
|         vol1 = self._volume_create() | ||||
|         vol2 = self._volume_create() | ||||
|         kwargs = {'image_id': 'ami-1', | ||||
|                   'instance_type': FLAGS.default_instance_type, | ||||
|                   'max_count': 1, | ||||
|                   'block_device_mapping': [{'device_name': '/dev/vdb', | ||||
|                                             'volume_id': vol1['id'], | ||||
|                                             'delete_on_termination': False,}, | ||||
|                                            {'device_name': '/dev/vdc', | ||||
|                                             'volume_id': vol2['id'],  | ||||
|                                             'delete_on_termination': True,}, | ||||
|                                            ]} | ||||
|         ec2_instance_id = self._run_instance_wait(**kwargs) | ||||
|         instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) | ||||
|  | ||||
|         vols = db.volume_get_all_by_instance(self.context, instance_id) | ||||
|         self.assertEqual(len(vols), 2) | ||||
|         for vol in vols: | ||||
|             self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) | ||||
|  | ||||
|         vol = db.volume_get(self.context, vol1['id']) | ||||
|         self._assert_volume_attached(vol, instance_id, '/dev/vdb') | ||||
|  | ||||
|         vol = db.volume_get(self.context, vol2['id']) | ||||
|         self._assert_volume_attached(vol, instance_id, '/dev/vdc') | ||||
|  | ||||
|         result = self.cloud.stop_instances(self.context, [ec2_instance_id]) | ||||
|         self.assertTrue(result) | ||||
|         self._wait_for_stopped(ec2_instance_id) | ||||
|  | ||||
|         vol = db.volume_get(self.context, vol1['id']) | ||||
|         self._assert_volume_detached(vol) | ||||
|         vol = db.volume_get(self.context, vol2['id']) | ||||
|         self._assert_volume_detached(vol) | ||||
|              | ||||
|         self.cloud.start_instances(self.context, [ec2_instance_id]) | ||||
|         self._wait_for_running(ec2_instance_id) | ||||
|         vols = db.volume_get_all_by_instance(self.context, instance_id) | ||||
|         self.assertEqual(len(vols), 2) | ||||
|         for vol in vols: | ||||
|             self.assertTrue(vol['id'] == vol1['id'] or vol['id'] == vol2['id']) | ||||
|             self.assertTrue(vol['mountpoint'] == '/dev/vdb' or | ||||
|                             vol['mountpoint'] == '/dev/vdc') | ||||
|             self.assertEqual(vol['instance_id'], instance_id) | ||||
|             self.assertEqual(vol['status'], "in-use") | ||||
|             self.assertEqual(vol['attach_status'], "attached") | ||||
|  | ||||
|         self.cloud.terminate_instances(self.context, [ec2_instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|  | ||||
|         admin_ctxt = context.get_admin_context(read_deleted=False) | ||||
|         vol = db.volume_get(admin_ctxt, vol1['id']) | ||||
|         self.assertFalse(vol['deleted']) | ||||
|         db.volume_destroy(self.context, vol1['id']) | ||||
|  | ||||
|         greenthread.sleep(0.3) | ||||
|         admin_ctxt = context.get_admin_context(read_deleted=True) | ||||
|         vol = db.volume_get(admin_ctxt, vol2['id']) | ||||
|         self.assertTrue(vol['deleted']) | ||||
|          | ||||
|         self._restart_compute_service() | ||||
|  | ||||
|     def test_stop_with_attached_volume(self): | ||||
|         """Make sure attach info is reflected to block device mapping""" | ||||
|         # enforce periodic tasks run in short time to avoid wait for 60s. | ||||
|         self._restart_compute_service(periodic_interval=0.3) | ||||
|  | ||||
|         vol1 = self._volume_create() | ||||
|         vol2 = self._volume_create() | ||||
|         kwargs = {'image_id': 'ami-1', | ||||
|                   'instance_type': FLAGS.default_instance_type, | ||||
|                   'max_count': 1, | ||||
|                   'block_device_mapping': [{'device_name': '/dev/vdb', | ||||
|                                             'volume_id': vol1['id'], | ||||
|                                             'delete_on_termination': True,},]} | ||||
|         ec2_instance_id = self._run_instance_wait(**kwargs) | ||||
|         instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) | ||||
|  | ||||
|         vols = db.volume_get_all_by_instance(self.context, instance_id) | ||||
|         self.assertEqual(len(vols), 1) | ||||
|         for vol in vols: | ||||
|             self.assertEqual(vol['id'], vol1['id']) | ||||
|             self._assert_volume_attached(vol, instance_id, '/dev/vdb') | ||||
|  | ||||
|         vol = db.volume_get(self.context, vol2['id']) | ||||
|         self._assert_volume_detached(vol) | ||||
|  | ||||
|         self.cloud.compute_api.attach_volume(self.context, | ||||
|                                              instance_id=instance_id, | ||||
|                                              volume_id=vol2['id'], | ||||
|                                              device='/dev/vdc') | ||||
|         greenthread.sleep(0.3) | ||||
|         vol = db.volume_get(self.context, vol2['id']) | ||||
|         self._assert_volume_attached(vol, instance_id, '/dev/vdc') | ||||
|  | ||||
|         self.cloud.compute_api.detach_volume(self.context, | ||||
|                                              volume_id=vol1['id']) | ||||
|         greenthread.sleep(0.3) | ||||
|         vol = db.volume_get(self.context, vol1['id']) | ||||
|         self._assert_volume_detached(vol) | ||||
|          | ||||
|         result = self.cloud.stop_instances(self.context, [ec2_instance_id]) | ||||
|         self.assertTrue(result) | ||||
|         self._wait_for_stopped(ec2_instance_id) | ||||
|  | ||||
|         for vol_id in (vol1['id'], vol2['id']): | ||||
|             vol = db.volume_get(self.context, vol_id) | ||||
|             self._assert_volume_detached(vol) | ||||
|              | ||||
|         self.cloud.start_instances(self.context, [ec2_instance_id]) | ||||
|         self._wait_for_running(ec2_instance_id) | ||||
|         vols = db.volume_get_all_by_instance(self.context, instance_id) | ||||
|         self.assertEqual(len(vols), 1) | ||||
|         for vol in vols: | ||||
|             self.assertEqual(vol['id'], vol2['id']) | ||||
|             self._assert_volume_attached(vol, instance_id, '/dev/vdc') | ||||
|  | ||||
|         vol = db.volume_get(self.context, vol1['id']) | ||||
|         self._assert_volume_detached(vol) | ||||
|  | ||||
|         self.cloud.terminate_instances(self.context, [ec2_instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|  | ||||
|         for vol_id in (vol1['id'], vol2['id']): | ||||
|             vol = db.volume_get(self.context, vol_id) | ||||
|             self.assertEqual(vol['id'], vol_id) | ||||
|             self._assert_volume_detached(vol) | ||||
|             db.volume_destroy(self.context, vol_id) | ||||
|          | ||||
|         self._restart_compute_service() | ||||
|          | ||||
|     def _create_snapshot(self, ec2_volume_id): | ||||
|         result = self.cloud.create_snapshot(self.context, | ||||
|                                             volume_id=ec2_volume_id) | ||||
|         greenthread.sleep(0.3) | ||||
|         return result['snapshotId'] | ||||
|          | ||||
|     def test_run_with_snapshot(self): | ||||
|         """Makes sure run/stop/start instance with snapshot works.""" | ||||
|         vol = self._volume_create() | ||||
|         ec2_volume_id = ec2utils.id_to_ec2_id(vol['id'], 'vol-%08x') | ||||
|  | ||||
|         ec2_snapshot1_id = self._create_snapshot(ec2_volume_id) | ||||
|         snapshot1_id = ec2utils.ec2_id_to_id(ec2_snapshot1_id) | ||||
|         ec2_snapshot2_id = self._create_snapshot(ec2_volume_id) | ||||
|         snapshot2_id = ec2utils.ec2_id_to_id(ec2_snapshot2_id) | ||||
|  | ||||
|         kwargs = {'image_id': 'ami-1', | ||||
|                   'instance_type': FLAGS.default_instance_type, | ||||
|                   'max_count': 1, | ||||
|                   'block_device_mapping': [{'device_name': '/dev/vdb', | ||||
|                                             'snapshot_id': snapshot1_id, | ||||
|                                             'delete_on_termination': False,}, | ||||
|                                            {'device_name': '/dev/vdc', | ||||
|                                             'snapshot_id': snapshot2_id, | ||||
|                                             'delete_on_termination': True,},],} | ||||
|         ec2_instance_id = self._run_instance_wait(**kwargs) | ||||
|         instance_id = ec2utils.ec2_id_to_id(ec2_instance_id) | ||||
|  | ||||
|         vols = db.volume_get_all_by_instance(self.context, instance_id) | ||||
|         self.assertEqual(len(vols), 2) | ||||
|         vol1_id = None | ||||
|         vol2_id = None | ||||
|         for vol in vols: | ||||
|             snapshot_id = vol['snapshot_id'] | ||||
|             if snapshot_id == snapshot1_id: | ||||
|                 vol1_id = vol['id'] | ||||
|                 mountpoint = '/dev/vdb' | ||||
|             elif snapshot_id == snapshot2_id: | ||||
|                 vol2_id = vol['id'] | ||||
|                 mountpoint = '/dev/vdc' | ||||
|             else: | ||||
|                 self.fail() | ||||
|  | ||||
|             self._assert_volume_attached(vol, instance_id, mountpoint) | ||||
|  | ||||
|         self.assertTrue(vol1_id) | ||||
|         self.assertTrue(vol2_id) | ||||
|  | ||||
|         self.cloud.terminate_instances(self.context, [ec2_instance_id]) | ||||
|         greenthread.sleep(0.3) | ||||
|         self._wait_for_terminate(ec2_instance_id) | ||||
|  | ||||
|         greenthread.sleep(0.3)         | ||||
|         admin_ctxt = context.get_admin_context(read_deleted=False) | ||||
|         vol = db.volume_get(admin_ctxt, vol1_id) | ||||
|         self._assert_volume_detached(vol) | ||||
|         self.assertFalse(vol['deleted']) | ||||
|         db.volume_destroy(self.context, vol1_id) | ||||
|  | ||||
|         greenthread.sleep(0.3)         | ||||
|         admin_ctxt = context.get_admin_context(read_deleted=True) | ||||
|         vol = db.volume_get(admin_ctxt, vol2_id) | ||||
|         self.assertTrue(vol['deleted']) | ||||
|  | ||||
|         for snapshot_id in (ec2_snapshot1_id, ec2_snapshot2_id): | ||||
|             self.cloud.delete_snapshot(self.context, snapshot_id) | ||||
|             greenthread.sleep(0.3) | ||||
|         db.volume_destroy(self.context, vol['id']) | ||||
|   | ||||
| @@ -229,6 +229,21 @@ class ComputeTestCase(test.TestCase): | ||||
|         self.assert_(instance_ref['launched_at'] < terminate) | ||||
|         self.assert_(instance_ref['deleted_at'] > terminate) | ||||
|  | ||||
|     def test_stop(self): | ||||
|         """Ensure instance can be stopped""" | ||||
|         instance_id = self._create_instance() | ||||
|         self.compute.run_instance(self.context, instance_id) | ||||
|         self.compute.stop_instance(self.context, instance_id) | ||||
|         self.compute.terminate_instance(self.context, instance_id) | ||||
|  | ||||
|     def test_start(self): | ||||
|         """Ensure instance can be started""" | ||||
|         instance_id = self._create_instance() | ||||
|         self.compute.run_instance(self.context, instance_id) | ||||
|         self.compute.stop_instance(self.context, instance_id) | ||||
|         self.compute.start_instance(self.context, instance_id) | ||||
|         self.compute.terminate_instance(self.context, instance_id) | ||||
|  | ||||
|     def test_pause(self): | ||||
|         """Ensure instance can be paused""" | ||||
|         instance_id = self._create_instance() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Isaku Yamahata
					Isaku Yamahata