diff --git a/esi_leap/api/controllers/v1/event.py b/esi_leap/api/controllers/v1/event.py index 7473f4f0..1d378727 100644 --- a/esi_leap/api/controllers/v1/event.py +++ b/esi_leap/api/controllers/v1/event.py @@ -21,7 +21,7 @@ from esi_leap.api.controllers import types from esi_leap.api.controllers.v1 import utils from esi_leap.common import exception -from esi_leap.common import keystone +from esi_leap.common.idp import idp import esi_leap.conf from esi_leap.objects import event as event_obj from esi_leap.resource_objects import get_resource_object @@ -72,7 +72,7 @@ def get_all(self, last_event_id=None, lessee_or_owner_id=None, lessee_or_owner_id = cdict['project_id'] if lessee_or_owner_id is not None: - lessee_or_owner_id = keystone.get_project_uuid_from_ident( + lessee_or_owner_id = idp.get_project_uuid_from_ident( lessee_or_owner_id) if resource_uuid is not None: diff --git a/esi_leap/api/controllers/v1/lease.py b/esi_leap/api/controllers/v1/lease.py index 4fc7101f..f52ff85e 100644 --- a/esi_leap/api/controllers/v1/lease.py +++ b/esi_leap/api/controllers/v1/lease.py @@ -25,8 +25,8 @@ from esi_leap.api.controllers.v1 import utils from esi_leap.common import constants from esi_leap.common import exception +from esi_leap.common.idp import idp from esi_leap.common import ironic -from esi_leap.common import keystone from esi_leap.common import statuses import esi_leap.conf from esi_leap.objects import lease as lease_obj @@ -84,7 +84,7 @@ def get_one(self, lease_id): lease = utils.check_lease_policy_and_retrieve( request, 'esi_leap:lease:get', lease_id) - return Lease(**utils.lease_get_dict_with_added_info(lease)) + return Lease(**self._lease_get_dict_with_added_info(lease)) @wsme_pecan.wsexpose(LeaseCollection, wtypes.text, datetime.datetime, datetime.datetime, wtypes.text, @@ -97,10 +97,10 @@ def get_all(self, project_id=None, start_time=None, end_time=None, cdict = request.to_policy_values() if project_id is not None: - project_id = keystone.get_project_uuid_from_ident(project_id) + project_id = idp.get_project_uuid_from_ident(project_id) if owner_id is not None: - owner_id = keystone.get_project_uuid_from_ident(owner_id) + owner_id = idp.get_project_uuid_from_ident(owner_id) if resource_uuid is not None: if resource_type is None: @@ -126,12 +126,12 @@ def get_all(self, project_id=None, start_time=None, end_time=None, with concurrent.futures.ThreadPoolExecutor() as executor: f1 = executor.submit(ironic.get_node_list) - f2 = executor.submit(keystone.get_project_list) + f2 = executor.submit(idp.get_project_list) node_list = f1.result() project_list = f2.result() leases_with_added_info = [ - Lease(**utils.lease_get_dict_with_added_info(l, project_list, + Lease(**self._lease_get_dict_with_added_info(l, project_list, node_list)) for l in leases] if resource_class: @@ -159,7 +159,7 @@ def post(self, new_lease): lease_dict['resource_uuid'] = resource.get_uuid() if 'project_id' in lease_dict: - lease_dict['project_id'] = keystone.get_project_uuid_from_ident( + lease_dict['project_id'] = idp.get_project_uuid_from_ident( lease_dict['project_id']) if 'start_time' not in lease_dict: @@ -189,7 +189,7 @@ def post(self, new_lease): lease = lease_obj.Lease(**lease_dict) lease.create(request) - return Lease(**utils.lease_get_dict_with_added_info(lease)) + return Lease(**self._lease_get_dict_with_added_info(lease)) @wsme_pecan.wsexpose(Lease, wtypes.text, body={wtypes.text: wtypes.text}) def patch(self, lease_uuid, patch=None): @@ -208,7 +208,7 @@ def patch(self, lease_uuid, patch=None): updates = {'end_time': new_end_time} lease.update(updates, request) - return Lease(**utils.lease_get_dict_with_added_info(lease)) + return Lease(**self._lease_get_dict_with_added_info(lease)) @wsme_pecan.wsexpose(Lease, wtypes.text) def delete(self, lease_id): @@ -285,3 +285,18 @@ def _lease_get_all_authorize_filters(cdict, del filters[k] return filters + + @staticmethod + def _lease_get_dict_with_added_info( + lease, project_list=None, node_list=None): + resource = lease.resource_object() + + lease_dict = lease.to_dict() + lease_dict['project'] = idp.get_project_name(lease.project_id, + project_list) + lease_dict['owner'] = idp.get_project_name(lease.owner_id, + project_list) + lease_dict['resource'] = resource.get_name(node_list) + lease_dict['resource_class'] = resource.get_resource_class(node_list) + lease_dict['resource_properties'] = resource.get_properties(node_list) + return lease_dict diff --git a/esi_leap/api/controllers/v1/node.py b/esi_leap/api/controllers/v1/node.py index fab221de..d298fc3a 100644 --- a/esi_leap/api/controllers/v1/node.py +++ b/esi_leap/api/controllers/v1/node.py @@ -20,8 +20,8 @@ from esi_leap.api.controllers import base from esi_leap.api.controllers import types +from esi_leap.common.idp import idp from esi_leap.common import ironic -from esi_leap.common import keystone from esi_leap.common import statuses import esi_leap.conf from esi_leap.objects import lease as lease_obj @@ -71,9 +71,9 @@ def get_all(self, resource_class=None, owner=None, context = pecan.request.context if owner is not None: - owner = keystone.get_project_uuid_from_ident(owner) + owner = idp.get_project_uuid_from_ident(owner) if lessee is not None: - lessee = keystone.get_project_uuid_from_ident(lessee) + lessee = idp.get_project_uuid_from_ident(lessee) filter_args = { 'resource_class': resource_class, @@ -89,7 +89,7 @@ def get_all(self, resource_class=None, owner=None, k: v for k, v in filter_args.items() if v is not None } f1 = executor.submit(ironic.get_node_list, context, **filter_args) - f2 = executor.submit(keystone.get_project_list) + f2 = executor.submit(idp.get_project_list) nodes = f1.result() project_list = f2.result() @@ -126,9 +126,9 @@ def get_all(self, resource_class=None, owner=None, properties=ironic.get_condensed_properties( node.properties), maintenance=str(node.maintenance), - owner=keystone.get_project_name(node.owner, project_list), - lessee=keystone.get_project_name(node.lessee, - project_list), + owner=idp.get_project_name(node.owner, project_list), + lessee=idp.get_project_name(node.lessee, + project_list), future_offers=future_offers, future_leases=f_lease_uuids) diff --git a/esi_leap/api/controllers/v1/offer.py b/esi_leap/api/controllers/v1/offer.py index d9f387b8..3eb5f134 100644 --- a/esi_leap/api/controllers/v1/offer.py +++ b/esi_leap/api/controllers/v1/offer.py @@ -25,8 +25,8 @@ from esi_leap.api.controllers.v1 import lease from esi_leap.api.controllers.v1 import utils from esi_leap.common import exception +from esi_leap.common.idp import idp from esi_leap.common import ironic -from esi_leap.common import keystone from esi_leap.common import statuses import esi_leap.conf from esi_leap.objects import lease as lease_obj @@ -90,7 +90,7 @@ def get_one(self, offer_id): request, 'esi_leap:offer:get', offer_id) utils.check_offer_lessee(cdict, offer) - o = utils.offer_get_dict_with_added_info(offer) + o = self._offer_get_dict_with_added_info(offer) return Offer(**o) @@ -108,7 +108,7 @@ def get_all(self, project_id=None, resource_type=None, utils.policy_authorize('esi_leap:offer:get_all', cdict, cdict) if project_id is not None: - project_id = keystone.get_project_uuid_from_ident(project_id) + project_id = idp.get_project_uuid_from_ident(project_id) if resource_uuid is not None: if resource_type is None: @@ -176,12 +176,12 @@ def get_all(self, project_id=None, resource_type=None, node_list = None with concurrent.futures.ThreadPoolExecutor() as executor: f1 = executor.submit(ironic.get_node_list) - f2 = executor.submit(keystone.get_project_list) + f2 = executor.submit(idp.get_project_list) node_list = f1.result() project_list = f2.result() offers_with_added_info = [ - Offer(**utils.offer_get_dict_with_added_info(o, project_list, + Offer(**self._offer_get_dict_with_added_info(o, project_list, node_list)) for o in offers] if resource_class: @@ -209,7 +209,7 @@ def post(self, new_offer): offer_dict['resource_uuid'] = resource.get_uuid() if 'lessee_id' in offer_dict: - offer_dict['lessee_id'] = keystone.get_project_uuid_from_ident( + offer_dict['lessee_id'] = idp.get_project_uuid_from_ident( offer_dict['lessee_id']) if 'start_time' not in offer_dict: @@ -238,7 +238,7 @@ def post(self, new_offer): o = offer_obj.Offer(**offer_dict) o.create() - return Offer(**utils.offer_get_dict_with_added_info(o)) + return Offer(**self._offer_get_dict_with_added_info(o)) @wsme_pecan.wsexpose(Offer, wtypes.text) def delete(self, offer_id): @@ -284,3 +284,17 @@ def claim(self, offer_uuid, new_lease): new_lease = lease_obj.Lease(**lease_dict) new_lease.create(request) return lease.Lease(**utils.lease_get_dict_with_added_info(new_lease)) + + @staticmethod + def _offer_get_dict_with_added_info( + offer, project_list=None, node_list=None): + resource = offer.resource_object() + + o = offer.to_dict() + o['availabilities'] = offer.get_availabilities() + o['project'] = idp.get_project_name(offer.project_id, project_list) + o['lessee'] = idp.get_project_name(offer.lessee_id, project_list) + o['resource'] = resource.get_name(node_list) + o['resource_class'] = resource.get_resource_class(node_list) + o['resource_properties'] = resource.get_properties(node_list) + return o diff --git a/esi_leap/api/controllers/v1/utils.py b/esi_leap/api/controllers/v1/utils.py index f4335d65..bbee9ffb 100644 --- a/esi_leap/api/controllers/v1/utils.py +++ b/esi_leap/api/controllers/v1/utils.py @@ -16,7 +16,7 @@ import datetime from esi_leap.common import exception -from esi_leap.common import keystone +from esi_leap.common.idp import idp from esi_leap.common import policy from esi_leap.objects import lease as lease_obj from esi_leap.objects import offer as offer_obj @@ -140,39 +140,12 @@ def check_offer_lessee(cdict, offer): if offer.lessee_id is None or offer.project_id == project_id: return - if offer.lessee_id not in keystone.get_parent_project_id_tree(project_id): + if offer.lessee_id not in idp.get_parent_project_id_tree(project_id): resource_policy_authorize( 'esi_leap:offer:offer_admin', cdict, cdict, 'offer', offer.uuid) -def offer_get_dict_with_added_info(offer, project_list=None, node_list=None): - resource = offer.resource_object() - - o = offer.to_dict() - o['availabilities'] = offer.get_availabilities() - o['project'] = keystone.get_project_name(offer.project_id, project_list) - o['lessee'] = keystone.get_project_name(offer.lessee_id, project_list) - o['resource'] = resource.get_name(node_list) - o['resource_class'] = resource.get_resource_class(node_list) - o['resource_properties'] = resource.get_properties(node_list) - return o - - -def lease_get_dict_with_added_info(lease, project_list=None, node_list=None): - resource = lease.resource_object() - - lease_dict = lease.to_dict() - lease_dict['project'] = keystone.get_project_name(lease.project_id, - project_list) - lease_dict['owner'] = keystone.get_project_name(lease.owner_id, - project_list) - lease_dict['resource'] = resource.get_name(node_list) - lease_dict['resource_class'] = resource.get_resource_class(node_list) - lease_dict['resource_properties'] = resource.get_properties(node_list) - return lease_dict - - def check_lease_length(cdict, start_time, end_time, max_time): if (end_time - start_time) > datetime.timedelta(days=max_time): # Check if the current project is admin diff --git a/esi_leap/common/idp/__init__.py b/esi_leap/common/idp/__init__.py new file mode 100644 index 00000000..6dfe5e94 --- /dev/null +++ b/esi_leap/common/idp/__init__.py @@ -0,0 +1,9 @@ +from importlib import import_module + +import esi_leap.conf + +CONF = esi_leap.conf.CONF + +module_path, class_name = CONF.esi.idp_plugin_class.rsplit('.', 1) +module = import_module(module_path) +idp = getattr(module, class_name)() diff --git a/esi_leap/common/idp/baseIDP.py b/esi_leap/common/idp/baseIDP.py new file mode 100644 index 00000000..122ea508 --- /dev/null +++ b/esi_leap/common/idp/baseIDP.py @@ -0,0 +1,32 @@ +# 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 abc + + +class BaseIDP(abc.ABC): + + @abc.abstractmethod + def get_project_list(): + pass + + @abc.abstractmethod + def get_project_name(self, id, project_list=None): + pass + + @abc.abstractmethod + def get_parent_project_id_tree(project_id): + pass + + @abc.abstractmethod + def get_project_uuid_from_ident(project_ident): + pass diff --git a/esi_leap/common/idp/dummyIDP.py b/esi_leap/common/idp/dummyIDP.py new file mode 100644 index 00000000..678dd6cd --- /dev/null +++ b/esi_leap/common/idp/dummyIDP.py @@ -0,0 +1,79 @@ +# 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 sys + +from keystoneclient.v3.projects import Project +from keystoneclient.v3.projects import ProjectManager +from keystoneclient.v3.users import User +from keystoneclient.v3.users import UserManager +from oslo_utils import uuidutils + +from esi_leap.common import exception +from esi_leap.common.idp import baseIDP + + +class DummyIDP(baseIDP.BaseIDP): + + dummy_project_list: list[Project] + dummy_user_list: list[User] + + def get_parent_project_id_tree(self, project_id): + project = self._get_project_obj_from_id(project_id) + project_ids = [project.id] + while project.parent_id is not None: + project = self._get_project_obj_from_id(project.parent_id) + project_ids.append(project.id) + return project_ids + + def get_project_uuid_from_ident(self, project_ident): + if uuidutils.is_uuid_like(project_ident): + return project_ident + else: + for p in self.dummy_project_list: + if p.name == project_ident: + return p.id + raise exception.ProjectNoSuchName(name=project_ident) + + def get_project_list(self): + return self.dummy_project_list + + def get_project_name(self, project_id, project_list=None): + if project_id: + if project_list is None: + project = self._get_project_obj_from_id(project_id) + else: + project = next((p for p in project_list + if getattr(p, 'id') == project_id), + None) + return project.name if project else '' + else: + return '' + + def add_project(self, id, name, parent_id): + self.dummy_project_list.append(Project(ProjectManager, { + 'id': id, + 'name': name, + 'parent_id': parent_id + })) + + def add_user(self, id, name, project_id): + self.dummy_user_list.append(User(UserManager, { + 'id': id, + 'name': name, + 'project_id': project_id + })) + + def _get_project_obj_from_id(self, project_id): + for p in self.dummy_project_list: + if p.id == project_id: + return p + sys.exit(f"No project with id {project_id} found") diff --git a/esi_leap/common/idp/keystoneIDP.py b/esi_leap/common/idp/keystoneIDP.py new file mode 100644 index 00000000..94ca0287 --- /dev/null +++ b/esi_leap/common/idp/keystoneIDP.py @@ -0,0 +1,75 @@ +# 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. + +from keystoneauth1 import loading as ks_loading +from keystoneclient import client as keystone_client +from oslo_utils import uuidutils + +from esi_leap.common import exception +from esi_leap.common.idp import baseIDP +import esi_leap.conf + +CONF = esi_leap.conf.CONF +_cached_keystone_client = None +_cached_project_list = None + + +class KeystoneIDP(baseIDP.BaseIDP): + + def get_keystone_client(self): + global _cached_keystone_client + if _cached_keystone_client is not None: + return _cached_keystone_client + + auth_plugin = ks_loading.load_auth_from_conf_options(CONF, 'keystone') + sess = ks_loading.load_session_from_conf_options(CONF, 'keystone', + auth=auth_plugin) + cli = keystone_client.Client(session=sess) + _cached_keystone_client = cli + + return cli + + def get_parent_project_id_tree(self, project_id): + ks_client = self.get_keystone_client() + project = ks_client.projects.get(project_id) + project_ids = [project.id] + while project.parent_id is not None: + project = ks_client.projects.get(project.parent_id) + project_ids.append(project.id) + return project_ids + + def get_project_uuid_from_ident(self, project_ident): + if uuidutils.is_uuid_like(project_ident): + return project_ident + else: + projects = self.get_keystone_client().projects.list( + name=project_ident + ) + if len(projects) > 0: + # projects have unique names + return projects[0].id + raise exception.ProjectNoSuchName(name=project_ident) + + def get_project_list(self): + return self.get_keystone_client().projects.list() + + def get_project_name(self, project_id, project_list=None): + if project_id: + if project_list is None: + project = self.get_keystone_client().projects.get(project_id) + else: + project = next((p for p in project_list + if getattr(p, 'id') == project_id), + None) + return project.name if project else '' + else: + return '' diff --git a/esi_leap/conf/__init__.py b/esi_leap/conf/__init__.py index e4e32405..9225fc98 100644 --- a/esi_leap/conf/__init__.py +++ b/esi_leap/conf/__init__.py @@ -13,6 +13,7 @@ from esi_leap.conf import api from esi_leap.conf import dummy_node +from esi_leap.conf import esi from esi_leap.conf import ironic from esi_leap.conf import keystone from esi_leap.conf import netconf @@ -31,3 +32,4 @@ netconf.register_opts(CONF) notification.register_opts(CONF) pecan.register_opts(CONF) +esi.register_opts(CONF) diff --git a/esi_leap/conf/esi.py b/esi_leap/conf/esi.py new file mode 100644 index 00000000..a92fe375 --- /dev/null +++ b/esi_leap/conf/esi.py @@ -0,0 +1,25 @@ +# 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. + +from oslo_config import cfg + +opts = [ + cfg.StrOpt( + 'idp_plugin_class', + default='esi_leap.common.idp.keystoneIDP.KeystoneIDP'), + ] + +api_group = cfg.OptGroup('esi', title='ESI Options') + + +def register_opts(conf): + conf.register_opts(opts, group=api_group) diff --git a/esi_leap/tests/api/controllers/v1/test_offer.py b/esi_leap/tests/api/controllers/v1/test_offer.py index 83684ae3..162e4fa8 100644 --- a/esi_leap/tests/api/controllers/v1/test_offer.py +++ b/esi_leap/tests/api/controllers/v1/test_offer.py @@ -121,8 +121,7 @@ def test_empty(self): @mock.patch('oslo_utils.uuidutils.generate_uuid') @mock.patch('esi_leap.api.controllers.v1.utils.check_resource_admin') @mock.patch('esi_leap.objects.offer.Offer.create') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') def test_post(self, mock_ogdwai, mock_create, mock_cra, mock_generate_uuid, mock_gro): resource = TestNode(self.test_offer.resource_uuid) @@ -161,8 +160,7 @@ def test_post(self, mock_ogdwai, mock_create, mock_cra, @mock.patch('oslo_utils.uuidutils.generate_uuid') @mock.patch('esi_leap.api.controllers.v1.utils.check_resource_admin') @mock.patch('esi_leap.objects.offer.Offer.create') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') def test_post_default_resource_type(self, mock_ogdwai, mock_create, mock_cra, mock_generate_uuid, mock_gro): @@ -202,8 +200,7 @@ def test_post_default_resource_type(self, mock_ogdwai, mock_create, @mock.patch('oslo_utils.uuidutils.generate_uuid') @mock.patch('esi_leap.api.controllers.v1.utils.check_resource_admin') @mock.patch('esi_leap.objects.offer.Offer.create') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') def test_post_lessee(self, mock_ogdwai, mock_create, mock_cra, mock_generate_uuid, mock_gpufi, mock_gro): resource = TestNode(self.test_offer_lessee.resource_uuid) @@ -247,8 +244,7 @@ def test_post_lessee(self, mock_ogdwai, mock_create, mock_cra, @mock.patch('oslo_utils.uuidutils.generate_uuid') @mock.patch('esi_leap.api.controllers.v1.utils.check_resource_admin') @mock.patch('esi_leap.objects.offer.Offer.create') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') def test_post_non_admin_parent_lease(self, mock_ogdwai, mock_create, mock_cra, mock_generate_uuid, mock_gro, mock_crla): @@ -302,8 +298,7 @@ def test_post_non_admin_parent_lease(self, mock_ogdwai, mock_create, @mock.patch('oslo_utils.uuidutils.generate_uuid') @mock.patch('esi_leap.api.controllers.v1.utils.check_resource_admin') @mock.patch('esi_leap.objects.offer.Offer.create') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') def test_post_non_admin_no_parent_lease(self, mock_ogdwai, mock_create, mock_cra, mock_generate_uuid, mock_gro, mock_crla): @@ -346,8 +341,7 @@ def test_post_non_admin_no_parent_lease(self, mock_ogdwai, mock_create, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_nofilters(self, mock_get_all, mock_ogdwai, mock_gpl, mock_gnl): @@ -372,8 +366,7 @@ def test_get_nofilters(self, mock_get_all, mock_ogdwai, mock_gpl, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_any_status(self, mock_get_all, mock_ogdwai, mock_gpl, mock_gnl): @@ -398,8 +391,7 @@ def test_get_any_status(self, mock_get_all, mock_ogdwai, mock_gpl, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_status_filter(self, mock_get_all, mock_ogdwai, mock_gpl, mock_gnl): @@ -426,8 +418,7 @@ def test_get_status_filter(self, mock_get_all, mock_ogdwai, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') @mock.patch('esi_leap.common.keystone.get_project_uuid_from_ident') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_project_filter(self, mock_get_all, mock_ogdwai, mock_gpufi, mock_gpl, mock_gnl): @@ -457,8 +448,7 @@ def test_get_project_filter(self, mock_get_all, mock_ogdwai, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') @mock.patch('esi_leap.api.controllers.v1.offer.get_resource_object') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_resource_filter(self, mock_get_all, mock_ogdwai, mock_gro, mock_gpl, mock_gnl): @@ -488,8 +478,7 @@ def test_get_resource_filter(self, mock_get_all, mock_ogdwai, mock_gro, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_resource_class_filter(self, mock_get_all, mock_ogdwai, mock_gpl, mock_gnl): @@ -515,8 +504,7 @@ def test_get_resource_class_filter(self, mock_get_all, mock_ogdwai, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') @mock.patch('esi_leap.api.controllers.v1.offer.get_resource_object') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') def test_get_resource_filter_default_resource_type(self, mock_get_all, mock_ogdwai, @@ -548,8 +536,7 @@ def test_get_resource_filter_default_resource_type(self, mock_get_all, @mock.patch('esi_leap.common.ironic.get_node_list') @mock.patch('esi_leap.common.keystone.get_project_list') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') @mock.patch('esi_leap.objects.offer.Offer.get_all') @mock.patch('esi_leap.api.controllers.v1.utils.policy_authorize') def test_get_lessee_filter(self, mock_authorize, mock_get_all, @@ -581,8 +568,7 @@ def test_get_lessee_filter(self, mock_authorize, mock_get_all, @mock.patch('esi_leap.api.controllers.v1.utils.check_offer_lessee') @mock.patch('esi_leap.api.controllers.v1.utils.' 'check_offer_policy_and_retrieve') - @mock.patch('esi_leap.api.controllers.v1.utils.' - 'offer_get_dict_with_added_info') + @mock.patch('esi_leap.api.controllers.v1.offer.OffersController._offer_get_dict_with_added_info') def test_get_one(self, mock_ogdwai, mock_copar, mock_col): mock_copar.return_value = self.test_offer mock_ogdwai.return_value = self.test_offer.to_dict()