From 93d2f4f56c2b09ca5908a72151c8e021eebe3860 Mon Sep 17 00:00:00 2001 From: Ben Nemec Date: Tue, 8 Aug 2017 12:12:07 -0500 Subject: [PATCH] Support deploying with multiple Heat environments Big changes here. This will make it easier to deploy some of the more advanced OVB options like network-isolation. Instead of users having to figure out which lines in the sample env.yaml to uncomment when deploying advanced options, they will simply be able to include one environment file that contains all the appropriate parameters to turn on the option. This _should_ be backwards compatible with existing monolithic env.yaml configurations. If it is not, that is a bug. To create the option environments, a slightly modified copy of the sample environment generator from tripleo-heat-templates has been copied into the project. The sample environments should _not_ be edited directly. Instead, the definition in the sample-env-generator directory should be altered and the tool re-run to update the environment. --- .gitignore | 2 +- bin/environment-generator.py | 216 ++++++++++++++++++ environments/all-networks-port-security.yaml | 17 ++ ...ll-networks-public-bond-port-security.yaml | 19 ++ environments/all-networks-public-bond.yaml | 15 ++ environments/all-networks.yaml | 13 ++ environments/base-role.yaml | 28 +++ environments/base.yaml | 76 ++++++ environments/create-private-network.yaml | 31 +++ environments/port-security.yaml | 14 ++ environments/quintupleo-no-undercloud.yaml | 12 + .../undercloud-floating-existing.yaml | 22 ++ environments/undercloud-floating-none.yaml | 11 + .../build_nodes_json.py | 10 +- openstack_virtual_baremetal/deploy.py | 141 +++++++----- .../tests/test_build_nodes_json.py | 15 +- .../tests/test_deploy.py | 187 ++++++++++----- sample-env-generator/environments.yaml | 141 ++++++++++++ templates/env.yaml.example | 4 + templates/quintupleo.yaml | 8 + tox.ini | 3 + 21 files changed, 857 insertions(+), 128 deletions(-) create mode 100644 bin/environment-generator.py create mode 100644 environments/all-networks-port-security.yaml create mode 100644 environments/all-networks-public-bond-port-security.yaml create mode 100644 environments/all-networks-public-bond.yaml create mode 100644 environments/all-networks.yaml create mode 100644 environments/base-role.yaml create mode 100644 environments/base.yaml create mode 100644 environments/create-private-network.yaml create mode 100644 environments/port-security.yaml create mode 100644 environments/quintupleo-no-undercloud.yaml create mode 100644 environments/undercloud-floating-existing.yaml create mode 100644 environments/undercloud-floating-none.yaml create mode 100644 sample-env-generator/environments.yaml diff --git a/.gitignore b/.gitignore index 0cd21ad..9e2b236 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ nodes.json -env*.yaml +env-*.yaml bmc_bm_pairs *.pyc *.pyo diff --git a/bin/environment-generator.py b/bin/environment-generator.py new file mode 100644 index 0000000..b93a11e --- /dev/null +++ b/bin/environment-generator.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python + +# Copyright 2015 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. + +# ************************************************************************* +# This is a copy of the environment-generator.py in tripleo-heat-templates. +# At some point that version should be generalized enough to be used by +# other projects in a less hacky way. +# ************************************************************************* + +import errno +import os +import sys +import yaml + + +_PARAM_FORMAT = u""" # %(description)s + %(mandatory)s# Type: %(type)s + %(name)s:%(default)s +""" +_STATIC_MESSAGE_START = ( + ' # ******************************************************\n' + ' # Static parameters - these are values that must be\n' + ' # included in the environment but should not be changed.\n' + ' # ******************************************************\n' + ) +_STATIC_MESSAGE_END = (' # *********************\n' + ' # End static parameters\n' + ' # *********************\n' + ) +_FILE_HEADER = ( + '# *******************************************************************\n' + '# This file was created automatically by the sample environment\n' + '# generator. Developers should use `tox -e genconfig` to update it.\n' + '# Users are recommended to make changes to a copy of the file instead\n' + '# of the original, if any customizations are needed.\n' + '# *******************************************************************\n' + ) +# Certain parameter names can't be changed, but shouldn't be shown because +# they are never intended for direct user input. +_PRIVATE_OVERRIDES = [] +# Hidden params are not included by default when the 'all' option is used, +# but can be explicitly included by referencing them in sample_defaults or +# static. This allows us to generate sample environments using them when +# necessary, but they won't be improperly included by accident. +_HIDDEN_PARAMS = [] + + +def _create_output_dir(target_file): + try: + os.makedirs(os.path.dirname(target_file)) + except OSError as e: + if e.errno == errno.EEXIST: + pass + else: + raise + + +def _generate_environment(input_env, parent_env=None): + if parent_env is None: + parent_env = {} + env = dict(parent_env) + env.pop('children', None) + env.update(input_env) + parameter_defaults = {} + param_names = [] + sample_values = env.get('sample_values', {}) + static_names = env.get('static', []) + for template_file, template_data in env['files'].items(): + with open(template_file) as f: + f_data = yaml.safe_load(f) + f_params = f_data['parameters'] + parameter_defaults.update(f_params) + if template_data['parameters'] == 'all': + new_names = [k for k, v in f_params.items()] + for hidden in _HIDDEN_PARAMS: + if (hidden not in (static_names + sample_values.keys()) and + hidden in new_names): + new_names.remove(hidden) + else: + new_names = template_data['parameters'] + missing_params = [name for name in new_names + if name not in f_params] + if missing_params: + raise RuntimeError('Did not find specified parameter names %s ' + 'in file %s for environment %s' % + (missing_params, template_file, + env['name'])) + param_names += new_names + + static_defaults = {k: v for k, v in parameter_defaults.items() + if k in param_names and + k in static_names + } + parameter_defaults = {k: v for k, v in parameter_defaults.items() + if k in param_names and + k not in _PRIVATE_OVERRIDES and + not k.startswith('_') and + k not in static_names + } + + for k, v in sample_values.items(): + if k in parameter_defaults: + parameter_defaults[k]['sample'] = v + if k in static_defaults: + static_defaults[k]['sample'] = v + + def write_sample_entry(f, name, value): + default = value.get('default') + mandatory = '' + if default is None: + mandatory = ('# Mandatory. This parameter must be set by the ' + 'user.\n ') + default = '' + if value.get('sample') is not None: + default = value['sample'] + # We ultimately cast this to str for output anyway + default = str(default) + if default == '': + default = "''" + # If the default value is something like %index%, yaml won't + # parse the output correctly unless we wrap it in quotes. + # However, not all default values can be wrapped so we need to + # do it conditionally. + if default.startswith('%'): + default = "'%s'" % default + if not default.startswith('\n'): + default = ' ' + default + + values = {'name': name, + 'type': value['type'], + 'description': + value.get('description', '').rstrip().replace('\n', + '\n # '), + 'default': default, + 'mandatory': mandatory, + } + f.write(_PARAM_FORMAT % values + '\n') + + target_file = os.path.join('environments', env['name'] + '.yaml') + _create_output_dir(target_file) + with open(target_file, 'w') as env_file: + env_file.write(_FILE_HEADER) + # TODO(bnemec): Once Heat allows the title and description to live in + # the environment itself, uncomment these entries and make them + # top-level keys in the YAML. + env_title = env.get('title', '') + env_file.write(u'# title: %s\n' % env_title) + env_desc = env.get('description', '') + env_file.write(u'# description: |\n') + for line in env_desc.splitlines(): + env_file.write(u'# %s\n' % line) + + if parameter_defaults: + env_file.write(u'parameter_defaults:\n') + for name, value in sorted(parameter_defaults.items()): + write_sample_entry(env_file, name, value) + if static_defaults: + env_file.write(_STATIC_MESSAGE_START) + for name, value in sorted(static_defaults.items()): + write_sample_entry(env_file, name, value) + if static_defaults: + env_file.write(_STATIC_MESSAGE_END) + + if env.get('resource_registry'): + env_file.write(u'resource_registry:\n') + for res, value in sorted(env.get('resource_registry', {}).items()): + env_file.write(u' %s: %s\n' % (res, value)) + print('Wrote sample environment "%s"' % target_file) + + for e in env.get('children', []): + _generate_environment(e, env) + + +def generate_environments(config_path): + if os.path.isdir(config_path): + config_files = os.listdir(config_path) + config_files = [os.path.join(config_path, i) for i in config_files + if os.path.splitext(i)[1] == '.yaml'] + else: + config_files = [config_path] + for config_file in config_files: + print('Reading environment definitions from %s' % config_file) + with open(config_file) as f: + config = yaml.safe_load(f) + for env in config['environments']: + _generate_environment(env) + + +def usage(exit_code=1): + print('Usage: %s [ | ]' % sys.argv[0]) + sys.exit(exit_code) + + +def main(): + try: + config_path = sys.argv[1] + except IndexError: + usage() + generate_environments(config_path) + + +if __name__ == '__main__': + main() diff --git a/environments/all-networks-port-security.yaml b/environments/all-networks-port-security.yaml new file mode 100644 index 0000000..8b407ea --- /dev/null +++ b/environments/all-networks-port-security.yaml @@ -0,0 +1,17 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Deploy with All Networks Enabled +# description: | +# Deploy an OVB stack that adds interfaces for all the standard TripleO +# network isolation networks. This version uses the port-security +# Neutron extension to allow OVB to be run on clouds with security +# groups enabled. +resource_registry: + OS::OVB::BMCPort: ../templates/bmc-port-port-security.yaml + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-all-port-security.yaml + OS::OVB::UndercloudPorts: ../templates/undercloud-ports-port-security.yaml diff --git a/environments/all-networks-public-bond-port-security.yaml b/environments/all-networks-public-bond-port-security.yaml new file mode 100644 index 0000000..0adecf7 --- /dev/null +++ b/environments/all-networks-public-bond-port-security.yaml @@ -0,0 +1,19 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Deploy with All Networks Enabled and Two Public Interfaces +# description: | +# Deploy an OVB stack that adds interfaces for all the standard TripleO +# network isolation networks. This version will deploy duplicate +# public network interfaces on the baremetal instances so that the +# public network can be configured as a bond. It will also use the +# port-security Neutron extension to allow OVB to be run on clouds with +# security groups enabled. +resource_registry: + OS::OVB::BMCPort: ../templates/bmc-port-port-security.yaml + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-public-bond-port-security.yaml + OS::OVB::UndercloudPorts: ../templates/undercloud-ports-port-security.yaml diff --git a/environments/all-networks-public-bond.yaml b/environments/all-networks-public-bond.yaml new file mode 100644 index 0000000..00ae71c --- /dev/null +++ b/environments/all-networks-public-bond.yaml @@ -0,0 +1,15 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Deploy with All Networks Enabled and Two Public Interfaces +# description: | +# Deploy an OVB stack that adds interfaces for all the standard TripleO +# network isolation networks. This version will deploy duplicate +# public network interfaces on the baremetal instances so that the +# public network can be configured as a bond. +resource_registry: + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-public-bond.yaml diff --git a/environments/all-networks.yaml b/environments/all-networks.yaml new file mode 100644 index 0000000..63923af --- /dev/null +++ b/environments/all-networks.yaml @@ -0,0 +1,13 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Deploy with All Networks Enabled +# description: | +# Deploy an OVB stack that adds interfaces for all the standard TripleO +# network isolation networks. +resource_registry: + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-all.yaml diff --git a/environments/base-role.yaml b/environments/base-role.yaml new file mode 100644 index 0000000..ec1e5de --- /dev/null +++ b/environments/base-role.yaml @@ -0,0 +1,28 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Base Configuration Options for Secondary Roles +# description: | +# Configuration options that need to be set when deploying an OVB +# environment that has multiple roles. +parameter_defaults: + # Recommended to be at least 1 vcpu, 4 GB RAM, 50 GB disk + # Type: string + baremetal_flavor: baremetal + + # Nova keypair to inject into the undercloud and bmc + # Type: string + key_name: default + + # Number of baremetal nodes to deploy + # Type: number + node_count: 2 + + # The default role for nodes in this environment. This parameter is + # ignored by Heat, but used by build-nodes-json. + # Type: string + role: compute + diff --git a/environments/base.yaml b/environments/base.yaml new file mode 100644 index 0000000..e4df115 --- /dev/null +++ b/environments/base.yaml @@ -0,0 +1,76 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Base Configuration Options +# description: | +# Basic configuration options needed for all OVB environments +parameter_defaults: + # Recommended to be at least 1 vcpu, 4 GB RAM, 50 GB disk + # Type: string + baremetal_flavor: baremetal + + # The base image to use for baremetal instances + # Type: string + baremetal_image: ipxe-boot + + # Prefix for the name of the baremetal instances + # Type: string + baremetal_prefix: baremetal + + # The Nova flavor to use for the bmc instance + # Type: string + bmc_flavor: m1.small + + # The base image for the bmc instance. A CentOS 7 image is currently the + # only one supported. + # Type: string + bmc_image: CentOS-7-x86_64-GenericCloud + + # Prefix for the name of the bmc instance + # Type: string + bmc_prefix: bmc + + # An external network from which floating ips can be provisioned + # Type: string + external_net: external + + # Nova keypair to inject into the undercloud and bmc + # Type: string + key_name: default + + # Number of baremetal nodes to deploy + # Type: number + node_count: 2 + + # Name of a private network which can have floating ips associated with it + # Type: string + private_net: private + + # Name of a network that will be used for provisioning traffic + # Type: string + provision_net: provision + + # Name of the overcloud external network + # Type: string + public_net: public + + # The default role for nodes in this environment. This parameter is + # ignored by Heat, but used by build-nodes-json. + # Type: string + role: '' + + # Nova flavor to use for the undercloud instance + # Type: string + undercloud_flavor: m1.large + + # Image to boot as the undercloud instance + # Type: string + undercloud_image: CentOS-7-x86_64-GenericCloud-1503 + + # Name of the undercloud instance + # Type: string + undercloud_name: undercloud + diff --git a/environments/create-private-network.yaml b/environments/create-private-network.yaml new file mode 100644 index 0000000..461603e --- /dev/null +++ b/environments/create-private-network.yaml @@ -0,0 +1,31 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Create a Private Network +# description: | +# Create the private network as part of the OVB stack instead of using an +# existing one. +parameter_defaults: + # List of DNS servers for the private network + # Type: comma_delimited_list + dns_nameservers: ['8.8.8.8'] + + # An external network for the private network to route to + # Mandatory. This parameter must be set by the user. + # Type: string + external_net: + + # Name of private network + # Mandatory. This parameter must be set by the user. + # Type: string + private_net: + + # CIDR for private network subnet + # Type: string + private_net_cidr: 10.0.1.0/24 + +resource_registry: + OS::OVB::PrivateNetwork: ../templates/private-net-create.yaml diff --git a/environments/port-security.yaml b/environments/port-security.yaml new file mode 100644 index 0000000..5b019d6 --- /dev/null +++ b/environments/port-security.yaml @@ -0,0 +1,14 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Deploy a Basic OVB Environment Using Neutron port-security +# description: | +# Deploy an OVB stack that uses the Neutron port-security extension to +# allow OVB functionality in clouds with security groups enabled. +resource_registry: + OS::OVB::BMCPort: ../templates/bmc-port-port-security.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-default-port-security.yaml + OS::OVB::UndercloudPorts: ../templates/undercloud-ports-port-security.yaml diff --git a/environments/quintupleo-no-undercloud.yaml b/environments/quintupleo-no-undercloud.yaml new file mode 100644 index 0000000..395e4b4 --- /dev/null +++ b/environments/quintupleo-no-undercloud.yaml @@ -0,0 +1,12 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Disable the Undercloud in a QuintupleO Stack +# description: | +# Deploy a QuintupleO environment, but do not create the undercloud +# instance. +resource_registry: + OS::OVB::UndercloudEnvironment: OS::Heat::None diff --git a/environments/undercloud-floating-existing.yaml b/environments/undercloud-floating-existing.yaml new file mode 100644 index 0000000..5a574b0 --- /dev/null +++ b/environments/undercloud-floating-existing.yaml @@ -0,0 +1,22 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Assign the Undercloud an Existing Floating IP +# description: | +# When deploying the undercloud, assign it an existing floating IP instead +# of creating a new one. +parameter_defaults: + # Address of existing floating ip to use. + # Type: string + undercloud_floating_ip: '' + + # ID of existing floating ip to use. + # Mandatory. This parameter must be set by the user. + # Type: string + undercloud_floating_ip_id: + +resource_registry: + OS::OVB::UndercloudFloating: ../templates/undercloud-floating-existing.yaml diff --git a/environments/undercloud-floating-none.yaml b/environments/undercloud-floating-none.yaml new file mode 100644 index 0000000..355a6e0 --- /dev/null +++ b/environments/undercloud-floating-none.yaml @@ -0,0 +1,11 @@ +# ******************************************************************* +# This file was created automatically by the sample environment +# generator. Developers should use `tox -e genconfig` to update it. +# Users are recommended to make changes to a copy of the file instead +# of the original, if any customizations are needed. +# ******************************************************************* +# title: Do Not Assign a Floating IP to the Undercloud +# description: | +# When deploying the undercloud, do not assign a floating ip to it. +resource_registry: + OS::OVB::UndercloudFloating: ../templates/undercloud-floating-none.yaml diff --git a/openstack_virtual_baremetal/build_nodes_json.py b/openstack_virtual_baremetal/build_nodes_json.py index ff565a0..500ced3 100755 --- a/openstack_virtual_baremetal/build_nodes_json.py +++ b/openstack_virtual_baremetal/build_nodes_json.py @@ -29,7 +29,7 @@ def _parse_args(): prog='build-nodes-json.py', description='Tool for collecting virtual IPMI details', ) - parser.add_argument('--env', + parser.add_argument('--env', '-e', dest='env', default=None, help='YAML file containing OVB environment details') @@ -72,14 +72,14 @@ def _get_names(args): else: with open(args.env) as f: e = yaml.safe_load(f) - bmc_base = e['parameters']['bmc_prefix'] - baremetal_base = e['parameters']['baremetal_prefix'] - provision_net = e['parameters']['provision_net'] + bmc_base = e['parameter_defaults']['bmc_prefix'] + baremetal_base = e['parameter_defaults']['baremetal_prefix'] + provision_net = e['parameter_defaults']['provision_net'] role = e['parameter_defaults'].get('role') if role and baremetal_base.endswith('-' + role): baremetal_base = baremetal_base[:-len(role) - 1] if args.add_undercloud: - undercloud_name = e['parameters']['undercloud_name'] + undercloud_name = e['parameter_defaults']['undercloud_name'] return bmc_base, baremetal_base, provision_net, undercloud_name diff --git a/openstack_virtual_baremetal/deploy.py b/openstack_virtual_baremetal/deploy.py index a63cba3..095d43f 100755 --- a/openstack_virtual_baremetal/deploy.py +++ b/openstack_virtual_baremetal/deploy.py @@ -28,10 +28,11 @@ import auth def _parse_args(): parser = argparse.ArgumentParser(description='Deploy an OVB environment') - parser.add_argument('--env', + parser.add_argument('--env', '-e', help='Path to Heat environment file describing the OVB ' 'environment to be deployed. Default: %(default)s', - default='env.yaml') + action='append', + default=[]) parser.add_argument('--id', help='Identifier to add to all resource names. The ' 'resulting names will look like undercloud-ID or ' @@ -68,7 +69,12 @@ def _process_args(args): if args.role and not args.quintupleo: raise RuntimeError('--role requires --quintupleo') - env_path = args.env + # NOTE(bnemec): We changed the way the --env parameter works such that the + # default is no longer 'env.yaml' but instead an empty list. However, for + # compatibility we need to maintain the ability to default to env.yaml + # if --env is not explicitly specified. + if not args.env: + args.env = ['env.yaml'] if args.name: stack_name = args.name else: @@ -81,60 +87,85 @@ def _process_args(args): stack_template = 'templates/quintupleo.yaml' return stack_name, stack_template -def _add_identifier(env_data, name, identifier, default=None, parameter=True): - param_key = 'parameters' - if not parameter: - param_key = 'parameter_defaults' - if param_key not in env_data or not env_data[param_key]: - env_data[param_key] = {} - original = env_data[param_key].get(name) +def _add_identifier(env_data, name, identifier, default=None): + # We require both sections for id environments + if not env_data.get('parameters'): + env_data['parameters'] = {} + if not env_data.get('parameter_defaults'): + env_data['parameter_defaults'] = {} + parameter = False + try: + original = env_data['parameters'][name] + parameter = True + except KeyError: + original = env_data['parameter_defaults'].get(name) if original is None: original = default if original is None: raise RuntimeError('No base value found when adding id') - env_data[param_key][name] = '%s-%s' % (original, identifier) + value = '%s-%s' % (original, identifier) + # If it was passed in as a parameter we need to set it in the parameters + # section or it will be overridden by the original value. We can't always + # do that though because some parameters are not exposed at the top-level. + if parameter: + env_data['parameters'][name] = value + env_data['parameter_defaults'][name] = value + + +def _build_env_data(env_paths): + """Merge env data from the provided paths + + Given a list of files in env_paths, merge the contents of all those + environment files and return the results. + + :param env_paths: A list of env files to operate on. + :returns: A dict containing the merged contents of the provided files. + """ + _, env_data = template_utils.process_multiple_environments_and_files( + env_paths) + return env_data def _generate_id_env(args): - with open(args.env) as f: - env_data = yaml.safe_load(f) + env_data = _build_env_data(args.env) _add_identifier(env_data, 'provision_net', args.id, default='provision') _add_identifier(env_data, 'public_net', args.id, default='public') _add_identifier(env_data, 'baremetal_prefix', args.id, default='baremetal') - # parameter_defaults may exist, but be None, so we need to handle that case - parameter_defaults = env_data.get('parameter_defaults') - if not parameter_defaults: - parameter_defaults = {} - role = parameter_defaults.get('role') + role = env_data['parameter_defaults'].get('role') if role is not None: - env_data['parameters']['baremetal_prefix'] += '-' + role + _add_identifier(env_data, 'baremetal_prefix', role) _add_identifier(env_data, 'bmc_prefix', args.id, default='bmc') _add_identifier(env_data, 'undercloud_name', args.id, default='undercloud') _add_identifier(env_data, 'overcloud_internal_net', args.id, - default='internal', parameter=False) + default='internal') _add_identifier(env_data, 'overcloud_storage_net', args.id, - default='storage', parameter=False) + default='storage') _add_identifier(env_data, 'overcloud_storage_mgmt_net', args.id, - default='storage_mgmt', parameter=False) + default='storage_mgmt') _add_identifier(env_data, 'overcloud_tenant_net', args.id, - default='tenant', parameter=False) + default='tenant') + # We don't modify any resource_registry entries, and because we may be + # writing the new env file to a different path it can break relative paths + # in the resource_registry. + env_data.pop('resource_registry', None) env_path = 'env-%s.yaml' % args.id with open(env_path, 'w') as f: yaml.safe_dump(env_data, f, default_flow_style=False) - return env_path + return args.env + [env_path] -def _validate_env(args, env_path): +def _validate_env(args, env_paths): """Check for invalid environment configurations :param args: Argparse args. - :param env_path: Path of the environment file to validate. + :param env_paths: Path(s) of the environment file(s) to validate. """ if not args.id: - with open(env_path) as f: - env_data = yaml.safe_load(f) + env_data = _build_env_data(env_paths) role = env_data.get('parameter_defaults', {}).get('role') - if (role and - env_data['parameters']['baremetal_prefix'].endswith('-' + - role)): + try: + prefix = env_data['parameters']['baremetal_prefix'] + except KeyError: + prefix = env_data['parameter_defaults']['baremetal_prefix'] + if role and prefix.endswith('-' + role): raise RuntimeError('baremetal_prefix ends with role name. This ' 'will break build-nodes-json. Please choose a ' 'different baremetal_prefix or role name.') @@ -143,13 +174,13 @@ def _get_heat_client(): return os_client_config.make_client('orchestration', cloud=auth.OS_CLOUD) -def _deploy(stack_name, stack_template, env_path, poll): +def _deploy(stack_name, stack_template, env_paths, poll): hclient = _get_heat_client() template_files, template = template_utils.get_template_contents( stack_template) env_files, env = template_utils.process_multiple_environments_and_files( - ['templates/resource-registry.yaml', env_path]) + ['templates/resource-registry.yaml'] + env_paths) all_files = {} all_files.update(template_files) all_files.update(env_files) @@ -182,31 +213,29 @@ def _poll_stack(stack_name, hclient): time.sleep(10) # Abstract out the role file interactions for easier unit testing -def _load_role_data(base_env, role_file, args): - with open(base_env) as f: - base_data = yaml.safe_load(f) +def _load_role_data(base_envs, role_file, args): + base_data = _build_env_data(base_envs) with open(role_file) as f: role_data = yaml.safe_load(f) - with open(args.env) as f: - orig_data = yaml.safe_load(f) + orig_data = _build_env_data(args.env) return base_data, role_data, orig_data def _write_role_file(role_env, role_file): with open(role_file, 'w') as f: yaml.safe_dump(role_env, f, default_flow_style=False) -def _process_role(role_file, base_env, stack_name, args): +def _process_role(role_file, base_envs, stack_name, args): """Merge a partial role env with the base env :param role: Filename of an environment file containing the definition of the role. - :param base_env: Filename of the environment file used to deploy the + :param base_envs: Filename(s) of the environment file(s) used to deploy the stack containing shared resources such as the undercloud and networks. - :param stack_name: Name of the stack deployed using base_env. + :param stack_name: Name of the stack deployed using base_envs. :param args: The command-line arguments object from argparse. """ - base_data, role_data, orig_data = _load_role_data(base_env, role_file, + base_data, role_data, orig_data = _load_role_data(base_envs, role_file, args) inherited_keys = ['baremetal_image', 'bmc_flavor', 'bmc_image', 'external_net', 'key_name', 'os_auth_url', @@ -219,7 +248,7 @@ def _process_role(role_file, base_env, stack_name, args): role_env = role_data # resource_registry is intentionally omitted as it should not be inherited for section in ['parameters', 'parameter_defaults']: - role_env[section].update({ + role_env.setdefault(section, {}).update({ k: v for k, v in base_data.get(section, {}).items() if k in inherited_keys}) # Most of the resource_registry should not be included in role envs. @@ -228,11 +257,17 @@ def _process_role(role_file, base_env, stack_name, args): k: v for k, v in role_env.get('resource_registry', {}).items() if k in allowed_registry_keys} # We need to start with the unmodified prefix - base_prefix = orig_data['parameters']['baremetal_prefix'] + try: + base_prefix = orig_data['parameters']['baremetal_prefix'] + except KeyError: + base_prefix = orig_data['parameter_defaults']['baremetal_prefix'] # But we do need to add the id if one is in use if args.id: base_prefix += '-%s' % args.id - bmc_prefix = base_data['parameters']['bmc_prefix'] + try: + bmc_prefix = base_data['parameters']['bmc_prefix'] + except KeyError: + bmc_prefix = base_data['parameter_defaults']['bmc_prefix'] role = role_data['parameter_defaults']['role'] role_env['parameters']['baremetal_prefix'] = '%s-%s' % (base_prefix, role) role_env['parameters']['bmc_prefix'] = '%s-%s' % (bmc_prefix, role) @@ -240,22 +275,22 @@ def _process_role(role_file, base_env, stack_name, args): _write_role_file(role_env, role_file) return role_file, role -def _deploy_roles(stack_name, args, env_path): +def _deploy_roles(stack_name, args, env_paths): for r in args.role: - role_env, role_name = _process_role(r, env_path, stack_name, args) + role_env, role_name = _process_role(r, env_paths, stack_name, args) _deploy(stack_name + '-%s' % role_name, 'templates/virtual-baremetal.yaml', - role_env, poll=True) + [role_env], poll=True) if __name__ == '__main__': args = _parse_args() - env_path = args.env + env_paths = args.env stack_name, stack_template = _process_args(args) if args.id: - env_path = _generate_id_env(args) - _validate_env(args, env_path) + env_paths = _generate_id_env(args) + _validate_env(args, env_paths) poll = args.poll if args.role: poll = True - _deploy(stack_name, stack_template, env_path, poll=poll) - _deploy_roles(stack_name, args, env_path) + _deploy(stack_name, stack_template, env_paths, poll=poll) + _deploy_roles(stack_name, args, env_paths) diff --git a/openstack_virtual_baremetal/tests/test_build_nodes_json.py b/openstack_virtual_baremetal/tests/test_build_nodes_json.py index 429c1ad..f43ee77 100644 --- a/openstack_virtual_baremetal/tests/test_build_nodes_json.py +++ b/openstack_virtual_baremetal/tests/test_build_nodes_json.py @@ -97,12 +97,11 @@ class TestBuildNodesJson(testtools.TestCase): args = mock.Mock() args.env = 'foo.yaml' args.add_undercloud = False - mock_env = {'parameters': + mock_env = {'parameter_defaults': {'bmc_prefix': 'bmc-foo', 'baremetal_prefix': 'baremetal-foo', 'provision_net': 'provision-foo' }, - 'parameter_defaults': {} } mock_load.return_value = mock_env bmc_base, baremetal_base, provision_net, undercloud_name = ( @@ -119,12 +118,12 @@ class TestBuildNodesJson(testtools.TestCase): args = mock.Mock() args.env = 'foo.yaml' args.add_undercloud = False - mock_env = {'parameters': + mock_env = {'parameter_defaults': {'bmc_prefix': 'bmc', 'baremetal_prefix': 'baremetal', - 'provision_net': 'provision' + 'provision_net': 'provision', + 'role': 'foo', }, - 'parameter_defaults': {'role': 'foo'} } mock_load.return_value = mock_env bmc_base, baremetal_base, provision_net, undercloud_name = ( @@ -141,12 +140,12 @@ class TestBuildNodesJson(testtools.TestCase): args = mock.Mock() args.env = 'foo.yaml' args.add_undercloud = False - mock_env = {'parameters': + mock_env = {'parameter_defaults': {'bmc_prefix': 'bmc-foo', 'baremetal_prefix': 'baremetal-foo-bar', - 'provision_net': 'provision-foo' + 'provision_net': 'provision-foo', + 'role': 'bar', }, - 'parameter_defaults': {'role': 'bar'} } mock_load.return_value = mock_env bmc_base, baremetal_base, provision_net, undercloud_name = ( diff --git a/openstack_virtual_baremetal/tests/test_deploy.py b/openstack_virtual_baremetal/tests/test_deploy.py index eb02378..90a8dba 100755 --- a/openstack_virtual_baremetal/tests/test_deploy.py +++ b/openstack_virtual_baremetal/tests/test_deploy.py @@ -67,27 +67,43 @@ class TestProcessArgs(unittest.TestCase): mock_args.quintupleo = False self.assertRaises(RuntimeError, deploy._process_args, mock_args) + def test_role_quintupleo(self): + mock_args = mock.Mock() + mock_args.role = 'foo.yaml' + mock_args.id = None + mock_args.quintupleo = False + self.assertRaises(RuntimeError, deploy._process_args, mock_args) + + def test_maintain_old_default(self): + mock_args = mock.Mock() + mock_args.name = 'foo' + mock_args.quintupleo = True + mock_args.env = [] + name, template = deploy._process_args(mock_args) + self.assertEqual('foo', name) + self.assertEqual('templates/quintupleo.yaml', template) + self.assertEqual(['env.yaml'], mock_args.env) test_env = u"""parameters: provision_net: provision public_net: public baremetal_prefix: baremetal bmc_prefix: bmc - os_user: admin +""" +test_env_param_defaults = u""" +parameter_defaults: + overcloud_internal_net: internalapi """ test_env_output = { - 'parameter_defaults': - {'overcloud_internal_net': 'internal-foo', - 'overcloud_storage_net': 'storage-foo', - 'overcloud_storage_mgmt_net': 'storage_mgmt-foo', - 'overcloud_tenant_net': 'tenant-foo'}, - 'parameters': - {'baremetal_prefix': 'baremetal-foo', - 'undercloud_name': 'undercloud-foo', - 'provision_net': 'provision-foo', - 'public_net': 'public-foo', - 'bmc_prefix': 'bmc-foo', - 'os_user': 'admin'} + 'baremetal_prefix': 'baremetal-foo', + 'undercloud_name': 'undercloud-foo', + 'provision_net': 'provision-foo', + 'public_net': 'public-foo', + 'bmc_prefix': 'bmc-foo', + 'overcloud_internal_net': 'internal-foo', + 'overcloud_storage_net': 'storage-foo', + 'overcloud_storage_mgmt_net': 'storage_mgmt-foo', + 'overcloud_tenant_net': 'tenant-foo' } @@ -96,39 +112,55 @@ class TestIdEnv(unittest.TestCase): env_data = {'parameters': {'foo': 'bar'}} deploy._add_identifier(env_data, 'foo', 'baz') self.assertEqual('bar-baz', env_data['parameters']['foo']) + self.assertEqual('bar-baz', env_data['parameter_defaults']['foo']) def test_add_identifier_defaults(self): env_data = {'parameter_defaults': {'foo': 'bar'}} - deploy._add_identifier(env_data, 'foo', 'baz', parameter=False) + deploy._add_identifier(env_data, 'foo', 'baz') + self.assertNotIn('foo', env_data['parameters']) self.assertEqual('bar-baz', env_data['parameter_defaults']['foo']) - @mock.patch('yaml.safe_dump') - def test_generate(self, mock_safe_dump): - mock_args = mock.Mock() - mock_args.id = 'foo' - env = test_env + 'parameter_defaults:' - with mock.patch('openstack_virtual_baremetal.deploy.open', - mock.mock_open(read_data=env), - create=True) as mock_open: - path = deploy._generate_id_env(mock_args) - self.assertEqual('env-foo.yaml', path) - mock_safe_dump.assert_called_once_with(test_env_output, mock.ANY, - default_flow_style=False) + def test_add_identifier_different_section(self): + env_data = {'parameter_defaults': {'foo': 'bar'}} + deploy._add_identifier(env_data, 'foo', 'baz') + self.assertNotIn('foo', env_data['parameters']) + self.assertEqual('bar-baz', env_data['parameter_defaults']['foo']) + @mock.patch('openstack_virtual_baremetal.deploy._build_env_data') @mock.patch('yaml.safe_dump') - def test_generate_undercloud_name(self, mock_safe_dump): + def test_generate(self, mock_safe_dump, mock_bed): mock_args = mock.Mock() mock_args.id = 'foo' - env = test_env + ' undercloud_name: undercloud\n' + mock_args.env = ['foo.yaml'] + env = test_env + 'parameter_defaults:' + mock_bed.return_value = yaml.safe_load(env) + path = deploy._generate_id_env(mock_args) + self.assertEqual(['foo.yaml', 'env-foo.yaml'], path) + dumped_dict = mock_safe_dump.call_args_list[0][0][0] + for k, v in test_env_output.items(): + if k in mock_bed.return_value['parameters']: + self.assertEqual(v, dumped_dict['parameters'][k]) + self.assertEqual(v, dumped_dict['parameter_defaults'][k]) + + @mock.patch('openstack_virtual_baremetal.deploy._build_env_data') + @mock.patch('yaml.safe_dump') + def test_generate_undercloud_name(self, mock_safe_dump, mock_bed): + mock_args = mock.Mock() + mock_args.id = 'foo' + mock_args.env = ['foo.yaml'] + env = (test_env + test_env_param_defaults + + ' undercloud_name: test-undercloud\n') + mock_bed.return_value = yaml.safe_load(env) env_output = dict(test_env_output) - env_output['parameters']['undercloud_name'] = 'undercloud-foo' - with mock.patch('openstack_virtual_baremetal.deploy.open', - mock.mock_open(read_data=env), - create=True) as mock_open: - path = deploy._generate_id_env(mock_args) - self.assertEqual('env-foo.yaml', path) - mock_safe_dump.assert_called_once_with(env_output, mock.ANY, - default_flow_style=False) + env_output['undercloud_name'] = 'test-undercloud-foo' + env_output['overcloud_internal_net'] = 'internalapi-foo' + path = deploy._generate_id_env(mock_args) + self.assertEqual(['foo.yaml', 'env-foo.yaml'], path) + dumped_dict = mock_safe_dump.call_args_list[0][0][0] + for k, v in env_output.items(): + if k in mock_bed.return_value['parameters']: + self.assertEqual(v, dumped_dict['parameters'][k]) + self.assertEqual(v, dumped_dict['parameter_defaults'][k]) # _process_role test data role_base_data = { @@ -185,6 +217,7 @@ role_specific_data = { role_original_data = { 'parameter_defaults': { 'role': 'control', + 'baremetal_prefix': 'baremetal', }, 'parameters': { 'os_user': 'admin', @@ -202,7 +235,6 @@ role_original_data = { 'external_net': 'external', 'os_password': 'password', 'private_net': 'private', - 'baremetal_prefix': 'baremetal', 'undercloud_flavor': 'undercloud-16', 'node_count': 3, 'bmc_flavor': 'bmc' @@ -240,11 +272,12 @@ class TestDeploy(testtools.TestCase): params = {'auth': auth} expected_params = {'cloud_data': params} mock_cj.return_value = params - deploy._deploy('test', 'template.yaml', 'env.yaml', poll) + deploy._deploy('test', 'template.yaml', ['env.yaml', 'test.yaml'], + poll) mock_tu.get_template_contents.assert_called_once_with('template.yaml') process = mock_tu.process_multiple_environments_and_files process.assert_called_once_with(['templates/resource-registry.yaml', - 'env.yaml']) + 'env.yaml', 'test.yaml']) mock_client.stacks.create.assert_called_once_with( stack_name='test', template=template, @@ -323,6 +356,35 @@ class TestDeploy(testtools.TestCase): self.assertEqual('templates/baremetal-ports-all.yaml', output['resource_registry']['OS::OVB::BaremetalPorts']) + @mock.patch('openstack_virtual_baremetal.deploy._write_role_file') + @mock.patch('openstack_virtual_baremetal.deploy._load_role_data') + def test_process_role_param_defaults(self, mock_load, mock_write): + def move_params_to_param_defaults(d): + data = dict(d) + for k, v in data['parameters'].items(): + data['parameter_defaults'][k] = v + data.pop('parameters', None) + return data + + pd_base_data = move_params_to_param_defaults(role_base_data) + pd_specific_data = move_params_to_param_defaults(role_specific_data) + pd_original_data = move_params_to_param_defaults(role_original_data) + mock_load.return_value = (pd_base_data, pd_specific_data, + pd_original_data) + args = mock.Mock() + args.id = 'foo' + role_file, role = deploy._process_role('foo-compute.yaml', 'foo.yaml', + 'foo', args) + mock_load.assert_called_once_with('foo.yaml', 'foo-compute.yaml', args) + self.assertEqual('env-foo-compute.yaml', role_file) + self.assertEqual('compute', role) + output = mock_write.call_args[0][0] + # These values are computed in _process_role + self.assertEqual('baremetal-foo-compute', + output['parameters']['baremetal_prefix']) + self.assertEqual('bmc-foo-compute', + output['parameters']['bmc_prefix']) + @mock.patch('openstack_virtual_baremetal.deploy._deploy') @mock.patch('openstack_virtual_baremetal.deploy._process_role') def test_deploy_roles(self, mock_process, mock_deploy): @@ -334,7 +396,7 @@ class TestDeploy(testtools.TestCase): 'foo', args) mock_deploy.assert_called_once_with('foo-compute', 'templates/virtual-baremetal.yaml', - 'env-foo-compute.yaml', + ['env-foo-compute.yaml'], poll=True) @mock.patch('openstack_virtual_baremetal.deploy._process_role') @@ -344,35 +406,38 @@ class TestDeploy(testtools.TestCase): deploy._deploy_roles('foo', args, 'foo.yaml') mock_process.assert_not_called() - def _test_validate_env_ends_with_profile(self, mock_id): + def _test_validate_env_ends_with_profile(self, mock_id, mock_bed, + section='parameters'): test_env = dict(role_original_data) - test_env['parameters']['baremetal_prefix'] = 'baremetal-control' - test_env = yaml.safe_dump(test_env) + test_env[section]['baremetal_prefix'] = 'baremetal-control' + mock_bed.return_value = test_env args = mock.Mock() args.id = mock_id - with mock.patch('openstack_virtual_baremetal.deploy.open', - mock.mock_open(read_data=test_env), - create=True) as mock_open: - if not mock_id: - self.assertRaises(RuntimeError, deploy._validate_env, - args, 'foo.yaml') - else: - deploy._validate_env(args, 'foo.yaml') + if not mock_id: + self.assertRaises(RuntimeError, deploy._validate_env, + args, ['foo.yaml']) + else: + deploy._validate_env(args, ['foo.yaml']) - def test_validate_env_fails(self): - self._test_validate_env_ends_with_profile(None) + @mock.patch('openstack_virtual_baremetal.deploy._build_env_data') + def test_validate_env_fails(self, mock_bed): + self._test_validate_env_ends_with_profile(None, mock_bed) - def test_validate_env_with_id(self): - self._test_validate_env_ends_with_profile('foo') + @mock.patch('openstack_virtual_baremetal.deploy._build_env_data') + def test_validate_env_fails_param_defaults(self, mock_bed): + self._test_validate_env_ends_with_profile(None, mock_bed, + 'parameter_defaults') - def test_validate_env(self): - test_env = yaml.safe_dump(role_original_data) + @mock.patch('openstack_virtual_baremetal.deploy._build_env_data') + def test_validate_env_with_id(self, mock_bed): + self._test_validate_env_ends_with_profile('foo', mock_bed) + + @mock.patch('openstack_virtual_baremetal.deploy._build_env_data') + def test_validate_env(self, mock_bed): + mock_bed.return_value = role_original_data args = mock.Mock() args.id = None - with mock.patch('openstack_virtual_baremetal.deploy.open', - mock.mock_open(read_data=test_env), - create=True) as mock_open: - deploy._validate_env(args, 'foo.yaml') + deploy._validate_env(args, ['foo.yaml']) class TestGetHeatClient(testtools.TestCase): diff --git a/sample-env-generator/environments.yaml b/sample-env-generator/environments.yaml new file mode 100644 index 0000000..3b62ac5 --- /dev/null +++ b/sample-env-generator/environments.yaml @@ -0,0 +1,141 @@ +environments: + - name: base + title: Base Configuration Options + description: Basic configuration options needed for all OVB environments + files: + templates/quintupleo.yaml: + parameters: + - bmc_flavor + - bmc_image + - baremetal_flavor + - baremetal_image + - key_name + - private_net + - bmc_prefix + - baremetal_prefix + - node_count + - public_net + - provision_net + - undercloud_name + - undercloud_image + - undercloud_flavor + - external_net + - role + sample_values: + baremetal_image: ipxe-boot + - + name: base-role + title: Base Configuration Options for Secondary Roles + description: | + Configuration options that need to be set when deploying an OVB + environment that has multiple roles. + files: + templates/quintupleo.yaml: + parameters: + - baremetal_flavor + - key_name + - node_count + - role + sample_values: + role: compute + - + name: all-networks + title: Deploy with All Networks Enabled + description: | + Deploy an OVB stack that adds interfaces for all the standard TripleO + network isolation networks. + files: {} + resource_registry: + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-all.yaml + children: + - + name: all-networks-port-security + description: | + Deploy an OVB stack that adds interfaces for all the standard TripleO + network isolation networks. This version uses the port-security + Neutron extension to allow OVB to be run on clouds with security + groups enabled. + resource_registry: + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-all-port-security.yaml + OS::OVB::BMCPort: ../templates/bmc-port-port-security.yaml + OS::OVB::UndercloudPorts: ../templates/undercloud-ports-port-security.yaml + - + name: all-networks-public-bond + title: Deploy with All Networks Enabled and Two Public Interfaces + description: | + Deploy an OVB stack that adds interfaces for all the standard TripleO + network isolation networks. This version will deploy duplicate + public network interfaces on the baremetal instances so that the + public network can be configured as a bond. + resource_registry: + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-public-bond.yaml + - + name: all-networks-public-bond-port-security + title: Deploy with All Networks Enabled and Two Public Interfaces + description: | + Deploy an OVB stack that adds interfaces for all the standard TripleO + network isolation networks. This version will deploy duplicate + public network interfaces on the baremetal instances so that the + public network can be configured as a bond. It will also use the + port-security Neutron extension to allow OVB to be run on clouds with + security groups enabled. + resource_registry: + OS::OVB::BaremetalNetworks: ../templates/baremetal-networks-all.yaml + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-public-bond-port-security.yaml + OS::OVB::BMCPort: ../templates/bmc-port-port-security.yaml + OS::OVB::UndercloudPorts: ../templates/undercloud-ports-port-security.yaml + - + name: port-security + title: Deploy a Basic OVB Environment Using Neutron port-security + description: | + Deploy an OVB stack that uses the Neutron port-security extension to + allow OVB functionality in clouds with security groups enabled. + files: {} + resource_registry: + OS::OVB::BaremetalPorts: ../templates/baremetal-ports-default-port-security.yaml + OS::OVB::BMCPort: ../templates/bmc-port-port-security.yaml + OS::OVB::UndercloudPorts: ../templates/undercloud-ports-port-security.yaml + - + name: create-private-network + title: Create a Private Network + description: | + Create the private network as part of the OVB stack instead of using an + existing one. + files: + templates/private-net-create.yaml: + parameters: all + resource_registry: + OS::OVB::PrivateNetwork: ../templates/private-net-create.yaml + - + name: quintupleo-no-undercloud + title: Disable the Undercloud in a QuintupleO Stack + description: | + Deploy a QuintupleO environment, but do not create the undercloud + instance. + files: {} + resource_registry: + OS::OVB::UndercloudEnvironment: OS::Heat::None + - + name: undercloud-floating-none + title: Do Not Assign a Floating IP to the Undercloud + description: | + When deploying the undercloud, do not assign a floating ip to it. + files: {} + resource_registry: + OS::OVB::UndercloudFloating: ../templates/undercloud-floating-none.yaml + - + name: undercloud-floating-existing + title: Assign the Undercloud an Existing Floating IP + description: | + When deploying the undercloud, assign it an existing floating IP instead + of creating a new one. + files: + templates/undercloud-floating-existing.yaml: + parameters: + - undercloud_floating_ip + - undercloud_floating_ip_id + resource_registry: + OS::OVB::UndercloudFloating: ../templates/undercloud-floating-existing.yaml diff --git a/templates/env.yaml.example b/templates/env.yaml.example index b48e2c5..b82985c 100644 --- a/templates/env.yaml.example +++ b/templates/env.yaml.example @@ -1,3 +1,7 @@ +# DEPRECATED: This sample environment file has been replaced by the one in +# environments/base.yaml and the other sample environments in that directory. +# This file should not be used for new OVB deployments. + parameters: bmc_flavor: bmc bmc_image: CentOS-7-x86_64-GenericCloud diff --git a/templates/quintupleo.yaml b/templates/quintupleo.yaml index 8fb5b41..9d5f947 100644 --- a/templates/quintupleo.yaml +++ b/templates/quintupleo.yaml @@ -162,6 +162,14 @@ parameters: type: string default: '{}' + # Unused parameter for compatibility with the environment generator + role: + type: string + description: | + The default role for nodes in this environment. This parameter is + ignored by Heat, but used by build-nodes-json. + default: '' + resources: provision_network: diff --git a/tox.ini b/tox.ini index ea45aee..f203f26 100644 --- a/tox.ini +++ b/tox.ini @@ -23,6 +23,9 @@ commands = flake8 [testenv:cover] commands = python setup.py test --coverage --coverage-package-name=openstack_virtual_baremetal --testr-args='{posargs}' +[testenv:genconfig] +commands = python bin/environment-generator.py sample-env-generator + [flake8] ignore = H803 show-source = True