def decorator(f): obj_min_ver = api_version.APIVersionRequest(min_ver) if max_ver: obj_max_ver = api_version.APIVersionRequest(max_ver) else: obj_max_ver = api_version.APIVersionRequest() # Add to list of versioned methods registered func_name = f.__name__ new_func = versioned_method.VersionedMethod( func_name, obj_min_ver, obj_max_ver, experimental, f) func_dict = getattr(cls, VER_METHOD_ATTR, {}) if not func_dict: setattr(cls, VER_METHOD_ATTR, func_dict) func_list = func_dict.get(func_name, []) if not func_list: func_dict[func_name] = func_list func_list.append(new_func) # Ensure the list is sorted by minimum version (reversed) # so later when we work through the list in order we find # the method which has the latest version which supports # the version requested. # TODO(cyeoh): Add check to ensure that there are no overlapping # ranges of valid versions as that is ambiguous func_list.sort(reverse=True) return f
def test_get_string(self): v1_string = '3.23' v1 = api_version_request.APIVersionRequest(v1_string) self.assertEqual(v1_string, v1.get_string()) self.assertRaises(ValueError, api_version_request.APIVersionRequest().get_string)
def test_index(self, version): url = '/share_instances' if (api_version_request.APIVersionRequest(version) >= api_version_request.APIVersionRequest('2.35')): url += "?export_location_path=/admin/export/location" req = self._get_request(url, version=version) req_context = req.environ['manila.context'] share_instances_count = 3 test_instances = [ db_utils.create_share(size=s + 1).instance for s in range(0, share_instances_count) ] db.share_export_locations_update(self.admin_context, test_instances[0]['id'], '/admin/export/location', False) actual_result = self.controller.index(req) if (api_version_request.APIVersionRequest(version) >= api_version_request.APIVersionRequest('2.35')): test_instances = test_instances[:1] self._validate_ids_in_share_instances_list( test_instances, actual_result['share_instances']) self.mock_policy_check.assert_called_once_with(req_context, self.resource_name, 'index')
def set_api_version_request(self): """Set API version request based on the request header information. Microversions starts with /v2, so if a client sends a /v1 URL, then ignore the headers and request 1.0 APIs. """ if not self.script_name: self.api_version_request = api_version.APIVersionRequest() elif self.script_name == V1_SCRIPT_NAME: self.api_version_request = api_version.APIVersionRequest('1.0') else: if API_VERSION_REQUEST_HEADER in self.headers: hdr_string = self.headers[API_VERSION_REQUEST_HEADER] self.api_version_request = api_version.APIVersionRequest( hdr_string) # Check that the version requested is within the global # minimum/maximum of supported API versions if not self.api_version_request.matches( api_version.min_api_version(), api_version.max_api_version()): raise exception.InvalidGlobalAPIVersion( req_ver=self.api_version_request.get_string(), min_ver=api_version.min_api_version().get_string(), max_ver=api_version.max_api_version().get_string()) else: self.api_version_request = api_version.APIVersionRequest( api_version.DEFAULT_API_VERSION) # Check if experimental API was requested if EXPERIMENTAL_API_REQUEST_HEADER in self.headers: self.api_version_request.experimental = strutils.bool_from_string( self.headers[EXPERIMENTAL_API_REQUEST_HEADER])
def expected_snapshot(version=None, id='fake_snapshot_id', **kwargs): self_link = 'http://localhost/v1/fake/snapshots/%s' % id bookmark_link = 'http://localhost/fake/snapshots/%s' % id snapshot = { 'id': id, 'share_id': 'fakeshareid', 'created_at': datetime.datetime(1, 1, 1, 1, 1, 1), 'status': 'fakesnapstatus', 'name': 'displaysnapname', 'description': 'displaysnapdesc', 'share_size': 1, 'size': 1, 'share_proto': 'fakesnapproto', 'links': [ { 'href': self_link, 'rel': 'self', }, { 'href': bookmark_link, 'rel': 'bookmark', }, ], } if version and (api_version.APIVersionRequest(version) >= api_version.APIVersionRequest('2.17')): snapshot.update({ 'user_id': 'fakesnapuser', 'project_id': 'fakesnapproject', }) snapshot.update(kwargs) return {'snapshot': snapshot}
def test_get_share_instances(self, version): test_share = db_utils.create_share(size=1) id = test_share['id'] req = self._get_request('fake', version=version) req_context = req.environ['manila.context'] share_policy_check_call = mock.call(req_context, 'share', 'get', mock.ANY) get_instances_policy_check_call = mock.call(req_context, 'share_instance', 'index') actual_result = self.controller.get_share_instances(req, id) self._validate_ids_in_share_instances_list( [test_share.instance], actual_result['share_instances']) self.assertEqual(1, len(actual_result.get("share_instances", 0))) for instance in actual_result["share_instances"]: if (api_version_request.APIVersionRequest(version) > api_version_request.APIVersionRequest("2.8")): assert_method = self.assertNotIn else: assert_method = self.assertIn assert_method("export_location", instance) assert_method("export_locations", instance) if (api_version_request.APIVersionRequest(version) > api_version_request.APIVersionRequest("2.10")): self.assertIn("replica_state", instance) self.mock_policy_check.assert_has_calls( [get_instances_policy_check_call, share_policy_check_call])
def test_detail_list_with_share_type(self, quota_class, microversion): req = fakes.HTTPRequest.blank('/quota-sets', version=microversion) quota_class_set = { "shares": 13, "gigabytes": 31, "snapshots": 14, "snapshot_gigabytes": 41, "share_groups": 15, "share_group_snapshots": 51, "share_networks": 16, } expected = { self.builder._collection_name: { "shares": quota_class_set["shares"], "gigabytes": quota_class_set["gigabytes"], "snapshots": quota_class_set["snapshots"], "snapshot_gigabytes": quota_class_set["snapshot_gigabytes"], "share_networks": quota_class_set["share_networks"], } } if quota_class: expected[self.builder._collection_name]['id'] = quota_class if (api_version.APIVersionRequest(microversion) >= (api_version.APIVersionRequest("2.40"))): expected[self.builder._collection_name][ "share_groups"] = quota_class_set["share_groups"] expected[self.builder._collection_name][ "share_group_snapshots"] = quota_class_set[ "share_group_snapshots"] result = self.builder.detail_list(req, quota_class_set, quota_class=quota_class) self.assertEqual(expected, result)
def _snapshot_list_summary_with_search_opts(self, version, use_admin_context): search_opts = fake_share.search_opts() if (api_version.APIVersionRequest(version) >= api_version.APIVersionRequest('2.36')): search_opts.pop('name') search_opts['display_name~'] = 'fake_name' # fake_key should be filtered for non-admin url = '/snapshots?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context, version=version) snapshots = [ { 'id': 'id1', 'display_name': 'n1', 'status': 'fake_status', }, { 'id': 'id2', 'display_name': 'n2', 'status': 'fake_status', }, { 'id': 'id3', 'display_name': 'n3', 'status': 'fake_status', }, ] self.mock_object(share_api.API, 'get_all_snapshots', mock.Mock(return_value=snapshots)) result = self.controller.index(req) search_opts_expected = { 'status': search_opts['status'], 'share_id': search_opts['share_id'], } if (api_version.APIVersionRequest(version) >= api_version.APIVersionRequest('2.36')): search_opts_expected['display_name~'] = 'fake_name' else: search_opts_expected['display_name'] = search_opts['name'] if use_admin_context: search_opts_expected.update({'fake_key': 'fake_value'}) share_api.API.get_all_snapshots.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['snapshots'])) self.assertEqual(snapshots[1]['id'], result['snapshots'][0]['id']) self.assertEqual(snapshots[1]['display_name'], result['snapshots'][0]['name'])
def _get_request(self, microversion, is_admin=False): experimental = (api_version.APIVersionRequest(microversion) <= api_version.APIVersionRequest(GRADUATION_VERSION)) req = fakes.HTTPRequest.blank('/share-replicas', version=microversion, experimental=experimental, use_admin_context=is_admin) return req
def test_build_share_networks_with_details(self, share_networks, microversion): gateway_support = (api_version.APIVersionRequest(microversion) >= api_version.APIVersionRequest('2.18')) mtu_support = (api_version.APIVersionRequest(microversion) >= api_version.APIVersionRequest('2.20')) nova_net_support = (api_version.APIVersionRequest(microversion) < api_version.APIVersionRequest('2.26')) default_net_info_support = (api_version.APIVersionRequest(microversion) <= api_version.APIVersionRequest('2.49')) subnets_support = (api_version.APIVersionRequest(microversion) > api_version.APIVersionRequest('2.49')) req = fakes.HTTPRequest.blank('/share-networks', version=microversion) expected_networks_list = [] for share_network in share_networks: expected_data = { 'id': share_network.get('id'), 'name': share_network.get('name'), 'project_id': share_network.get('project_id'), 'created_at': share_network.get('created_at'), 'updated_at': share_network.get('updated_at'), 'description': share_network.get('description'), } if subnets_support: share_network.update({'share_network_subnets': []}) expected_data.update({'share_network_subnets': []}) else: if default_net_info_support: network_data = { 'neutron_net_id': share_network.get('neutron_net_id'), 'neutron_subnet_id': share_network.get('neutron_subnet_id'), 'network_type': share_network.get('network_type'), 'segmentation_id': share_network.get('segmentation_id'), 'cidr': share_network.get('cidr'), 'ip_version': share_network.get('ip_version'), } expected_data.update(network_data) if gateway_support: share_network.update({'gateway': 'fake_gateway'}) expected_data.update( {'gateway': share_network.get('gateway')}) if mtu_support: share_network.update({'mtu': 1509}) expected_data.update({'mtu': share_network.get('mtu')}) if nova_net_support: share_network.update({'nova_net_id': 'fake_nova_net_id'}) expected_data.update({'nova_net_id': None}) expected_networks_list.append(expected_data) expected = {'share_networks': expected_networks_list} result = self.builder.build_share_networks(req, share_networks, is_detail=True) self.assertEqual(expected, result)
def test_view(self, version): req = fakes.HTTPRequest.blank('/shares', version=version) result = self.builder.view(req, self.fake_access) if (api_version.APIVersionRequest(version) < api_version.APIVersionRequest("2.21")): del self.fake_access['access_key'] self.assertEqual({'access': self.fake_access}, result)
def update(self, req, id, body): if req.api_version_request < api_version.APIVersionRequest("2.39"): self._ensure_share_type_arg_is_absent(req) elif req.api_version_request < api_version.APIVersionRequest("2.40"): self._ensure_specific_microversion_args_are_absent( body, ['share_groups', 'share_group_snapshots'], "2.40") elif req.api_version_request < api_version.APIVersionRequest("2.53"): self._ensure_specific_microversion_args_are_absent( body, ['share_replicas', 'replica_gigabytes'], "2.53") return self._update(req, id, body)
def allow_access(self, req, id, body): """Add share access rule.""" args = (req, id, body) kwargs = {} if req.api_version_request >= api_version.APIVersionRequest("2.13"): kwargs['enable_ceph'] = True if req.api_version_request >= api_version.APIVersionRequest("2.28"): kwargs['allow_on_error_status'] = True return self._allow_access(*args, **kwargs)
def test_detail_list_with_share_type(self, project_id, share_type, microversion): req = fakes.HTTPRequest.blank('/quota-sets', version=microversion) quota_set = { "shares": 13, "gigabytes": 31, "snapshots": 14, "snapshot_gigabytes": 41, "share_groups": 15, "share_group_snapshots": 51, "share_networks": 16, } expected = { self.builder._collection_name: { "shares": quota_set["shares"], "gigabytes": quota_set["gigabytes"], "snapshots": quota_set["snapshots"], "snapshot_gigabytes": quota_set["snapshot_gigabytes"], } } if project_id: expected[self.builder._collection_name]['id'] = project_id if not share_type: expected[self.builder._collection_name][ "share_networks"] = quota_set["share_networks"] if (api_version.APIVersionRequest(microversion) >= (api_version.APIVersionRequest("2.40"))): expected[self.builder._collection_name][ "share_groups"] = quota_set["share_groups"] expected[self.builder._collection_name][ "share_group_snapshots"] = quota_set[ "share_group_snapshots"] if req.api_version_request >= api_version.APIVersionRequest("2.53"): fake_share_replicas_value = 46 fake_replica_gigabytes_value = 100 expected[self.builder._collection_name]["share_replicas"] = ( fake_share_replicas_value) expected[self.builder._collection_name][ "replica_gigabytes"] = fake_replica_gigabytes_value quota_set['share_replicas'] = fake_share_replicas_value quota_set['replica_gigabytes'] = fake_replica_gigabytes_value if req.api_version_request >= api_version.APIVersionRequest("2.62"): fake_per_share_gigabytes = 10 expected[self.builder._collection_name]["per_share_gigabytes"] = ( fake_per_share_gigabytes) quota_set['per_share_gigabytes'] = fake_per_share_gigabytes result = self.builder.detail_list(req, quota_set, project_id=project_id, share_type=share_type) self.assertEqual(expected, result)
def detail(self, req): """Returns a detailed list of shares.""" if req.api_version_request < api_version.APIVersionRequest("2.35"): req.GET.pop('export_location_id', None) req.GET.pop('export_location_path', None) if req.api_version_request < api_version.APIVersionRequest("2.36"): req.GET.pop('name~', None) req.GET.pop('description~', None) req.GET.pop('description', None) return self._get_shares(req, is_detail=True)
def test_view(self, version): req = fakes.HTTPRequest.blank('/shares', version=version) self.mock_object(api.API, 'get', mock.Mock(return_value=self.fake_share)) result = self.builder.view(req, self.fake_access) if (api_version.APIVersionRequest(version) < api_version.APIVersionRequest("2.21")): del self.fake_access['access_key'] self.assertEqual({'access': self.fake_access}, result)
def decorator(f): obj_min_ver = api_version.APIVersionRequest(min_ver) if max_ver: obj_max_ver = api_version.APIVersionRequest(max_ver) else: obj_max_ver = api_version.APIVersionRequest() # Add to list of versioned methods registered func_name = f.__name__ new_func = versioned_method.VersionedMethod( func_name, obj_min_ver, obj_max_ver, experimental, f) return new_func
def test_pools_index_with_filters(self, microversion): mock_get_pools = self.mock_object(rpcapi.SchedulerAPI, 'get_pools', mock.Mock(return_value=FAKE_POOLS)) self.mock_object( share_types, 'get_share_type_by_name', mock.Mock(return_value={'extra_specs': { 'snapshot_support': True }})) url = '/v1/fake_project/scheduler-stats/pools/detail' url += '?backend=.%2A&host=host1&pool=pool%2A&share_type=test_type' req = fakes.HTTPRequest.blank(url, version=microversion) req.environ['manila.context'] = self.ctxt result = self.controller.pools_index(req) expected = { 'pools': [{ 'name': 'host1@backend1#pool1', 'host': 'host1', 'backend': 'backend1', 'pool': 'pool1', }, { 'name': 'host1@backend1#pool2', 'host': 'host1', 'backend': 'backend1', 'pool': 'pool2', }] } expected_filters = { 'host': 'host1', 'pool': 'pool*', 'backend': '.*', 'share_type': 'test_type', } if (api_version.APIVersionRequest(microversion) >= api_version.APIVersionRequest('2.23')): expected_filters.update( {'capabilities': { 'snapshot_support': True }}) expected_filters.pop('share_type', None) self.assertDictMatch(result, expected) mock_get_pools.assert_called_once_with(self.ctxt, filters=expected_filters, cached=True) self.mock_policy_check.assert_called_once_with(self.ctxt, self.resource_name, 'index')
def test_list_view(self, version): req = fakes.HTTPRequest.blank('/shares', version=version) accesses = [ self.fake_access, ] result = self.builder.list_view(req, accesses) if (api_version.APIVersionRequest(version) < api_version.APIVersionRequest("2.21")): del self.fake_access['access_key'] del self.fake_access['share_id'] self.assertEqual({'access_list': accesses}, result)
def test_share_create_with_consistency_group(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) expected['share']['consistency_group_id'] = None expected['share']['source_cgsnapshot_member_id'] = None if (api_version.APIVersionRequest(microversion) >= api_version.APIVersionRequest('2.5')): expected['share']['task_state'] = None self.assertEqual(expected, res_dict)
def index(self, req): """Returns a summary list of shares.""" if req.api_version_request < api_version.APIVersionRequest("2.35"): req.GET.pop('export_location_id', None) req.GET.pop('export_location_path', None) if req.api_version_request < api_version.APIVersionRequest("2.36"): req.GET.pop('name~', None) req.GET.pop('description~', None) req.GET.pop('description', None) if req.api_version_request < api_version.APIVersionRequest("2.42"): req.GET.pop('with_count', None) return self._get_shares(req, is_detail=False)
def test_init(self): result = api_version_request.APIVersionRequest() self.assertIsNone(result._ver_major) self.assertIsNone(result._ver_minor) self.assertFalse(result._experimental)
def detail(self, req): """Returns a detailed list of shares.""" if req.api_version_request < api_version.APIVersionRequest("2.36"): req.GET.pop('name~', None) req.GET.pop('description~', None) req.GET.pop('description', None) return self._get_snapshots(req, is_detail=True)
def _get_share_groups(self, req, is_detail): """Returns a list of share groups, transformed through view builder.""" context = req.environ['manila.context'] search_opts = {} search_opts.update(req.GET) # Remove keys that are not related to share group attrs search_opts.pop('limit', None) search_opts.pop('offset', None) sort_key = search_opts.pop('sort_key', 'created_at') sort_dir = search_opts.pop('sort_dir', 'desc') if req.api_version_request < api_version.APIVersionRequest("2.36"): search_opts.pop('name~', None) search_opts.pop('description~', None) if 'group_type_id' in search_opts: search_opts['share_group_type_id'] = search_opts.pop( 'group_type_id') share_groups = self.share_group_api.get_all( context, detailed=is_detail, search_opts=search_opts, sort_dir=sort_dir, sort_key=sort_key, ) limited_list = common.limited(share_groups, req) if is_detail: share_groups = self._view_builder.detail_list(req, limited_list) else: share_groups = self._view_builder.summary_list(req, limited_list) return share_groups
def test_show(self, version): test_instance = db_utils.create_share(size=1).instance id = test_instance['id'] actual_result = self.controller.show( self._get_request('fake', version=version), id) self.assertEqual(id, actual_result['share_instance']['id']) if (api_version_request.APIVersionRequest(version) >= api_version_request.APIVersionRequest("2.54")): self.assertIn("progress", actual_result['share_instance']) else: self.assertNotIn("progress", actual_result['share_instance']) self.mock_policy_check.assert_called_once_with(self.admin_context, self.resource_name, 'show')
def test_snapshot_updates_display_name_and_description(self, version): snp = self.snp_example body = {"snapshot": snp} req = fakes.HTTPRequest.blank('/snapshot/1', version=version) res_dict = self.controller.update(req, 1, body) self.assertEqual(snp["display_name"], res_dict['snapshot']["name"]) if (api_version.APIVersionRequest(version) <= api_version.APIVersionRequest('2.16')): self.assertNotIn('user_id', res_dict['snapshot']) self.assertNotIn('project_id', res_dict['snapshot']) else: self.assertIn('user_id', res_dict['snapshot']) self.assertIn('project_id', res_dict['snapshot'])
def test_set_api_version_request_exception(self): min_version = api_version.APIVersionRequest('2.0') max_version = api_version.APIVersionRequest('2.45') self.mock_object(api_version, 'max_api_version', mock.Mock(return_value=max_version)) self.mock_object(api_version, 'min_api_version', mock.Mock(return_value=min_version)) headers = {'X-OpenStack-Manila-API-Version': '2.50'} request = wsgi.Request.blank( 'https://openstack.acme.com/v2/shares', method='GET', headers=headers, script_name='/v2/shares') self.assertRaises(exception.InvalidGlobalAPIVersion, request.set_api_version_request) self.assertEqual(api_version.APIVersionRequest('2.50'), request.api_version_request)
def test_set_api_version_request_no_version_header(self): min_version = api_version.APIVersionRequest('2.0') max_version = api_version.APIVersionRequest('2.45') self.mock_object(api_version, 'max_api_version', mock.Mock(return_value=max_version)) self.mock_object(api_version, 'min_api_version', mock.Mock(return_value=min_version)) headers = {} request = wsgi.Request.blank( 'https://openstack.acme.com/v2/shares', method='GET', headers=headers, script_name='/v2/shares') self.assertIsNone(request.set_api_version_request()) self.assertEqual(api_version.APIVersionRequest('2.0'), request.api_version_request)
def _get_share_types(self, req): """Helper function that returns a list of type dicts.""" filters = {} context = req.environ['manila.context'] if context.is_admin: # Only admin has query access to all share types filters['is_public'] = self._parse_is_public( req.params.get('is_public')) else: filters['is_public'] = True if (req.api_version_request < api_version.APIVersionRequest("2.43")): extra_specs = req.params.get('extra_specs') if extra_specs: msg = _("Filter by 'extra_specs' is not supported by this " "microversion. Use 2.43 or greater microversion to " "be able to use filter search by 'extra_specs.") raise webob.exc.HTTPBadRequest(explanation=msg) else: extra_specs = req.params.get('extra_specs') if extra_specs: filters['extra_specs'] = ast.literal_eval(extra_specs) limited_types = share_types.get_all_types( context, search_opts=filters).values() return list(limited_types)
def test_version_comparisons(self): v1 = api_version_request.APIVersionRequest('2.0') v2 = api_version_request.APIVersionRequest('2.5') v3 = api_version_request.APIVersionRequest('5.23') v4 = api_version_request.APIVersionRequest('2.0') v_null = api_version_request.APIVersionRequest() self.assertTrue(v1 < v2) self.assertTrue(v1 <= v2) self.assertTrue(v3 > v2) self.assertTrue(v3 >= v2) self.assertTrue(v1 != v2) self.assertTrue(v1 == v4) self.assertTrue(v1 != v_null) self.assertTrue(v_null == v_null) self.assertFalse(v1 == '2.0')