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.
  • Loading branch information
QuanMPhm committed Jul 10, 2024
1 parent 822016c commit 217fddd
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 30 deletions.
4 changes: 2 additions & 2 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 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 @@ -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:
Expand Down
32 changes: 23 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 idp
from esi_leap.common import statuses
import esi_leap.conf
from esi_leap.objects import lease as lease_obj
Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand Down Expand Up @@ -285,3 +285,17 @@ 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
12 changes: 6 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 idp
from esi_leap.common import statuses
import esi_leap.conf
from esi_leap.objects import lease as lease_obj
Expand Down Expand Up @@ -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,
Expand All @@ -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()

Expand Down Expand Up @@ -126,8 +126,8 @@ 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,
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)
Expand Down
27 changes: 20 additions & 7 deletions esi_leap/api/controllers/v1/offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from esi_leap.api.controllers.v1 import utils
from esi_leap.common import exception
from esi_leap.common import ironic
from esi_leap.common import keystone
from esi_leap.common.idp import idp
from esi_leap.common import statuses
import esi_leap.conf
from esi_leap.objects import lease as lease_obj
Expand Down Expand Up @@ -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)

Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -284,3 +284,16 @@ 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
12 changes: 6 additions & 6 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 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 @@ -140,7 +140,7 @@ 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)
Expand All @@ -151,8 +151,8 @@ def offer_get_dict_with_added_info(offer, project_list=None, node_list=None):

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['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)
Expand All @@ -163,9 +163,9 @@ 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,
lease_dict['project'] = idp.get_project_name(lease.project_id,
project_list)
lease_dict['owner'] = keystone.get_project_name(lease.owner_id,
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)
Expand Down
8 changes: 8 additions & 0 deletions esi_leap/common/idp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import os

from esi_leap.common.idp import keystoneIDP, dummyIDP

if os.environ.get('ESI_DEBUG', '') == 'True':
idp = dummyIDP.DummyIDP()
else:
idp = keystoneIDP.KeystoneIDP()
15 changes: 15 additions & 0 deletions esi_leap/common/idp/baseIDP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import abc

class BaseIDP(abc.ABC):

def get_project_list():
pass

def get_project_name(self, id, project_list=None):
pass

def get_parent_project_id_tree(project_id):
pass

def get_project_uuid_from_ident(project_ident):
pass
36 changes: 36 additions & 0 deletions esi_leap/common/idp/dummyIDP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from oslo_utils import uuidutils
from keystoneclient.v3.projects import Project, ProjectManager

from esi_leap.common import exception
from esi_leap.common.idp import baseIDP

dummy_project = Project(manager=ProjectManager, info={
'id' : 1,
'name' : 'test'
})

class DummyIDP(baseIDP.BaseIDP):

def get_parent_project_id_tree(self, project_id):
return [1]


def get_project_uuid_from_ident(self, project_ident):
if uuidutils.is_uuid_like(project_ident):
return project_ident
else:
if project_ident == "test":
return 1
raise exception.ProjectNoSuchName(name=project_ident)


def get_project_list(self):

return [dummy_project]


def get_project_name(self, project_id, project_list=None):
if project_id == 1:
return 'test'
else:
return ''
64 changes: 64 additions & 0 deletions esi_leap/common/idp/keystoneIDP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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
import esi_leap.conf
from esi_leap.common.idp import baseIDP

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 ''

0 comments on commit 217fddd

Please sign in to comment.