From c39d98ccafa690cc88d0ed3da1eb37aefc52a3b0 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Fri, 1 Sep 2017 11:09:37 -0500 Subject: [PATCH] Move role normalization to normalize.py Location has specific semantics for identity resources. Add a method to get a projectless location. Add domain_id to project since all of the identity resources have it already, but keep the parent-project semantics already in place for project. Change-Id: Ife37833baabf58d9e329071acb4187842815c7d2 --- doc/source/user/model.rst | 84 ++++++++++++++++++++++++++------------- shade/_normalize.py | 27 +++++++++---- shade/_utils.py | 12 ------ shade/openstackcloud.py | 12 ++++++ shade/operatorcloud.py | 6 +-- 5 files changed, 91 insertions(+), 50 deletions(-) diff --git a/doc/source/user/model.rst b/doc/source/user/model.rst index 3293b0306..ebfc3af97 100644 --- a/doc/source/user/model.rst +++ b/doc/source/user/model.rst @@ -65,6 +65,9 @@ If all of the project information is None, then domain_name=str() or None)) +Resources +========= + Flavor ------ @@ -324,34 +327,6 @@ A Floating IP from Neutron or Nova revision_number=int() or None, properties=dict()) -Project -------- - -A Project from Keystone (or a tenant if Keystone v2) - -Location information for Project has some specific semantics. - -If the project has a parent project, that will be in location.project.id, -and if it doesn't that should be None. If the Project is associated with -a domain that will be in location.project.domain_id regardless of the current -user's token scope. location.project.name and location.project.domain_name -will always be None. Finally, location.region_name will always be None as -Projects are global to a cloud. If a deployer happens to deploy OpenStack -in such a way that users and projects are not shared amongst regions, that -necessitates treating each of those regions as separate clouds from shade's -POV. - -.. code-block:: python - - Project = dict( - location=Location(), - id=str(), - name=str(), - description=str(), - is_enabled=bool(), - is_domain=bool(), - properties=dict()) - Volume ------ @@ -502,3 +477,56 @@ A Stack from Heat tempate_description=str(), timeout_mins=int(), properties=dict()) + +Identity Resources +================== + +Identity Resources are slightly different. + +They are global to a cloud, so location.availability_zone and +location.region_name and will always be None. If a deployer happens to deploy +OpenStack in such a way that users and projects are not shared amongst regions, +that necessitates treating each of those regions as separate clouds from +shade's POV. + +The Identity Resources that are not Project do not exist within a Project, +so all of the values in ``location.project`` will be None. + +Project +------- + +A Project from Keystone (or a tenant if Keystone v2) + +Location information for Project has some additional specific semantics. +If the project has a parent project, that will be in ``location.project.id``, +and if it doesn't that should be ``None``. + +If the Project is associated with a domain that will be in +``location.project.domain_id`` in addition to the normal ``domain_id`` +regardless of the current user's token scope. + +.. code-block:: python + + Project = dict( + location=Location(), + id=str(), + name=str(), + description=str(), + is_enabled=bool(), + is_domain=bool(), + domain_id=str(), + properties=dict()) + +Role +---- + +A Role from Keystone + +.. code-block:: python + + Project = dict( + location=Location(), + id=str(), + name=str(), + domain_id=str(), + properties=dict()) diff --git a/shade/_normalize.py b/shade/_normalize.py index b8e242b56..83783c776 100644 --- a/shade/_normalize.py +++ b/shade/_normalize.py @@ -643,19 +643,14 @@ class Normalizer(object): description = project.pop('description', '') is_enabled = project.pop('enabled', True) - # Projects are global - strip region - location = self._get_current_location(project_id=project_id) - location['region_name'] = None - # v3 additions domain_id = project.pop('domain_id', 'default') parent_id = project.pop('parent_id', None) is_domain = project.pop('is_domain', False) # Projects have a special relationship with location + location = self._get_identity_location() location['project']['domain_id'] = domain_id - location['project']['domain_name'] = None - location['project']['name'] = None location['project']['id'] = parent_id ret = munch.Munch( @@ -665,13 +660,13 @@ class Normalizer(object): description=description, is_enabled=is_enabled, is_domain=is_domain, + domain_id=domain_id, properties=project.copy() ) # Backwards compat if not self.strict_mode: ret['enabled'] = is_enabled - ret['domain_id'] = domain_id ret['parent_id'] = parent_id for key, val in ret['properties'].items(): ret.setdefault(key, val) @@ -1089,3 +1084,21 @@ class Normalizer(object): # TODO(mordred) Normalize this resource return machine + + def _normalize_roles(self, roles): + """Normalize Keystone roles""" + ret = [] + for role in roles: + ret.append(self._normalize_role(role)) + return ret + + def _normalize_role(self, role): + """Normalize Identity roles.""" + + return munch.Munch( + id=role.get('id'), + name=role.get('name'), + domain_id=role.get('domain_id'), + location=self._get_identity_location(), + properties={}, + ) diff --git a/shade/_utils.py b/shade/_utils.py index 4838fc7e7..750f07ab8 100644 --- a/shade/_utils.py +++ b/shade/_utils.py @@ -374,18 +374,6 @@ def normalize_role_assignments(assignments): return new_assignments -def normalize_roles(roles): - """Normalize Identity roles.""" - ret = [ - dict( - domain_id=role.get('domain_id'), - id=role.get('id'), - name=role.get('name'), - ) for role in roles - ] - return meta.obj_list_to_munch(ret) - - def normalize_flavor_accesses(flavor_accesses): """Normalize Flavor access list.""" return [munch.Munch( diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index 39012bc72..531a66ba3 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -670,6 +670,18 @@ class OpenStackCloud( project=self._get_project_info(project_id), ) + def _get_identity_location(self): + '''Identity resources do not exist inside of projects.''' + return munch.Munch( + cloud=self.name, + region_name=None, + zone=None, + project=munch.Munch( + id=None, + name=None, + domain_id=None, + domain_name=None)) + def _get_project_id_param_dict(self, name_or_id): if name_or_id: project = self.get_project(name_or_id) diff --git a/shade/operatorcloud.py b/shade/operatorcloud.py index 248bcd91f..3270a8f98 100644 --- a/shade/operatorcloud.py +++ b/shade/operatorcloud.py @@ -1390,7 +1390,7 @@ class OperatorCloud(openstackcloud.OpenStackCloud): url = '/OS-KSADM/roles' if v2 else '/roles' data = self._identity_client.get( url, params=kwargs, error_message="Failed to list roles") - return _utils.normalize_roles(self._get_and_munchify('roles', data)) + return self._normalize_roles(self._get_and_munchify('roles', data)) @_utils.valid_kwargs('domain_id') def search_roles(self, name_or_id=None, filters=None, **kwargs): @@ -1711,7 +1711,7 @@ class OperatorCloud(openstackcloud.OpenStackCloud): data = self._identity_client.post( url, json={'role': kwargs}, error_message=msg) role = self._get_and_munchify('role', data) - return _utils.normalize_roles([role])[0] + return self._normalize_role(role) @_utils.valid_kwargs('domain_id') def update_role(self, name_or_id, name, **kwargs): @@ -1740,7 +1740,7 @@ class OperatorCloud(openstackcloud.OpenStackCloud): data = self._identity_client.patch('/roles', error_message=msg, json=json_kwargs) role = self._get_and_munchify('role', data) - return _utils.normalize_roles([role])[0] + return self._normalize_role(role) @_utils.valid_kwargs('domain_id') def delete_role(self, name_or_id, **kwargs):