Codebase list cinder-tempest-plugin / d5eab10
Merge "Add tempest tests for Consistency Groups" Jenkins authored 9 years ago Gerrit Code Review committed 9 years ago
5 changed file(s) with 534 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
0 # Copyright (C) 2015 EMC Corporation.
1 # Copyright (C) 2016 Pure Storage, Inc.
2 # All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15
16 from oslo_log import log as logging
17 from tempest.api.volume import base
18 from tempest.common import waiters
19 from tempest import config
20 from tempest.lib.common.utils import data_utils
21 from tempest import test
22
23 from cinder.tests.tempest import cinder_clients
24
25 CONF = config.CONF
26 LOG = logging.getLogger(__name__)
27
28
29 class ConsistencyGroupsV2Test(base.BaseVolumeAdminTest):
30
31 @classmethod
32 def setup_clients(cls):
33 cls._api_version = 2
34 super(ConsistencyGroupsV2Test, cls).setup_clients()
35
36 manager = cinder_clients.Manager(cls.os_adm)
37 cls.consistencygroups_adm_client = manager.consistencygroups_adm_client
38
39 @classmethod
40 def skip_checks(cls):
41 super(ConsistencyGroupsV2Test, cls).skip_checks()
42 if not CONF.cinder.consistency_group:
43 raise cls.skipException("Cinder consistency group "
44 "feature disabled")
45
46 def _delete_consistencygroup(self, cg_id):
47 self.consistencygroups_adm_client.delete_consistencygroup(cg_id)
48 vols = self.admin_volume_client.list_volumes(detail=True)['volumes']
49 for vol in vols:
50 if vol['consistencygroup_id'] == cg_id:
51 self.admin_volume_client.wait_for_resource_deletion(vol['id'])
52 self.consistencygroups_adm_client.wait_for_consistencygroup_deletion(
53 cg_id)
54
55 def _delete_cgsnapshot(self, cgsnapshot_id, cg_id):
56 self.consistencygroups_adm_client.delete_cgsnapshot(cgsnapshot_id)
57 vols = self.admin_volume_client.list_volumes(detail=True)['volumes']
58 snapshots = self.admin_snapshots_client.list_snapshots(
59 detail=True)['snapshots']
60 for vol in vols:
61 for snap in snapshots:
62 if (vol['consistencygroup_id'] == cg_id and
63 vol['id'] == snap['volume_id']):
64 self.snapshots_client.wait_for_resource_deletion(
65 snap['id'])
66 self.consistencygroups_adm_client.wait_for_cgsnapshot_deletion(
67 cgsnapshot_id)
68
69 @test.idempotent_id('3fe776ba-ec1f-4e6c-8d78-4b14c3a7fc44')
70 def test_consistencygroup_create_delete(self):
71 # Create volume type
72 name = data_utils.rand_name("volume-type")
73 volume_type = self.admin_volume_types_client.create_volume_type(
74 name=name)['volume_type']
75
76 # Create CG
77 cg_name = data_utils.rand_name('CG')
78 create_consistencygroup = (
79 self.consistencygroups_adm_client.create_consistencygroup)
80 cg = create_consistencygroup(volume_type['id'],
81 name=cg_name)['consistencygroup']
82 vol_name = data_utils.rand_name("volume")
83 self.name_field = self.special_fields['name_field']
84 params = {self.name_field: vol_name,
85 'volume_type': volume_type['id'],
86 'consistencygroup_id': cg['id']}
87
88 # Create volume
89 volume = self.admin_volume_client.create_volume(**params)['volume']
90
91 waiters.wait_for_volume_status(self.admin_volume_client,
92 volume['id'], 'available')
93 self.consistencygroups_adm_client.wait_for_consistencygroup_status(
94 cg['id'], 'available')
95 self.assertEqual(cg_name, cg['name'])
96
97 # Get a given CG
98 cg = self.consistencygroups_adm_client.show_consistencygroup(
99 cg['id'])['consistencygroup']
100 self.assertEqual(cg_name, cg['name'])
101
102 # Get all CGs with detail
103 cgs = self.consistencygroups_adm_client.list_consistencygroups(
104 detail=True)['consistencygroups']
105 self.assertIn((cg['name'], cg['id']),
106 [(m['name'], m['id']) for m in cgs])
107
108 # Clean up
109 self._delete_consistencygroup(cg['id'])
110 self.admin_volume_types_client.delete_volume_type(volume_type['id'])
111
112 @test.idempotent_id('2134dd52-f333-4456-bb05-6cb0f009a44f')
113 def test_consistencygroup_cgsnapshot_create_delete(self):
114 # Create volume type
115 name = data_utils.rand_name("volume-type")
116 volume_type = self.admin_volume_types_client.create_volume_type(
117 name=name)['volume_type']
118
119 # Create CG
120 cg_name = data_utils.rand_name('CG')
121 create_consistencygroup = (
122 self.consistencygroups_adm_client.create_consistencygroup)
123 cg = create_consistencygroup(volume_type['id'],
124 name=cg_name)['consistencygroup']
125 vol_name = data_utils.rand_name("volume")
126 self.name_field = self.special_fields['name_field']
127 params = {self.name_field: vol_name,
128 'volume_type': volume_type['id'],
129 'consistencygroup_id': cg['id']}
130
131 # Create volume
132 volume = self.admin_volume_client.create_volume(**params)['volume']
133 waiters.wait_for_volume_status(self.admin_volume_client,
134 volume['id'], 'available')
135 self.consistencygroups_adm_client.wait_for_consistencygroup_status(
136 cg['id'], 'available')
137 self.assertEqual(cg_name, cg['name'])
138
139 # Create cgsnapshot
140 cgsnapshot_name = data_utils.rand_name('cgsnapshot')
141 create_cgsnapshot = (
142 self.consistencygroups_adm_client.create_cgsnapshot)
143 cgsnapshot = create_cgsnapshot(cg['id'],
144 name=cgsnapshot_name)['cgsnapshot']
145 snapshots = self.admin_snapshots_client.list_snapshots(
146 detail=True)['snapshots']
147 for snap in snapshots:
148 if volume['id'] == snap['volume_id']:
149 waiters.wait_for_snapshot_status(self.admin_snapshots_client,
150 snap['id'], 'available')
151 self.consistencygroups_adm_client.wait_for_cgsnapshot_status(
152 cgsnapshot['id'], 'available')
153 self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
154
155 # Get a given CG snapshot
156 cgsnapshot = self.consistencygroups_adm_client.show_cgsnapshot(
157 cgsnapshot['id'])['cgsnapshot']
158 self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
159
160 # Get all CG snapshots with detail
161 cgsnapshots = self.consistencygroups_adm_client.list_cgsnapshots(
162 detail=True)['cgsnapshots']
163 self.assertIn((cgsnapshot['name'], cgsnapshot['id']),
164 [(m['name'], m['id']) for m in cgsnapshots])
165
166 # Clean up
167 self._delete_cgsnapshot(cgsnapshot['id'], cg['id'])
168 self._delete_consistencygroup(cg['id'])
169 self.admin_volume_types_client.delete_volume_type(volume_type['id'])
170
171 @test.idempotent_id('3a6a5525-25ca-4a6c-aac4-cac6fa8f5b43')
172 def test_create_consistencygroup_from_cgsnapshot(self):
173 # Create volume type
174 name = data_utils.rand_name("volume-type")
175 volume_type = self.admin_volume_types_client.create_volume_type(
176 name=name)['volume_type']
177
178 # Create CG
179 cg_name = data_utils.rand_name('CG')
180 create_consistencygroup = (
181 self.consistencygroups_adm_client.create_consistencygroup)
182 cg = create_consistencygroup(volume_type['id'],
183 name=cg_name)['consistencygroup']
184 vol_name = data_utils.rand_name("volume")
185 self.name_field = self.special_fields['name_field']
186 params = {self.name_field: vol_name,
187 'volume_type': volume_type['id'],
188 'consistencygroup_id': cg['id']}
189
190 # Create volume
191 volume = self.admin_volume_client.create_volume(**params)['volume']
192 waiters.wait_for_volume_status(self.admin_volume_client,
193 volume['id'], 'available')
194 self.consistencygroups_adm_client.wait_for_consistencygroup_status(
195 cg['id'], 'available')
196 self.assertEqual(cg_name, cg['name'])
197
198 # Create cgsnapshot
199 cgsnapshot_name = data_utils.rand_name('cgsnapshot')
200 create_cgsnapshot = (
201 self.consistencygroups_adm_client.create_cgsnapshot)
202 cgsnapshot = create_cgsnapshot(cg['id'],
203 name=cgsnapshot_name)['cgsnapshot']
204 snapshots = self.snapshots_client.list_snapshots(
205 detail=True)['snapshots']
206 for snap in snapshots:
207 if volume['id'] == snap['volume_id']:
208 waiters.wait_for_snapshot_status(self.admin_snapshots_client,
209 snap['id'], 'available')
210 self.consistencygroups_adm_client.wait_for_cgsnapshot_status(
211 cgsnapshot['id'], 'available')
212 self.assertEqual(cgsnapshot_name, cgsnapshot['name'])
213
214 # Create CG from CG snapshot
215 cg_name2 = data_utils.rand_name('CG_from_snap')
216 create_consistencygroup2 = (
217 self.consistencygroups_adm_client.create_consistencygroup_from_src)
218 cg2 = create_consistencygroup2(cgsnapshot_id=cgsnapshot['id'],
219 name=cg_name2)['consistencygroup']
220 vols = self.admin_volume_client.list_volumes(
221 detail=True)['volumes']
222 for vol in vols:
223 if vol['consistencygroup_id'] == cg2['id']:
224 waiters.wait_for_volume_status(self.admin_volume_client,
225 vol['id'], 'available')
226 self.consistencygroups_adm_client.wait_for_consistencygroup_status(
227 cg2['id'], 'available')
228 self.assertEqual(cg_name2, cg2['name'])
229
230 # Clean up
231 self._delete_consistencygroup(cg2['id'])
232 self._delete_cgsnapshot(cgsnapshot['id'], cg['id'])
233 self._delete_consistencygroup(cg['id'])
234 self.admin_volume_types_client.delete_volume_type(volume_type['id'])
235
236 @test.idempotent_id('556121ae-de9c-4342-9897-e54260447a19')
237 def test_create_consistencygroup_from_consistencygroup(self):
238 # Create volume type
239 name = data_utils.rand_name("volume-type")
240 volume_type = self.admin_volume_types_client.create_volume_type(
241 name=name)['volume_type']
242
243 # Create CG
244 cg_name = data_utils.rand_name('CG')
245 create_consistencygroup = (
246 self.consistencygroups_adm_client.create_consistencygroup)
247 cg = create_consistencygroup(volume_type['id'],
248 name=cg_name)['consistencygroup']
249 vol_name = data_utils.rand_name("volume")
250 self.name_field = self.special_fields['name_field']
251 params = {self.name_field: vol_name,
252 'volume_type': volume_type['id'],
253 'consistencygroup_id': cg['id']}
254
255 # Create volume
256 volume = self.admin_volume_client.create_volume(**params)['volume']
257 waiters.wait_for_volume_status(self.admin_volume_client,
258 volume['id'], 'available')
259 self.consistencygroups_adm_client.wait_for_consistencygroup_status(
260 cg['id'], 'available')
261 self.assertEqual(cg_name, cg['name'])
262
263 # Create CG from CG
264 cg_name2 = data_utils.rand_name('CG_from_cg')
265 create_consistencygroup2 = (
266 self.consistencygroups_adm_client.create_consistencygroup_from_src)
267 cg2 = create_consistencygroup2(source_cgid=cg['id'],
268 name=cg_name2)['consistencygroup']
269 vols = self.admin_volume_client.list_volumes(
270 detail=True)['volumes']
271 for vol in vols:
272 if vol['consistencygroup_id'] == cg2['id']:
273 waiters.wait_for_volume_status(self.admin_volume_client,
274 vol['id'], 'available')
275 self.consistencygroups_adm_client.wait_for_consistencygroup_status(
276 cg2['id'], 'available')
277 self.assertEqual(cg_name2, cg2['name'])
278
279 # Clean up
280 self._delete_consistencygroup(cg2['id'])
281 self._delete_consistencygroup(cg['id'])
282 self.admin_volume_types_client.delete_volume_type(volume_type['id'])
0 # Copyright (c) 2016 Pure Storage, Inc.
1 # All Rights Reserved.
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
15 from tempest import config
16
17 from cinder.tests.tempest.services import consistencygroups_client
18
19 CONF = config.CONF
20
21
22 class Manager(object):
23 def __init__(self, base_manager):
24 params = {
25 'service': CONF.volume.catalog_type,
26 'region': CONF.volume.region or CONF.identity.region,
27 'endpoint_type': CONF.volume.endpoint_type,
28 'build_interval': CONF.volume.build_interval,
29 'build_timeout': CONF.volume.build_timeout
30 }
31 params.update(base_manager.default_params)
32 auth_provider = base_manager.auth_provider
33
34 self.consistencygroups_adm_client = (
35 consistencygroups_client.ConsistencyGroupsClient(auth_provider,
36 **params))
2323 default=True,
2424 help="Whether or not cinder is expected to be available"),
2525 ]
26
27 # Use a new config group specific to the cinder in-tree tests to avoid
28 # any naming confusion with the upstream tempest config options.
29 cinder_group = cfg.OptGroup(name='cinder',
30 title='Cinder Tempest Config Options')
31
32 CinderGroup = [
33 cfg.BoolOpt('consistency_group',
34 default=False,
35 help='Enable to run Cinder volume consistency group tests'),
36 ]
1616 import os
1717
1818 from cinder.tests.tempest import config as project_config
19
1920 from tempest import config
2021 from tempest.test_discover import plugins
2122
3233 config.register_opt_group(
3334 conf, project_config.service_available_group,
3435 project_config.ServiceAvailableGroup)
36 config.register_opt_group(
37 conf, project_config.cinder_group,
38 project_config.CinderGroup
39 )
3540
3641 def get_opt_lists(self):
37 pass
42 return [
43 (project_config.service_available_group.name,
44 project_config.ServiceAvailableGroup),
45 (project_config.cinder_group.name,
46 project_config.CinderGroup),
47 ]
0 # Copyright (C) 2015 EMC Corporation.
1 # Copyright (C) 2016 Pure Storage, Inc.
2 # All Rights Reserved.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
14 # under the License.
15
16 import time
17
18 from oslo_serialization import jsonutils as json
19 from tempest import exceptions
20 from tempest.lib.common import rest_client
21 from tempest.lib import exceptions as lib_exc
22
23
24 class ConsistencyGroupsClient(rest_client.RestClient):
25 """Client class to send CRUD Volume ConsistencyGroup API requests"""
26
27 def __init__(self, auth_provider, service, region, **kwargs):
28 super(ConsistencyGroupsClient, self).__init__(
29 auth_provider, service, region, **kwargs)
30
31 def create_consistencygroup(self, volume_types, **kwargs):
32 """Creates a consistency group."""
33 post_body = {'volume_types': volume_types}
34 if kwargs.get('availability_zone'):
35 post_body['availability_zone'] = kwargs.get('availability_zone')
36 if kwargs.get('name'):
37 post_body['name'] = kwargs.get('name')
38 if kwargs.get('description'):
39 post_body['description'] = kwargs.get('description')
40 post_body = json.dumps({'consistencygroup': post_body})
41 resp, body = self.post('consistencygroups', post_body)
42 body = json.loads(body)
43 self.expected_success(202, resp.status)
44 return rest_client.ResponseBody(resp, body)
45
46 def create_consistencygroup_from_src(self, **kwargs):
47 """Creates a consistency group from source."""
48 post_body = {}
49 if kwargs.get('cgsnapshot_id'):
50 post_body['cgsnapshot_id'] = kwargs.get('cgsnapshot_id')
51 if kwargs.get('source_cgid'):
52 post_body['source_cgid'] = kwargs.get('source_cgid')
53 if kwargs.get('name'):
54 post_body['name'] = kwargs.get('name')
55 if kwargs.get('description'):
56 post_body['description'] = kwargs.get('description')
57 post_body = json.dumps({'consistencygroup-from-src': post_body})
58 resp, body = self.post('consistencygroups/create_from_src', post_body)
59 body = json.loads(body)
60 self.expected_success(202, resp.status)
61 return rest_client.ResponseBody(resp, body)
62
63 def delete_consistencygroup(self, cg_id):
64 """Delete a consistency group."""
65 post_body = {'force': True}
66 post_body = json.dumps({'consistencygroup': post_body})
67 resp, body = self.post('consistencygroups/%s/delete' % cg_id,
68 post_body)
69 self.expected_success(202, resp.status)
70 return rest_client.ResponseBody(resp, body)
71
72 def show_consistencygroup(self, cg_id):
73 """Returns the details of a single consistency group."""
74 url = "consistencygroups/%s" % str(cg_id)
75 resp, body = self.get(url)
76 body = json.loads(body)
77 self.expected_success(200, resp.status)
78 return rest_client.ResponseBody(resp, body)
79
80 def list_consistencygroups(self, detail=False):
81 """Information for all the tenant's consistency groups."""
82 url = "consistencygroups"
83 if detail:
84 url += "/detail"
85 resp, body = self.get(url)
86 body = json.loads(body)
87 self.expected_success(200, resp.status)
88 return rest_client.ResponseBody(resp, body)
89
90 def create_cgsnapshot(self, consistencygroup_id, **kwargs):
91 """Creates a consistency group snapshot."""
92 post_body = {'consistencygroup_id': consistencygroup_id}
93 if kwargs.get('name'):
94 post_body['name'] = kwargs.get('name')
95 if kwargs.get('description'):
96 post_body['description'] = kwargs.get('description')
97 post_body = json.dumps({'cgsnapshot': post_body})
98 resp, body = self.post('cgsnapshots', post_body)
99 body = json.loads(body)
100 self.expected_success(202, resp.status)
101 return rest_client.ResponseBody(resp, body)
102
103 def delete_cgsnapshot(self, cgsnapshot_id):
104 """Delete a consistency group snapshot."""
105 resp, body = self.delete('cgsnapshots/%s' % (str(cgsnapshot_id)))
106 self.expected_success(202, resp.status)
107 return rest_client.ResponseBody(resp, body)
108
109 def show_cgsnapshot(self, cgsnapshot_id):
110 """Returns the details of a single consistency group snapshot."""
111 url = "cgsnapshots/%s" % str(cgsnapshot_id)
112 resp, body = self.get(url)
113 body = json.loads(body)
114 self.expected_success(200, resp.status)
115 return rest_client.ResponseBody(resp, body)
116
117 def list_cgsnapshots(self, detail=False):
118 """Information for all the tenant's consistency group snapshotss."""
119 url = "cgsnapshots"
120 if detail:
121 url += "/detail"
122 resp, body = self.get(url)
123 body = json.loads(body)
124 self.expected_success(200, resp.status)
125 return rest_client.ResponseBody(resp, body)
126
127 def wait_for_consistencygroup_status(self, cg_id, status):
128 """Waits for a consistency group to reach a given status."""
129 body = self.show_consistencygroup(cg_id)['consistencygroup']
130 cg_status = body['status']
131 start = int(time.time())
132
133 while cg_status != status:
134 time.sleep(self.build_interval)
135 body = self.show_consistencygroup(cg_id)['consistencygroup']
136 cg_status = body['status']
137 if cg_status == 'error':
138 raise exceptions.ConsistencyGroupException(cg_id=cg_id)
139
140 if int(time.time()) - start >= self.build_timeout:
141 message = ('Consistency group %s failed to reach %s status '
142 '(current %s) within the required time (%s s).' %
143 (cg_id, status, cg_status,
144 self.build_timeout))
145 raise exceptions.TimeoutException(message)
146
147 def wait_for_consistencygroup_deletion(self, cg_id):
148 """Waits for consistency group deletion"""
149 start_time = int(time.time())
150 while True:
151 try:
152 self.show_consistencygroup(cg_id)
153 except lib_exc.NotFound:
154 return
155 if int(time.time()) - start_time >= self.build_timeout:
156 raise exceptions.TimeoutException
157 time.sleep(self.build_interval)
158
159 def wait_for_cgsnapshot_status(self, cgsnapshot_id, status):
160 """Waits for a consistency group snapshot to reach a given status."""
161 body = self.show_cgsnapshot(cgsnapshot_id)['cgsnapshot']
162 cgsnapshot_status = body['status']
163 start = int(time.time())
164
165 while cgsnapshot_status != status:
166 time.sleep(self.build_interval)
167 body = self.show_cgsnapshot(cgsnapshot_id)['cgsnapshot']
168 cgsnapshot_status = body['status']
169 if cgsnapshot_status == 'error':
170 raise exceptions.ConsistencyGroupSnapshotException(
171 cgsnapshot_id=cgsnapshot_id)
172
173 if int(time.time()) - start >= self.build_timeout:
174 message = ('Consistency group snapshot %s failed to reach '
175 '%s status (current %s) within the required time '
176 '(%s s).' %
177 (cgsnapshot_id, status, cgsnapshot_status,
178 self.build_timeout))
179 raise exceptions.TimeoutException(message)
180
181 def wait_for_cgsnapshot_deletion(self, cgsnapshot_id):
182 """Waits for consistency group snapshot deletion"""
183 start_time = int(time.time())
184 while True:
185 try:
186 self.show_cgsnapshot(cgsnapshot_id)
187 except lib_exc.NotFound:
188 return
189 if int(time.time()) - start_time >= self.build_timeout:
190 raise exceptions.TimeoutException
191 time.sleep(self.build_interval)