cinder/cinder/tests/unit/api/contrib/test_consistencygroups.py

1573 lines
71 KiB
Python

# Copyright (C) 2012 - 2014 EMC Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Tests for consistency group code."""
from unittest import mock
import ddt
from oslo_serialization import jsonutils
from six.moves import http_client
import webob
from cinder import context
from cinder import db
from cinder import exception
import cinder.group
from cinder.i18n import _
from cinder import objects
from cinder.objects import fields
from cinder import test
from cinder.tests.unit.api import fakes
from cinder.tests.unit.api.v2 import fakes as v2_fakes
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import utils
from cinder.volume import api as volume_api
@ddt.ddt
class ConsistencyGroupsAPITestCase(test.TestCase):
"""Test Case for consistency groups API."""
def setUp(self):
super(ConsistencyGroupsAPITestCase, self).setUp()
self.cg_api = cinder.group.API()
self.ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID,
auth_token=True,
is_admin=True)
self.user_ctxt = context.RequestContext(
fake.USER_ID, fake.PROJECT_ID, auth_token=True)
self.admin_ctxt = context.get_admin_context()
db.volume_type_create(self.admin_ctxt,
v2_fakes.fake_default_type_get(
fake.VOLUME_TYPE2_ID))
self.vol_type = db.volume_type_get_by_name(self.admin_ctxt,
'vol_type_name')
def _create_consistencygroup(
self,
ctxt=None,
name='test_consistencygroup',
user_id=fake.USER_ID,
project_id=fake.PROJECT_ID,
description='this is a test consistency group',
group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],
availability_zone='az1',
host='fakehost',
status=fields.ConsistencyGroupStatus.CREATING,
**kwargs):
"""Create a consistency group object."""
ctxt = ctxt or self.ctxt
consistencygroup = objects.Group(ctxt)
consistencygroup.user_id = user_id
consistencygroup.project_id = project_id
consistencygroup.availability_zone = availability_zone
consistencygroup.name = name
consistencygroup.description = description
consistencygroup.group_type_id = group_type_id
consistencygroup.volume_type_ids = volume_type_ids
consistencygroup.host = host
consistencygroup.status = status
consistencygroup.update(kwargs)
consistencygroup.create()
return consistencygroup
def test_show_consistencygroup(self):
vol_type = utils.create_volume_type(context.get_admin_context(),
self, name='my_vol_type')
consistencygroup = self._create_consistencygroup(
volume_type_ids=[vol_type['id']])
req = webob.Request.blank('/v2/%s/consistencygroups/%s' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
consistencygroup.destroy()
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual('az1',
res_dict['consistencygroup']['availability_zone'])
self.assertEqual('this is a test consistency group',
res_dict['consistencygroup']['description'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroup']['name'])
self.assertEqual('creating',
res_dict['consistencygroup']['status'])
self.assertEqual([vol_type['id']],
res_dict['consistencygroup']['volume_types'])
def test_show_consistencygroup_with_consistencygroup_NotFound(self):
req = webob.Request.blank('/v2/%s/consistencygroups/%s' %
(fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID))
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.NOT_FOUND, res.status_int)
self.assertEqual(http_client.NOT_FOUND,
res_dict['itemNotFound']['code'])
self.assertEqual('Group %s could not be found.' %
fake.WILL_NOT_BE_FOUND_ID,
res_dict['itemNotFound']['message'])
def test_show_consistencygroup_with_null_volume_type(self):
consistencygroup = self._create_consistencygroup(volume_type_id=None)
req = webob.Request.blank('/v2/%s/consistencygroups/%s' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual('az1',
res_dict['consistencygroup']['availability_zone'])
self.assertEqual('this is a test consistency group',
res_dict['consistencygroup']['description'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroup']['name'])
self.assertEqual('creating',
res_dict['consistencygroup']['status'])
self.assertEqual([], res_dict['consistencygroup']['volume_types'])
consistencygroup.destroy()
@ddt.data(2, 3)
def test_list_consistencygroups_json(self, version):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup()
consistencygroup3 = self._create_consistencygroup()
req = webob.Request.blank('/v%(version)s/%(project_id)s/'
'consistencygroups'
% {'version': version,
'project_id': fake.PROJECT_ID})
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual(consistencygroup3.id,
res_dict['consistencygroups'][0]['id'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroups'][0]['name'])
self.assertEqual(consistencygroup2.id,
res_dict['consistencygroups'][1]['id'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroups'][1]['name'])
self.assertEqual(consistencygroup1.id,
res_dict['consistencygroups'][2]['id'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroups'][2]['name'])
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
@ddt.data(False, True)
def test_list_consistencygroups_with_limit(self, is_detail):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup()
consistencygroup3 = self._create_consistencygroup()
url = '/v2/%s/consistencygroups?limit=1' % fake.PROJECT_ID
if is_detail:
url = '/v2/%s/consistencygroups/detail?limit=1' % fake.PROJECT_ID
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual(1, len(res_dict['consistencygroups']))
self.assertEqual(consistencygroup3.id,
res_dict['consistencygroups'][0]['id'])
next_link = (
'http://localhost/v2/%s/consistencygroups?limit='
'1&marker=%s' %
(fake.PROJECT_ID, res_dict['consistencygroups'][0]['id']))
self.assertEqual(next_link,
res_dict['consistencygroup_links'][0]['href'])
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
@ddt.data(False, True)
def test_list_consistencygroups_with_offset(self, is_detail):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup()
consistencygroup3 = self._create_consistencygroup()
url = '/v2/%s/consistencygroups?offset=1' % fake.PROJECT_ID
if is_detail:
url = '/v2/%s/consistencygroups/detail?offset=1' % fake.PROJECT_ID
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual(2, len(res_dict['consistencygroups']))
self.assertEqual(consistencygroup2.id,
res_dict['consistencygroups'][0]['id'])
self.assertEqual(consistencygroup1.id,
res_dict['consistencygroups'][1]['id'])
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
@ddt.data(False, True)
def test_list_consistencygroups_with_offset_out_of_range(self, is_detail):
url = ('/v2/%s/consistencygroups?offset=234523423455454' %
fake.PROJECT_ID)
if is_detail:
url = ('/v2/%s/consistencygroups/detail?offset=234523423455454' %
fake.PROJECT_ID)
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
@ddt.data(False, True)
def test_list_consistencygroups_with_limit_and_offset(self, is_detail):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup()
consistencygroup3 = self._create_consistencygroup()
url = '/v2/%s/consistencygroups?limit=2&offset=1' % fake.PROJECT_ID
if is_detail:
url = ('/v2/%s/consistencygroups/detail?limit=2&offset=1' %
fake.PROJECT_ID)
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual(2, len(res_dict['consistencygroups']))
self.assertEqual(consistencygroup2.id,
res_dict['consistencygroups'][0]['id'])
self.assertEqual(consistencygroup1.id,
res_dict['consistencygroups'][1]['id'])
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
@ddt.data(False, True)
def test_list_consistencygroups_with_filter(self, is_detail):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup()
common_ctxt = context.RequestContext(fake.USER_ID, fake.PROJECT_ID,
auth_token=True,
is_admin=False)
consistencygroup3 = self._create_consistencygroup(ctxt=common_ctxt)
url = ('/v2/%s/consistencygroups?'
'all_tenants=True&id=%s') % (fake.PROJECT_ID,
consistencygroup3.id)
if is_detail:
url = ('/v2/%s/consistencygroups/detail?'
'all_tenants=True&id=%s') % (fake.PROJECT_ID,
consistencygroup3.id)
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(fake_auth_context=self.ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual(1, len(res_dict['consistencygroups']))
self.assertEqual(consistencygroup3.id,
res_dict['consistencygroups'][0]['id'])
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
@ddt.data(False, True)
def test_list_consistencygroups_with_project_id(self, is_detail):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup(
name="group", project_id=fake.PROJECT2_ID)
url = ('/v2/%s/consistencygroups?'
'all_tenants=True&project_id=%s') % (fake.PROJECT_ID,
fake.PROJECT2_ID)
if is_detail:
url = ('/v2/%s/consistencygroups/detail?'
'all_tenants=True&project_id=%s') % (fake.PROJECT_ID,
fake.PROJECT2_ID)
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(fake_auth_context=self.ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(200, res.status_int)
self.assertEqual(1, len(res_dict['consistencygroups']))
self.assertEqual("group",
res_dict['consistencygroups'][0]['name'])
consistencygroup1.destroy()
consistencygroup2.destroy()
@ddt.data(False, True)
def test_list_consistencygroups_with_sort(self, is_detail):
consistencygroup1 = self._create_consistencygroup()
consistencygroup2 = self._create_consistencygroup()
consistencygroup3 = self._create_consistencygroup()
url = '/v2/%s/consistencygroups?sort=id:asc' % fake.PROJECT_ID
if is_detail:
url = ('/v2/%s/consistencygroups/detail?sort=id:asc' %
fake.PROJECT_ID)
req = webob.Request.blank(url)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
expect_result = [consistencygroup1.id, consistencygroup2.id,
consistencygroup3.id]
expect_result.sort()
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual(3, len(res_dict['consistencygroups']))
self.assertEqual(expect_result[0],
res_dict['consistencygroups'][0]['id'])
self.assertEqual(expect_result[1],
res_dict['consistencygroups'][1]['id'])
self.assertEqual(expect_result[2],
res_dict['consistencygroups'][2]['id'])
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
def test_list_consistencygroups_detail_json(self):
vol_type1 = utils.create_volume_type(context.get_admin_context(),
self, name='my_vol_type1')
vol_type2 = utils.create_volume_type(context.get_admin_context(),
self, name='my_vol_type2')
consistencygroup1 = self._create_consistencygroup(
volume_type_ids=[vol_type1['id']])
consistencygroup2 = self._create_consistencygroup(
volume_type_ids=[vol_type1['id']])
consistencygroup3 = self._create_consistencygroup(
volume_type_ids=[vol_type1['id'], vol_type2['id']])
req = webob.Request.blank('/v2/%s/consistencygroups/detail' %
fake.PROJECT_ID)
req.method = 'GET'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
cg_ids = [consistencygroup1.id, consistencygroup2.id,
consistencygroup3.id]
vol_type_ids = [vol_type1['id'], vol_type2['id']]
consistencygroup1.destroy()
consistencygroup2.destroy()
consistencygroup3.destroy()
self.assertEqual(http_client.OK, res.status_int)
self.assertEqual('az1',
res_dict['consistencygroups'][0]['availability_zone'])
self.assertEqual('this is a test consistency group',
res_dict['consistencygroups'][0]['description'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroups'][0]['name'])
self.assertIn(res_dict['consistencygroups'][0]['id'], cg_ids)
self.assertEqual('creating',
res_dict['consistencygroups'][0]['status'])
for vol_type_id in res_dict['consistencygroups'][0]['volume_types']:
self.assertIn(vol_type_id, vol_type_ids)
self.assertEqual('az1',
res_dict['consistencygroups'][1]['availability_zone'])
self.assertEqual('this is a test consistency group',
res_dict['consistencygroups'][1]['description'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroups'][1]['name'])
self.assertIn(res_dict['consistencygroups'][0]['id'], cg_ids)
self.assertEqual('creating',
res_dict['consistencygroups'][1]['status'])
for vol_type_id in res_dict['consistencygroups'][1]['volume_types']:
self.assertIn(vol_type_id, vol_type_ids)
self.assertEqual('az1',
res_dict['consistencygroups'][2]['availability_zone'])
self.assertEqual('this is a test consistency group',
res_dict['consistencygroups'][2]['description'])
self.assertEqual('test_consistencygroup',
res_dict['consistencygroups'][2]['name'])
self.assertIn(res_dict['consistencygroups'][0]['id'], cg_ids)
self.assertEqual('creating',
res_dict['consistencygroups'][2]['status'])
for vol_type_id in res_dict['consistencygroups'][2]['volume_types']:
self.assertIn(vol_type_id, vol_type_ids)
@mock.patch(
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
def test_create_consistencygroup_json(self, mock_validate):
group_id = fake.CONSISTENCY_GROUP_ID
# Create volume type
vol_type = 'test'
vol_type_id = db.volume_type_create(
self.ctxt, {'name': vol_type, 'extra_specs': {}})['id']
body = {"consistencygroup": {"name": "cg1",
"volume_types": vol_type_id,
"description":
"Consistency Group 1", }}
req = webob.Request.blank('/v2/%s/consistencygroups' % fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertIn('id', res_dict['consistencygroup'])
self.assertTrue(mock_validate.called)
group_id = res_dict['consistencygroup']['id']
cg = objects.Group.get_by_id(self.ctxt, group_id)
cg.destroy()
def test_create_consistencygroup_with_no_body(self):
# omit body from the request
req = webob.Request.blank('/v2/%s/consistencygroups' % fake.PROJECT_ID)
req.body = jsonutils.dump_as_bytes(None)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.headers['Accept'] = 'application/json'
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertEqual("Missing required element 'consistencygroup' in "
"request body.",
res_dict['badRequest']['message'])
def test_delete_consistencygroup_available(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes({})
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertEqual('deleting', consistencygroup.status)
consistencygroup.destroy()
def test_delete_consistencygroup_available_used_as_source_success(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
# The other CG used the first CG as source, but it's no longer in
# creating status, so we should be able to delete it.
cg2 = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE,
source_cgid=consistencygroup.id)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes({})
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertEqual('deleting', consistencygroup.status)
consistencygroup.destroy()
cg2.destroy()
def test_delete_consistencygroup_available_no_force(self):
consistencygroup = self._create_consistencygroup(status='available')
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": False}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertEqual(fields.ConsistencyGroupStatus.DELETING,
consistencygroup.status)
consistencygroup.destroy()
def test_delete_consistencygroup_with_consistencygroup_NotFound(self):
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(None)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.NOT_FOUND, res.status_int)
self.assertEqual(http_client.NOT_FOUND,
res_dict['itemNotFound']['code'])
self.assertEqual('Group %s could not be found.' %
fake.WILL_NOT_BE_FOUND_ID,
res_dict['itemNotFound']['message'])
def test_delete_consistencygroup_with_invalid_consistencygroup(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.CREATING)
self._assert_deleting_result_400(consistencygroup.id)
consistencygroup.destroy()
def test_delete_consistencygroup_invalid_force(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.CREATING)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": True}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertEqual('deleting', consistencygroup.status)
def test_delete_consistencygroup_no_host(self):
consistencygroup = self._create_consistencygroup(
host=None,
status=fields.ConsistencyGroupStatus.ERROR)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": True}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(http_client.ACCEPTED, res.status_int)
cg = objects.Group.get_by_id(
context.get_admin_context(read_deleted='yes'),
consistencygroup.id)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED, cg.status)
self.assertIsNone(cg.host)
@mock.patch('cinder.quota.GROUP_QUOTAS.reserve',
return_value='reservations')
@mock.patch('cinder.quota.GROUP_QUOTAS.commit')
def test_create_delete_consistencygroup_update_quota(self, mock_commit,
mock_reserve):
name = 'mycg'
description = 'consistency group 1'
fake_grp_type = {'id': fake.GROUP_TYPE_ID, 'name': 'fake_grp_type'}
fake_vol_type = {'id': fake.VOLUME_TYPE_ID, 'name': 'fake_vol_type'}
self.mock_object(db, 'group_type_get',
return_value=fake_grp_type)
self.mock_object(db, 'volume_types_get_by_name_or_id',
return_value=[fake_vol_type])
self.mock_object(self.cg_api, '_cast_create_group')
self.mock_object(self.cg_api, 'update_quota')
cg = self.cg_api.create(self.ctxt, name, description,
fake.GROUP_TYPE_ID, fake_vol_type['name'])
# Verify the quota reservation and commit was called
mock_reserve.assert_called_once_with(self.ctxt,
project_id=self.ctxt.project_id,
groups=1)
mock_commit.assert_called_once_with(self.ctxt, 'reservations')
self.assertEqual(fields.ConsistencyGroupStatus.CREATING, cg.status)
self.assertIsNone(cg.host)
cg.status = fields.ConsistencyGroupStatus.ERROR
self.cg_api.delete(self.ctxt, cg)
self.cg_api.update_quota.assert_called_once_with(
self.ctxt, cg, -1, self.ctxt.project_id)
cg = objects.Group.get_by_id(
context.get_admin_context(read_deleted='yes'),
cg.id)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED, cg.status)
def test_delete_consistencygroup_with_invalid_body(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"invalid_request_element": {"force": False}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
def test_delete_consistencygroup_with_invalid_force_value_in_body(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": "abcd"}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
def test_delete_consistencygroup_with_empty_force_value_in_body(self):
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": ""}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
def _assert_deleting_result_400(self, cg_id, force=False):
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, cg_id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": force}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
def test_delete_consistencygroup_with_volumes(self):
consistencygroup = self._create_consistencygroup(status='available')
utils.create_volume(self.ctxt, group_id=consistencygroup.id,
testcase_instance=self)
self._assert_deleting_result_400(consistencygroup.id)
consistencygroup.destroy()
def test_delete_consistencygroup_with_cgsnapshot(self):
consistencygroup = self._create_consistencygroup(status='available')
# If we don't add a volume to the CG the cgsnapshot creation will fail
vol = utils.create_volume(self.ctxt,
group_id=consistencygroup.id,
testcase_instance=self)
cg_snap = utils.create_group_snapshot(self.ctxt, consistencygroup.id,
group_type_id=fake.GROUP_TYPE_ID)
utils.create_snapshot(self.ctxt, volume_id=vol.id,
group_snapshot_id=cg_snap.id,
testcase_instance=self)
self._assert_deleting_result_400(consistencygroup.id)
cg_snap.destroy()
consistencygroup.destroy()
def test_delete_consistencygroup_with_cgsnapshot_force(self):
consistencygroup = self._create_consistencygroup(status='available')
# If we don't add a volume to the CG the cgsnapshot creation will fail
vol = utils.create_volume(self.ctxt,
group_id=consistencygroup.id,
testcase_instance=self)
cg_snap = utils.create_group_snapshot(self.ctxt, consistencygroup.id,
group_type_id=fake.GROUP_TYPE_ID)
utils.create_snapshot(self.ctxt, volume_id=vol.id,
group_snapshot_id=cg_snap.id,
testcase_instance=self)
self._assert_deleting_result_400(consistencygroup.id, force=True)
cg_snap.destroy()
consistencygroup.destroy()
def test_delete_consistencygroup_force_with_volumes(self):
consistencygroup = self._create_consistencygroup(status='available')
utils.create_volume(self.ctxt, consistencygroup_id=consistencygroup.id,
testcase_instance=self)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": True}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertEqual('deleting', consistencygroup.status)
consistencygroup.destroy()
def test_delete_cg_force_with_volumes_with_deleted_snapshots(self):
consistencygroup = self._create_consistencygroup(status='available')
vol = utils.create_volume(self.ctxt, testcase_instance=self,
consistencygroup_id=consistencygroup.id)
utils.create_snapshot(self.ctxt, vol.id, status='deleted',
deleted=True, testcase_instance=self)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/delete' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"force": True}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertEqual('deleting', consistencygroup.status)
consistencygroup.destroy()
def test_create_consistencygroup_failed_no_volume_type(self):
name = 'cg1'
body = {"consistencygroup": {"name": name,
"description":
"Consistency Group 1", }}
req = webob.Request.blank('/v2/%s/consistencygroups' % fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
@mock.patch(
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
def test_update_consistencygroup_success(self, mock_validate):
volume_type_id = utils.create_volume_type(
context.get_admin_context(), self, name='my_vol_type')['id']
fake_grp_type = {'id': fake.GROUP_TYPE_ID, 'name': 'fake_grp_type'}
self.mock_object(db, 'group_type_get',
return_value=fake_grp_type)
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE,
volume_type_ids=[volume_type_id],
group_type_id=fake.GROUP_TYPE_ID,
host='test_host')
# We create another CG from the one we are updating to confirm that
# it will not affect the update if it is not CREATING
cg2 = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE,
host='test_host',
volume_type_ids=[volume_type_id],
source_group_id=consistencygroup.id,)
remove_volume_id = utils.create_volume(
self.ctxt,
testcase_instance=self,
volume_type_id=volume_type_id,
group_id=consistencygroup.id)['id']
remove_volume_id2 = utils.create_volume(
self.ctxt,
testcase_instance=self,
volume_type_id=volume_type_id,
group_id=consistencygroup.id,
status='error')['id']
remove_volume_id3 = utils.create_volume(
self.ctxt,
testcase_instance=self,
volume_type_id=volume_type_id,
group_id=consistencygroup.id,
status='error_deleting')['id']
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
consistencygroup.status)
cg_volumes = db.volume_get_all_by_generic_group(self.ctxt.elevated(),
consistencygroup.id)
cg_vol_ids = [cg_vol['id'] for cg_vol in cg_volumes]
self.assertIn(remove_volume_id, cg_vol_ids)
self.assertIn(remove_volume_id2, cg_vol_ids)
self.assertIn(remove_volume_id3, cg_vol_ids)
add_volume_id = utils.create_volume(
self.ctxt,
testcase_instance=self,
volume_type_id=volume_type_id)['id']
add_volume_id2 = utils.create_volume(
self.ctxt,
testcase_instance=self,
volume_type_id=volume_type_id)['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
name = 'newcg'
description = 'New Consistency Group Description'
add_volumes = add_volume_id + "," + add_volume_id2
remove_volumes = ','.join(
[remove_volume_id, remove_volume_id2, remove_volume_id3])
body = {"consistencygroup": {"name": name,
"description": description,
"add_volumes": add_volumes,
"remove_volumes": remove_volumes, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertTrue(mock_validate.called)
self.assertEqual(fields.ConsistencyGroupStatus.UPDATING,
consistencygroup.status)
consistencygroup.destroy()
cg2.destroy()
@mock.patch(
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
def test_update_consistencygroup_sourcing_cg(self, mock_validate):
volume_type_id = fake.VOLUME_TYPE_ID
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE,
host='test_host')
cg2 = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.CREATING,
host='test_host',
source_cgid=consistencygroup.id)
remove_volume_id = utils.create_volume(
self.ctxt,
volume_type_id=volume_type_id,
consistencygroup_id=consistencygroup.id)['id']
remove_volume_id2 = utils.create_volume(
self.ctxt,
volume_type_id=volume_type_id,
consistencygroup_id=consistencygroup.id)['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
name = 'newcg'
description = 'New Consistency Group Description'
remove_volumes = remove_volume_id + "," + remove_volume_id2
body = {"consistencygroup": {"name": name,
"description": description,
"remove_volumes": remove_volumes, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
consistencygroup.status)
consistencygroup.destroy()
cg2.destroy()
@mock.patch(
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
def test_update_consistencygroup_creating_cgsnapshot(self, mock_validate):
volume_type_id = fake.VOLUME_TYPE_ID
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.AVAILABLE,
host='test_host')
# If we don't add a volume to the CG the cgsnapshot creation will fail
utils.create_volume(self.ctxt,
consistencygroup_id=consistencygroup.id,
testcase_instance=self)
cgsnapshot = utils.create_cgsnapshot(
self.ctxt, consistencygroup_id=consistencygroup.id)
add_volume_id = utils.create_volume(
self.ctxt,
volume_type_id=volume_type_id)['id']
add_volume_id2 = utils.create_volume(
self.ctxt,
volume_type_id=volume_type_id)['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
name = 'newcg'
description = 'New Consistency Group Description'
add_volumes = add_volume_id + "," + add_volume_id2
body = {"consistencygroup": {"name": name,
"description": description,
"add_volumes": add_volumes}}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app())
consistencygroup = objects.Group.get_by_id(
self.ctxt, consistencygroup.id)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(fields.ConsistencyGroupStatus.AVAILABLE,
consistencygroup.status)
consistencygroup.destroy()
cgsnapshot.destroy()
def test_update_consistencygroup_add_volume_not_found(self):
consistencygroup = self._create_consistencygroup(
ctxt=self.ctxt,
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"name": None,
"description": None,
"add_volumes": "fake-volume-uuid",
"remove_volumes": None, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
consistencygroup.destroy()
def test_update_consistencygroup_remove_volume_not_found(self):
consistencygroup = self._create_consistencygroup(
ctxt=self.ctxt,
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"name": None,
"description": "new description",
"add_volumes": None,
"remove_volumes": "fake-volume-uuid", }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
consistencygroup.destroy()
def test_update_consistencygroup_empty_parameters(self):
consistencygroup = self._create_consistencygroup(
ctxt=self.ctxt,
status=fields.ConsistencyGroupStatus.AVAILABLE)
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"name": "",
"description": "",
"add_volumes": None,
"remove_volumes": None, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
consistencygroup.destroy()
def test_update_consistencygroup_add_volume_invalid_state(self):
volume_type_id = fake.VOLUME_TYPE_ID
consistencygroup = self._create_consistencygroup(
ctxt=self.ctxt,
status=fields.ConsistencyGroupStatus.AVAILABLE)
add_volume_id = utils.create_volume(
self.ctxt,
volume_type_id=volume_type_id,
status='wrong_status')['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
add_volumes = add_volume_id
body = {"consistencygroup": {"name": "cg1",
"description": "",
"add_volumes": add_volumes,
"remove_volumes": None, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
consistencygroup.destroy()
def test_update_consistencygroup_add_volume_invalid_volume_type(self):
consistencygroup = self._create_consistencygroup(
ctxt=self.ctxt,
status=fields.ConsistencyGroupStatus.AVAILABLE)
wrong_type = fake.VOLUME_TYPE2_ID
add_volume_id = utils.create_volume(
self.ctxt,
volume_type_id=wrong_type)['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
add_volumes = add_volume_id
body = {"consistencygroup": {"name": "cg1",
"description": "",
"add_volumes": add_volumes,
"remove_volumes": None, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
consistencygroup.destroy()
def test_update_consistencygroup_add_volume_already_in_cg(self):
consistencygroup = self._create_consistencygroup(
ctxt=self.ctxt,
status=fields.ConsistencyGroupStatus.AVAILABLE)
add_volume_id = utils.create_volume(
self.ctxt,
consistencygroup_id=fake.CONSISTENCY_GROUP2_ID)['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
add_volumes = add_volume_id
body = {"consistencygroup": {"name": "cg1",
"description": "",
"add_volumes": add_volumes,
"remove_volumes": None, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
consistencygroup.destroy()
def test_update_consistencygroup_invalid_state(self):
volume_type_id = utils.create_volume_type(
context.get_admin_context(), self, name='my_vol_type')['id']
consistencygroup = self._create_consistencygroup(
status=fields.ConsistencyGroupStatus.CREATING,
volume_type_ids=[volume_type_id],
ctxt=self.ctxt)
add_volume_id = utils.create_volume(
self.ctxt,
testcase_instance=self,
volume_type_id=volume_type_id)['id']
req = webob.Request.blank('/v2/%s/consistencygroups/%s/update' %
(fake.PROJECT_ID, consistencygroup.id))
req.method = 'PUT'
req.headers['Content-Type'] = 'application/json'
body = {"consistencygroup": {"name": "new name",
"description": None,
"add_volumes": add_volume_id,
"remove_volumes": None, }}
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
consistencygroup.destroy()
@mock.patch(
'cinder.api.openstack.wsgi.Controller.validate_name_and_description')
@mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.validate_host_capacity')
def test_create_consistencygroup_from_src_snap(self, mock_validate_host,
mock_validate):
self.mock_object(volume_api.API, "create", v2_fakes.fake_volume_create)
consistencygroup = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
volume_id = utils.create_volume(
self.ctxt,
volume_type_id=fake.VOLUME_TYPE_ID,
group_id=consistencygroup.id)['id']
cgsnapshot = utils.create_group_snapshot(
self.ctxt, group_id=consistencygroup.id,
group_type_id=fake.GROUP_TYPE_ID)
snapshot = utils.create_snapshot(
self.ctxt,
volume_id,
group_snapshot_id=cgsnapshot.id,
status=fields.SnapshotStatus.AVAILABLE)
mock_validate_host.return_value = True
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"cgsnapshot_id": cgsnapshot.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertIn('id', res_dict['consistencygroup'])
self.assertEqual(test_cg_name, res_dict['consistencygroup']['name'])
self.assertTrue(mock_validate.called)
cg_ref = objects.Group.get_by_id(
self.ctxt.elevated(), res_dict['consistencygroup']['id'])
cg_ref.destroy()
snapshot.destroy()
db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy()
cgsnapshot.destroy()
@mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.validate_host_capacity')
def test_create_consistencygroup_from_src_cg(self, mock_validate):
self.mock_object(volume_api.API, "create", v2_fakes.fake_volume_create)
source_cg = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[self.vol_type['id']],)
volume_id = utils.create_volume(
self.ctxt,
group_id=source_cg.id)['id']
mock_validate.return_value = True
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"source_cgid": source_cg.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.ACCEPTED, res.status_int)
self.assertIn('id', res_dict['consistencygroup'])
self.assertEqual(test_cg_name, res_dict['consistencygroup']['name'])
cg = objects.Group.get_by_id(
self.ctxt, res_dict['consistencygroup']['id'])
cg.destroy()
db.volume_destroy(self.ctxt.elevated(), volume_id)
source_cg.destroy()
def test_create_consistencygroup_from_src_both_snap_cg(self):
self.mock_object(volume_api.API, "create", v2_fakes.fake_volume_create)
consistencygroup = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
volume_id = utils.create_volume(
self.ctxt,
group_id=consistencygroup.id)['id']
cgsnapshot_id = utils.create_group_snapshot(
self.ctxt,
group_type_id=fake.GROUP_TYPE_ID,
group_id=consistencygroup.id)['id']
snapshot = utils.create_snapshot(
self.ctxt,
volume_id,
group_snapshot_id=cgsnapshot_id,
status=fields.SnapshotStatus.AVAILABLE)
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"cgsnapshot_id": cgsnapshot_id,
"source_cgid":
consistencygroup.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
snapshot.destroy()
db.cgsnapshot_destroy(self.ctxt.elevated(), cgsnapshot_id)
db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy()
def test_create_consistencygroup_from_src_invalid_body(self):
name = 'cg1'
body = {"invalid": {"name": name,
"description":
"Consistency Group 1", }}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
# Missing 'consistencygroup-from-src' in the body.
self.assertIsNotNone(res_dict['badRequest']['message'])
def test_create_consistencygroup_from_src_no_source_id(self):
name = 'cg1'
body = {"consistencygroup-from-src": {"name": name,
"description":
"Consistency Group 1", }}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
def test_create_consistencygroup_from_src_no_host(self):
consistencygroup = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID], host=None)
volume_id = utils.create_volume(
self.ctxt,
group_id=consistencygroup.id)['id']
cgsnapshot = utils.create_group_snapshot(
self.ctxt, group_id=consistencygroup.id,
group_type_id=fake.GROUP_TYPE_ID,)
snapshot = utils.create_snapshot(
self.ctxt,
volume_id,
group_snapshot_id=cgsnapshot.id,
status=fields.SnapshotStatus.AVAILABLE)
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"cgsnapshot_id": cgsnapshot.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
msg = _('Invalid Group: No valid host to create group')
self.assertIn(msg, res_dict['badRequest']['message'])
snapshot.destroy()
db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy()
cgsnapshot.destroy()
@mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.validate_host_capacity')
def test_create_consistencygroup_from_src_cgsnapshot_empty(self,
mock_validate):
consistencygroup = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
volume_id = utils.create_volume(
self.ctxt,
group_id=consistencygroup.id)['id']
cgsnapshot = utils.create_group_snapshot(
self.ctxt, group_id=consistencygroup.id,
group_type_id=fake.GROUP_TYPE_ID,)
mock_validate.return_value = True
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"cgsnapshot_id": cgsnapshot.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy()
cgsnapshot.destroy()
@mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.validate_host_capacity')
def test_create_consistencygroup_from_src_source_cg_empty(self,
mock_validate):
source_cg = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
mock_validate.return_value = True
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"source_cgid": source_cg.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
source_cg.destroy()
def test_create_consistencygroup_from_src_cgsnapshot_notfound(self):
consistencygroup = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
volume_id = utils.create_volume(
self.ctxt,
group_id=consistencygroup.id)['id']
test_cg_name = 'test cg'
body = {
"consistencygroup-from-src":
{
"name": test_cg_name,
"description": "Consistency Group 1",
"source_cgid": fake.CGSNAPSHOT_ID
}
}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.NOT_FOUND, res.status_int)
self.assertEqual(http_client.NOT_FOUND,
res_dict['itemNotFound']['code'])
self.assertIsNotNone(res_dict['itemNotFound']['message'])
db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy()
def test_create_consistencygroup_from_src_source_cg_notfound(self):
test_cg_name = 'test cg'
body = {
"consistencygroup-from-src":
{
"name": test_cg_name,
"description": "Consistency Group 1",
"source_cgid": fake.CONSISTENCY_GROUP_ID
}
}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.NOT_FOUND, res.status_int)
self.assertEqual(http_client.NOT_FOUND,
res_dict['itemNotFound']['code'])
self.assertIsNotNone(res_dict['itemNotFound']['message'])
@mock.patch.object(volume_api.API, 'create',
side_effect=exception.CinderException(
'Create volume failed.'))
@mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.validate_host_capacity')
def test_create_consistencygroup_from_src_cgsnapshot_create_volume_failed(
self, mock_validate, mock_create):
consistencygroup = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
volume_id = utils.create_volume(
self.ctxt,
group_id=consistencygroup.id)['id']
cgsnapshot = utils.create_group_snapshot(
self.ctxt, group_id=consistencygroup.id,
group_type_id=fake.GROUP_TYPE_ID,)
snapshot = utils.create_snapshot(
self.ctxt,
volume_id,
group_snapshot_id=cgsnapshot.id,
status=fields.SnapshotStatus.AVAILABLE)
mock_validate.return_value = True
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"cgsnapshot_id": cgsnapshot.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
msg = _("Create volume failed.")
self.assertEqual(msg, res_dict['badRequest']['message'])
snapshot.destroy()
db.volume_destroy(self.ctxt.elevated(), volume_id)
consistencygroup.destroy()
cgsnapshot.destroy()
@mock.patch.object(volume_api.API, 'create',
side_effect=exception.CinderException(
'Create volume failed.'))
@mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.validate_host_capacity')
@mock.patch('cinder.db.sqlalchemy.api.volume_type_get')
def test_create_consistencygroup_from_src_cg_create_volume_failed(
self, mock_validate, mock_create, mock_vol_type_get):
source_cg = utils.create_group(
self.ctxt, group_type_id=fake.GROUP_TYPE_ID,
volume_type_ids=[fake.VOLUME_TYPE_ID],)
volume_id = utils.create_volume(
self.ctxt,
group_id=source_cg.id,
volume_type_id=fake.VOLUME_TYPE_ID)['id']
mock_validate.return_value = True
test_cg_name = 'test cg'
body = {"consistencygroup-from-src": {"name": test_cg_name,
"description":
"Consistency Group 1",
"source_cgid": source_cg.id}}
req = webob.Request.blank('/v2/%s/consistencygroups/create_from_src' %
fake.PROJECT_ID)
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = jsonutils.dump_as_bytes(body)
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.user_ctxt))
res_dict = jsonutils.loads(res.body)
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
self.assertEqual(http_client.BAD_REQUEST,
res_dict['badRequest']['code'])
self.assertIsNotNone(res_dict['badRequest']['message'])
db.volume_destroy(self.ctxt.elevated(), volume_id)
source_cg.destroy()