fda3233451
The patch to fix the related bug (not this patch) fixes an inconsistency where the ceph client data is somtimes exported to the wrong path. If anyone deployed before they got the fix to the related bug, then this patch will workaround that problem if they export later. When 'openstack overcloud export ceph' is run look in the correct default location for the ceph client data and if it is not found, then fall back to incorrect location. Change-Id: I0b8c747481e561645eefea50cb77ca806a7f0de2 Related-Bug: #1978846
262 lines
9.6 KiB
Python
262 lines
9.6 KiB
Python
# Copyright 2019 Red Hat, Inc.
|
|
#
|
|
# 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 logging
|
|
import os
|
|
import re
|
|
import yaml
|
|
|
|
from osc_lib.i18n import _
|
|
|
|
from tripleo_common.utils import plan as plan_utils
|
|
from tripleoclient import constants
|
|
from tripleoclient import utils as oooutils
|
|
|
|
|
|
LOG = logging.getLogger(__name__ + ".utils")
|
|
|
|
|
|
def export_passwords(working_dir, stack, excludes=True):
|
|
"""For each password, check if it's excluded, then check if there's a user
|
|
defined value from parameter_defaults, and if not use the value from the
|
|
generated passwords.
|
|
:param working_dir: Working dir for the deployment
|
|
:type working_dir: string
|
|
:param stack: stack name for password generator
|
|
:type stack: string
|
|
:param excludes: filter the passwords or not, defaults to `True`
|
|
:type excludes: bool
|
|
:returns: filtered password dictionary
|
|
:rtype: dict
|
|
"""
|
|
|
|
def exclude_password(password):
|
|
for pattern in constants.EXPORT_PASSWORD_EXCLUDE_PATTERNS:
|
|
if re.match(pattern, password, re.I):
|
|
return True
|
|
|
|
passwords_file = os.path.join(
|
|
working_dir,
|
|
constants.PASSWORDS_ENV_FORMAT.format(stack))
|
|
with open(passwords_file) as f:
|
|
passwords_env = yaml.safe_load(f.read())
|
|
generated_passwords = plan_utils.generate_passwords(
|
|
passwords_env=passwords_env)
|
|
|
|
filtered_passwords = generated_passwords.copy()
|
|
|
|
if excludes:
|
|
for password in generated_passwords:
|
|
if exclude_password(password):
|
|
filtered_passwords.pop(password, None)
|
|
|
|
return filtered_passwords
|
|
|
|
|
|
def export_stack(working_dir, stack, should_filter=False,
|
|
config_download_dir=constants.DEFAULT_WORK_DIR):
|
|
"""Export stack information.
|
|
Iterates over parameters selected for export and loads
|
|
additional data from the referenced files.
|
|
|
|
:param working_dir: Working dir for the deployment
|
|
:type working_dir: string
|
|
:param stack: stack name for password generator
|
|
:type stack: string
|
|
:params should_filter:
|
|
should the export only include values with keys
|
|
defined in the 'filter' list. Defaults to `False`
|
|
:type should_filter: bool
|
|
:param config_download_dir:
|
|
path to download directory,
|
|
defaults to `constants.DEFAULT_WORK_DIR`
|
|
:type config_download_dir: string
|
|
|
|
:returns: data to export
|
|
:rtype: dict
|
|
|
|
The function detetermines what data to export using information,
|
|
obtained from the preset `tripleoclient.constants.EXPORT_DATA` dictionary.
|
|
parameter: Parameter to be exported
|
|
file: If file is specified it is taken as source instead of heat
|
|
output. File is relative to <config-download-dir>/stack.
|
|
filter: in case only specific settings should be
|
|
exported from parameter data.
|
|
"""
|
|
|
|
data = {}
|
|
|
|
for export_key, export_param in constants.EXPORT_DATA.items():
|
|
param = export_param["parameter"]
|
|
|
|
if "file" in export_param:
|
|
# get file data
|
|
file = os.path.join(config_download_dir,
|
|
stack,
|
|
export_param["file"])
|
|
export_data = oooutils.get_parameter_file(file)
|
|
else:
|
|
# get stack data
|
|
export_data = oooutils.get_stack_saved_output_item(
|
|
export_key, working_dir)
|
|
|
|
if export_data:
|
|
# When we export information from a cell controller stack
|
|
# we don't want to filter.
|
|
if "filter" in export_param and should_filter:
|
|
for filter_key in export_param["filter"]:
|
|
if filter_key in export_data:
|
|
element = {filter_key: export_data[filter_key]}
|
|
data.setdefault(param, {}).update(element)
|
|
else:
|
|
data[param] = export_data
|
|
|
|
else:
|
|
LOG.warning("No data returned to export %s from." % param)
|
|
|
|
# Check if AuthCloudName is in the stack environment, and if so add it to
|
|
# the export data. Otherwise set it to the exported stack's name.
|
|
auth_cloud_name = oooutils.get_stack_saved_output_item(
|
|
'AuthCloudName', working_dir)
|
|
if auth_cloud_name:
|
|
data['AuthCloudName'] = auth_cloud_name
|
|
else:
|
|
data['AuthCloudName'] = stack
|
|
|
|
# Check if AuthCloudName is in the stack environment, and if so add it to
|
|
# the export data. Otherwise set it to the exported stack's name.
|
|
auth_cloud_name = oooutils.get_stack_saved_output_item(
|
|
'AuthCloudName', working_dir)
|
|
if auth_cloud_name:
|
|
data['AuthCloudName'] = auth_cloud_name
|
|
else:
|
|
data['AuthCloudName'] = stack
|
|
|
|
return data
|
|
|
|
|
|
def export_ceph_net_key(stack, config_download_dir=constants.DEFAULT_WORK_DIR):
|
|
file = os.path.join(config_download_dir, stack, "global_vars.yaml")
|
|
with open(file, 'r') as ff:
|
|
try:
|
|
global_data = yaml.safe_load(ff)
|
|
except yaml.MarkedYAMLError as e:
|
|
LOG.error(
|
|
_('Could not read file %s') % file)
|
|
LOG.error(e)
|
|
return str(global_data['service_net_map']['ceph_mon_network']) + '_ip'
|
|
|
|
|
|
def export_storage_ips(stack, config_download_dir=constants.DEFAULT_WORK_DIR,
|
|
ceph_net_key=''):
|
|
if len(ceph_net_key) == 0:
|
|
ceph_net_key = export_ceph_net_key(stack, config_download_dir)
|
|
inventory_file = "ceph-ansible/inventory.yml"
|
|
file = os.path.join(config_download_dir, stack, inventory_file)
|
|
with open(file, 'r') as ff:
|
|
try:
|
|
inventory_data = yaml.safe_load(ff)
|
|
except yaml.MarkedYAMLError as e:
|
|
LOG.error(
|
|
_('Could not read file %s') % file)
|
|
LOG.error(e)
|
|
mon_ips = []
|
|
for mon_role in inventory_data['mons']['children'].keys():
|
|
for hostname in inventory_data[mon_role]['hosts']:
|
|
ip = inventory_data[mon_role]['hosts'][hostname][ceph_net_key]
|
|
mon_ips.append(ip)
|
|
|
|
return mon_ips
|
|
|
|
|
|
def export_ceph(stack, cephx,
|
|
config_download_dir=constants.DEFAULT_WORK_DIR,
|
|
mon_ips=[], config_download_files=[]):
|
|
# Return a map of ceph data for a list item in CephExternalMultiConfig
|
|
# by parsing files within the config_download_dir of a certain stack
|
|
|
|
if len(config_download_files) == 0:
|
|
config_download_files = os.listdir(os.path.join(
|
|
config_download_dir, stack))
|
|
if 'ceph-ansible' in config_download_files:
|
|
if len(mon_ips) == 0:
|
|
mon_ips = export_storage_ips(stack, config_download_dir)
|
|
external_cluster_mon_ips = str(','.join(mon_ips))
|
|
|
|
# Use ceph-ansible group_vars/all.yml to get remaining values
|
|
ceph_ansible_all = "ceph-ansible/group_vars/all.yml"
|
|
file = os.path.join(config_download_dir, stack, ceph_ansible_all)
|
|
with open(file, 'r') as ff:
|
|
try:
|
|
ceph_data = yaml.safe_load(ff)
|
|
except yaml.MarkedYAMLError as e:
|
|
LOG.error(
|
|
_('Could not read file %s') % file)
|
|
LOG.error(e)
|
|
cluster = ceph_data['cluster']
|
|
fsid = ceph_data['fsid']
|
|
|
|
if 'cephadm' in config_download_files:
|
|
ceph_client = "cephadm/ceph_client.yml"
|
|
file = os.path.join(config_download_dir, stack, ceph_client)
|
|
if not os.path.exists(file):
|
|
# fall back to old path if user had LP 1978846 during deployment
|
|
file = "/home/stack/ceph_client.yaml"
|
|
with open(file, 'r') as ff:
|
|
try:
|
|
ceph_data = yaml.safe_load(ff)
|
|
except yaml.MarkedYAMLError as e:
|
|
LOG.error(
|
|
_('Could not read file %s') % file)
|
|
LOG.error(e)
|
|
external_cluster_mon_ips = ceph_data['external_cluster_mon_ips']
|
|
cluster = ceph_data['tripleo_ceph_client_cluster']
|
|
fsid = ceph_data['tripleo_ceph_client_fsid']
|
|
|
|
# set cephx_keys
|
|
for key in ceph_data['keys']:
|
|
if key['name'] == 'client.' + str(cephx):
|
|
cephx_keys = [key]
|
|
# set ceph_conf_overrides
|
|
ceph_conf_overrides = {}
|
|
ceph_conf_overrides['client'] = {}
|
|
ceph_conf_overrides['client']['keyring'] = '/etc/ceph/' \
|
|
+ cluster \
|
|
+ '.client.' + cephx \
|
|
+ '.keyring'
|
|
# Combine extracted data into one map to return
|
|
data = {}
|
|
data['external_cluster_mon_ips'] = external_cluster_mon_ips
|
|
data['keys'] = cephx_keys
|
|
data['ceph_conf_overrides'] = ceph_conf_overrides
|
|
data['cluster'] = cluster
|
|
data['fsid'] = fsid
|
|
data['dashboard_enabled'] = False
|
|
|
|
return data
|
|
|
|
|
|
def export_overcloud(working_dir, stack, excludes, should_filter,
|
|
config_download_dir):
|
|
data = export_passwords(working_dir, stack, excludes)
|
|
data.update(export_stack(
|
|
working_dir, stack, should_filter, config_download_dir))
|
|
# do not add extra host entries for VIPs for stacks deployed off that
|
|
# exported data, since it already contains those entries
|
|
data.update({'AddVipsToEtcHosts': False})
|
|
data = dict(parameter_defaults=data)
|
|
return data
|