distcloud/dcorch/engine/fernet_key_manager.py
Andy Ning 67215f30fe Keystone DB sync - update dcorch to use dcdbsync
This commit updates dcorch to use the newly introduced dbsync service
APIs to synchronize identity resources from central cloud to subclouds.
The following identity resources are synced:

- users (local users only)
- user passwords
- projects
- roles
- project role assignments
- token revocation events

Story: 2002842
Task: 22787

Signed-off-by: Andy Ning <andy.ning@windriver.com>
(cherry picked from commit e9096c7a23)

Depends-On: https://review.opendev.org/#/c/655921
Depends-On: https://review.opendev.org/#/c/655773
Depends-On: https://review.opendev.org/#/c/655776
Depends-On: https://review.opendev.org/#/c/655927
Change-Id: I77c2cc712a1c3dc8a228883c3fea1423e5207dea
2019-04-30 14:50:55 -04:00

142 lines
5.2 KiB
Python

# Copyright 2018 Wind River
#
# 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 os
import subprocess
from oslo_config import cfg
from oslo_log import log as logging
from oslo_serialization import jsonutils
from dcorch.common import consts
from dcorch.common import context
from dcorch.common import exceptions
from dcorch.common.i18n import _
from dcorch.common import manager
from dcorch.common import utils
from dcorch.drivers.openstack import sdk_platform as sdk
FERNET_REPO_MASTER_ID = "keys"
KEY_ROTATE_CMD = "/usr/bin/keystone-fernet-keys-rotate-active"
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class FernetKeyManager(manager.Manager):
"""Manages tasks related to fernet key management"""
def __init__(self, gsm, *args, **kwargs):
LOG.debug(_('FernetKeyManager initialization...'))
super(FernetKeyManager, self).__init__(service_name="fernet_manager",
*args, **kwargs)
self.gsm = gsm
self.context = context.get_admin_context()
self.endpoint_type = consts.ENDPOINT_TYPE_PLATFORM
self.resource_type = consts.RESOURCE_TYPE_SYSINV_FERNET_REPO
@classmethod
def to_resource_info(cls, key_list):
return dict((getattr(key, 'id'), getattr(key, 'key'))
for key in key_list)
@classmethod
def from_resource_info(cls, keys):
key_list = [dict(id=k, key=v) for k, v in keys.items()]
return key_list
@classmethod
def get_resource_hash(cls, resource_info):
return hash(tuple(sorted(hash(x) for x in resource_info.items())))
def _schedule_work(self, operation_type, subcloud=None):
keys = self._get_master_keys()
if not keys:
LOG.info(_("No fernet keys returned from %s") % consts.CLOUD_0)
return
try:
resource_info = FernetKeyManager.to_resource_info(keys)
utils.enqueue_work(self.context,
self.endpoint_type,
self.resource_type,
FERNET_REPO_MASTER_ID,
operation_type,
resource_info=jsonutils.dumps(resource_info),
subcloud=subcloud)
# wake up sync thread
if self.gsm:
self.gsm.sync_request(self.context, self.endpoint_type)
except Exception as e:
LOG.error(_("Exception in schedule_work: %s") % e.message)
@staticmethod
def _get_master_keys():
"""get the keys from the local fernet key repo"""
keys = []
try:
os_client = sdk.OpenStackDriver(consts.CLOUD_0)
keys = os_client.sysinv_client.get_fernet_keys()
except (exceptions.ConnectionRefused, exceptions.NotAuthorized,
exceptions.TimeOut):
LOG.info(_("Retrieving the fernet keys from %s timeout") %
consts.CLOUD_0)
except Exception as e:
LOG.info(_("Fail to retrieve the master fernet keys: %s") %
e.message)
return keys
def rotate_fernet_keys(self):
"""Rotate fernet keys."""
with open(os.devnull, "w") as fnull:
try:
subprocess.check_call(KEY_ROTATE_CMD,
stdout=fnull,
stderr=fnull)
except subprocess.CalledProcessError:
msg = _("Failed to rotate the keys")
LOG.exception(msg)
raise exceptions.InternalError(msg)
self._schedule_work(consts.OPERATION_TYPE_PUT)
def distribute_keys(self, ctxt, subcloud_name):
keys = self._get_master_keys()
if not keys:
LOG.info(_("No fernet keys returned from %s") % consts.CLOUD_0)
return
resource_info = FernetKeyManager.to_resource_info(keys)
key_list = FernetKeyManager.from_resource_info(resource_info)
self.update_fernet_repo(subcloud_name, key_list)
def reset_keys(self, subcloud_name):
self.update_fernet_repo(subcloud_name)
@staticmethod
def update_fernet_repo(subcloud_name, key_list=None):
try:
os_client = sdk.OpenStackDriver(subcloud_name)
os_client.sysinv_client.post_fernet_repo(key_list)
except (exceptions.ConnectionRefused, exceptions.NotAuthorized,
exceptions.TimeOut):
LOG.info(_("Update the fernet repo on %s timeout") %
subcloud_name)
except Exception as e:
error_msg = "subcloud: {}, {}".format(subcloud_name, e.message)
LOG.info(_("Fail to update fernet repo %s") % error_msg)