blob: 4d8a4004fd4b85f97c7a0db8cb56da02409f915a [file] [log] [blame]
Giulio Fidenteb3c3cb92013-08-06 12:19:10 +02001# 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.openstack.common import log as logging
16
17from tempest.common.utils.data_utils import rand_name
18from tempest.scenario import manager
19
20LOG = logging.getLogger(__name__)
21
22
23class TestVolumeSnapshotPattern(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 * Create a volume snapshot while the instance is running
31 * Boot an additional instance from the new snapshot based volume
32 """
33
34 def _create_volume_from_image(self):
35 img_uuid = self.config.compute.image_ref
36 vol_name = rand_name('volume-origin')
37 vol = self.volume_client.volumes.create(size=1,
38 display_name=vol_name,
39 imageRef=img_uuid)
40 self.set_resource(vol.id, vol)
41 self.status_timeout(self.volume_client.volumes,
42 vol.id,
43 'available')
44 return vol
45
46 def _boot_instance_from_volume(self, vol_id):
47 # NOTE(gfidente): the img_uuid here is only needed because
48 # the novaclient requires it to be passed as arg
49 img_uuid = self.config.compute.image_ref
50 i_name = rand_name('instance')
51 flavor_id = self.config.compute.flavor_ref
52 # NOTE(gfidente): the syntax for block_device_mapping is
53 # dev_name=id:type:size:delete_on_terminate
54 # where type needs to be "snap" if the server is booted
55 # from a snapshot, size instead can be safely left empty
56 bd_map = {
57 'vda': vol_id + ':::0'
58 }
59 create_kwargs = {
60 'block_device_mapping': bd_map
61 }
62 i = self.compute_client.servers.create(name=i_name,
63 image=img_uuid,
64 flavor=flavor_id,
65 **create_kwargs)
66 self.set_resource(i.id, i)
67 self.status_timeout(self.compute_client.servers,
68 i.id,
69 'ACTIVE')
70 return i
71
72 def _create_snapshot_from_volume(self, vol_id):
73 volume_snapshots = self.volume_client.volume_snapshots
74 snap_name = rand_name('snapshot')
75 snap = volume_snapshots.create(volume_id=vol_id,
76 force=True,
77 display_name=snap_name)
78 self.set_resource(snap.id, snap)
79 self.status_timeout(volume_snapshots,
80 snap.id,
81 'available')
82 return snap
83
84 def _create_volume_from_snapshot(self, snap_id):
85 vol_name = rand_name('volume')
86 vol = self.volume_client.volumes.create(size=1,
87 display_name=vol_name,
88 snapshot_id=snap_id)
89 self.set_resource(vol.id, vol)
90 self.status_timeout(self.volume_client.volumes,
91 vol.id,
92 'available')
93 return vol
94
95 def _stop_instances(self, instances):
96 # NOTE(gfidente): two loops so we do not wait for the status twice
97 for i in instances:
98 self.compute_client.servers.stop(i)
99 for i in instances:
100 self.status_timeout(self.compute_client.servers,
101 i.id,
102 'SHUTOFF')
103
104 def _detach_volumes(self, volumes):
105 # NOTE(gfidente): two loops so we do not wait for the status twice
106 for v in volumes:
107 self.volume_client.volumes.detach(v)
108 for v in volumes:
109 self.status_timeout(self.volume_client.volumes,
110 v.id,
111 'available')
112
113 def test_volume_snapshot_pattern(self):
114 volume_origin = self._create_volume_from_image()
115 i_origin = self._boot_instance_from_volume(volume_origin.id)
116 snapshot = self._create_snapshot_from_volume(volume_origin.id)
117 volume = self._create_volume_from_snapshot(snapshot.id)
118 i = self._boot_instance_from_volume(volume.id)
119 # NOTE(gfidente): ensure resources are in clean state for
120 # deletion operations to succeed
121 self._stop_instances([i_origin, i])
122 self._detach_volumes([volume_origin, volume])