Add master reauthentication for identity data sync

This fixes Issue #4 from Bug 1870999 where some subclouds failed to sync
an identity resource change.  This was due to unauthorized request error
on the master cloud due to expired token.  The current error handling
only covers reauthentication of subcloud dbs client.

In addition, the number of sync tries is increased from 2 to 3 to
accommodate the case were data sync fails authentication on master and
subcloud.

Also fix exception in dcdbsync on subcloud due to uninitialized variable
when handling change to project resource from dcorch audit on system
controller.

Change-Id: Ife8d86481a64ed841f5231a6df055028ee6597b0
Partial-Bug: 1870999
Signed-off-by: Gerry Kopec <gerry.kopec@windriver.com>
This commit is contained in:
Gerry Kopec 2020-07-23 08:06:07 -04:00
parent 8c94888424
commit 54ef00192d
4 changed files with 63 additions and 18 deletions

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2019 Wind River Systems, Inc. # Copyright (c) 2019-2020 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -392,6 +392,7 @@ def project_update(context, project_id, payload):
domain_ref_projects = [] domain_ref_projects = []
parent_ref_projects = [] parent_ref_projects = []
domain_ref_users = [] domain_ref_users = []
domain_ref_local_users = []
project = payload[table] project = payload[table]
new_project_id = project.get('id') new_project_id = project.get('id')
if project_id != new_project_id: if project_id != new_project_id:

View File

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# Copyright (c) 2019 Wind River Systems, Inc. # Copyright (c) 2019-2020 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -90,6 +90,15 @@ class Unauthorized(DBsyncClientException):
self.message = message self.message = message
class UnauthorizedMaster(DBsyncClientException):
message = "Unauthorized request - master resource"
code = "UNAUTHORIZED_EXCEPTION_MASTER"
def __init__(self, message=None):
if message:
self.message = message
class NotFound(DBsyncClientException): class NotFound(DBsyncClientException):
message = "NotFoundException occurred" message = "NotFoundException occurred"
code = "NOTFOUND_EXCEPTION" code = "NOTFOUND_EXCEPTION"

View File

@ -391,12 +391,21 @@ class IdentitySyncThread(SyncThread):
raise exceptions.SyncRequestTimeout raise exceptions.SyncRequestTimeout
except (dbsync_exceptions.Unauthorized, except (dbsync_exceptions.Unauthorized,
keystone_exceptions.Unauthorized) as e: keystone_exceptions.Unauthorized) as e:
LOG.info("Request [{}] failed for {}: {}" LOG.info("Request [{} {}] failed for {}: {}"
.format(request.orch_job.operation_type, .format(request.orch_job.operation_type,
rsrc.resource_type,
self.subcloud_engine.subcloud.region_name, self.subcloud_engine.subcloud.region_name,
str(e)), extra=self.log_extra) str(e)), extra=self.log_extra)
self.reauthenticate_sc_clients() self.reauthenticate_sc_clients()
raise exceptions.SyncRequestFailedRetry raise exceptions.SyncRequestFailedRetry
except dbsync_exceptions.UnauthorizedMaster as e:
LOG.info("Request [{} {}] failed for {}: {}"
.format(request.orch_job.operation_type,
rsrc.resource_type,
self.subcloud_engine.subcloud.region_name,
str(e)), extra=self.log_extra)
self.reauthenticate_m_dbs_client()
raise exceptions.SyncRequestFailedRetry
except exceptions.SyncRequestFailed: except exceptions.SyncRequestFailed:
raise raise
except Exception as e: except Exception as e:
@ -417,7 +426,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the user just created. The records is in JSON # Retrieve DB records of the user just created. The records is in JSON
# format # format
user_records = self.m_dbs_client.identity_manager.user_detail(user_id) try:
user_records = self.m_dbs_client.identity_manager.\
user_detail(user_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not user_records: if not user_records:
LOG.error("No data retrieved from master cloud for user {} to" LOG.error("No data retrieved from master cloud for user {} to"
" create its equivalent in subcloud.".format(user_id), " create its equivalent in subcloud.".format(user_id),
@ -464,7 +477,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the user. The records is in JSON # Retrieve DB records of the user. The records is in JSON
# format # format
user_records = self.m_dbs_client.identity_manager.user_detail(user_id) try:
user_records = self.m_dbs_client.identity_manager.\
user_detail(user_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not user_records: if not user_records:
LOG.error("No data retrieved from master cloud for user {} to" LOG.error("No data retrieved from master cloud for user {} to"
" update its equivalent in subcloud.".format(user_id), " update its equivalent in subcloud.".format(user_id),
@ -584,8 +601,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the project just created. # Retrieve DB records of the project just created.
# The records is in JSON format. # The records is in JSON format.
project_records = self.m_dbs_client.project_manager.\ try:
project_detail(project_id) project_records = self.m_dbs_client.project_manager.\
project_detail(project_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not project_records: if not project_records:
LOG.error("No data retrieved from master cloud for project {} to" LOG.error("No data retrieved from master cloud for project {} to"
" create its equivalent in subcloud.".format(project_id), " create its equivalent in subcloud.".format(project_id),
@ -633,8 +653,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the project. The records is in JSON # Retrieve DB records of the project. The records is in JSON
# format # format
project_records = self.m_dbs_client.project_manager.\ try:
project_detail(project_id) project_records = self.m_dbs_client.project_manager.\
project_detail(project_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not project_records: if not project_records:
LOG.error("No data retrieved from master cloud for project {} to" LOG.error("No data retrieved from master cloud for project {} to"
" update its equivalent in subcloud.".format(project_id), " update its equivalent in subcloud.".format(project_id),
@ -749,8 +772,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the role just created. The records is in JSON # Retrieve DB records of the role just created. The records is in JSON
# format. # format.
role_records = self.m_dbs_client.role_manager.\ try:
role_detail(role_id) role_records = self.m_dbs_client.role_manager.\
role_detail(role_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not role_records: if not role_records:
LOG.error("No data retrieved from master cloud for role {} to" LOG.error("No data retrieved from master cloud for role {} to"
" create its equivalent in subcloud.".format(role_id), " create its equivalent in subcloud.".format(role_id),
@ -798,8 +824,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the role. The records is in JSON # Retrieve DB records of the role. The records is in JSON
# format # format
role_records = self.m_dbs_client.role_manager.\ try:
role_detail(role_id) role_records = self.m_dbs_client.role_manager.\
role_detail(role_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not role_records: if not role_records:
LOG.error("No data retrieved from master cloud for role {} to" LOG.error("No data retrieved from master cloud for role {} to"
" update its equivalent in subcloud.".format(role_id), " update its equivalent in subcloud.".format(role_id),
@ -1057,8 +1086,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the revoke event just created. The records # Retrieve DB records of the revoke event just created. The records
# is in JSON format. # is in JSON format.
revoke_event_records = self.m_dbs_client.revoke_event_manager.\ try:
revoke_event_detail(audit_id=audit_id) revoke_event_records = self.m_dbs_client.revoke_event_manager.\
revoke_event_detail(audit_id=audit_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not revoke_event_records: if not revoke_event_records:
LOG.error("No data retrieved from master cloud for token" LOG.error("No data retrieved from master cloud for token"
" revocation event with audit_id {} to create its" " revocation event with audit_id {} to create its"
@ -1128,8 +1160,11 @@ class IdentitySyncThread(SyncThread):
# Retrieve DB records of the revoke event just created. The records # Retrieve DB records of the revoke event just created. The records
# is in JSON format. # is in JSON format.
revoke_event_records = self.m_dbs_client.revoke_event_manager.\ try:
revoke_event_detail(user_id=event_id) revoke_event_records = self.m_dbs_client.revoke_event_manager.\
revoke_event_detail(user_id=event_id)
except dbsync_exceptions.Unauthorized:
raise dbsync_exceptions.UnauthorizedMaster
if not revoke_event_records: if not revoke_event_records:
LOG.error("No data retrieved from master cloud for token" LOG.error("No data retrieved from master cloud for token"
" revocation event with event_id {} to create its" " revocation event with event_id {} to create its"

View File

@ -63,7 +63,7 @@ AUDIT_LOCK_NAME = 'dcorch-audit'
class SyncThread(object): class SyncThread(object):
"""Manages tasks related to resource management.""" """Manages tasks related to resource management."""
MAX_RETRY = 2 MAX_RETRY = 3
# used by the audit to cache the master resources # used by the audit to cache the master resources
master_resources_dict = collections.defaultdict(dict) master_resources_dict = collections.defaultdict(dict)