4e7965ad25
This commit updates the default tripleo_containers jinja template
splitting off the Ceph related container images.
With this new approach pulling the ceph containers is optional,
and can be avoided by setting the 'ceph_images' boolean to False.
To make this possible, a new jinja template processing approach
has been introduced, and a template basedir parameter (required
by the jinja loader) has been added to the BaseImageManager.
In particular:
- the 'template_dir' parameter represents the location path to the
j2 templates that can be included in the main tripleo containers
template; a default location (which matches with the default j2
path) has been added, but if nothing is passed the old behavior
is maintained;
This is not clean cherry-pick as long as the CephIngress daemon
is not part of the wallaby cherry-pick.
Change-Id: I7e337596b653cf635f07a36606e9f673044402a3
(cherry picked from commit 08a8118f1b
)
187 lines
6.4 KiB
Python
187 lines
6.4 KiB
Python
# Copyright 2017 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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 sys
|
|
|
|
from heatclient import exc as heat_exc
|
|
|
|
from tripleo_common import constants
|
|
from tripleo_common.image import kolla_builder
|
|
from tripleo_common.utils import passwords as password_utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
def default_image_params():
|
|
|
|
def ffunc(entry):
|
|
return entry
|
|
|
|
template_file = os.path.join(sys.prefix, 'share', 'tripleo-common',
|
|
'container-images',
|
|
'tripleo_containers.yaml.j2')
|
|
template_dir = os.path.join(sys.prefix, 'share', 'tripleo-common',
|
|
'container-images')
|
|
builder = kolla_builder.KollaImageBuilder([template_file], template_dir)
|
|
result = builder.container_images_from_template(filter=ffunc)
|
|
|
|
params = {}
|
|
for entry in result:
|
|
imagename = entry.get('imagename', '')
|
|
if 'params' in entry:
|
|
for p in entry.pop('params'):
|
|
params[p] = imagename
|
|
return params
|
|
|
|
|
|
def generate_passwords(swift=None, heat=None,
|
|
container=constants.DEFAULT_CONTAINER_NAME,
|
|
rotate_passwords=False, rotate_pw_list=None,
|
|
passwords_env=None):
|
|
"""Generates passwords needed for Overcloud deployment
|
|
|
|
This method generates passwords. By default, this method respects
|
|
previously generated passwords and in stack environment.
|
|
|
|
If rotate_passwords is set to True, then passwords will be replaced as
|
|
follows:
|
|
- if password names are specified in the rotate_pw_list, then only those
|
|
passwords will be replaced.
|
|
- otherwise, all passwords not in the DO_NOT_ROTATE list (as they require
|
|
special handling, like KEKs and Fernet keys) will be replaced.
|
|
"""
|
|
if rotate_pw_list is None:
|
|
rotate_pw_list = []
|
|
|
|
if passwords_env:
|
|
stack_env = passwords_env
|
|
placement_extracted = True
|
|
elif heat is None:
|
|
stack_env = None
|
|
placement_extracted = True
|
|
else:
|
|
try:
|
|
stack_env = heat.stacks.environment(
|
|
stack_id=container)
|
|
except heat_exc.HTTPNotFound:
|
|
stack_env = None
|
|
|
|
placement_extracted = False
|
|
try:
|
|
# We can't rely on the existence of PlacementPassword to
|
|
# determine if placement extraction has occured as it was added
|
|
# in stein while the service extraction was delayed to train.
|
|
# Inspect the endpoint map instead.
|
|
endpoint_res = heat.resources.get(container, 'EndpointMap')
|
|
endpoints = endpoint_res.attributes.get('endpoint_map', None)
|
|
placement_extracted = endpoints and 'PlacementPublic' in endpoints
|
|
except heat_exc.HTTPNotFound:
|
|
pass
|
|
|
|
passwords = password_utils.generate_passwords(
|
|
stack_env=stack_env,
|
|
rotate_passwords=rotate_passwords,
|
|
rotate_pw_list=rotate_pw_list)
|
|
|
|
# NOTE(ansmith): if rabbit password previously generated and
|
|
# stored, facilitate upgrade and use for oslo messaging in plan env
|
|
if 'RabbitPassword' in passwords:
|
|
for i in ('RpcPassword', 'NotifyPassword'):
|
|
if i not in passwords:
|
|
passwords[i] = passwords['RabbitPassword']
|
|
|
|
# NOTE(owalsh): placement previously used NovaPassword
|
|
# Default to the same password for PlacementPassword if it is an
|
|
# upgrade (i.e NovaPassword is set) so we do not need to update the
|
|
# password in keystone
|
|
if not placement_extracted and 'NovaPassword' in passwords:
|
|
LOG.debug('Setting PlacementPassword to NovaPassword')
|
|
passwords['PlacementPassword'] = passwords['NovaPassword']
|
|
|
|
return passwords
|
|
|
|
|
|
def rotate_fernet_keys(heat,
|
|
container=constants.DEFAULT_CONTAINER_NAME):
|
|
try:
|
|
stack_env = heat.stacks.environment(
|
|
stack_id=container)
|
|
except heat_exc.HTTPNotFound:
|
|
raise RuntimeError('Can not rotate fernet keys without an'
|
|
'existing stack %s.' % container)
|
|
|
|
parameter_defaults = stack_env.get('parameter_defaults', {})
|
|
passwords = get_overriden_passwords({}, parameter_defaults)
|
|
|
|
next_index = get_next_index(passwords['KeystoneFernetKeys'])
|
|
keys_map = rotate_keys(passwords['KeystoneFernetKeys'],
|
|
next_index)
|
|
max_keys = get_max_keys_value(parameter_defaults)
|
|
return purge_excess_keys(max_keys, keys_map)
|
|
|
|
|
|
def get_overriden_passwords(env_passwords, parameter_defaults):
|
|
for name in constants.PASSWORD_PARAMETER_NAMES:
|
|
if name in parameter_defaults:
|
|
env_passwords[name] = parameter_defaults[name]
|
|
return env_passwords
|
|
|
|
|
|
def get_key_index_from_path(path):
|
|
return int(path[path.rfind('/') + 1:])
|
|
|
|
|
|
def get_next_index(keys_map):
|
|
return get_key_index_from_path(
|
|
max(keys_map, key=get_key_index_from_path)) + 1
|
|
|
|
|
|
def get_key_path(index):
|
|
return password_utils.KEYSTONE_FERNET_REPO + str(index)
|
|
|
|
|
|
def rotate_keys(keys_map, next_index):
|
|
next_index_path = get_key_path(next_index)
|
|
zero_index_path = get_key_path(0)
|
|
|
|
# promote staged key to be new primary
|
|
keys_map[next_index_path] = keys_map[zero_index_path]
|
|
# Set new staged key
|
|
keys_map[zero_index_path] = {
|
|
'content': password_utils.create_keystone_credential()}
|
|
return keys_map
|
|
|
|
|
|
def get_max_keys_value(parameter_defaults):
|
|
# The number of max keys should always be positive. The minimum amount
|
|
# of keys is 3.
|
|
return max(parameter_defaults.get('KeystoneFernetMaxActiveKeys', 5), 3)
|
|
|
|
|
|
def purge_excess_keys(max_keys, keys_map):
|
|
current_repo_size = len(keys_map)
|
|
if current_repo_size <= max_keys:
|
|
return keys_map
|
|
key_paths = sorted(keys_map.keys(), key=get_key_index_from_path)
|
|
|
|
keys_to_be_purged = current_repo_size - max_keys
|
|
|
|
for key_path in key_paths[1:keys_to_be_purged + 1]:
|
|
del keys_map[key_path]
|
|
return keys_map
|