manila/manila/tests/api/v2/test_shares.py

2984 lines
120 KiB
Python

# Copyright (c) 2015 Mirantis inc.
# 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.
import copy
import datetime
import itertools
from unittest import mock
import ddt
from oslo_config import cfg
from oslo_serialization import jsonutils
from oslo_utils import uuidutils
import six
import webob
import webob.exc
from manila.api import common
from manila.api.openstack import api_version_request as api_version
from manila.api.v2 import share_replicas
from manila.api.v2 import shares
from manila.common import constants
from manila import context
from manila import db
from manila import exception
from manila import policy
from manila.share import api as share_api
from manila.share import share_types
from manila import test
from manila.tests.api.contrib import stubs
from manila.tests.api import fakes
from manila.tests import db_utils
from manila.tests import fake_share
from manila.tests import utils as test_utils
from manila import utils
CONF = cfg.CONF
LATEST_MICROVERSION = api_version._MAX_API_VERSION
@ddt.ddt
class ShareAPITest(test.TestCase):
"""Share API Test."""
def setUp(self):
super(ShareAPITest, self).setUp()
self.controller = shares.ShareController()
self.mock_object(db, 'availability_zone_get')
self.mock_object(share_api.API, 'get_all',
stubs.stub_get_all_shares)
self.mock_object(share_api.API, 'get',
stubs.stub_share_get)
self.mock_object(share_api.API, 'update', stubs.stub_share_update)
self.mock_object(share_api.API, 'delete', stubs.stub_share_delete)
self.mock_object(share_api.API, 'get_snapshot',
stubs.stub_snapshot_get)
self.mock_object(share_types, 'get_share_type',
stubs.stub_share_type_get)
self.maxDiff = None
self.share = {
"id": "1",
"size": 100,
"display_name": "Share Test Name",
"display_description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"is_public": False,
"task_state": None,
}
self.create_mock = mock.Mock(
return_value=stubs.stub_share(
'1',
display_name=self.share['display_name'],
display_description=self.share['display_description'],
size=100,
share_proto=self.share['share_proto'].upper(),
instance={
'availability_zone': self.share['availability_zone'],
})
)
self.vt = {
'id': 'fake_volume_type_id',
'name': 'fake_volume_type_name',
'required_extra_specs': {
'driver_handles_share_servers': 'False'
},
'extra_specs': {
'driver_handles_share_servers': 'False'
}
}
self.snapshot = {
'id': '2',
'share_id': '1',
'status': constants.STATUS_AVAILABLE,
}
CONF.set_default("default_share_type", None)
def _process_expected_share_detailed_response(self, shr_dict, req_version):
"""Sets version based parameters on share dictionary."""
share_dict = copy.deepcopy(shr_dict)
changed_parameters = {
'2.2': {'snapshot_support': True},
'2.5': {'task_state': None},
'2.6': {'share_type_name': None},
'2.10': {'access_rules_status': constants.ACCESS_STATE_ACTIVE},
'2.11': {'replication_type': None, 'has_replicas': False},
'2.16': {'user_id': 'fakeuser'},
'2.24': {'create_share_from_snapshot_support': True},
'2.27': {'revert_to_snapshot_support': False},
'2.31': {'share_group_id': None,
'source_share_group_snapshot_member_id': None},
'2.32': {'mount_snapshot_support': False},
}
# Apply all the share transformations
if self.is_microversion_ge(req_version, '2.9'):
share_dict.pop('export_locations', None)
share_dict.pop('export_location', None)
for version, parameters in changed_parameters.items():
for param, default in parameters.items():
if self.is_microversion_ge(req_version, version):
share_dict[param] = share_dict.get(param, default)
else:
share_dict.pop(param, None)
return share_dict
def _get_expected_share_detailed_response(self, values=None,
admin=False, version='2.0'):
share = {
'id': '1',
'name': 'displayname',
'availability_zone': 'fakeaz',
'description': 'displaydesc',
'export_location': 'fake_location',
'export_locations': ['fake_location', 'fake_location2'],
'project_id': 'fakeproject',
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'share_proto': 'FAKEPROTO',
'metadata': {},
'size': 1,
'snapshot_id': '2',
'share_network_id': None,
'status': 'fakestatus',
'share_type': '1',
'volume_type': '1',
'snapshot_support': True,
'is_public': False,
'task_state': None,
'share_type_name': None,
'links': [
{
'href': 'http://localhost/v1/fake/shares/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/shares/1',
'rel': 'bookmark'
}
],
}
if values:
if 'display_name' in values:
values['name'] = values.pop('display_name')
if 'display_description' in values:
values['description'] = values.pop('display_description')
share.update(values)
if share.get('share_proto'):
share['share_proto'] = share['share_proto'].upper()
if admin:
share['share_server_id'] = 'fake_share_server_id'
share['host'] = 'fakehost'
return {
'share': self._process_expected_share_detailed_response(
share, version)
}
def test__revert(self):
share = copy.deepcopy(self.share)
share['status'] = constants.STATUS_AVAILABLE
share['revert_to_snapshot_support'] = True
share["instances"] = [
{
"id": "fakeid",
"access_rules_status": constants.ACCESS_STATE_ACTIVE,
},
]
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = constants.STATUS_AVAILABLE
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
mock_validate_revert_parameters = self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
mock_get = self.mock_object(
share_api.API, 'get', mock.Mock(return_value=share))
mock_get_snapshot = self.mock_object(
share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
mock_get_latest_snapshot_for_share = self.mock_object(
share_api.API, 'get_latest_snapshot_for_share',
mock.Mock(return_value=snapshot))
mock_revert_to_snapshot = self.mock_object(
share_api.API, 'revert_to_snapshot')
response = self.controller._revert(req, '1', body=body)
self.assertEqual(202, response.status_int)
mock_validate_revert_parameters.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), body)
mock_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), '1')
mock_get_snapshot.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), '2')
mock_get_latest_snapshot_for_share.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), '1')
mock_revert_to_snapshot.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share, snapshot)
def test__revert_not_supported(self):
share = copy.deepcopy(self.share)
share['revert_to_snapshot_support'] = False
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = constants.STATUS_AVAILABLE
snapshot['share_id'] = 'wrong_id'
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(
share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._revert,
req,
'1',
body=body)
def test__revert_id_mismatch(self):
share = copy.deepcopy(self.share)
share['status'] = constants.STATUS_AVAILABLE
share['revert_to_snapshot_support'] = True
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = constants.STATUS_AVAILABLE
snapshot['share_id'] = 'wrong_id'
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(
share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._revert,
req,
'1',
body=body)
@ddt.data(
{
'share_status': constants.STATUS_ERROR,
'share_is_busy': False,
'snapshot_status': constants.STATUS_AVAILABLE,
}, {
'share_status': constants.STATUS_AVAILABLE,
'share_is_busy': True,
'snapshot_status': constants.STATUS_AVAILABLE,
}, {
'share_status': constants.STATUS_AVAILABLE,
'share_is_busy': False,
'snapshot_status': constants.STATUS_ERROR,
})
@ddt.unpack
def test__revert_invalid_status(self, share_status, share_is_busy,
snapshot_status):
share = copy.deepcopy(self.share)
share['status'] = share_status
share['is_busy'] = share_is_busy
share['revert_to_snapshot_support'] = True
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = snapshot_status
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(
share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
self.assertRaises(webob.exc.HTTPConflict,
self.controller._revert,
req,
'1',
body=body)
def test__revert_snapshot_latest_not_found(self):
share = copy.deepcopy(self.share)
share['status'] = constants.STATUS_AVAILABLE
share['revert_to_snapshot_support'] = True
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = constants.STATUS_AVAILABLE
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(
share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
self.mock_object(
share_api.API, 'get_latest_snapshot_for_share',
mock.Mock(return_value=None))
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._revert,
req,
'1',
body=body)
def test__revert_snapshot_access_applying(self):
share = copy.deepcopy(self.share)
share['status'] = constants.STATUS_AVAILABLE
share['revert_to_snapshot_support'] = True
share["instances"] = [
{
"id": "fakeid",
"access_rules_status": constants.SHARE_INSTANCE_RULES_SYNCING,
},
]
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = constants.STATUS_AVAILABLE
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, 'get_snapshot',
mock.Mock(return_value=snapshot))
self.mock_object(share_api.API, 'get_latest_snapshot_for_share',
mock.Mock(return_value=snapshot))
self.mock_object(share_api.API, 'revert_to_snapshot')
self.assertRaises(webob.exc.HTTPConflict,
self.controller._revert,
req,
'1',
body=body)
def test__revert_snapshot_not_latest(self):
share = copy.deepcopy(self.share)
share['status'] = constants.STATUS_AVAILABLE
share['revert_to_snapshot_support'] = True
share = fake_share.fake_share(**share)
snapshot = copy.deepcopy(self.snapshot)
snapshot['status'] = constants.STATUS_AVAILABLE
latest_snapshot = copy.deepcopy(self.snapshot)
latest_snapshot['status'] = constants.STATUS_AVAILABLE
latest_snapshot['id'] = '3'
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(
share_api.API, 'get_snapshot', mock.Mock(return_value=snapshot))
self.mock_object(
share_api.API, 'get_latest_snapshot_for_share',
mock.Mock(return_value=latest_snapshot))
self.assertRaises(webob.exc.HTTPConflict,
self.controller._revert,
req,
'1',
body=body)
@ddt.data(
{
'caught': exception.ShareNotFound,
'exc_args': {
'share_id': '1',
},
'thrown': webob.exc.HTTPNotFound,
}, {
'caught': exception.ShareSnapshotNotFound,
'exc_args': {
'snapshot_id': '2',
},
'thrown': webob.exc.HTTPBadRequest,
}, {
'caught': exception.ShareSizeExceedsAvailableQuota,
'exc_args': {},
'thrown': webob.exc.HTTPForbidden,
}, {
'caught': exception.ReplicationException,
'exc_args': {
'reason': 'catastrophic failure',
},
'thrown': webob.exc.HTTPBadRequest,
})
@ddt.unpack
def test__revert_exception(self, caught, exc_args, thrown):
body = {'revert': {'snapshot_id': '2'}}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.27')
self.mock_object(
self.controller, '_validate_revert_parameters',
mock.Mock(return_value=body['revert']))
self.mock_object(
share_api.API, 'get', mock.Mock(side_effect=caught(**exc_args)))
self.assertRaises(thrown,
self.controller._revert,
req,
'1',
body=body)
def test_validate_revert_parameters(self):
body = {'revert': {'snapshot_id': 'fake_snapshot_id'}}
result = self.controller._validate_revert_parameters(
'fake_context', body)
self.assertEqual(body['revert'], result)
@ddt.data(
None,
{},
{'manage': {'snapshot_id': 'fake_snapshot_id'}},
{'revert': {'share_id': 'fake_snapshot_id'}},
{'revert': {'snapshot_id': ''}},
)
def test_validate_revert_parameters_invalid(self, body):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._validate_revert_parameters,
'fake_context',
body)
@ddt.data("2.0", "2.1")
def test_share_create_original(self, microversion):
self.mock_object(share_api.API, 'create', self.create_mock)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank('/shares', version=microversion)
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
self.share, version=microversion)
self.assertEqual(expected, res_dict)
@ddt.data("2.2", "2.3")
def test_share_create_with_snapshot_support_without_cg(self, microversion):
self.mock_object(share_api.API, 'create', self.create_mock)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank('/shares', version=microversion)
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
self.share, version=microversion)
self.assertEqual(expected, res_dict)
def test_share_create_with_share_group(self):
self.mock_object(share_api.API, 'create', self.create_mock)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank('/shares', version="2.31",
experimental=True)
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
self.share, version="2.31")
self.assertEqual(expected, res_dict)
def test_share_create_with_sg_and_availability_zone(self):
sg_id = 'fake_sg_id'
az_id = 'bar_az_id'
self.mock_object(share_api.API, 'create', self.create_mock)
self.mock_object(
db, 'availability_zone_get',
mock.Mock(return_value=type('ReqAZ', (object, ), {"id": az_id})))
self.mock_object(
db, 'share_group_get',
mock.Mock(return_value={"availability_zone_id": az_id}))
body = {"share": {
"size": 100,
"share_proto": "fakeproto",
"availability_zone": az_id,
"share_group_id": sg_id,
}}
req = fakes.HTTPRequest.blank(
'/shares', version="2.31", experimental=True)
self.controller.create(req, body)
db.availability_zone_get.assert_called_once_with(
req.environ['manila.context'], az_id)
db.share_group_get.assert_called_once_with(
req.environ['manila.context'], sg_id)
share_api.API.create.assert_called_once_with(
req.environ['manila.context'],
body['share']['share_proto'].upper(),
body['share']['size'],
None,
None,
share_group_id=body['share']['share_group_id'],
is_public=False,
metadata=None,
snapshot_id=None,
availability_zone=az_id)
def test_share_create_with_sg_and_different_availability_zone(self):
sg_id = 'fake_sg_id'
sg_az = 'foo_az_id'
req_az = 'bar_az_id'
self.mock_object(share_api.API, 'create', self.create_mock)
self.mock_object(
db, 'availability_zone_get',
mock.Mock(return_value=type('ReqAZ', (object, ), {"id": req_az})))
self.mock_object(
db, 'share_group_get',
mock.Mock(return_value={"availability_zone_id": sg_az}))
body = {"share": {
"size": 100,
"share_proto": "fakeproto",
"availability_zone": req_az,
"share_group_id": sg_id,
}}
req = fakes.HTTPRequest.blank(
'/shares', version="2.31", experimental=True)
self.assertRaises(
exception.InvalidInput, self.controller.create, req, body)
db.availability_zone_get.assert_called_once_with(
req.environ['manila.context'], req_az)
db.share_group_get.assert_called_once_with(
req.environ['manila.context'], sg_id)
self.assertEqual(0, share_api.API.create.call_count)
def test_share_create_with_nonexistent_share_group(self):
sg_id = 'fake_sg_id'
self.mock_object(share_api.API, 'create', self.create_mock)
self.mock_object(db, 'availability_zone_get')
self.mock_object(
db, 'share_group_get',
mock.Mock(side_effect=exception.ShareGroupNotFound(
share_group_id=sg_id)))
body = {"share": {
"size": 100,
"share_proto": "fakeproto",
"share_group_id": sg_id,
}}
req = fakes.HTTPRequest.blank(
'/shares', version="2.31", experimental=True)
self.assertRaises(
webob.exc.HTTPNotFound, self.controller.create, req, body)
self.assertEqual(0, db.availability_zone_get.call_count)
self.assertEqual(0, share_api.API.create.call_count)
db.share_group_get.assert_called_once_with(
req.environ['manila.context'], sg_id)
def test_share_create_with_valid_default_share_type(self):
self.mock_object(share_types, 'get_share_type_by_name',
mock.Mock(return_value=self.vt))
CONF.set_default("default_share_type", self.vt['name'])
self.mock_object(share_api.API, 'create', self.create_mock)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(self.share,
version='2.7')
share_types.get_share_type_by_name.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), self.vt['name'])
self.assertEqual(expected, res_dict)
def test_share_create_with_invalid_default_share_type(self):
self.mock_object(
share_types, 'get_default_share_type',
mock.Mock(side_effect=exception.ShareTypeNotFoundByName(
self.vt['name'])),
)
CONF.set_default("default_share_type", self.vt['name'])
req = fakes.HTTPRequest.blank('/shares', version='2.7')
self.assertRaises(exception.ShareTypeNotFoundByName,
self.controller.create, req, {'share': self.share})
share_types.get_default_share_type.assert_called_once_with()
def test_share_create_with_replication(self):
self.mock_object(share_api.API, 'create', self.create_mock)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank(
'/shares', version=share_replicas.MIN_SUPPORTED_API_VERSION)
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
self.share, version=share_replicas.MIN_SUPPORTED_API_VERSION)
self.assertEqual(expected, res_dict)
def test_share_create_with_share_net(self):
shr = {
"size": 100,
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"share_network_id": "fakenetid"
}
create_mock = mock.Mock(return_value=stubs.stub_share('1',
display_name=shr['name'],
display_description=shr['description'],
size=shr['size'],
share_proto=shr['share_proto'].upper(),
availability_zone=shr['availability_zone'],
share_network_id=shr['share_network_id']))
self.mock_object(share_api.API, 'create', create_mock)
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': 'fakenetid'}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertDictMatch(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual("fakenetid",
create_mock.call_args[1]['share_network_id'])
@ddt.data("2.15", "2.16")
def test_share_create_original_with_user_id(self, microversion):
self.mock_object(share_api.API, 'create', self.create_mock)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank('/shares', version=microversion)
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
self.share, version=microversion)
self.assertEqual(expected, res_dict)
@ddt.data(test_utils.annotated('v2.0_az_unsupported', ('2.0', False)),
test_utils.annotated('v2.0_az_supported', ('2.0', True)),
test_utils.annotated('v2.47_az_unsupported', ('2.47', False)),
test_utils.annotated('v2.47_az_supported', ('2.47', True)))
@ddt.unpack
def test_share_create_with_share_type_azs(self, version, az_supported):
"""For API version<2.48, AZ validation should not be performed."""
self.mock_object(share_api.API, 'create', self.create_mock)
create_args = copy.deepcopy(self.share)
create_args['availability_zone'] = 'az1' if az_supported else 'az2'
create_args['share_type'] = uuidutils.generate_uuid()
stype_with_azs = copy.deepcopy(self.vt)
stype_with_azs['extra_specs']['availability_zones'] = 'az1,az3'
self.mock_object(share_types, 'get_share_type', mock.Mock(
return_value=stype_with_azs))
req = fakes.HTTPRequest.blank('/shares', version=version)
res_dict = self.controller.create(req, {'share': create_args})
expected = self._get_expected_share_detailed_response(
values=self.share, version=version)
self.assertEqual(expected, res_dict)
@ddt.data(*set([
test_utils.annotated('v2.48_share_from_snap', ('2.48', True)),
test_utils.annotated('v2.48_share_not_from_snap', ('2.48', False)),
test_utils.annotated('v%s_share_from_snap' % LATEST_MICROVERSION,
(LATEST_MICROVERSION, True)),
test_utils.annotated('v%s_share_not_from_snap' % LATEST_MICROVERSION,
(LATEST_MICROVERSION, False))]))
@ddt.unpack
def test_share_create_az_not_in_share_type(self, version, snap):
"""For API version>=2.48, AZ validation should be performed."""
self.mock_object(share_api.API, 'create', self.create_mock)
create_args = copy.deepcopy(self.share)
create_args['availability_zone'] = 'az2'
create_args['share_type'] = (uuidutils.generate_uuid() if not snap
else None)
create_args['snapshot_id'] = (uuidutils.generate_uuid() if snap
else None)
stype_with_azs = copy.deepcopy(self.vt)
stype_with_azs['extra_specs']['availability_zones'] = 'az1 , az3'
self.mock_object(share_types, 'get_share_type', mock.Mock(
return_value=stype_with_azs))
self.mock_object(share_api.API, 'get_snapshot',
stubs.stub_snapshot_get)
req = fakes.HTTPRequest.blank('/shares', version=version)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create,
req, {'share': create_args})
share_api.API.create.assert_not_called()
def test_migration_start(self):
share = db_utils.create_share()
share_network = db_utils.create_share_network()
share_type = {'share_type_id': 'fake_type_id'}
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.29')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
context = req.environ['manila.context']
self.mock_object(db, 'share_network_get', mock.Mock(
return_value=share_network))
self.mock_object(db, 'share_type_get', mock.Mock(
return_value=share_type))
body = {
'migration_start': {
'host': 'fake_host',
'preserve_metadata': True,
'preserve_snapshots': True,
'writable': True,
'nondisruptive': True,
'new_share_network_id': 'fake_net_id',
'new_share_type_id': 'fake_type_id',
}
}
method = 'migration_start'
self.mock_object(share_api.API, 'migration_start',
mock.Mock(return_value=202))
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
response = getattr(self.controller, method)(req, share['id'], body)
self.assertEqual(202, response.status_int)
share_api.API.get.assert_called_once_with(context, share['id'])
share_api.API.migration_start.assert_called_once_with(
context, share, 'fake_host', False, True, True, True, True,
new_share_network=share_network, new_share_type=share_type)
db.share_network_get.assert_called_once_with(
context, 'fake_net_id')
db.share_type_get.assert_called_once_with(
context, 'fake_type_id')
def test_migration_start_conflict(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True)
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request = api_version.APIVersionRequest('2.29')
req.api_version_request.experimental = True
body = {
'migration_start': {
'host': 'fake_host',
'preserve_metadata': True,
'preserve_snapshots': True,
'writable': True,
'nondisruptive': True,
}
}
self.mock_object(share_api.API, 'migration_start',
mock.Mock(side_effect=exception.Conflict(err='err')))
self.assertRaises(webob.exc.HTTPConflict,
self.controller.migration_start,
req, share['id'], body)
@ddt.data('nondisruptive', 'writable', 'preserve_metadata',
'preserve_snapshots', 'host', 'body')
def test_migration_start_missing_mandatory(self, param):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True,
version='2.29')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {
'migration_start': {
'host': 'fake_host',
'preserve_metadata': True,
'preserve_snapshots': True,
'writable': True,
'nondisruptive': True,
}
}
if param == 'body':
body.pop('migration_start')
else:
body['migration_start'].pop(param)
method = 'migration_start'
self.mock_object(share_api.API, 'migration_start')
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=share))
self.assertRaises(webob.exc.HTTPBadRequest,
getattr(self.controller, method),
req, 'fake_id', body)
@ddt.data('nondisruptive', 'writable', 'preserve_metadata',
'preserve_snapshots', 'force_host_assisted_migration')
def test_migration_start_non_boolean(self, param):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True,
version='2.29')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {
'migration_start': {
'host': 'fake_host',
'preserve_metadata': True,
'preserve_snapshots': True,
'writable': True,
'nondisruptive': True,
}
}
body['migration_start'][param] = None
method = 'migration_start'
self.mock_object(share_api.API, 'migration_start')
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=share))
self.assertRaises(webob.exc.HTTPBadRequest,
getattr(self.controller, method),
req, 'fake_id', body)
def test_migration_start_no_share_id(self):
req = fakes.HTTPRequest.blank('/shares/%s/action' % 'fake_id',
use_admin_context=True, version='2.29')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_start': {'host': 'fake_host'}}
method = 'migration_start'
self.mock_object(share_api.API, 'get',
mock.Mock(side_effect=[exception.NotFound]))
self.assertRaises(webob.exc.HTTPNotFound,
getattr(self.controller, method),
req, 'fake_id', body)
def test_migration_start_new_share_network_not_found(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.29')
context = req.environ['manila.context']
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {
'migration_start': {
'host': 'fake_host',
'preserve_metadata': True,
'preserve_snapshots': True,
'writable': True,
'nondisruptive': True,
'new_share_network_id': 'nonexistent'}}
self.mock_object(db, 'share_network_get',
mock.Mock(side_effect=exception.NotFound()))
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.migration_start,
req, share['id'], body)
db.share_network_get.assert_called_once_with(context, 'nonexistent')
def test_migration_start_new_share_type_not_found(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.29')
context = req.environ['manila.context']
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {
'migration_start': {
'host': 'fake_host',
'preserve_metadata': True,
'preserve_snapshots': True,
'writable': True,
'nondisruptive': True,
'new_share_type_id': 'nonexistent'}}
self.mock_object(db, 'share_type_get',
mock.Mock(side_effect=exception.NotFound()))
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.migration_start,
req, share['id'], body)
db.share_type_get.assert_called_once_with(context, 'nonexistent')
def test_migration_start_invalid_force_host_assisted_migration(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.29')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_start': {'host': 'fake_host',
'force_host_assisted_migration': 'fake'}}
method = 'migration_start'
self.assertRaises(webob.exc.HTTPBadRequest,
getattr(self.controller, method),
req, share['id'], body)
@ddt.data('writable', 'preserve_metadata')
def test_migration_start_invalid_writable_preserve_metadata(
self, parameter):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.29')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_start': {'host': 'fake_host',
parameter: 'invalid'}}
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.migration_start, req, share['id'],
body)
@ddt.data(constants.TASK_STATE_MIGRATION_ERROR, None)
def test_reset_task_state(self, task_state):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
update = {'task_state': task_state}
body = {'reset_task_state': update}
self.mock_object(db, 'share_update')
response = self.controller.reset_task_state(req, share['id'], body)
self.assertEqual(202, response.status_int)
db.share_update.assert_called_once_with(utils.IsAMatcher(
context.RequestContext), share['id'], update)
def test_reset_task_state_error_body(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
update = {'error': 'error'}
body = {'reset_task_state': update}
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.reset_task_state, req, share['id'],
body)
def test_reset_task_state_error_invalid(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
update = {'task_state': 'error'}
body = {'reset_task_state': update}
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.reset_task_state, req, share['id'],
body)
def test_reset_task_state_not_found(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
update = {'task_state': constants.TASK_STATE_MIGRATION_ERROR}
body = {'reset_task_state': update}
self.mock_object(db, 'share_update',
mock.Mock(side_effect=exception.NotFound()))
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.reset_task_state, req, share['id'],
body)
db.share_update.assert_called_once_with(utils.IsAMatcher(
context.RequestContext), share['id'], update)
def test_migration_complete(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_complete': None}
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=share))
self.mock_object(share_api.API, 'migration_complete')
response = self.controller.migration_complete(req, share['id'], body)
self.assertEqual(202, response.status_int)
share_api.API.migration_complete.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share)
def test_migration_complete_not_found(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_complete': None}
self.mock_object(share_api.API, 'get',
mock.Mock(side_effect=exception.NotFound()))
self.mock_object(share_api.API, 'migration_complete')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.migration_complete, req, share['id'],
body)
def test_migration_cancel(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_cancel': None}
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=share))
self.mock_object(share_api.API, 'migration_cancel')
response = self.controller.migration_cancel(req, share['id'], body)
self.assertEqual(202, response.status_int)
share_api.API.migration_cancel.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share)
def test_migration_cancel_not_found(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_cancel': None}
self.mock_object(share_api.API, 'get',
mock.Mock(side_effect=exception.NotFound()))
self.mock_object(share_api.API, 'migration_cancel')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.migration_cancel, req, share['id'],
body)
def test_migration_get_progress(self):
share = db_utils.create_share(
task_state=constants.TASK_STATE_MIGRATION_SUCCESS)
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_get_progress': None}
expected = {
'total_progress': 'fake',
'task_state': constants.TASK_STATE_MIGRATION_SUCCESS,
}
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=share))
self.mock_object(share_api.API, 'migration_get_progress',
mock.Mock(return_value=expected))
response = self.controller.migration_get_progress(req, share['id'],
body)
self.assertEqual(expected, response)
share_api.API.migration_get_progress.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share)
def test_migration_get_progress_not_found(self):
share = db_utils.create_share()
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
use_admin_context=True, version='2.22')
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.api_version_request.experimental = True
body = {'migration_get_progress': None}
self.mock_object(share_api.API, 'get',
mock.Mock(side_effect=exception.NotFound()))
self.mock_object(share_api.API, 'migration_get_progress')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.migration_get_progress, req,
share['id'], body)
def test_share_create_from_snapshot_without_share_net_no_parent(self):
shr = {
"size": 100,
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"snapshot_id": 333,
"share_network_id": None,
}
create_mock = mock.Mock(return_value=stubs.stub_share('1',
display_name=shr['name'],
display_description=shr['description'],
size=shr['size'],
share_proto=shr['share_proto'].upper(),
snapshot_id=shr['snapshot_id'],
instance=dict(
availability_zone=shr['availability_zone'],
share_network_id=shr['share_network_id'])))
self.mock_object(share_api.API, 'create', create_mock)
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertEqual(expected, res_dict)
def test_share_create_from_snapshot_without_share_net_parent_exists(self):
shr = {
"size": 100,
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"snapshot_id": 333,
"share_network_id": None,
}
parent_share_net = 444
create_mock = mock.Mock(return_value=stubs.stub_share('1',
display_name=shr['name'],
display_description=shr['description'],
size=shr['size'],
share_proto=shr['share_proto'].upper(),
snapshot_id=shr['snapshot_id'],
instance=dict(
availability_zone=shr['availability_zone'],
share_network_id=shr['share_network_id'])))
self.mock_object(share_api.API, 'create', create_mock)
self.mock_object(share_api.API, 'get_snapshot',
stubs.stub_snapshot_get)
parent_share = stubs.stub_share(
'1', instance={'share_network_id': parent_share_net},
create_share_from_snapshot_support=True)
self.mock_object(share_api.API, 'get', mock.Mock(
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertEqual(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
def test_share_create_from_snapshot_with_share_net_equals_parent(self):
parent_share_net = 444
shr = {
"size": 100,
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"snapshot_id": 333,
"share_network_id": parent_share_net,
}
create_mock = mock.Mock(return_value=stubs.stub_share('1',
display_name=shr['name'],
display_description=shr['description'],
size=shr['size'],
share_proto=shr['share_proto'].upper(),
snapshot_id=shr['snapshot_id'],
instance=dict(
availability_zone=shr['availability_zone'],
share_network_id=shr['share_network_id'])))
self.mock_object(share_api.API, 'create', create_mock)
self.mock_object(share_api.API, 'get_snapshot',
stubs.stub_snapshot_get)
parent_share = stubs.stub_share(
'1', instance={'share_network_id': parent_share_net},
create_share_from_snapshot_support=True)
self.mock_object(share_api.API, 'get', mock.Mock(
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
res_dict = self.controller.create(req, body)
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertDictMatch(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
def test_share_create_from_snapshot_invalid_share_net(self):
self.mock_object(share_api.API, 'create')
shr = {
"size": 100,
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"snapshot_id": 333,
"share_network_id": 1234,
}
body = {"share": shr}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, body)
def test_share_create_from_snapshot_not_supported(self):
parent_share_net = 444
self.mock_object(share_api.API, 'create')
shr = {
"size": 100,
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1",
"snapshot_id": 333,
"share_network_id": parent_share_net,
}
parent_share = stubs.stub_share(
'1', instance={'share_network_id': parent_share_net},
create_share_from_snapshot_support=False)
self.mock_object(share_api.API, 'get', mock.Mock(
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
body = {"share": shr}
req = fakes.HTTPRequest.blank('/shares', version='2.24')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.create, req, body)
def test_share_creation_fails_with_bad_size(self):
shr = {"size": '',
"name": "Share Test Name",
"description": "Share Test Desc",
"share_proto": "fakeproto",
"availability_zone": "zone1:host1"}
body = {"share": shr}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
self.assertRaises(exception.InvalidInput,
self.controller.create, req, body)
def test_share_create_no_body(self):
req = fakes.HTTPRequest.blank('/shares', version='2.7')
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.create, req, {})
def test_share_create_invalid_availability_zone(self):
self.mock_object(
db,
'availability_zone_get',
mock.Mock(side_effect=exception.AvailabilityZoneNotFound(id='id'))
)
body = {"share": copy.deepcopy(self.share)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.create,
req,
body)
def test_share_show(self):
req = fakes.HTTPRequest.blank('/shares/1')
expected = self._get_expected_share_detailed_response()
res_dict = self.controller.show(req, '1')
self.assertEqual(expected, res_dict)
def test_share_show_with_share_group(self):
req = fakes.HTTPRequest.blank(
'/shares/1', version='2.31', experimental=True)
expected = self._get_expected_share_detailed_response(version='2.31')
res_dict = self.controller.show(req, '1')
self.assertDictMatch(expected, res_dict)
def test_share_show_with_share_group_earlier_version(self):
req = fakes.HTTPRequest.blank(
'/shares/1', version='2.23', experimental=True)
expected = self._get_expected_share_detailed_response(version='2.23')
res_dict = self.controller.show(req, '1')
self.assertDictMatch(expected, res_dict)
def test_share_show_with_share_type_name(self):
req = fakes.HTTPRequest.blank('/shares/1', version='2.6')
res_dict = self.controller.show(req, '1')
expected = self._get_expected_share_detailed_response(version='2.6')
self.assertEqual(expected, res_dict)
@ddt.data("2.15", "2.16")
def test_share_show_with_user_id(self, microversion):
req = fakes.HTTPRequest.blank('/shares/1', version=microversion)
res_dict = self.controller.show(req, '1')
expected = self._get_expected_share_detailed_response(
version=microversion)
self.assertEqual(expected, res_dict)
def test_share_show_admin(self):
req = fakes.HTTPRequest.blank('/shares/1', use_admin_context=True)
expected = self._get_expected_share_detailed_response(admin=True)
res_dict = self.controller.show(req, '1')
self.assertEqual(expected, res_dict)
def test_share_show_no_share(self):
self.mock_object(share_api.API, 'get',
stubs.stub_share_get_notfound)
req = fakes.HTTPRequest.blank('/shares/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.show,
req, '1')
def test_share_show_with_replication_type(self):
req = fakes.HTTPRequest.blank(
'/shares/1', version=share_replicas.MIN_SUPPORTED_API_VERSION)
res_dict = self.controller.show(req, '1')
expected = self._get_expected_share_detailed_response(
version=share_replicas.MIN_SUPPORTED_API_VERSION)
self.assertEqual(expected, res_dict)
@ddt.data(('2.10', True), ('2.27', True), ('2.28', False))
@ddt.unpack
def test_share_show_access_rules_status_translated(self, version,
translated):
share = db_utils.create_share(
access_rules_status=constants.SHARE_INSTANCE_RULES_SYNCING,
status=constants.STATUS_AVAILABLE)
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
req = fakes.HTTPRequest.blank(
'/shares/%s' % share['id'], version=version)
res_dict = self.controller.show(req, share['id'])
expected = (constants.STATUS_OUT_OF_SYNC if translated else
constants.SHARE_INSTANCE_RULES_SYNCING)
self.assertEqual(expected, res_dict['share']['access_rules_status'])
def test_share_delete(self):
req = fakes.HTTPRequest.blank('/shares/1')
resp = self.controller.delete(req, 1)
self.assertEqual(202, resp.status_int)
def test_share_delete_has_replicas(self):
req = fakes.HTTPRequest.blank('/shares/1')
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=self.share))
self.mock_object(share_api.API, 'delete',
mock.Mock(side_effect=exception.Conflict(err='err')))
self.assertRaises(
webob.exc.HTTPConflict, self.controller.delete, req, 1)
def test_share_delete_in_share_group_param_not_provided(self):
fake_share = stubs.stub_share('fake_share',
share_group_id='fake_group_id')
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=fake_share))
req = fakes.HTTPRequest.blank('/shares/1')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.delete, req, 1)
def test_share_delete_in_share_group(self):
fake_share = stubs.stub_share('fake_share',
share_group_id='fake_group_id')
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=fake_share))
req = fakes.HTTPRequest.blank(
'/shares/1?share_group_id=fake_group_id')
resp = self.controller.delete(req, 1)
self.assertEqual(202, resp.status_int)
def test_share_delete_in_share_group_wrong_id(self):
fake_share = stubs.stub_share('fake_share',
share_group_id='fake_group_id')
self.mock_object(share_api.API, 'get',
mock.Mock(return_value=fake_share))
req = fakes.HTTPRequest.blank(
'/shares/1?share_group_id=not_fake_group_id')
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.delete, req, 1)
def test_share_update(self):
shr = self.share
body = {"share": shr}
req = fakes.HTTPRequest.blank('/share/1')
res_dict = self.controller.update(req, 1, body)
self.assertEqual(shr["display_name"], res_dict['share']["name"])
self.assertEqual(shr["display_description"],
res_dict['share']["description"])
self.assertEqual(shr['is_public'],
res_dict['share']['is_public'])
def test_share_update_with_share_group(self):
shr = self.share
body = {"share": shr}
req = fakes.HTTPRequest.blank(
'/share/1', version="2.31", experimental=True)
res_dict = self.controller.update(req, 1, body)
self.assertIsNone(res_dict['share']["share_group_id"])
self.assertIsNone(
res_dict['share']["source_share_group_snapshot_member_id"])
def test_share_not_updates_size(self):
req = fakes.HTTPRequest.blank('/share/1')
res_dict = self.controller.update(req, 1, {"share": self.share})
self.assertNotEqual(res_dict['share']["size"], self.share["size"])
def test_share_delete_no_share(self):
self.mock_object(share_api.API, 'get',
stubs.stub_share_get_notfound)
req = fakes.HTTPRequest.blank('/shares/1')
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.delete,
req,
1)
@ddt.data({'use_admin_context': False, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.35'},
{'use_admin_context': False, 'version': '2.35'},
{'use_admin_context': True, 'version': '2.36'},
{'use_admin_context': False, 'version': '2.36'},
{'use_admin_context': True, 'version': '2.42'},
{'use_admin_context': False, 'version': '2.42'})
@ddt.unpack
def test_share_list_summary_with_search_opts(self, use_admin_context,
version):
search_opts = {
'name': 'fake_name',
'status': constants.STATUS_AVAILABLE,
'share_server_id': 'fake_share_server_id',
'share_type_id': 'fake_share_type_id',
'snapshot_id': 'fake_snapshot_id',
'share_network_id': 'fake_share_network_id',
'metadata': '%7B%27k1%27%3A+%27v1%27%7D', # serialized k1=v1
'extra_specs': '%7B%27k2%27%3A+%27v2%27%7D', # serialized k2=v2
'sort_key': 'fake_sort_key',
'sort_dir': 'fake_sort_dir',
'limit': '1',
'offset': '1',
'is_public': 'False',
'export_location_id': 'fake_export_location_id',
'export_location_path': 'fake_export_location_path',
}
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.36')):
search_opts.update(
{'display_name~': 'fake',
'display_description~': 'fake'})
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.42')):
search_opts.update({'with_count': 'true'})
if use_admin_context:
search_opts['host'] = 'fake_host'
# fake_key should be filtered for non-admin
url = '/shares?fake_key=fake_value'
for k, v in search_opts.items():
url = url + '&' + k + '=' + v
req = fakes.HTTPRequest.blank(url, version=version,
use_admin_context=use_admin_context)
shares = [
{'id': 'id1', 'display_name': 'n1'},
{'id': 'id2', 'display_name': 'n2'},
{'id': 'id3', 'display_name': 'n3'},
]
self.mock_object(share_api.API, 'get_all',
mock.Mock(return_value=[shares[1]]))
result = self.controller.index(req)
search_opts_expected = {
'display_name': search_opts['name'],
'status': search_opts['status'],
'share_server_id': search_opts['share_server_id'],
'share_type_id': search_opts['share_type_id'],
'snapshot_id': search_opts['snapshot_id'],
'share_network_id': search_opts['share_network_id'],
'metadata': {'k1': 'v1'},
'extra_specs': {'k2': 'v2'},
'is_public': 'False',
'limit': '1',
'offset': '1'
}
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.35')):
search_opts_expected['export_location_id'] = (
search_opts['export_location_id'])
search_opts_expected['export_location_path'] = (
search_opts['export_location_path'])
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.36')):
search_opts_expected.update(
{'display_name~': search_opts['display_name~'],
'display_description~': search_opts['display_description~']})
if use_admin_context:
search_opts_expected.update({'fake_key': 'fake_value'})
search_opts_expected['host'] = search_opts['host']
share_api.API.get_all.assert_called_once_with(
req.environ['manila.context'],
sort_key=search_opts['sort_key'],
sort_dir=search_opts['sort_dir'],
search_opts=search_opts_expected,
)
self.assertEqual(1, len(result['shares']))
self.assertEqual(shares[1]['id'], result['shares'][0]['id'])
self.assertEqual(
shares[1]['display_name'], result['shares'][0]['name'])
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.42')):
self.assertEqual(1, result['count'])
@ddt.data({'use_admin_context': True, 'version': '2.42'},
{'use_admin_context': False, 'version': '2.42'})
@ddt.unpack
def test_share_list_summary_with_search_opt_count_0(self,
use_admin_context,
version):
search_opts = {
'sort_key': 'fake_sort_key',
'sort_dir': 'fake_sort_dir',
'with_count': 'true'
}
if use_admin_context:
search_opts['host'] = 'fake_host'
# fake_key should be filtered
url = '/shares?fake_key=fake_value'
for k, v in search_opts.items():
url = url + '&' + k + '=' + v
req = fakes.HTTPRequest.blank(url, version=version,
use_admin_context=use_admin_context)
self.mock_object(share_api.API, 'get_all',
mock.Mock(return_value=[]))
result = self.controller.index(req)
search_opts_expected = {}
if use_admin_context:
search_opts_expected.update({'fake_key': 'fake_value'})
search_opts_expected['host'] = search_opts['host']
share_api.API.get_all.assert_called_once_with(
req.environ['manila.context'],
sort_key=search_opts['sort_key'],
sort_dir=search_opts['sort_dir'],
search_opts=search_opts_expected,
)
self.assertEqual(0, len(result['shares']))
self.assertEqual(0, result['count'])
def test_share_list_summary(self):
self.mock_object(share_api.API, 'get_all',
stubs.stub_share_get_all_by_project)
req = fakes.HTTPRequest.blank('/shares')
res_dict = self.controller.index(req)
expected = {
'shares': [
{
'name': 'displayname',
'id': '1',
'links': [
{
'href': 'http://localhost/v1/fake/shares/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/shares/1',
'rel': 'bookmark'
}
],
}
]
}
self.assertEqual(expected, res_dict)
@ddt.data({'use_admin_context': False, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.35'},
{'use_admin_context': False, 'version': '2.35'},
{'use_admin_context': True, 'version': '2.42'},
{'use_admin_context': False, 'version': '2.42'})
@ddt.unpack
def test_share_list_detail_with_search_opts(self, use_admin_context,
version):
search_opts = {
'name': 'fake_name',
'status': constants.STATUS_AVAILABLE,
'share_server_id': 'fake_share_server_id',
'share_type_id': 'fake_share_type_id',
'snapshot_id': 'fake_snapshot_id',
'share_network_id': 'fake_share_network_id',
'metadata': '%7B%27k1%27%3A+%27v1%27%7D', # serialized k1=v1
'extra_specs': '%7B%27k2%27%3A+%27v2%27%7D', # serialized k2=v2
'sort_key': 'fake_sort_key',
'sort_dir': 'fake_sort_dir',
'limit': '1',
'offset': '1',
'is_public': 'False',
'export_location_id': 'fake_export_location_id',
'export_location_path': 'fake_export_location_path',
}
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.42')):
search_opts.update({'with_count': 'true'})
if use_admin_context:
search_opts['host'] = 'fake_host'
# fake_key should be filtered for non-admin
url = '/shares/detail?fake_key=fake_value'
for k, v in search_opts.items():
url = url + '&' + k + '=' + v
req = fakes.HTTPRequest.blank(url, version=version,
use_admin_context=use_admin_context)
shares = [
{'id': 'id1', 'display_name': 'n1'},
{
'id': 'id2',
'display_name': 'n2',
'status': constants.STATUS_AVAILABLE,
'snapshot_id': 'fake_snapshot_id',
'instance': {
'host': 'fake_host',
'share_network_id': 'fake_share_network_id',
'share_type_id': 'fake_share_type_id',
},
'has_replicas': False,
},
{'id': 'id3', 'display_name': 'n3'},
]
self.mock_object(share_api.API, 'get_all',
mock.Mock(return_value=[shares[1]]))
result = self.controller.detail(req)
search_opts_expected = {
'display_name': search_opts['name'],
'status': search_opts['status'],
'share_server_id': search_opts['share_server_id'],
'share_type_id': search_opts['share_type_id'],
'snapshot_id': search_opts['snapshot_id'],
'share_network_id': search_opts['share_network_id'],
'metadata': {'k1': 'v1'},
'extra_specs': {'k2': 'v2'},
'is_public': 'False',
'limit': '1',
'offset': '1'
}
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.35')):
search_opts_expected['export_location_id'] = (
search_opts['export_location_id'])
search_opts_expected['export_location_path'] = (
search_opts['export_location_path'])
if use_admin_context:
search_opts_expected.update({'fake_key': 'fake_value'})
search_opts_expected['host'] = search_opts['host']
share_api.API.get_all.assert_called_once_with(
req.environ['manila.context'],
sort_key=search_opts['sort_key'],
sort_dir=search_opts['sort_dir'],
search_opts=search_opts_expected,
)
self.assertEqual(1, len(result['shares']))
self.assertEqual(shares[1]['id'], result['shares'][0]['id'])
self.assertEqual(
shares[1]['display_name'], result['shares'][0]['name'])
self.assertEqual(
shares[1]['snapshot_id'], result['shares'][0]['snapshot_id'])
self.assertEqual(
shares[1]['status'], result['shares'][0]['status'])
self.assertEqual(
shares[1]['instance']['share_type_id'],
result['shares'][0]['share_type'])
self.assertEqual(
shares[1]['snapshot_id'], result['shares'][0]['snapshot_id'])
if use_admin_context:
self.assertEqual(
shares[1]['instance']['host'], result['shares'][0]['host'])
self.assertEqual(
shares[1]['instance']['share_network_id'],
result['shares'][0]['share_network_id'])
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.42')):
self.assertEqual(1, result['count'])
def _list_detail_common_expected(self, admin=False):
share_dict = {
'status': 'fakestatus',
'description': 'displaydesc',
'export_location': 'fake_location',
'export_locations': ['fake_location', 'fake_location2'],
'availability_zone': 'fakeaz',
'name': 'displayname',
'share_proto': 'FAKEPROTO',
'metadata': {},
'project_id': 'fakeproject',
'id': '1',
'snapshot_id': '2',
'snapshot_support': True,
'share_network_id': None,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'share_type': '1',
'volume_type': '1',
'is_public': False,
'links': [
{
'href': 'http://localhost/v1/fake/shares/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/shares/1',
'rel': 'bookmark'
}
],
}
if admin:
share_dict['host'] = 'fakehost'
return {'shares': [share_dict]}
def _list_detail_test_common(self, req, expected):
self.mock_object(share_api.API, 'get_all',
stubs.stub_share_get_all_by_project)
res_dict = self.controller.detail(req)
self.assertDictListMatch(expected['shares'], res_dict['shares'])
self.assertEqual(res_dict['shares'][0]['volume_type'],
res_dict['shares'][0]['share_type'])
def test_share_list_detail(self):
env = {'QUERY_STRING': 'name=Share+Test+Name'}
req = fakes.HTTPRequest.blank('/shares/detail', environ=env)
expected = self._list_detail_common_expected()
expected['shares'][0].pop('snapshot_support')
self._list_detail_test_common(req, expected)
def test_share_list_detail_with_share_group(self):
env = {'QUERY_STRING': 'name=Share+Test+Name'}
req = fakes.HTTPRequest.blank(
'/shares/detail', environ=env, version="2.31", experimental=True)
expected = self._list_detail_common_expected()
expected['shares'][0]['task_state'] = None
expected['shares'][0]['share_type_name'] = None
expected['shares'][0].pop('export_location')
expected['shares'][0].pop('export_locations')
expected['shares'][0]['access_rules_status'] = 'active'
expected['shares'][0]['replication_type'] = None
expected['shares'][0]['has_replicas'] = False
expected['shares'][0]['user_id'] = 'fakeuser'
expected['shares'][0]['create_share_from_snapshot_support'] = True
expected['shares'][0]['revert_to_snapshot_support'] = False
expected['shares'][0]['share_group_id'] = None
expected['shares'][0]['source_share_group_snapshot_member_id'] = None
self._list_detail_test_common(req, expected)
def test_share_list_detail_with_task_state(self):
env = {'QUERY_STRING': 'name=Share+Test+Name'}
req = fakes.HTTPRequest.blank('/shares/detail', environ=env,
version="2.5")
expected = self._list_detail_common_expected()
expected['shares'][0]['task_state'] = None
self._list_detail_test_common(req, expected)
def test_share_list_detail_without_export_locations(self):
env = {'QUERY_STRING': 'name=Share+Test+Name'}
req = fakes.HTTPRequest.blank('/shares/detail', environ=env,
version="2.9")
expected = self._list_detail_common_expected()
expected['shares'][0]['task_state'] = None
expected['shares'][0]['share_type_name'] = None
expected['shares'][0].pop('export_location')
expected['shares'][0].pop('export_locations')
self._list_detail_test_common(req, expected)
def test_share_list_detail_with_replication_type(self):
self.mock_object(share_api.API, 'get_all',
stubs.stub_share_get_all_by_project)
env = {'QUERY_STRING': 'name=Share+Test+Name'}
req = fakes.HTTPRequest.blank(
'/shares/detail', environ=env,
version=share_replicas.MIN_SUPPORTED_API_VERSION)
res_dict = self.controller.detail(req)
expected = {
'shares': [
{
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'displayname',
'share_proto': 'FAKEPROTO',
'metadata': {},
'project_id': 'fakeproject',
'access_rules_status': 'active',
'id': '1',
'snapshot_id': '2',
'share_network_id': None,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'share_type_name': None,
'share_type': '1',
'volume_type': '1',
'is_public': False,
'snapshot_support': True,
'has_replicas': False,
'replication_type': None,
'task_state': None,
'links': [
{
'href': 'http://localhost/v1/fake/shares/1',
'rel': 'self'
},
{
'href': 'http://localhost/fake/shares/1',
'rel': 'bookmark'
}
],
}
]
}
self.assertEqual(expected, res_dict)
self.assertEqual(res_dict['shares'][0]['volume_type'],
res_dict['shares'][0]['share_type'])
def test_remove_invalid_options(self):
ctx = context.RequestContext('fakeuser', 'fakeproject', is_admin=False)
search_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
expected_opts = {'a': 'a', 'c': 'c'}
allowed_opts = ['a', 'c']
common.remove_invalid_options(ctx, search_opts, allowed_opts)
self.assertEqual(expected_opts, search_opts)
def test_remove_invalid_options_admin(self):
ctx = context.RequestContext('fakeuser', 'fakeproject', is_admin=True)
search_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
expected_opts = {'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
allowed_opts = ['a', 'c']
common.remove_invalid_options(ctx, search_opts, allowed_opts)
self.assertEqual(expected_opts, search_opts)
def _fake_access_get(self, ctxt, access_id):
class Access(object):
def __init__(self, **kwargs):
self.STATE_NEW = 'fake_new'
self.STATE_ACTIVE = 'fake_active'
self.STATE_ERROR = 'fake_error'
self.params = kwargs
self.params['state'] = self.STATE_NEW
self.share_id = kwargs.get('share_id')
self.id = access_id
def __getitem__(self, item):
return self.params[item]
access = Access(access_id=access_id, share_id='fake_share_id')
return access
@ddt.ddt
class ShareActionsTest(test.TestCase):
def setUp(self):
super(ShareActionsTest, self).setUp()
self.controller = shares.ShareController()
self.mock_object(share_api.API, 'get', stubs.stub_share_get)
@ddt.unpack
@ddt.data(
{"access": {'access_type': 'ip', 'access_to': '127.0.0.1'},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': '1' * 4},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': '1' * 255},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': 'fake{.-_\'`}'},
"version": "2.7"},
{"access": {'access_type': 'user',
'access_to': 'MYDOMAIN-Administrator'},
"version": "2.7"},
{"access": {'access_type': 'user',
'access_to': 'test group name'},
"version": "2.7"},
{"access": {'access_type': 'user',
'access_to': 'group$.-_\'`{}'},
"version": "2.7"},
{"access": {'access_type': 'cert', 'access_to': 'x'},
"version": "2.7"},
{"access": {'access_type': 'cert', 'access_to': 'tenant.example.com'},
"version": "2.7"},
{"access": {'access_type': 'cert', 'access_to': 'x' * 64},
"version": "2.7"},
{"access": {'access_type': 'ip', 'access_to': 'ad80::abaa:0:c2:2'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': 'AD80:ABAA::'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': 'AD80::/36'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': 'AD80:ABAA::/128'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.1'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
'metadata': {'test_key': 'test_value'}},
"version": "2.45"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
'metadata': {'k' * 255: 'v' * 1023}},
"version": "2.45"},
)
def test_allow_access(self, access, version):
self.mock_object(share_api.API,
'allow_access',
mock.Mock(return_value={'fake': 'fake'}))
self.mock_object(self.controller._access_view_builder, 'view',
mock.Mock(return_value={'access':
{'fake': 'fake'}}))
id = 'fake_share_id'
body = {'allow_access': access}
expected = {'access': {'fake': 'fake'}}
req = fakes.HTTPRequest.blank(
'/v2/tenant1/shares/%s/action' % id, version=version)
res = self.controller.allow_access(req, id, body)
self.assertEqual(expected, res)
@ddt.unpack
@ddt.data(
{"access": {'access_type': 'error_type',
'access_to': '127.0.0.1'},
"version": "2.7"},
{"access": {'access_type': 'ip', 'access_to': 'localhost'},
"version": "2.7"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.*'},
"version": "2.7"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.0/33'},
"version": "2.7"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.256'},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': '1'},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': '1' * 3},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': '1' * 256},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': 'root<>'},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': 'group\\'},
"version": "2.7"},
{"access": {'access_type': 'user', 'access_to': '+=*?group'},
"version": "2.7"},
{"access": {'access_type': 'cert', 'access_to': ''},
"version": "2.7"},
{"access": {'access_type': 'cert', 'access_to': ' '},
"version": "2.7"},
{"access": {'access_type': 'cert', 'access_to': 'x' * 65},
"version": "2.7"},
{"access": {'access_type': 'ip', 'access_to': 'ad80::abaa:0:c2:2'},
"version": "2.37"},
{"access": {'access_type': 'ip', 'access_to': '127.4.0.3/33'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': 'AD80:ABAA::*'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': 'AD80::/129'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': 'ad80::abaa:0:c2:2/64'},
"version": "2.38"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
'metadata': {'k' * 256: 'v' * 1024}},
"version": "2.45"},
{"access": {'access_type': 'ip', 'access_to': '127.0.0.1',
'metadata': {'key': None}},
"version": "2.45"},
)
def test_allow_access_error(self, access, version):
id = 'fake_share_id'
body = {'allow_access': access}
req = fakes.HTTPRequest.blank('/v2/tenant1/shares/%s/action' % id,
version=version)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.allow_access, req, id, body)
@ddt.unpack
@ddt.data(
{'exc': None, 'access_to': 'alice', 'version': '2.13'},
{'exc': webob.exc.HTTPBadRequest, 'access_to': 'alice',
'version': '2.11'}
)
def test_allow_access_ceph(self, exc, access_to, version):
share_id = "fake_id"
self.mock_object(share_api.API,
'allow_access',
mock.Mock(return_value={'fake': 'fake'}))
self.mock_object(self.controller._access_view_builder, 'view',
mock.Mock(return_value={'access':
{'fake': 'fake'}}))
req = fakes.HTTPRequest.blank(
'/v2/shares/%s/action' % share_id, version=version)
body = {'allow_access':
{
'access_type': 'cephx',
'access_to': access_to,
'access_level': 'rw'
}}
if exc:
self.assertRaises(exc, self.controller.allow_access, req, share_id,
body)
else:
expected = {'access': {'fake': 'fake'}}
res = self.controller.allow_access(req, id, body)
self.assertEqual(expected, res)
@ddt.data('2.1', '2.27')
def test_allow_access_access_rules_status_is_in_error(self, version):
share = db_utils.create_share(
access_rules_status=constants.SHARE_INSTANCE_RULES_ERROR)
req = fakes.HTTPRequest.blank(
'/v2/shares/%s/action' % share['id'], version=version)
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, 'allow_access')
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.7')):
key = 'allow_access'
method = self.controller.allow_access
else:
key = 'os-allow_access'
method = self.controller.allow_access_legacy
body = {
key: {
'access_type': 'user',
'access_to': 'crimsontide',
'access_level': 'rw',
}
}
self.assertRaises(webob.exc.HTTPBadRequest,
method, req, share['id'], body)
self.assertFalse(share_api.API.allow_access.called)
@ddt.data(*itertools.product(
('2.1', '2.27'), (constants.SHARE_INSTANCE_RULES_SYNCING,
constants.STATUS_ACTIVE)))
@ddt.unpack
def test_allow_access_no_transitional_states(self, version, status):
share = db_utils.create_share(access_rules_status=status,
status=constants.STATUS_AVAILABLE)
req = fakes.HTTPRequest.blank(
'/v2/shares/%s/action' % share['id'], version=version)
ctxt = req.environ['manila.context']
access = {
'access_type': 'user',
'access_to': 'clemsontigers',
'access_level': 'rw',
}
expected_mapping = {
constants.SHARE_INSTANCE_RULES_SYNCING: constants.STATUS_NEW,
constants.SHARE_INSTANCE_RULES_ERROR:
constants.ACCESS_STATE_ERROR,
constants.STATUS_ACTIVE: constants.ACCESS_STATE_ACTIVE,
}
share = db.share_get(ctxt, share['id'])
updated_access = db_utils.create_access(share_id=share['id'], **access)
expected_access = access
expected_access.update(
{
'id': updated_access['id'],
'state': expected_mapping[share['access_rules_status']],
'share_id': updated_access['share_id'],
})
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.7')):
key = 'allow_access'
method = self.controller.allow_access
else:
key = 'os-allow_access'
method = self.controller.allow_access_legacy
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.13')):
expected_access['access_key'] = None
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, 'allow_access',
mock.Mock(return_value=updated_access))
body = {key: access}
access = method(req, share['id'], body)
self.assertEqual(expected_access, access['access'])
share_api.API.allow_access.assert_called_once_with(
req.environ['manila.context'], share, 'user',
'clemsontigers', 'rw', None)
@ddt.data(*itertools.product(
set(['2.28', api_version._MAX_API_VERSION]),
(constants.SHARE_INSTANCE_RULES_ERROR,
constants.SHARE_INSTANCE_RULES_SYNCING, constants.STATUS_ACTIVE)))
@ddt.unpack
def test_allow_access_access_rules_status_dont_care(self, version, status):
access = {
'access_type': 'user',
'access_to': 'clemsontigers',
'access_level': 'rw',
}
updated_access = db_utils.create_access(**access)
expected_access = access
expected_access.update(
{
'id': updated_access['id'],
'state': updated_access['state'],
'share_id': updated_access['share_id'],
'access_key': None,
})
share = db_utils.create_share(access_rules_status=status)
req = fakes.HTTPRequest.blank(
'/v2/shares/%s/action' % share['id'], version=version)
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, 'allow_access',
mock.Mock(return_value=updated_access))
body = {'allow_access': access}
access = self.controller.allow_access(req, share['id'], body)
if api_version.APIVersionRequest(version) >= (
api_version.APIVersionRequest("2.33")):
expected_access.update(
{
'created_at': updated_access['created_at'],
'updated_at': updated_access['updated_at'],
})
if api_version.APIVersionRequest(version) >= (
api_version.APIVersionRequest("2.45")):
expected_access.update(
{
'metadata': {},
})
self.assertEqual(expected_access, access['access'])
share_api.API.allow_access.assert_called_once_with(
req.environ['manila.context'], share, 'user',
'clemsontigers', 'rw', None)
def test_deny_access(self):
def _stub_deny_access(*args, **kwargs):
pass
self.mock_object(share_api.API, "deny_access", _stub_deny_access)
self.mock_object(share_api.API, "access_get", _fake_access_get)
id = 'fake_share_id'
body = {"os-deny_access": {"access_id": 'fake_acces_id'}}
req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id)
res = self.controller._deny_access(req, id, body)
self.assertEqual(202, res.status_int)
def test_deny_access_not_found(self):
def _stub_deny_access(*args, **kwargs):
pass
self.mock_object(share_api.API, "deny_access", _stub_deny_access)
self.mock_object(share_api.API, "access_get", _fake_access_get)
id = 'super_fake_share_id'
body = {"os-deny_access": {"access_id": 'fake_acces_id'}}
req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id)
self.assertRaises(webob.exc.HTTPNotFound,
self.controller._deny_access,
req,
id,
body)
def test_access_list(self):
fake_access_list = [
{
"state": "fakestatus",
"id": "fake_access_id",
"access_type": "fakeip",
"access_to": "127.0.0.1",
}
]
self.mock_object(self.controller._access_view_builder, 'list_view',
mock.Mock(return_value={'access_list':
fake_access_list}))
id = 'fake_share_id'
body = {"os-access_list": None}
req = fakes.HTTPRequest.blank('/v2/tenant1/shares/%s/action' % id)
res_dict = self.controller._access_list(req, id, body)
self.assertEqual({'access_list': fake_access_list}, res_dict)
@ddt.unpack
@ddt.data(
{'body': {'os-extend': {'new_size': 2}}, 'version': '2.6'},
{'body': {'extend': {'new_size': 2}}, 'version': '2.7'},
)
def test_extend(self, body, version):
id = 'fake_share_id'
share = stubs.stub_share_get(None, None, id)
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, "extend")
size = '2'
req = fakes.HTTPRequest.blank(
'/v2/shares/%s/action' % id, version=version)
actual_response = self.controller._extend(req, id, body)
share_api.API.get.assert_called_once_with(mock.ANY, id)
share_api.API.extend.assert_called_once_with(
mock.ANY, share, int(size))
self.assertEqual(202, actual_response.status_int)
@ddt.data({"os-extend": ""},
{"os-extend": {"new_size": "foo"}},
{"os-extend": {"new_size": {'foo': 'bar'}}})
def test_extend_invalid_body(self, body):
id = 'fake_share_id'
req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._extend, req, id, body)
@ddt.data({'source': exception.InvalidInput,
'target': webob.exc.HTTPBadRequest},
{'source': exception.InvalidShare,
'target': webob.exc.HTTPBadRequest},
{'source': exception.ShareSizeExceedsAvailableQuota,
'target': webob.exc.HTTPForbidden})
@ddt.unpack
def test_extend_exception(self, source, target):
id = 'fake_share_id'
req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
body = {"os-extend": {'new_size': '123'}}
self.mock_object(share_api.API, "extend",
mock.Mock(side_effect=source('fake')))
self.assertRaises(target, self.controller._extend, req, id, body)
@ddt.unpack
@ddt.data(
{'body': {'os-shrink': {'new_size': 1}}, 'version': '2.6'},
{'body': {'shrink': {'new_size': 1}}, 'version': '2.7'},
)
def test_shrink(self, body, version):
id = 'fake_share_id'
share = stubs.stub_share_get(None, None, id)
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, "shrink")
size = '1'
req = fakes.HTTPRequest.blank(
'/v2/shares/%s/action' % id, version=version)
actual_response = self.controller._shrink(req, id, body)
share_api.API.get.assert_called_once_with(mock.ANY, id)
share_api.API.shrink.assert_called_once_with(
mock.ANY, share, int(size))
self.assertEqual(202, actual_response.status_int)
@ddt.data({"os-shrink": ""},
{"os-shrink": {"new_size": "foo"}},
{"os-shrink": {"new_size": {'foo': 'bar'}}})
def test_shrink_invalid_body(self, body):
id = 'fake_share_id'
req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._shrink, req, id, body)
@ddt.data({'source': exception.InvalidInput,
'target': webob.exc.HTTPBadRequest},
{'source': exception.InvalidShare,
'target': webob.exc.HTTPBadRequest})
@ddt.unpack
def test_shrink_exception(self, source, target):
id = 'fake_share_id'
req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id)
body = {"os-shrink": {'new_size': '123'}}
self.mock_object(share_api.API, "shrink",
mock.Mock(side_effect=source('fake')))
self.assertRaises(target, self.controller._shrink, req, id, body)
@ddt.ddt
class ShareAdminActionsAPITest(test.TestCase):
def setUp(self):
super(ShareAdminActionsAPITest, self).setUp()
CONF.set_default("default_share_type", None)
self.flags(transport_url='rabbit://fake:fake@mqhost:5672')
self.share_api = share_api.API()
self.admin_context = context.RequestContext('admin', 'fake', True)
self.member_context = context.RequestContext('fake', 'fake')
def _get_context(self, role):
return getattr(self, '%s_context' % role)
def _setup_share_data(self, share=None, version='2.7'):
if share is None:
share = db_utils.create_share(status=constants.STATUS_AVAILABLE,
size='1',
override_defaults=True)
path = '/v2/fake/shares/%s/action' % share['id']
req = fakes.HTTPRequest.blank(path, script_name=path, version=version)
return share, req
def _reset_status(self, ctxt, model, req, db_access_method,
valid_code, valid_status=None, body=None, version='2.7'):
if float(version) > 2.6:
action_name = 'reset_status'
else:
action_name = 'os-reset_status'
if body is None:
body = {action_name: {'status': constants.STATUS_ERROR}}
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.headers['X-Openstack-Manila-Api-Version'] = version
req.body = six.b(jsonutils.dumps(body))
req.environ['manila.context'] = ctxt
resp = req.get_response(fakes.app())
# validate response code and model status
self.assertEqual(valid_code, resp.status_int)
if valid_code == 404:
self.assertRaises(exception.NotFound,
db_access_method,
ctxt,
model['id'])
else:
actual_model = db_access_method(ctxt, model['id'])
self.assertEqual(valid_status, actual_model['status'])
@ddt.data(*fakes.fixture_reset_status_with_different_roles)
@ddt.unpack
def test_share_reset_status_with_different_roles(self, role, valid_code,
valid_status, version):
share, req = self._setup_share_data(version=version)
ctxt = self._get_context(role)
self._reset_status(ctxt, share, req, db.share_get, valid_code,
valid_status, version=version)
@ddt.data(*fakes.fixture_invalid_reset_status_body)
def test_share_invalid_reset_status_body(self, body):
share, req = self._setup_share_data(version='2.6')
ctxt = self.admin_context
self._reset_status(ctxt, share, req, db.share_get, 400,
constants.STATUS_AVAILABLE, body, version='2.6')
@ddt.data('2.6', '2.7')
def test_share_reset_status_for_missing(self, version):
fake_share = {'id': 'missing-share-id'}
req = fakes.HTTPRequest.blank(
'/v2/fake/shares/%s/action' % fake_share['id'], version=version)
self._reset_status(self.admin_context, fake_share, req,
db.share_snapshot_get, 404, version=version)
def _force_delete(self, ctxt, model, req, db_access_method, valid_code,
check_model_in_db=False, version='2.7'):
if float(version) > 2.6:
action_name = 'force_delete'
else:
action_name = 'os-force_delete'
req.method = 'POST'
req.headers['content-type'] = 'application/json'
req.headers['X-Openstack-Manila-Api-Version'] = version
req.body = six.b(jsonutils.dumps({action_name: {}}))
req.environ['manila.context'] = ctxt
resp = req.get_response(fakes.app())
# validate response
self.assertEqual(valid_code, resp.status_int)
if valid_code == 202 and check_model_in_db:
self.assertRaises(exception.NotFound,
db_access_method,
ctxt,
model['id'])
@ddt.data(*fakes.fixture_force_delete_with_different_roles)
@ddt.unpack
def test_share_force_delete_with_different_roles(self, role, resp_code,
version):
share, req = self._setup_share_data(version=version)
ctxt = self._get_context(role)
self._force_delete(ctxt, share, req, db.share_get, resp_code,
check_model_in_db=True, version=version)
@ddt.data('2.6', '2.7')
def test_share_force_delete_missing(self, version):
share, req = self._setup_share_data(
share={'id': 'fake'}, version=version)
ctxt = self._get_context('admin')
self._force_delete(
ctxt, share, req, db.share_get, 404, version=version)
@ddt.ddt
class ShareUnmanageTest(test.TestCase):
def setUp(self):
super(ShareUnmanageTest, self).setUp()
self.controller = shares.ShareController()
self.mock_object(share_api.API, 'get_all',
stubs.stub_get_all_shares)
self.mock_object(share_api.API, 'get',
stubs.stub_share_get)
self.mock_object(share_api.API, 'update', stubs.stub_share_update)
self.mock_object(share_api.API, 'delete', stubs.stub_share_delete)
self.mock_object(share_api.API, 'get_snapshot',
stubs.stub_snapshot_get)
self.share_id = 'fake'
self.request = fakes.HTTPRequest.blank(
'/share/%s/unmanage' % self.share_id,
use_admin_context=True, version='2.7',
)
def test_unmanage_share(self):
share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
instance={})
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, 'unmanage', mock.Mock())
self.mock_object(
self.controller.share_api.db, 'share_snapshot_get_all_for_share',
mock.Mock(return_value=[]))
actual_result = self.controller.unmanage(self.request, share['id'])
self.assertEqual(202, actual_result.status_int)
(self.controller.share_api.db.share_snapshot_get_all_for_share.
assert_called_once_with(
self.request.environ['manila.context'], share['id']))
self.controller.share_api.get.assert_called_once_with(
self.request.environ['manila.context'], share['id'])
share_api.API.unmanage.assert_called_once_with(
self.request.environ['manila.context'], share)
def test__unmanage(self):
body = {}
req = fakes.HTTPRequest.blank(
'/shares/1/action', use_admin_context=False, version='2.49')
share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
instance={})
mock_unmanage = self.mock_object(self.controller, '_unmanage')
self.controller.unmanage(req, share['id'], body)
mock_unmanage.assert_called_once_with(
req, share['id'], body, allow_dhss_true=True
)
def test_unmanage_share_that_has_snapshots(self):
share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
instance={})
snapshots = ['foo', 'bar']
self.mock_object(self.controller.share_api, 'unmanage')
self.mock_object(
self.controller.share_api.db, 'share_snapshot_get_all_for_share',
mock.Mock(return_value=snapshots))
self.mock_object(
self.controller.share_api, 'get',
mock.Mock(return_value=share))
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.unmanage, self.request, share['id'])
self.assertFalse(self.controller.share_api.unmanage.called)
(self.controller.share_api.db.share_snapshot_get_all_for_share.
assert_called_once_with(
self.request.environ['manila.context'], share['id']))
self.controller.share_api.get.assert_called_once_with(
self.request.environ['manila.context'], share['id'])
def test_unmanage_share_based_on_share_server(self):
share = dict(instance=dict(share_server_id='foo_id'), id='bar_id')
self.mock_object(
self.controller.share_api, 'get',
mock.Mock(return_value=share))
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.unmanage, self.request, share['id'])
self.controller.share_api.get.assert_called_once_with(
self.request.environ['manila.context'], share['id'])
@ddt.data(*constants.TRANSITIONAL_STATUSES)
def test_unmanage_share_with_transitional_state(self, share_status):
share = dict(status=share_status, id='foo_id', instance={})
self.mock_object(
self.controller.share_api, 'get',
mock.Mock(return_value=share))
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.unmanage, self.request, share['id'])
self.controller.share_api.get.assert_called_once_with(
self.request.environ['manila.context'], share['id'])
def test_unmanage_share_not_found(self):
self.mock_object(share_api.API, 'get', mock.Mock(
side_effect=exception.NotFound))
self.mock_object(share_api.API, 'unmanage', mock.Mock())
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.unmanage,
self.request, self.share_id)
@ddt.data(exception.InvalidShare(reason="fake"),
exception.PolicyNotAuthorized(action="fake"),)
def test_unmanage_share_invalid(self, side_effect):
share = dict(status=constants.STATUS_AVAILABLE, id='foo_id',
instance={})
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
self.mock_object(share_api.API, 'unmanage', mock.Mock(
side_effect=side_effect))
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.unmanage,
self.request, self.share_id)
def test_wrong_permissions(self):
share_id = 'fake'
req = fakes.HTTPRequest.blank('/share/%s/unmanage' % share_id,
use_admin_context=False, version='2.7')
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.unmanage,
req,
share_id)
def test_unsupported_version(self):
share_id = 'fake'
req = fakes.HTTPRequest.blank('/share/%s/unmanage' % share_id,
use_admin_context=False, version='2.6')
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.unmanage,
req,
share_id)
def get_fake_manage_body(export_path='/fake', service_host='fake@host#POOL',
protocol='fake', share_type='fake', **kwargs):
fake_share = {
'export_path': export_path,
'service_host': service_host,
'protocol': protocol,
'share_type': share_type,
}
fake_share.update(kwargs)
return {'share': fake_share}
@ddt.ddt
class ShareManageTest(test.TestCase):
def setUp(self):
super(ShareManageTest, self).setUp()
self.controller = shares.ShareController()
self.resource_name = self.controller.resource_name
self.request = fakes.HTTPRequest.blank(
'/v2/shares/manage', use_admin_context=True, version='2.7')
self.mock_policy_check = self.mock_object(
policy, 'check_policy', mock.Mock(return_value=True))
def _setup_manage_mocks(self, service_is_up=True):
self.mock_object(db, 'service_get_by_host_and_topic', mock.Mock(
return_value={'host': 'fake'}))
self.mock_object(share_types, 'get_share_type_by_name_or_id',
mock.Mock(return_value={'id': 'fake'}))
self.mock_object(utils, 'service_is_up', mock.Mock(
return_value=service_is_up))
if service_is_up:
self.mock_object(utils, 'validate_service_host')
else:
self.mock_object(
utils,
'validate_service_host',
mock.Mock(side_effect=exception.ServiceIsDown(service='fake')))
def test__manage(self):
body = {}
req = fakes.HTTPRequest.blank(
'/v2/shares/manage', use_admin_context=True, version='2.49')
mock_manage = self.mock_object(self.controller, '_manage')
self.controller.manage(req, body)
mock_manage.assert_called_once_with(
req, body, allow_dhss_true=True
)
@ddt.data({},
{'shares': {}},
{'share': get_fake_manage_body('', None, None)})
def test_share_manage_invalid_body(self, body):
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.manage,
self.request,
body)
def test_share_manage_service_not_found(self):
body = get_fake_manage_body()
self.mock_object(db, 'service_get_by_host_and_topic', mock.Mock(
side_effect=exception.ServiceNotFound(service_id='fake')))
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.manage,
self.request,
body)
def test_share_manage_share_type_not_found(self):
body = get_fake_manage_body()
self.mock_object(db, 'service_get_by_host_and_topic', mock.Mock())
self.mock_object(utils, 'service_is_up', mock.Mock(return_value=True))
self.mock_object(db, 'share_type_get_by_name', mock.Mock(
side_effect=exception.ShareTypeNotFoundByName(
share_type_name='fake')))
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.manage,
self.request,
body)
@ddt.data({'service_is_up': False, 'service_host': 'fake@host#POOL'},
{'service_is_up': True, 'service_host': 'fake@host'})
def test_share_manage_bad_request(self, settings):
body = get_fake_manage_body(service_host=settings.pop('service_host'))
self._setup_manage_mocks(**settings)
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.manage,
self.request,
body)
def test_share_manage_duplicate_share(self):
body = get_fake_manage_body()
exc = exception.InvalidShare(reason="fake")
self._setup_manage_mocks()
self.mock_object(share_api.API, 'manage', mock.Mock(side_effect=exc))
self.assertRaises(webob.exc.HTTPConflict,
self.controller.manage,
self.request,
body)
def test_share_manage_forbidden_manage(self):
body = get_fake_manage_body()
self._setup_manage_mocks()
error = mock.Mock(side_effect=exception.PolicyNotAuthorized(action=''))
self.mock_object(share_api.API, 'manage', error)
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.manage,
self.request,
body)
def test_share_manage_forbidden_validate_service_host(self):
body = get_fake_manage_body()
self._setup_manage_mocks()
error = mock.Mock(side_effect=exception.PolicyNotAuthorized(action=''))
self.mock_object(
utils, 'validate_service_host', mock.Mock(side_effect=error))
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.manage,
self.request,
body)
@ddt.data(
get_fake_manage_body(name='foo', description='bar'),
get_fake_manage_body(display_name='foo', description='bar'),
get_fake_manage_body(name='foo', display_description='bar'),
get_fake_manage_body(display_name='foo', display_description='bar'),
get_fake_manage_body(display_name='foo', display_description='bar',
driver_options=dict(volume_id='quuz')),
)
def test_share_manage(self, data):
self._test_share_manage(data, "2.7")
@ddt.data(
get_fake_manage_body(name='foo', description='bar', is_public=True),
get_fake_manage_body(name='foo', description='bar', is_public=False)
)
def test_share_manage_with_is_public(self, data):
self._test_share_manage(data, "2.8")
def test_share_manage_with_user_id(self):
self._test_share_manage(get_fake_manage_body(
name='foo', description='bar', is_public=True), "2.16")
def _test_share_manage(self, data, version):
expected = {
'share': {
'status': 'fakestatus',
'description': 'displaydesc',
'availability_zone': 'fakeaz',
'name': 'displayname',
'share_proto': 'FAKEPROTO',
'metadata': {},
'project_id': 'fakeproject',
'host': 'fakehost',
'id': 'fake',
'snapshot_id': '2',
'share_network_id': None,
'created_at': datetime.datetime(1, 1, 1, 1, 1, 1),
'size': 1,
'share_type_name': None,
'share_server_id': 'fake_share_server_id',
'share_type': '1',
'volume_type': '1',
'is_public': False,
'snapshot_support': True,
'task_state': None,
'links': [
{
'href': 'http://localhost/v1/fake/shares/fake',
'rel': 'self'
},
{
'href': 'http://localhost/fake/shares/fake',
'rel': 'bookmark'
}
],
}
}
self._setup_manage_mocks()
return_share = mock.Mock(
return_value=stubs.stub_share(
'fake',
instance={
'share_type_id': '1',
})
)
self.mock_object(
share_api.API, 'manage', return_share)
self.mock_object(
common, 'validate_public_share_policy',
mock.Mock(side_effect=lambda *args, **kwargs: args[1]))
share = {
'host': data['share']['service_host'],
'export_location': data['share']['export_path'],
'share_proto': data['share']['protocol'].upper(),
'share_type_id': 'fake',
'display_name': 'foo',
'display_description': 'bar',
}
driver_options = data['share'].get('driver_options', {})
if (api_version.APIVersionRequest(version) <=
api_version.APIVersionRequest('2.8')):
expected['share']['export_location'] = 'fake_location'
expected['share']['export_locations'] = (
['fake_location', 'fake_location2'])
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.10')):
expected['share']['access_rules_status'] = (
constants.STATUS_ACTIVE)
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.11')):
expected['share']['has_replicas'] = False
expected['share']['replication_type'] = None
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.16')):
expected['share']['user_id'] = 'fakeuser'
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.8')):
share['is_public'] = data['share']['is_public']
req = fakes.HTTPRequest.blank('/v2/shares/manage', version=version,
use_admin_context=True)
actual_result = self.controller.manage(req, data)
share_api.API.manage.assert_called_once_with(
mock.ANY, share, driver_options)
self.assertIsNotNone(actual_result)
self.assertEqual(expected, actual_result)
self.mock_policy_check.assert_called_once_with(
req.environ['manila.context'], self.resource_name, 'manage')
def test_wrong_permissions(self):
body = get_fake_manage_body()
self.assertRaises(
webob.exc.HTTPForbidden,
self.controller.manage,
fakes.HTTPRequest.blank(
'/share/manage', use_admin_context=False, version='2.7'),
body,
)
def test_unsupported_version(self):
share_id = 'fake'
req = fakes.HTTPRequest.blank(
'/share/manage', use_admin_context=False, version='2.6')
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.manage,
req,
share_id)
def test_revert(self):
mock_revert = self.mock_object(
self.controller, '_revert',
mock.Mock(return_value='fake_response'))
req = fakes.HTTPRequest.blank(
'/shares/fake_id/action', use_admin_context=False, version='2.27')
result = self.controller.revert(req, 'fake_id', 'fake_body')
self.assertEqual('fake_response', result)
mock_revert.assert_called_once_with(
req, 'fake_id', 'fake_body')
def test_revert_unsupported(self):
req = fakes.HTTPRequest.blank(
'/shares/fake_id/action', use_admin_context=False, version='2.24')
self.assertRaises(exception.VersionNotFoundForAPIMethod,
self.controller.revert,
req,
'fake_id',
'fake_body')