Skip to content

Commit

Permalink
Added dummy identity provider to remove Keystone dependancy
Browse files Browse the repository at this point in the history
during testing

The dummy identity provider (idp) can be enabled by setting
the environment variable ESI_DEBUG to True. For now, the
dummy idp returns information about a dummy project

Some functions from `api/controllers/v1/utils.py` have been
moved into the only controllers that use them and turned into
static class methods.

Allow idp injection through config file
  • Loading branch information
QuanMPhm committed Jul 22, 2024
1 parent f8001f3 commit 488dedd
Show file tree
Hide file tree
Showing 17 changed files with 423 additions and 125 deletions.
7 changes: 3 additions & 4 deletions esi_leap/api/controllers/v1/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 get_idp
import esi_leap.conf
from esi_leap.objects import event as event_obj
from esi_leap.resource_objects import get_resource_object
Expand Down Expand Up @@ -81,10 +81,9 @@ def get_all(
except exception.HTTPForbidden:
lessee_or_owner_id = cdict["project_id"]

idp = get_idp()
if lessee_or_owner_id is not None:
lessee_or_owner_id = keystone.get_project_uuid_from_ident(
lessee_or_owner_id
)
lessee_or_owner_id = idp.get_project_uuid_from_ident(lessee_or_owner_id)

if resource_uuid is not None:
if resource_type is None:
Expand Down
33 changes: 24 additions & 9 deletions esi_leap/api/controllers/v1/lease.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from esi_leap.common import constants
from esi_leap.common import exception
from esi_leap.common import ironic
from esi_leap.common import keystone
from esi_leap.common.idp import get_idp
from esi_leap.common import statuses
import esi_leap.conf
from esi_leap.objects import lease as lease_obj
Expand Down Expand Up @@ -88,7 +88,7 @@ def get_one(self, lease_id):
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,
Expand Down Expand Up @@ -119,11 +119,12 @@ def get_all(
request = pecan.request.context
cdict = request.to_policy_values()

idp = get_idp()
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:
Expand Down Expand Up @@ -156,13 +157,13 @@ def get_all(

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(
**self._lease_get_dict_with_added_info(
lease, project_list, node_list
)
)
Expand Down Expand Up @@ -195,8 +196,9 @@ def post(self, new_lease):
)
lease_dict["resource_uuid"] = resource.get_uuid()

idp = get_idp()
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"]
)

Expand Down Expand Up @@ -231,7 +233,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):
Expand All @@ -252,7 +254,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):
Expand Down Expand Up @@ -339,3 +341,16 @@ def _lease_get_all_authorize_filters(
del filters[k]

return filters

@staticmethod
def _lease_get_dict_with_added_info(lease, project_list=None, node_list=None):
resource = lease.resource_object()

idp = get_idp()
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
13 changes: 7 additions & 6 deletions esi_leap/api/controllers/v1/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from esi_leap.api.controllers import base
from esi_leap.api.controllers import types
from esi_leap.common import ironic
from esi_leap.common import keystone
from esi_leap.common.idp import get_idp
from esi_leap.common import statuses
import esi_leap.conf
from esi_leap.objects import lease as lease_obj
Expand Down Expand Up @@ -82,10 +82,11 @@ class NodesController(rest.RestController):
def get_all(self, resource_class=None, owner=None, lessee=None):
context = pecan.request.context

idp = get_idp()
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,
Expand All @@ -99,7 +100,7 @@ def get_all(self, resource_class=None, owner=None, lessee=None):
with concurrent.futures.ThreadPoolExecutor() as executor:
filter_args = {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()

Expand Down Expand Up @@ -139,8 +140,8 @@ def get_all(self, resource_class=None, owner=None, lessee=None):
resource_class=node.resource_class,
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=f_offer_uuids,
future_leases=f_lease_uuids,
)
Expand Down
34 changes: 26 additions & 8 deletions esi_leap/api/controllers/v1/offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 get_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
Expand Down Expand Up @@ -91,7 +91,7 @@ def get_one(self, 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)

Expand Down Expand Up @@ -123,8 +123,9 @@ def get_all(
cdict = request.to_policy_values()
utils.policy_authorize("esi_leap:offer:get_all", cdict, cdict)

idp = get_idp()
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:
Expand Down Expand Up @@ -193,13 +194,13 @@ def get_all(
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, node_list)
**self._offer_get_dict_with_added_info(o, project_list, node_list)
)
for o in offers
]
Expand Down Expand Up @@ -230,8 +231,9 @@ def post(self, new_offer):
)
offer_dict["resource_uuid"] = resource.get_uuid()

idp = get_idp()
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"]
)

Expand Down Expand Up @@ -263,7 +265,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):
Expand Down Expand Up @@ -309,4 +311,20 @@ 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))
return lease.Lease(
**lease.LeasesController._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()

idp = get_idp()
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
30 changes: 3 additions & 27 deletions esi_leap/api/controllers/v1/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import datetime

from esi_leap.common import exception
from esi_leap.common import keystone
from esi_leap.common.idp import get_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
Expand Down Expand Up @@ -148,37 +148,13 @@ 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):
idp = get_idp()
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
Expand Down
11 changes: 11 additions & 0 deletions esi_leap/common/idp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import importlib

import esi_leap.conf

CONF = esi_leap.conf.CONF


def get_idp():
module_path, class_name = CONF.esi.idp_plugin_class.rsplit(".", 1)
module = importlib.import_module(module_path)
return getattr(module, class_name)()
31 changes: 31 additions & 0 deletions esi_leap/common/idp/baseIDP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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
Loading

0 comments on commit 488dedd

Please sign in to comment.