From eb572c47f808ce2dd241f7aede44c14a550e5c96 Mon Sep 17 00:00:00 2001 From: Andy Ning Date: Tue, 22 Oct 2019 15:49:06 -0400 Subject: [PATCH] Check ids instead of names for DC assignment synchronization In distributed cloud, subcloud's user ids, project ids and role ids are synced with System Controller. But project role assignment functions still use names to check if master resources and subcloud resources has the same id, and if user, project and role exist before POST call to grant project role to user. This will cause an assignment PUT job created and identity sync status flip from "in-sync" to "out-of-sync" and back to "in-sync" again for every audit cycle. A more detailed explanation, at the very first audit, roles are queued for sync but the job doesn't run and their ids don't changed at the subcloud yet. At the same audit dcorch finds the project role assignment actually exist (since it check names in has_same_ids()), so it maps the the assginment of center cloud to the assignment of the subcloud with the current ids. Once the roles sync job queued get executed, roles ids are changed. At this point the assignment mappings becomes invalid. The next audit can no longer find the mapped assignment from subcloud so the logic falls into audit_discrepancy() where the has_same_ids() return TRUE again and a PUT job is queued for the assignment. The sync endpoint type becomes "out-of-sync" since there is a job for it. Once the PUT function return, its status returns to "in-sync" again. This change updated project role assignment functions to use ids instead of names. Change-Id: I024f2c2f97aaf9670d7b2c5c70a2dae7d6d08d38 Closes-Bug: 1847661 Signed-off-by: Andy Ning --- dcorch/engine/sync_services/identity.py | 32 ++++++++++++++----------- dcorch/engine/sync_thread.py | 1 - 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/dcorch/engine/sync_services/identity.py b/dcorch/engine/sync_services/identity.py index 9e1cd7beb..e8281a52e 100644 --- a/dcorch/engine/sync_services/identity.py +++ b/dcorch/engine/sync_services/identity.py @@ -816,48 +816,44 @@ class IdentitySyncThread(SyncThread): user_id = resource_tags[1] role_id = resource_tags[2] - project_name = self.m_ks_client.projects.get(project_id).name - user_name = self.m_ks_client.users.get(user_id).name - role_name = self.m_ks_client.roles.get(role_id).name - # Ensure that we have already synced the project, user and role # prior to syncing the assignment sc_role = None sc_role_list = self.sc_ks_client.roles.list() for role in sc_role_list: - if role.name == role_name: + if role.id == role_id: sc_role = role break if not sc_role: LOG.error("Unable to assign role to user on project reference {}:" "{}, cannot find equivalent Keystone Role in subcloud." - .format(rsrc, role_name), + .format(rsrc, role_id), extra=self.log_extra) raise exceptions.SyncRequestFailed sc_proj = None sc_proj_list = self.sc_ks_client.projects.list() for proj in sc_proj_list: - if proj.name == project_name: + if proj.id == project_id: sc_proj = proj break if not sc_proj: LOG.error("Unable to assign role to user on project reference {}:" "{}, cannot find equivalent Keystone Project in subcloud" - .format(rsrc, project_name), + .format(rsrc, project_id), extra=self.log_extra) raise exceptions.SyncRequestFailed sc_user = None sc_user_list = self.sc_ks_client.users.list() for user in sc_user_list: - if user.name == user_name: + if user.id == user_id: sc_user = user break if not sc_user: LOG.error("Unable to assign role to user on project reference {}:" "{}, cannot find equivalent Keystone User in subcloud." - .format(rsrc, user_name), + .format(rsrc, user_id), extra=self.log_extra) raise exceptions.SyncRequestFailed @@ -1420,7 +1416,14 @@ class IdentitySyncThread(SyncThread): LOG.debug("same_assignment master={}, subcloud={}".format(m, sc), extra=self.log_extra) # For an assignment to be the same, all 3 of its role, project and - # user information must match up + # user information must match up. + # Compare by names here is fine, since this comparison gets called + # only if the mapped subcloud assignment is found by id in subcloud + # resources just retrieved. In another word, the ids are guaranteed + # to be the same by the time same_resource() is called in + # audit_find_missing(). same_resource() in audit_find_missing() is + # actually redundant for assignment but it's the generic algorithm + # for all types of resources. return((m.user.name == sc.user.name and m.user.domain_id == sc.user.domain_id) and (m.role.name == sc.role.name and @@ -1429,9 +1432,10 @@ class IdentitySyncThread(SyncThread): m.project.domain_id == sc.project.domain_id)) def _has_same_assignment_ids(self, m, sc): - # For assignment the triple(user, project, role) is the unique id. - # The two resources have same id only when all of them are identical. - return self._same_assignment_resource(m, sc) + # For assignment the unique id is projectID_userID_roleID. + # The two resources have same id only when all of the three IDs are + # identical. + return m.id == sc.id def _same_revoke_event_resource(self, m, sc): LOG.debug("same_revoke_event master={}, subcloud={}".format(m, sc), diff --git a/dcorch/engine/sync_thread.py b/dcorch/engine/sync_thread.py index 8527343a2..d7f6c4609 100644 --- a/dcorch/engine/sync_thread.py +++ b/dcorch/engine/sync_thread.py @@ -543,7 +543,6 @@ class SyncThread(object): extra=self.log_extra) # Subcloud resource is present in DB, but the check # for same_resource() was negative. Either the resource - # disappeared from subcloud or the resource details # are different from that of master cloud. Let the # resource implementation decide on the audit action.