blob: ec8575a5812fbd65915aa31fc547319c72c105cd [file] [log] [blame]
fujioka yuuichi636f8db2013-08-09 12:05:24 +09001# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
Masayuki Igawa259c1132013-10-31 17:48:44 +090013from tempest.common.utils import data_utils
Matthew Treinish6c072292014-01-29 19:15:52 +000014from tempest import config
Nachi Ueno95b41282014-01-15 06:54:21 -080015from tempest.openstack.common import log
fujioka yuuichi636f8db2013-08-09 12:05:24 +090016from tempest.scenario import manager
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090017from tempest import test
fujioka yuuichi636f8db2013-08-09 12:05:24 +090018
Matthew Treinish6c072292014-01-29 19:15:52 +000019CONF = config.CONF
fujioka yuuichi636f8db2013-08-09 12:05:24 +090020
Nachi Ueno95b41282014-01-15 06:54:21 -080021LOG = log.getLogger(__name__)
22
23
Joseph Lanouxeef192f2014-08-01 14:32:53 +000024class TestVolumeBootPattern(manager.ScenarioTest):
fujioka yuuichi636f8db2013-08-09 12:05:24 +090025
26 """
27 This test case attempts to reproduce the following steps:
28
29 * Create in Cinder some bootable volume importing a Glance image
30 * Boot an instance from the bootable volume
31 * Write content to the volume
32 * Delete an instance and Boot a new instance from the volume
33 * Check written content in the instance
34 * Create a volume snapshot while the instance is running
35 * Boot an additional instance from the new snapshot based volume
36 * Check written content in the instance booted from snapshot
37 """
JordanPbce55532014-03-19 12:10:32 +010038 @classmethod
39 def setUpClass(cls):
40 super(TestVolumeBootPattern, cls).setUpClass()
41
42 if not CONF.volume_feature_enabled.snapshot:
43 raise cls.skipException("Cinder volume snapshots are disabled")
fujioka yuuichi636f8db2013-08-09 12:05:24 +090044
45 def _create_volume_from_image(self):
Matthew Treinish6c072292014-01-29 19:15:52 +000046 img_uuid = CONF.compute.image_ref
Masayuki Igawa259c1132013-10-31 17:48:44 +090047 vol_name = data_utils.rand_name('volume-origin')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090048 return self.create_volume(name=vol_name, imageRef=img_uuid)
49
50 def _boot_instance_from_volume(self, vol_id, keypair):
51 # NOTE(gfidente): the syntax for block_device_mapping is
52 # dev_name=id:type:size:delete_on_terminate
53 # where type needs to be "snap" if the server is booted
54 # from a snapshot, size instead can be safely left empty
Joseph Lanouxeef192f2014-08-01 14:32:53 +000055 bd_map = [{
56 'device_name': 'vda',
57 'volume_id': vol_id,
58 'delete_on_termination': '0'}]
59 self.security_group = self._create_security_group_nova()
60 security_groups = [{'name': self.security_group['name']}]
fujioka yuuichi636f8db2013-08-09 12:05:24 +090061 create_kwargs = {
62 'block_device_mapping': bd_map,
Joseph Lanouxeef192f2014-08-01 14:32:53 +000063 'key_name': keypair['name'],
Grishkin0f1e11c2014-05-04 20:44:52 +040064 'security_groups': security_groups
fujioka yuuichi636f8db2013-08-09 12:05:24 +090065 }
Xavier Queralt249cac32014-03-05 13:51:39 +010066 return self.create_server(image='', create_kwargs=create_kwargs)
fujioka yuuichi636f8db2013-08-09 12:05:24 +090067
68 def _create_snapshot_from_volume(self, vol_id):
Masayuki Igawa259c1132013-10-31 17:48:44 +090069 snap_name = data_utils.rand_name('snapshot')
Joseph Lanouxeef192f2014-08-01 14:32:53 +000070 _, snap = self.snapshots_client.create_snapshot(
71 volume_id=vol_id,
72 force=True,
73 display_name=snap_name)
74 self.addCleanup_with_wait(
75 waiter_callable=self.snapshots_client.wait_for_resource_deletion,
76 thing_id=snap['id'], thing_id_param='id',
77 cleanup_callable=self.delete_wrapper,
78 cleanup_args=[self.snapshots_client.delete_snapshot, snap['id']])
79 self.snapshots_client.wait_for_snapshot_status(snap['id'], 'available')
80 self.assertEqual(snap_name, snap['display_name'])
fujioka yuuichi636f8db2013-08-09 12:05:24 +090081 return snap
82
83 def _create_volume_from_snapshot(self, snap_id):
Masayuki Igawa259c1132013-10-31 17:48:44 +090084 vol_name = data_utils.rand_name('volume')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090085 return self.create_volume(name=vol_name, snapshot_id=snap_id)
86
87 def _stop_instances(self, instances):
88 # NOTE(gfidente): two loops so we do not wait for the status twice
89 for i in instances:
Joseph Lanouxeef192f2014-08-01 14:32:53 +000090 self.servers_client.stop(i['id'])
fujioka yuuichi636f8db2013-08-09 12:05:24 +090091 for i in instances:
Joseph Lanouxeef192f2014-08-01 14:32:53 +000092 self.servers_client.wait_for_server_status(i['id'], 'SHUTOFF')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090093
94 def _detach_volumes(self, volumes):
95 # NOTE(gfidente): two loops so we do not wait for the status twice
96 for v in volumes:
Joseph Lanouxeef192f2014-08-01 14:32:53 +000097 self.volumes_client.detach_volume(v['id'])
fujioka yuuichi636f8db2013-08-09 12:05:24 +090098 for v in volumes:
Joseph Lanouxeef192f2014-08-01 14:32:53 +000099 self.volumes_client.wait_for_volume_status(v['id'], 'available')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900100
101 def _ssh_to_server(self, server, keypair):
Matthew Treinish6c072292014-01-29 19:15:52 +0000102 if CONF.compute.use_floatingip_for_ssh:
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000103 _, floating_ip = self.floating_ips_client.create_floating_ip()
104 self.addCleanup(self.delete_wrapper,
105 self.floating_ips_client.delete_floating_ip,
106 floating_ip['id'])
107 self.floating_ips_client.associate_floating_ip_to_server(
108 floating_ip['ip'], server['id'])
109 ip = floating_ip['ip']
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900110 else:
Matthew Treinish6c072292014-01-29 19:15:52 +0000111 network_name_for_ssh = CONF.compute.network_for_ssh
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900112 ip = server.networks[network_name_for_ssh][0]
113
Nachi Ueno95b41282014-01-15 06:54:21 -0800114 try:
Elena Ezhova91db24e2014-02-28 20:47:10 +0400115 return self.get_remote_client(
Nachi Ueno95b41282014-01-15 06:54:21 -0800116 ip,
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000117 private_key=keypair['private_key'])
Nachi Ueno95b41282014-01-15 06:54:21 -0800118 except Exception:
119 LOG.exception('ssh to server failed')
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000120 self._log_console_output(self)
Nachi Ueno95b41282014-01-15 06:54:21 -0800121 raise
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900122
123 def _get_content(self, ssh_client):
124 return ssh_client.exec_command('cat /tmp/text')
125
126 def _write_text(self, ssh_client):
Masayuki Igawa259c1132013-10-31 17:48:44 +0900127 text = data_utils.rand_name('text-')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900128 ssh_client.exec_command('echo "%s" > /tmp/text; sync' % (text))
129
130 return self._get_content(ssh_client)
131
132 def _delete_server(self, server):
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000133 self.servers_client.delete_server(server['id'])
134 self.servers_client.wait_for_server_termination(server['id'])
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900135
136 def _check_content_of_written_file(self, ssh_client, expected):
137 actual = self._get_content(ssh_client)
138 self.assertEqual(expected, actual)
139
Masayuki Igawa4ded9f02014-02-17 15:05:59 +0900140 @test.services('compute', 'volume', 'image')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900141 def test_volume_boot_pattern(self):
142 keypair = self.create_keypair()
Grishkin0f1e11c2014-05-04 20:44:52 +0400143 self.security_group = self._create_security_group_nova()
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900144
145 # create an instance from volume
146 volume_origin = self._create_volume_from_image()
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000147 instance_1st = self._boot_instance_from_volume(volume_origin['id'],
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900148 keypair)
149
150 # write content to volume on instance
151 ssh_client_for_instance_1st = self._ssh_to_server(instance_1st,
152 keypair)
153 text = self._write_text(ssh_client_for_instance_1st)
154
155 # delete instance
156 self._delete_server(instance_1st)
157
158 # create a 2nd instance from volume
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000159 instance_2nd = self._boot_instance_from_volume(volume_origin['id'],
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900160 keypair)
161
162 # check the content of written file
163 ssh_client_for_instance_2nd = self._ssh_to_server(instance_2nd,
164 keypair)
165 self._check_content_of_written_file(ssh_client_for_instance_2nd, text)
166
167 # snapshot a volume
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000168 snapshot = self._create_snapshot_from_volume(volume_origin['id'])
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900169
170 # create a 3rd instance from snapshot
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000171 volume = self._create_volume_from_snapshot(snapshot['id'])
172 instance_from_snapshot = self._boot_instance_from_volume(volume['id'],
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900173 keypair)
174
175 # check the content of written file
176 ssh_client = self._ssh_to_server(instance_from_snapshot, keypair)
177 self._check_content_of_written_file(ssh_client, text)
178
179 # NOTE(gfidente): ensure resources are in clean state for
180 # deletion operations to succeed
181 self._stop_instances([instance_2nd, instance_from_snapshot])
182 self._detach_volumes([volume_origin, volume])
Nikola Dipanov7cff03f2014-03-12 14:06:25 +0100183
184
185class TestVolumeBootPatternV2(TestVolumeBootPattern):
186 def _boot_instance_from_volume(self, vol_id, keypair):
187 bdms = [{'uuid': vol_id, 'source_type': 'volume',
188 'destination_type': 'volume', 'boot_index': 0,
189 'delete_on_termination': False}]
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000190 self.security_group = self._create_security_group_nova()
191 security_groups = [{'name': self.security_group['name']}]
Nikola Dipanov7cff03f2014-03-12 14:06:25 +0100192 create_kwargs = {
193 'block_device_mapping_v2': bdms,
Joseph Lanouxeef192f2014-08-01 14:32:53 +0000194 'key_name': keypair['name'],
Grishkin0f1e11c2014-05-04 20:44:52 +0400195 'security_groups': security_groups
Nikola Dipanov7cff03f2014-03-12 14:06:25 +0100196 }
197 return self.create_server(image='', create_kwargs=create_kwargs)