blob: fa9a2285464765144c8ea2a0fb3af27f145da39f [file] [log] [blame]
fujioka yuuichi636f8db2013-08-09 12:05:24 +09001# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
Masayuki Igawa259c1132013-10-31 17:48:44 +090015from tempest.common.utils import data_utils
fujioka yuuichi636f8db2013-08-09 12:05:24 +090016from tempest.scenario import manager
Matthew Treinish2153ec02013-09-09 20:57:30 +000017from tempest.test import services
fujioka yuuichi636f8db2013-08-09 12:05:24 +090018
19
20class TestVolumeBootPattern(manager.OfficialClientTest):
21
22 """
23 This test case attempts to reproduce the following steps:
24
25 * Create in Cinder some bootable volume importing a Glance image
26 * Boot an instance from the bootable volume
27 * Write content to the volume
28 * Delete an instance and Boot a new instance from the volume
29 * Check written content in the instance
30 * Create a volume snapshot while the instance is running
31 * Boot an additional instance from the new snapshot based volume
32 * Check written content in the instance booted from snapshot
33 """
34
35 def _create_volume_from_image(self):
36 img_uuid = self.config.compute.image_ref
Masayuki Igawa259c1132013-10-31 17:48:44 +090037 vol_name = data_utils.rand_name('volume-origin')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090038 return self.create_volume(name=vol_name, imageRef=img_uuid)
39
40 def _boot_instance_from_volume(self, vol_id, keypair):
41 # NOTE(gfidente): the syntax for block_device_mapping is
42 # dev_name=id:type:size:delete_on_terminate
43 # where type needs to be "snap" if the server is booted
44 # from a snapshot, size instead can be safely left empty
45 bd_map = {
46 'vda': vol_id + ':::0'
47 }
48 create_kwargs = {
49 'block_device_mapping': bd_map,
50 'key_name': keypair.name
51 }
Giulio Fidente61cadca2013-09-24 18:33:37 +020052 return self.create_server(create_kwargs=create_kwargs)
fujioka yuuichi636f8db2013-08-09 12:05:24 +090053
54 def _create_snapshot_from_volume(self, vol_id):
55 volume_snapshots = self.volume_client.volume_snapshots
Masayuki Igawa259c1132013-10-31 17:48:44 +090056 snap_name = data_utils.rand_name('snapshot')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090057 snap = volume_snapshots.create(volume_id=vol_id,
58 force=True,
59 display_name=snap_name)
60 self.set_resource(snap.id, snap)
61 self.status_timeout(volume_snapshots,
62 snap.id,
63 'available')
64 return snap
65
66 def _create_volume_from_snapshot(self, snap_id):
Masayuki Igawa259c1132013-10-31 17:48:44 +090067 vol_name = data_utils.rand_name('volume')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090068 return self.create_volume(name=vol_name, snapshot_id=snap_id)
69
70 def _stop_instances(self, instances):
71 # NOTE(gfidente): two loops so we do not wait for the status twice
72 for i in instances:
73 self.compute_client.servers.stop(i)
74 for i in instances:
75 self.status_timeout(self.compute_client.servers,
76 i.id,
77 'SHUTOFF')
78
79 def _detach_volumes(self, volumes):
80 # NOTE(gfidente): two loops so we do not wait for the status twice
81 for v in volumes:
82 self.volume_client.volumes.detach(v)
83 for v in volumes:
84 self.status_timeout(self.volume_client.volumes,
85 v.id,
86 'available')
87
88 def _ssh_to_server(self, server, keypair):
89 if self.config.compute.use_floatingip_for_ssh:
90 floating_ip = self.compute_client.floating_ips.create()
Masayuki Igawa259c1132013-10-31 17:48:44 +090091 fip_name = data_utils.rand_name('scenario-fip')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090092 self.set_resource(fip_name, floating_ip)
93 server.add_floating_ip(floating_ip)
94 ip = floating_ip.ip
95 else:
96 network_name_for_ssh = self.config.compute.network_for_ssh
97 ip = server.networks[network_name_for_ssh][0]
98
99 client = self.get_remote_client(ip,
100 private_key=keypair.private_key)
101 return client.ssh_client
102
103 def _get_content(self, ssh_client):
104 return ssh_client.exec_command('cat /tmp/text')
105
106 def _write_text(self, ssh_client):
Masayuki Igawa259c1132013-10-31 17:48:44 +0900107 text = data_utils.rand_name('text-')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900108 ssh_client.exec_command('echo "%s" > /tmp/text; sync' % (text))
109
110 return self._get_content(ssh_client)
111
112 def _delete_server(self, server):
113 self.compute_client.servers.delete(server)
114 self.delete_timeout(self.compute_client.servers, server.id)
115
116 def _check_content_of_written_file(self, ssh_client, expected):
117 actual = self._get_content(ssh_client)
118 self.assertEqual(expected, actual)
119
Matthew Treinish2153ec02013-09-09 20:57:30 +0000120 @services('compute', 'volume', 'image')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900121 def test_volume_boot_pattern(self):
122 keypair = self.create_keypair()
Yair Friedeb69f3f2013-10-10 13:18:16 +0300123 self._create_loginable_secgroup_rule_nova()
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900124
125 # create an instance from volume
126 volume_origin = self._create_volume_from_image()
127 instance_1st = self._boot_instance_from_volume(volume_origin.id,
128 keypair)
129
130 # write content to volume on instance
131 ssh_client_for_instance_1st = self._ssh_to_server(instance_1st,
132 keypair)
133 text = self._write_text(ssh_client_for_instance_1st)
134
135 # delete instance
136 self._delete_server(instance_1st)
137
138 # create a 2nd instance from volume
139 instance_2nd = self._boot_instance_from_volume(volume_origin.id,
140 keypair)
141
142 # check the content of written file
143 ssh_client_for_instance_2nd = self._ssh_to_server(instance_2nd,
144 keypair)
145 self._check_content_of_written_file(ssh_client_for_instance_2nd, text)
146
147 # snapshot a volume
148 snapshot = self._create_snapshot_from_volume(volume_origin.id)
149
150 # create a 3rd instance from snapshot
151 volume = self._create_volume_from_snapshot(snapshot.id)
152 instance_from_snapshot = self._boot_instance_from_volume(volume.id,
153 keypair)
154
155 # check the content of written file
156 ssh_client = self._ssh_to_server(instance_from_snapshot, keypair)
157 self._check_content_of_written_file(ssh_client, text)
158
159 # NOTE(gfidente): ensure resources are in clean state for
160 # deletion operations to succeed
161 self._stop_instances([instance_2nd, instance_from_snapshot])
162 self._detach_volumes([volume_origin, volume])