blob: 35721661a2a29ffcb4445cc777e03b1bfd3db435 [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
15from tempest.common.utils.data_utils import rand_name
16from 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
37 vol_name = rand_name('volume-origin')
38 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 }
52 return self.create_server(self.compute_client,
53 create_kwargs=create_kwargs)
54
55 def _create_snapshot_from_volume(self, vol_id):
56 volume_snapshots = self.volume_client.volume_snapshots
57 snap_name = rand_name('snapshot')
58 snap = volume_snapshots.create(volume_id=vol_id,
59 force=True,
60 display_name=snap_name)
61 self.set_resource(snap.id, snap)
62 self.status_timeout(volume_snapshots,
63 snap.id,
64 'available')
65 return snap
66
67 def _create_volume_from_snapshot(self, snap_id):
68 vol_name = rand_name('volume')
69 return self.create_volume(name=vol_name, snapshot_id=snap_id)
70
71 def _stop_instances(self, instances):
72 # NOTE(gfidente): two loops so we do not wait for the status twice
73 for i in instances:
74 self.compute_client.servers.stop(i)
75 for i in instances:
76 self.status_timeout(self.compute_client.servers,
77 i.id,
78 'SHUTOFF')
79
80 def _detach_volumes(self, volumes):
81 # NOTE(gfidente): two loops so we do not wait for the status twice
82 for v in volumes:
83 self.volume_client.volumes.detach(v)
84 for v in volumes:
85 self.status_timeout(self.volume_client.volumes,
86 v.id,
87 'available')
88
89 def _ssh_to_server(self, server, keypair):
90 if self.config.compute.use_floatingip_for_ssh:
91 floating_ip = self.compute_client.floating_ips.create()
92 fip_name = rand_name('scenario-fip')
93 self.set_resource(fip_name, floating_ip)
94 server.add_floating_ip(floating_ip)
95 ip = floating_ip.ip
96 else:
97 network_name_for_ssh = self.config.compute.network_for_ssh
98 ip = server.networks[network_name_for_ssh][0]
99
100 client = self.get_remote_client(ip,
101 private_key=keypair.private_key)
102 return client.ssh_client
103
104 def _get_content(self, ssh_client):
105 return ssh_client.exec_command('cat /tmp/text')
106
107 def _write_text(self, ssh_client):
108 text = rand_name('text-')
109 ssh_client.exec_command('echo "%s" > /tmp/text; sync' % (text))
110
111 return self._get_content(ssh_client)
112
113 def _delete_server(self, server):
114 self.compute_client.servers.delete(server)
115 self.delete_timeout(self.compute_client.servers, server.id)
116
117 def _check_content_of_written_file(self, ssh_client, expected):
118 actual = self._get_content(ssh_client)
119 self.assertEqual(expected, actual)
120
Matthew Treinish2153ec02013-09-09 20:57:30 +0000121 @services('compute', 'volume', 'image')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900122 def test_volume_boot_pattern(self):
123 keypair = self.create_keypair()
124 self.create_loginable_secgroup_rule()
125
126 # create an instance from volume
127 volume_origin = self._create_volume_from_image()
128 instance_1st = self._boot_instance_from_volume(volume_origin.id,
129 keypair)
130
131 # write content to volume on instance
132 ssh_client_for_instance_1st = self._ssh_to_server(instance_1st,
133 keypair)
134 text = self._write_text(ssh_client_for_instance_1st)
135
136 # delete instance
137 self._delete_server(instance_1st)
138
139 # create a 2nd instance from volume
140 instance_2nd = self._boot_instance_from_volume(volume_origin.id,
141 keypair)
142
143 # check the content of written file
144 ssh_client_for_instance_2nd = self._ssh_to_server(instance_2nd,
145 keypair)
146 self._check_content_of_written_file(ssh_client_for_instance_2nd, text)
147
148 # snapshot a volume
149 snapshot = self._create_snapshot_from_volume(volume_origin.id)
150
151 # create a 3rd instance from snapshot
152 volume = self._create_volume_from_snapshot(snapshot.id)
153 instance_from_snapshot = self._boot_instance_from_volume(volume.id,
154 keypair)
155
156 # check the content of written file
157 ssh_client = self._ssh_to_server(instance_from_snapshot, keypair)
158 self._check_content_of_written_file(ssh_client, text)
159
160 # NOTE(gfidente): ensure resources are in clean state for
161 # deletion operations to succeed
162 self._stop_instances([instance_2nd, instance_from_snapshot])
163 self._detach_volumes([volume_origin, volume])