blob: c4f8ceddfa27b412e4965b77acc194cc3967254b [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
Nachi Ueno95b41282014-01-15 06:54:21 -080014from tempest.openstack.common import log
fujioka yuuichi636f8db2013-08-09 12:05:24 +090015from tempest.scenario import manager
Sean Daguecb6c99f2014-01-20 19:37:59 -050016import tempest.test
Matthew Treinish2153ec02013-09-09 20:57:30 +000017from tempest.test import services
fujioka yuuichi636f8db2013-08-09 12:05:24 +090018
19
Nachi Ueno95b41282014-01-15 06:54:21 -080020LOG = log.getLogger(__name__)
21
22
fujioka yuuichi636f8db2013-08-09 12:05:24 +090023class TestVolumeBootPattern(manager.OfficialClientTest):
24
25 """
26 This test case attempts to reproduce the following steps:
27
28 * Create in Cinder some bootable volume importing a Glance image
29 * Boot an instance from the bootable volume
30 * Write content to the volume
31 * Delete an instance and Boot a new instance from the volume
32 * Check written content in the instance
33 * Create a volume snapshot while the instance is running
34 * Boot an additional instance from the new snapshot based volume
35 * Check written content in the instance booted from snapshot
36 """
37
38 def _create_volume_from_image(self):
39 img_uuid = self.config.compute.image_ref
Masayuki Igawa259c1132013-10-31 17:48:44 +090040 vol_name = data_utils.rand_name('volume-origin')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090041 return self.create_volume(name=vol_name, imageRef=img_uuid)
42
43 def _boot_instance_from_volume(self, vol_id, keypair):
44 # NOTE(gfidente): the syntax for block_device_mapping is
45 # dev_name=id:type:size:delete_on_terminate
46 # where type needs to be "snap" if the server is booted
47 # from a snapshot, size instead can be safely left empty
48 bd_map = {
49 'vda': vol_id + ':::0'
50 }
51 create_kwargs = {
52 'block_device_mapping': bd_map,
53 'key_name': keypair.name
54 }
Giulio Fidente61cadca2013-09-24 18:33:37 +020055 return self.create_server(create_kwargs=create_kwargs)
fujioka yuuichi636f8db2013-08-09 12:05:24 +090056
57 def _create_snapshot_from_volume(self, vol_id):
58 volume_snapshots = self.volume_client.volume_snapshots
Masayuki Igawa259c1132013-10-31 17:48:44 +090059 snap_name = data_utils.rand_name('snapshot')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090060 snap = volume_snapshots.create(volume_id=vol_id,
61 force=True,
62 display_name=snap_name)
63 self.set_resource(snap.id, snap)
64 self.status_timeout(volume_snapshots,
65 snap.id,
66 'available')
67 return snap
68
69 def _create_volume_from_snapshot(self, snap_id):
Masayuki Igawa259c1132013-10-31 17:48:44 +090070 vol_name = data_utils.rand_name('volume')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090071 return self.create_volume(name=vol_name, snapshot_id=snap_id)
72
73 def _stop_instances(self, instances):
74 # NOTE(gfidente): two loops so we do not wait for the status twice
75 for i in instances:
76 self.compute_client.servers.stop(i)
77 for i in instances:
78 self.status_timeout(self.compute_client.servers,
79 i.id,
80 'SHUTOFF')
81
82 def _detach_volumes(self, volumes):
83 # NOTE(gfidente): two loops so we do not wait for the status twice
84 for v in volumes:
85 self.volume_client.volumes.detach(v)
86 for v in volumes:
87 self.status_timeout(self.volume_client.volumes,
88 v.id,
89 'available')
90
91 def _ssh_to_server(self, server, keypair):
92 if self.config.compute.use_floatingip_for_ssh:
93 floating_ip = self.compute_client.floating_ips.create()
Masayuki Igawa259c1132013-10-31 17:48:44 +090094 fip_name = data_utils.rand_name('scenario-fip')
fujioka yuuichi636f8db2013-08-09 12:05:24 +090095 self.set_resource(fip_name, floating_ip)
96 server.add_floating_ip(floating_ip)
97 ip = floating_ip.ip
98 else:
99 network_name_for_ssh = self.config.compute.network_for_ssh
100 ip = server.networks[network_name_for_ssh][0]
101
Nachi Ueno95b41282014-01-15 06:54:21 -0800102 try:
103 client = self.get_remote_client(
104 ip,
105 private_key=keypair.private_key)
106 except Exception:
107 LOG.exception('ssh to server failed')
108 self._log_console_output()
109 raise
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900110 return client.ssh_client
111
112 def _get_content(self, ssh_client):
113 return ssh_client.exec_command('cat /tmp/text')
114
115 def _write_text(self, ssh_client):
Masayuki Igawa259c1132013-10-31 17:48:44 +0900116 text = data_utils.rand_name('text-')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900117 ssh_client.exec_command('echo "%s" > /tmp/text; sync' % (text))
118
119 return self._get_content(ssh_client)
120
121 def _delete_server(self, server):
122 self.compute_client.servers.delete(server)
123 self.delete_timeout(self.compute_client.servers, server.id)
124
125 def _check_content_of_written_file(self, ssh_client, expected):
126 actual = self._get_content(ssh_client)
127 self.assertEqual(expected, actual)
128
Sean Daguecb6c99f2014-01-20 19:37:59 -0500129 @tempest.test.skip_because(bug="1270608")
Matthew Treinish2153ec02013-09-09 20:57:30 +0000130 @services('compute', 'volume', 'image')
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900131 def test_volume_boot_pattern(self):
132 keypair = self.create_keypair()
Yair Friedeb69f3f2013-10-10 13:18:16 +0300133 self._create_loginable_secgroup_rule_nova()
fujioka yuuichi636f8db2013-08-09 12:05:24 +0900134
135 # create an instance from volume
136 volume_origin = self._create_volume_from_image()
137 instance_1st = self._boot_instance_from_volume(volume_origin.id,
138 keypair)
139
140 # write content to volume on instance
141 ssh_client_for_instance_1st = self._ssh_to_server(instance_1st,
142 keypair)
143 text = self._write_text(ssh_client_for_instance_1st)
144
145 # delete instance
146 self._delete_server(instance_1st)
147
148 # create a 2nd instance from volume
149 instance_2nd = self._boot_instance_from_volume(volume_origin.id,
150 keypair)
151
152 # check the content of written file
153 ssh_client_for_instance_2nd = self._ssh_to_server(instance_2nd,
154 keypair)
155 self._check_content_of_written_file(ssh_client_for_instance_2nd, text)
156
157 # snapshot a volume
158 snapshot = self._create_snapshot_from_volume(volume_origin.id)
159
160 # create a 3rd instance from snapshot
161 volume = self._create_volume_from_snapshot(snapshot.id)
162 instance_from_snapshot = self._boot_instance_from_volume(volume.id,
163 keypair)
164
165 # check the content of written file
166 ssh_client = self._ssh_to_server(instance_from_snapshot, keypair)
167 self._check_content_of_written_file(ssh_client, text)
168
169 # NOTE(gfidente): ensure resources are in clean state for
170 # deletion operations to succeed
171 self._stop_instances([instance_2nd, instance_from_snapshot])
172 self._detach_volumes([volume_origin, volume])