tool: convert heat network-config to ansible j2
Add a script that does a best effort conversion of a heat network-config tempalte to an ansible j2 network-config template. The script uses a networks data file as input to genereta a map of Heat Parameters to ansible vars. For parameters not in the generated map the stack environment is used, parameter values from the stack environment is hard-coded in the j2 template. A j2 comment is added whenever a value was hard coded, in a header comment and also an inline comment if possible. NOTE: The j2 reference files in the unit tests was created by converting heat templates. Change-Id: I8165a077b87307ca3c2ebee54703a939517dc9bf
This commit is contained in:
parent
666091c949
commit
7de39925d0
|
@ -0,0 +1,512 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# 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 argparse
|
||||||
|
import collections
|
||||||
|
import openstack
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
MIN_VIABLE_MTU_HEADER = (
|
||||||
|
"{% set mtu_list = [ctlplane_mtu] %}\n"
|
||||||
|
"{% for network in role_networks %}\n"
|
||||||
|
"{{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}\n"
|
||||||
|
"{%- endfor %}\n"
|
||||||
|
"{% set min_viable_mtu = mtu_list | max %}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
DUAL_MIN_VIABLE_MTU_HEADER = (
|
||||||
|
"{% set mtu_ctlplane_list = [ctlplane_mtu] %}\n"
|
||||||
|
"{% set mtu_dataplane_list = [] %}\n"
|
||||||
|
"{% for network in role_networks %}\n"
|
||||||
|
"{# This block resolves the minimum viable MTU for interfaces connected to #}\n" # noqa
|
||||||
|
"{# the dataplane network(s), which start by Tenant, and also bonds #}\n"
|
||||||
|
"{# and bridges that carry multiple VLANs. Each VLAN may have different MTU. #}\n" # noqa
|
||||||
|
"{# The bridge, bond or interface must have an MTU to allow the VLAN with the #}\n" # noqa
|
||||||
|
"{# largest MTU. #}\n"
|
||||||
|
"{% if network.startswith('Tenant') %}\n"
|
||||||
|
"{{ mtu_dataplane_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}\n" # noqa
|
||||||
|
"{# This block resolves the minimum viable MTU for interfaces connected to #}\n" # noqa
|
||||||
|
"{# the control plane network(s) (don't start by Tenant), and also bonds #}\n" # noqa
|
||||||
|
"{# and bridges that carry multiple VLANs. Each VLAN may have different MTU. #}\n" # noqa
|
||||||
|
"{# The bridge, bond or interface must have an MTU to allow the VLAN with the #}\n" # noqa
|
||||||
|
"{# largest MTU. #}\n"
|
||||||
|
"{% else %}\n"
|
||||||
|
"{{ mtu_ctlplane_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}\n" # noqa
|
||||||
|
"{%- endfor %}\n"
|
||||||
|
"{% set min_viable_mtu_ctlplane = mtu_ctlplane_list | max %}\n"
|
||||||
|
"{% set min_viable_mtu_dataplane = mtu_dataplane_list | max %}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
UNSUPPORTED_HEAT_INTRINSIC_FUNCTIONS = {
|
||||||
|
'get_file', 'get_resource', 'digest', 'repeat', 'resource_facade',
|
||||||
|
'str_replace', 'str_replace_strict', 'str_split', 'map_merge',
|
||||||
|
'map_replace', 'yaql', 'equals', 'if', 'not', 'and', 'or', 'filter',
|
||||||
|
'make_url', 'contains'
|
||||||
|
}
|
||||||
|
|
||||||
|
QUOTE_FIX = '%_fix_quote_%'
|
||||||
|
DBL_QUOTE_FIX = '%_double_fix_quote_%'
|
||||||
|
|
||||||
|
|
||||||
|
def parse_opts(argv):
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Convert to Ansible Jinja2 NIC config templates.')
|
||||||
|
parser.add_argument('--stack',
|
||||||
|
metavar='STACK_NAME',
|
||||||
|
help='Name or ID of heat stack (default=overcloud)',
|
||||||
|
default='overcloud')
|
||||||
|
parser.add_argument('-n', '--networks_file',
|
||||||
|
metavar='<network_data.yaml>',
|
||||||
|
required=True,
|
||||||
|
help=('Configuration file describing the network '
|
||||||
|
'deployment.'))
|
||||||
|
parser.add_argument('-y', '--yes',
|
||||||
|
default=False,
|
||||||
|
action='store_true',
|
||||||
|
help='Overwrite existing files.')
|
||||||
|
parser.add_argument('template',
|
||||||
|
metavar='TEMPLATE_FILE',
|
||||||
|
help='Existing NIC config template to convert.')
|
||||||
|
|
||||||
|
opts = parser.parse_args(argv[1:])
|
||||||
|
|
||||||
|
return opts
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateDumper(yaml.SafeDumper):
|
||||||
|
def represent_ordered_dict(self, data):
|
||||||
|
return self.represent_dict(data.items())
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateLoader(yaml.SafeLoader):
|
||||||
|
def construct_mapping(self, node):
|
||||||
|
self.flatten_mapping(node)
|
||||||
|
return collections.OrderedDict(self.construct_pairs(node))
|
||||||
|
|
||||||
|
|
||||||
|
TemplateDumper.add_representer(collections.OrderedDict,
|
||||||
|
TemplateDumper.represent_ordered_dict)
|
||||||
|
TemplateLoader.add_constructor(yaml.BaseLoader,
|
||||||
|
TemplateLoader.construct_mapping)
|
||||||
|
|
||||||
|
|
||||||
|
class ConvertToAnsibleJ2(object):
|
||||||
|
|
||||||
|
def __init__(self, stack_env, networks_file):
|
||||||
|
self.stack_env = stack_env
|
||||||
|
self.param_to_var_map = self.create_param_to_var_map(networks_file)
|
||||||
|
self.hard_coded_parameters = list()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def unwrap_j2_var(x):
|
||||||
|
"""Strip jinja2 brackets from string
|
||||||
|
|
||||||
|
When nesting ansible vars in jinja2 the brackets must be
|
||||||
|
removed. This also adds appropriate quote fix prefix and
|
||||||
|
suffix.
|
||||||
|
"""
|
||||||
|
is_ansible_var = False
|
||||||
|
if isinstance(x, str):
|
||||||
|
if x.startswith('{{ ') and x.endswith(' }}'):
|
||||||
|
is_ansible_var = True
|
||||||
|
x = x[3:]
|
||||||
|
x = x[:-3]
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
'Unsupported type {} for method unwrap_j2_var'.format(type(x)))
|
||||||
|
|
||||||
|
if is_ansible_var:
|
||||||
|
return DBL_QUOTE_FIX + '{}'.format(x) + DBL_QUOTE_FIX
|
||||||
|
else:
|
||||||
|
return QUOTE_FIX + '{}'.format(x) + QUOTE_FIX
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def strip_j2_comment(x):
|
||||||
|
"""Strip jinja2 comment from string
|
||||||
|
|
||||||
|
When nesting hard-coded parameter conversions in jinja2 the
|
||||||
|
comment must be removed.
|
||||||
|
"""
|
||||||
|
return re.sub('{#.*#}', '', x)
|
||||||
|
|
||||||
|
def normalize_complex(self, old):
|
||||||
|
if isinstance(old, list):
|
||||||
|
new = list()
|
||||||
|
for i in old:
|
||||||
|
if isinstance(i, str):
|
||||||
|
new.append(self.strip_j2_comment(self.unwrap_j2_var(i)))
|
||||||
|
if isinstance(i, (bool, int)):
|
||||||
|
new.append(i)
|
||||||
|
if isinstance(i, (list, dict)):
|
||||||
|
new.append(self.normalize_complex(i))
|
||||||
|
elif isinstance(old, dict):
|
||||||
|
new = dict()
|
||||||
|
for k, v in old.items():
|
||||||
|
k = QUOTE_FIX + '{}'.format(k) + QUOTE_FIX
|
||||||
|
if isinstance(v, str):
|
||||||
|
new[k] = self.strip_j2_comment(self.unwrap_j2_var(v))
|
||||||
|
if isinstance(v, (bool, int)):
|
||||||
|
new[k] = v
|
||||||
|
if isinstance(v, (list, dict)):
|
||||||
|
new[k] = self.normalize_complex(v)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
'Unsupported type {} for method normalize_complex'.format(
|
||||||
|
type(old)))
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def to_j2_var(x):
|
||||||
|
if not isinstance(x, str):
|
||||||
|
raise RuntimeError(
|
||||||
|
'Unsupported type {} for method to_j2_var'.format(type(x)))
|
||||||
|
|
||||||
|
return '{{{{ {} }}}}'.format(x)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def quote_fix(x):
|
||||||
|
return QUOTE_FIX + '{}'.format(x) + QUOTE_FIX
|
||||||
|
|
||||||
|
def create_param_to_var_map(self, networks_file):
|
||||||
|
_map = {
|
||||||
|
'ControlPlaneIp': self.to_j2_var('ctlplane_ip'),
|
||||||
|
'ControlPlaneSubnetCidr': self.to_j2_var('ctlplane_subnet_cidr'),
|
||||||
|
'ControlPlaneMtu': self.to_j2_var('ctlplane_mtu'),
|
||||||
|
'ControlPlaneDefaultRoute': self.to_j2_var('ctlplane_gateway_ip'),
|
||||||
|
'ControlPlaneStaticRoutes': self.to_j2_var('ctlplane_host_routes'),
|
||||||
|
'DnsServers': self.to_j2_var('ctlplane_dns_nameservers'),
|
||||||
|
'DnsSearchDomains': self.to_j2_var('dns_search_domains'),
|
||||||
|
'NumDpdkInterfaceRxQueues':
|
||||||
|
self.to_j2_var('num_dpdk_interface_rx_queues'),
|
||||||
|
'BondInterfaceOvsOptions':
|
||||||
|
self.to_j2_var('bond_interface_ovs_options')
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(networks_file, 'r') as f:
|
||||||
|
networks = yaml.safe_load(f.read())
|
||||||
|
|
||||||
|
for net in networks:
|
||||||
|
name = net['name']
|
||||||
|
name_lower = net.get('name_lower', net['name'].lower())
|
||||||
|
_map.update({
|
||||||
|
name + 'NetworkVlanID':
|
||||||
|
self.to_j2_var('{}_vlan_id'.format(name_lower)),
|
||||||
|
name + 'IpSubnet':
|
||||||
|
'/'.join([self.to_j2_var('{}_ip'.format(name_lower)),
|
||||||
|
self.to_j2_var('{}_cidr'.format(name_lower))]),
|
||||||
|
name + 'InterfaceDefaultRoute':
|
||||||
|
self.to_j2_var('{}_gateway_ip'.format(name_lower)),
|
||||||
|
name + 'InterfaceRoutes':
|
||||||
|
self.to_j2_var('{}_host_routes'.format(name_lower)),
|
||||||
|
name + 'Mtu':
|
||||||
|
self.to_j2_var('{}_mtu'.format(name_lower))
|
||||||
|
})
|
||||||
|
|
||||||
|
return _map
|
||||||
|
|
||||||
|
def convert_get_param(self, old):
|
||||||
|
param = old['get_param']
|
||||||
|
if isinstance(param, str):
|
||||||
|
if param in self.param_to_var_map:
|
||||||
|
return self.param_to_var_map[param]
|
||||||
|
elif param in self.stack_env.get('parameter_defaults', {}):
|
||||||
|
stack_value = self.stack_env['parameter_defaults'][param]
|
||||||
|
print('INFO - Custom Parameter {} was hard-coded in the '
|
||||||
|
'converted template using the value from the Heat stack '
|
||||||
|
'environment.\n'
|
||||||
|
' To parameterize the value an ansible var must be '
|
||||||
|
'added using the {{role.name}}ExtraGroupVars '
|
||||||
|
'THT interface and the template modified to use the '
|
||||||
|
'ansible var.'.format(param))
|
||||||
|
j2_comment = (
|
||||||
|
'{{# NOTE! Custom parameter {} was hard-coded in '
|
||||||
|
'the converted template. To parameterize use the '
|
||||||
|
'{{role.name}}ExtraGroupVars THT interface and update the '
|
||||||
|
'template to use an ansible var. #}}'.format(param))
|
||||||
|
self.hard_coded_parameters.append(param)
|
||||||
|
if isinstance(stack_value, str):
|
||||||
|
return self.quote_fix(stack_value + j2_comment)
|
||||||
|
else:
|
||||||
|
return stack_value
|
||||||
|
else:
|
||||||
|
print('WARNING - Manual intervention required. Unable to '
|
||||||
|
'convert get_param occurrence: {}'.format(old))
|
||||||
|
return self.quote_fix(
|
||||||
|
'NEED MANUAL CONVERSION: {}'.format(str(old)))
|
||||||
|
elif isinstance(param, list):
|
||||||
|
print('WARNING - can not convert get_param referencing values in '
|
||||||
|
'complex datastructures. Please review the Ansible Jinja2 '
|
||||||
|
'template and convert this manually.')
|
||||||
|
return self.quote_fix(
|
||||||
|
'NEED MANUAL CONVERSION: {}'.format(str(old)))
|
||||||
|
|
||||||
|
raise RuntimeError(
|
||||||
|
'Unexpected Type {} in get_param: {}'.format(type(param), old))
|
||||||
|
|
||||||
|
def convert_get_attr(self, old):
|
||||||
|
attr = old['get_attr']
|
||||||
|
if not isinstance(attr, list):
|
||||||
|
raise RuntimeError(
|
||||||
|
'Attributes for get_attr convertsion must of type list.')
|
||||||
|
|
||||||
|
if 'MinViableMtu' in attr:
|
||||||
|
return self.to_j2_var('min_viable_mtu')
|
||||||
|
elif 'MinViableMtuBondApi' in attr:
|
||||||
|
return self.to_j2_var('min_viable_mtu_ctlplane')
|
||||||
|
elif 'MinViableMtuBondData' in attr:
|
||||||
|
return self.to_j2_var('min_viable_mtu_dataplane')
|
||||||
|
else:
|
||||||
|
print('WARNING - only MinViableMtu and combined '
|
||||||
|
'MinViableMtuBondApi + MinViableMtuBondData attribute can '
|
||||||
|
'be converted. Please review the Ansible Jinja2 template '
|
||||||
|
'and convert this manually.')
|
||||||
|
return 'NEED MANUAL CONVERSION: {}'.format(str(old))
|
||||||
|
|
||||||
|
def convert_list_join(self, list_join_attrs):
|
||||||
|
to_join = list()
|
||||||
|
for x in list_join_attrs[1]:
|
||||||
|
to_join.append(self.recursive_convert(x))
|
||||||
|
|
||||||
|
return list_join_attrs[0].join(to_join)
|
||||||
|
|
||||||
|
def convert_list_concat(self, list_concat_attrs):
|
||||||
|
ansible_concat_tpl = "{} | flatten"
|
||||||
|
to_concatenate = list()
|
||||||
|
if not isinstance(list_concat_attrs, list):
|
||||||
|
raise RuntimeError('list_concat_args must be a list')
|
||||||
|
|
||||||
|
for x in list_concat_attrs:
|
||||||
|
to_concatenate.append(self.recursive_convert(x))
|
||||||
|
|
||||||
|
to_concatenate = self.normalize_complex(to_concatenate)
|
||||||
|
new = ansible_concat_tpl.format(to_concatenate)
|
||||||
|
|
||||||
|
return self.to_j2_var(new)
|
||||||
|
|
||||||
|
def convert_list_concat_unique(self, list_concat_unique_attrs):
|
||||||
|
ansible_concat_unique_tpl = "{} | flatten | unique"
|
||||||
|
to_concatenate = list()
|
||||||
|
if not isinstance(list_concat_unique_attrs, list):
|
||||||
|
raise RuntimeError('list_concat_unique_attrs must be a list')
|
||||||
|
|
||||||
|
for x in list_concat_unique_attrs:
|
||||||
|
to_concatenate.append(self.recursive_convert(x))
|
||||||
|
|
||||||
|
to_concatenate = self.normalize_complex(to_concatenate)
|
||||||
|
new = ansible_concat_unique_tpl.format(to_concatenate)
|
||||||
|
|
||||||
|
return self.to_j2_var(new)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convert_unsupported(old, fn):
|
||||||
|
print('WARNING - can not convert unsupported heat intrinsic function '
|
||||||
|
' {}. Please review the Ansible Jinja2 template and convert '
|
||||||
|
'this manually.'.format(fn))
|
||||||
|
return ('UNSUPPORTED HEAT INTRINSIC FUNCTION {} '
|
||||||
|
'REQUIRES MANUAL CONVERSION {}'.format(fn, old))
|
||||||
|
|
||||||
|
def recursive_convert(self, old):
|
||||||
|
if isinstance(old, (bool, str, int)):
|
||||||
|
new = old
|
||||||
|
elif isinstance(old, dict):
|
||||||
|
for fn in UNSUPPORTED_HEAT_INTRINSIC_FUNCTIONS:
|
||||||
|
if fn in old:
|
||||||
|
return self.convert_unsupported(old, fn)
|
||||||
|
|
||||||
|
if 'get_param' in old:
|
||||||
|
return self.convert_get_param(old)
|
||||||
|
elif 'get_attr' in old:
|
||||||
|
return self.convert_get_attr(old)
|
||||||
|
elif 'list_join' in old:
|
||||||
|
return self.convert_list_join(old['list_join'])
|
||||||
|
elif 'list_concat_unique' in old:
|
||||||
|
return self.convert_list_concat_unique(
|
||||||
|
old['list_concat_unique'])
|
||||||
|
else:
|
||||||
|
new = collections.OrderedDict()
|
||||||
|
for k, v in old.items():
|
||||||
|
if isinstance(v, (bool, str, int)):
|
||||||
|
new[k] = v
|
||||||
|
elif isinstance(v, (list, dict)):
|
||||||
|
new[k] = self.recursive_convert(v)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
'Unexpected Type {} for key: {}'.format(
|
||||||
|
type(v), k))
|
||||||
|
|
||||||
|
elif isinstance(old, list):
|
||||||
|
new = list()
|
||||||
|
for x in old:
|
||||||
|
new.append(self.recursive_convert(x))
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
'Unknown type {} for recursive convert'.format(type(old)))
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def convert_template(self, template):
|
||||||
|
with open(template, 'r') as f:
|
||||||
|
heat_tpl = yaml.safe_load(f.read())
|
||||||
|
|
||||||
|
resources = set(heat_tpl['resources'].keys())
|
||||||
|
|
||||||
|
if not resources.issubset({'OsNetConfigImpl',
|
||||||
|
'MinViableMtu',
|
||||||
|
'MinViableMtuBondApi',
|
||||||
|
'MinViableMtuBondData'}):
|
||||||
|
msg = ('Only OsNetConfigImpl and MinViableMtu resoureces '
|
||||||
|
'supported. Found resources: {}'.format(resources))
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
|
net_config_res = heat_tpl['resources'].get('OsNetConfigImpl')
|
||||||
|
mtu_header = None
|
||||||
|
if heat_tpl['resources'].get('MinViableMtu'):
|
||||||
|
mtu_header = 'single'
|
||||||
|
elif (heat_tpl['resources'].get('MinViableMtuBondApi')
|
||||||
|
and heat_tpl['resources'].get('MinViableMtuBondData')):
|
||||||
|
mtu_header = 'dual'
|
||||||
|
|
||||||
|
if not net_config_res:
|
||||||
|
raise RuntimeError('OsNetConfigImpl resource not found in '
|
||||||
|
'template.')
|
||||||
|
|
||||||
|
net_config_res_props = net_config_res['properties']
|
||||||
|
|
||||||
|
if net_config_res['type'] == 'OS::Heat::Value':
|
||||||
|
h_net_conf = net_config_res_props['value']
|
||||||
|
elif net_config_res['type'] == 'OS::Heat::SoftwareConfig':
|
||||||
|
h_net_conf = net_config_res_props['config']['str_replace'][
|
||||||
|
'params']['$network_config']['network_config']
|
||||||
|
else:
|
||||||
|
raise RuntimeError('No network config found in provided template.')
|
||||||
|
|
||||||
|
j2_config = collections.OrderedDict({'network_config': []})
|
||||||
|
j2_net_conf = j2_config['network_config']
|
||||||
|
|
||||||
|
j2_net_conf.extend(self.recursive_convert(h_net_conf))
|
||||||
|
|
||||||
|
j2_header = None
|
||||||
|
if self.hard_coded_parameters:
|
||||||
|
j2_header = (
|
||||||
|
'{# The values of the following custom heat parameters was '
|
||||||
|
'hard-coded into this template:\n')
|
||||||
|
for param in self.hard_coded_parameters:
|
||||||
|
j2_header += ' * {}\n'.format(param)
|
||||||
|
j2_header += (
|
||||||
|
'To parameterize use the {{role.name}}ExtraGroupVars THT '
|
||||||
|
'interface and update the template to use an ansible var.\n'
|
||||||
|
'#}\n')
|
||||||
|
|
||||||
|
return j2_config, mtu_header, j2_header
|
||||||
|
|
||||||
|
|
||||||
|
def write_j2_template(j2_template, j2_config, mtu_header, j2_header):
|
||||||
|
"""Write the Jinja2 template file
|
||||||
|
|
||||||
|
This is done in three steps because the YAML dumper insists
|
||||||
|
to add quotes:
|
||||||
|
write the template file
|
||||||
|
read the template file
|
||||||
|
re-write it with quotes removed
|
||||||
|
"""
|
||||||
|
with open(j2_template, 'w') as f:
|
||||||
|
if j2_header:
|
||||||
|
f.write(j2_header)
|
||||||
|
f.write('---\n')
|
||||||
|
if mtu_header:
|
||||||
|
if mtu_header == 'single':
|
||||||
|
f.write(MIN_VIABLE_MTU_HEADER)
|
||||||
|
elif mtu_header == 'dual':
|
||||||
|
f.write(DUAL_MIN_VIABLE_MTU_HEADER)
|
||||||
|
yaml.dump(j2_config, f, TemplateDumper, width=256,
|
||||||
|
default_flow_style=False)
|
||||||
|
|
||||||
|
with open(j2_template, 'r') as f:
|
||||||
|
data = f.read()
|
||||||
|
# Remove quote before jinja2 var reference
|
||||||
|
data = data.replace('\'{{', '{{')
|
||||||
|
# Remove quote after jinja2 var reference
|
||||||
|
data = data.replace('}}\'', '}}')
|
||||||
|
# Remove quote before value imported from stack environment
|
||||||
|
data = data.replace('\'' + QUOTE_FIX, '')
|
||||||
|
# Remove quote after value imported from stack environment
|
||||||
|
data = data.replace(QUOTE_FIX + '\'', '')
|
||||||
|
# Remove quote before value imported from stack environment
|
||||||
|
data = data.replace('\'\'' + DBL_QUOTE_FIX, '')
|
||||||
|
# Remove quote after value imported from stack environment
|
||||||
|
data = data.replace(DBL_QUOTE_FIX + '\'\'', '')
|
||||||
|
# Remove quote_fix string
|
||||||
|
data = data.replace(QUOTE_FIX, '')
|
||||||
|
data = data.replace(DBL_QUOTE_FIX, '')
|
||||||
|
|
||||||
|
with open(j2_template, 'w') as f:
|
||||||
|
f.write(data)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_files(opts, template, networks_file, j2_template):
|
||||||
|
if not os.path.exists(template):
|
||||||
|
raise RuntimeError('Template file not found {}.'.format(template))
|
||||||
|
if not os.path.isfile(template):
|
||||||
|
raise RuntimeError('Template {} is not a file.'.format(template))
|
||||||
|
if not os.path.exists(networks_file):
|
||||||
|
raise RuntimeError('Networks file not found, {}.'.format(
|
||||||
|
networks_file))
|
||||||
|
if not os.path.isfile(networks_file):
|
||||||
|
raise RuntimeError('Networks file {} is not a file.'.format(
|
||||||
|
networks_file))
|
||||||
|
if os.path.exists(j2_template) and not opts.yes:
|
||||||
|
raise RuntimeError('Ansible Jinja2 template {} already exists'.format(
|
||||||
|
j2_template))
|
||||||
|
if os.path.exists(j2_template) and not os.path.isfile(j2_template):
|
||||||
|
raise RuntimeError('Existing {} is not a file.'.format(j2_template))
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_stack_environment(stack_name):
|
||||||
|
try:
|
||||||
|
conn = openstack.connect('undercloud')
|
||||||
|
stack = conn.orchestration.find_stack(stack_name)
|
||||||
|
if not stack:
|
||||||
|
print('INFO: Heat stack {} not found.'.format(stack_name))
|
||||||
|
return {}
|
||||||
|
stack_env = conn.orchestration.get_stack_environment(stack)
|
||||||
|
except Exception as e:
|
||||||
|
print('ERROR: Unable to get stack environment.')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
return stack_env
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
opts = parse_opts(sys.argv)
|
||||||
|
|
||||||
|
template = os.path.abspath(opts.template)
|
||||||
|
networks_file = os.path.abspath(opts.networks_file)
|
||||||
|
j2_template = os.path.splitext(template)[0] + '.j2'
|
||||||
|
validate_files(opts, template, networks_file, j2_template)
|
||||||
|
|
||||||
|
stack_env = get_stack_environment(opts.stack)
|
||||||
|
|
||||||
|
converter = ConvertToAnsibleJ2(stack_env, networks_file)
|
||||||
|
|
||||||
|
j2_config, mtu_header, j2_header = converter.convert_template(template)
|
||||||
|
write_j2_template(j2_template, j2_config, mtu_header, j2_header)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
|
@ -0,0 +1,344 @@
|
||||||
|
|
||||||
|
heat_template_version: rocky
|
||||||
|
description: >
|
||||||
|
Software Config to drive os-net-config with 2 Linux bonds. One bond is on a
|
||||||
|
bridge with VLANs attached for the Controller role.
|
||||||
|
parameters:
|
||||||
|
ControlPlaneIp:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the ctlplane network
|
||||||
|
type: string
|
||||||
|
ControlPlaneSubnetCidr:
|
||||||
|
default: ''
|
||||||
|
description: >
|
||||||
|
The subnet CIDR of the control plane network. (The parameter is
|
||||||
|
automatically resolved from the ctlplane subnet's cidr attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: The default route of the control plane network. (The parameter
|
||||||
|
is automatically resolved from the ctlplane subnet's gateway_ip attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneStaticRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the ctlplane network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ControlPlaneMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the network.
|
||||||
|
(The parameter is automatically resolved from the ctlplane network's mtu attribute.)
|
||||||
|
type: number
|
||||||
|
|
||||||
|
StorageIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage network
|
||||||
|
type: string
|
||||||
|
StorageNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Storage network.
|
||||||
|
type: number
|
||||||
|
StorageInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
|
||||||
|
StorageMgmtIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage_mgmt network
|
||||||
|
type: string
|
||||||
|
StorageMgmtNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage_mgmt network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMgmtMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
StorageMgmt network.
|
||||||
|
type: number
|
||||||
|
StorageMgmtInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage_mgmt network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
|
||||||
|
InternalApiIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the internal_api network
|
||||||
|
type: string
|
||||||
|
InternalApiNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the internal_api network traffic.
|
||||||
|
type: number
|
||||||
|
InternalApiMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
InternalApi network.
|
||||||
|
type: number
|
||||||
|
InternalApiInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the internal_api network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
|
||||||
|
TenantIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the tenant network
|
||||||
|
type: string
|
||||||
|
TenantNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the tenant network traffic.
|
||||||
|
type: number
|
||||||
|
TenantMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Tenant network.
|
||||||
|
type: number
|
||||||
|
TenantInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the tenant network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
|
||||||
|
ExternalIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the external network
|
||||||
|
type: string
|
||||||
|
ExternalNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the external network traffic.
|
||||||
|
type: number
|
||||||
|
ExternalMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
External network.
|
||||||
|
type: number
|
||||||
|
ExternalInterfaceDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: default route for the external network
|
||||||
|
type: string
|
||||||
|
ExternalInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the external network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
|
||||||
|
DnsServers: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
DNS servers to use for the Overcloud (2 max for some implementations).
|
||||||
|
If not set the nameservers configured in the ctlplane subnet's
|
||||||
|
dns_nameservers attribute will be used.
|
||||||
|
type: comma_delimited_list
|
||||||
|
DnsSearchDomains: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: A list of DNS search domains to be added (in order) to resolv.conf.
|
||||||
|
type: comma_delimited_list
|
||||||
|
BondInterfaceOvsOptions:
|
||||||
|
default: bond_mode=active-backup
|
||||||
|
description: 'The ovs_options or bonding_options string for the bond
|
||||||
|
interface. Set things like lacp=active and/or bond_mode=balance-slb
|
||||||
|
for OVS bonds or like mode=4 for Linux bonds using this option.'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
|
||||||
|
resources:
|
||||||
|
|
||||||
|
MinViableMtuBondApi:
|
||||||
|
# This resource resolves the minimum viable MTU for interfaces, bonds and
|
||||||
|
# bridges that carry multiple VLANs. Each VLAN may have different MTU. The
|
||||||
|
# bridge, bond or interface must have an MTU to allow the VLAN with the
|
||||||
|
# largest MTU.
|
||||||
|
type: OS::Heat::Value
|
||||||
|
properties:
|
||||||
|
type: number
|
||||||
|
value:
|
||||||
|
yaql:
|
||||||
|
expression: $.data.max()
|
||||||
|
data:
|
||||||
|
- {get_param: ControlPlaneMtu}
|
||||||
|
- {get_param: StorageMtu}
|
||||||
|
- {get_param: StorageMgmtMtu}
|
||||||
|
- {get_param: InternalApiMtu}
|
||||||
|
- {get_param: ExternalMtu}
|
||||||
|
|
||||||
|
MinViableMtuBondData:
|
||||||
|
# This resource resolves the minimum viable MTU for interfaces, bonds and
|
||||||
|
# bridges that carry multiple VLANs. Each VLAN may have different MTU. The
|
||||||
|
# bridge, bond or interface must have an MTU to allow the VLAN with the
|
||||||
|
# largest MTU.
|
||||||
|
type: OS::Heat::Value
|
||||||
|
properties:
|
||||||
|
type: number
|
||||||
|
value:
|
||||||
|
yaql:
|
||||||
|
expression: $.data.max()
|
||||||
|
data:
|
||||||
|
- {get_param: ControlPlaneMtu}
|
||||||
|
- {get_param: TenantMtu}
|
||||||
|
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: ../../scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu:
|
||||||
|
get_param: ControlPlaneMtu
|
||||||
|
use_dhcp: false
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneSubnetCidr
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ControlPlaneStaticRoutes
|
||||||
|
- type: linux_bond
|
||||||
|
name: bond_api
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtuBondApi, value]
|
||||||
|
use_dhcp: false
|
||||||
|
bonding_options:
|
||||||
|
get_param: BondInterfaceOvsOptions
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
domain:
|
||||||
|
get_param: DnsSearchDomains
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtuBondApi, value]
|
||||||
|
primary: true
|
||||||
|
- type: interface
|
||||||
|
name: nic3
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtuBondApi, value]
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMgmtMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageMgmtNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageMgmtIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageMgmtInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu:
|
||||||
|
get_param: InternalApiMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: InternalApiInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: ExternalNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: ExternalIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ExternalInterfaceRoutes
|
||||||
|
- - default: true
|
||||||
|
next_hop:
|
||||||
|
get_param: ExternalInterfaceDefaultRoute
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
members:
|
||||||
|
- type: linux_bond
|
||||||
|
name: bond-data
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtuBondData, value]
|
||||||
|
bonding_options:
|
||||||
|
get_param: BondInterfaceOvsOptions
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic4
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtuBondData, value]
|
||||||
|
primary: true
|
||||||
|
- type: interface
|
||||||
|
name: nic5
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtuBondData, value]
|
||||||
|
- type: vlan
|
||||||
|
device: bond-data
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: TenantInterfaceRoutes
|
||||||
|
outputs:
|
||||||
|
OS::stack_id:
|
||||||
|
description: The OsNetConfigImpl resource.
|
||||||
|
value:
|
||||||
|
get_resource: OsNetConfigImpl
|
|
@ -0,0 +1,298 @@
|
||||||
|
|
||||||
|
heat_template_version: rocky
|
||||||
|
description: >
|
||||||
|
Software Config to drive os-net-config with 2 bonded nics on a bridge with VLANs attached for the Controller role.
|
||||||
|
parameters:
|
||||||
|
ControlPlaneIp:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the ctlplane network
|
||||||
|
type: string
|
||||||
|
ControlPlaneSubnetCidr:
|
||||||
|
default: ''
|
||||||
|
description: >
|
||||||
|
The subnet CIDR of the control plane network. (The parameter is
|
||||||
|
automatically resolved from the ctlplane subnet's cidr attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: The default route of the control plane network. (The parameter
|
||||||
|
is automatically resolved from the ctlplane subnet's gateway_ip attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneStaticRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the ctlplane network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ControlPlaneMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the network.
|
||||||
|
(The parameter is automatically resolved from the ctlplane network's mtu attribute.)
|
||||||
|
type: number
|
||||||
|
|
||||||
|
StorageIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage network
|
||||||
|
type: string
|
||||||
|
StorageNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Storage network.
|
||||||
|
type: number
|
||||||
|
StorageInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
StorageMgmtIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage_mgmt network
|
||||||
|
type: string
|
||||||
|
StorageMgmtNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage_mgmt network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMgmtMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
StorageMgmt network.
|
||||||
|
type: number
|
||||||
|
StorageMgmtInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage_mgmt network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
InternalApiIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the internal_api network
|
||||||
|
type: string
|
||||||
|
InternalApiNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the internal_api network traffic.
|
||||||
|
type: number
|
||||||
|
InternalApiMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
InternalApi network.
|
||||||
|
type: number
|
||||||
|
InternalApiInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the internal_api network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
TenantIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the tenant network
|
||||||
|
type: string
|
||||||
|
TenantNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the tenant network traffic.
|
||||||
|
type: number
|
||||||
|
TenantMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Tenant network.
|
||||||
|
type: number
|
||||||
|
TenantInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the tenant network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ExternalIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the external network
|
||||||
|
type: string
|
||||||
|
ExternalNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the external network traffic.
|
||||||
|
type: number
|
||||||
|
ExternalMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
External network.
|
||||||
|
type: number
|
||||||
|
ExternalInterfaceDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: default route for the external network
|
||||||
|
type: string
|
||||||
|
ExternalInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the external network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
DnsServers: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
DNS servers to use for the Overcloud (2 max for some implementations).
|
||||||
|
If not set the nameservers configured in the ctlplane subnet's
|
||||||
|
dns_nameservers attribute will be used.
|
||||||
|
type: comma_delimited_list
|
||||||
|
DnsSearchDomains: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: A list of DNS search domains to be added (in order) to resolv.conf.
|
||||||
|
type: comma_delimited_list
|
||||||
|
BondInterfaceOvsOptions:
|
||||||
|
default: bond_mode=active-backup
|
||||||
|
description: 'The ovs_options or bonding_options string for the bond
|
||||||
|
interface. Set things like lacp=active and/or bond_mode=balance-slb
|
||||||
|
for OVS bonds or like mode=4 for Linux bonds using this option.'
|
||||||
|
type: string
|
||||||
|
resources:
|
||||||
|
|
||||||
|
MinViableMtu:
|
||||||
|
# This resource resolves the minimum viable MTU for interfaces, bonds and
|
||||||
|
# bridges that carry multiple VLANs. Each VLAN may have different MTU. The
|
||||||
|
# bridge, bond or interface must have an MTU to allow the VLAN with the
|
||||||
|
# largest MTU.
|
||||||
|
type: OS::Heat::Value
|
||||||
|
properties:
|
||||||
|
type: number
|
||||||
|
value:
|
||||||
|
yaql:
|
||||||
|
expression: $.data.max()
|
||||||
|
data:
|
||||||
|
- {get_param: ControlPlaneMtu}
|
||||||
|
- {get_param: StorageMtu}
|
||||||
|
- {get_param: StorageMgmtMtu}
|
||||||
|
- {get_param: InternalApiMtu}
|
||||||
|
- {get_param: TenantMtu}
|
||||||
|
- {get_param: ExternalMtu}
|
||||||
|
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: ../../scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu:
|
||||||
|
get_param: ControlPlaneMtu
|
||||||
|
use_dhcp: false
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneSubnetCidr
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ControlPlaneStaticRoutes
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
domain:
|
||||||
|
get_param: DnsSearchDomains
|
||||||
|
members:
|
||||||
|
- type: ovs_bond
|
||||||
|
name: bond1
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
ovs_options:
|
||||||
|
get_param: BondInterfaceOvsOptions
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
primary: true
|
||||||
|
- type: interface
|
||||||
|
name: nic3
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMgmtMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageMgmtNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageMgmtIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageMgmtInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: InternalApiMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: InternalApiInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: TenantInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: ExternalNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: ExternalIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ExternalInterfaceRoutes
|
||||||
|
- - default: true
|
||||||
|
next_hop:
|
||||||
|
get_param: ExternalInterfaceDefaultRoute
|
||||||
|
outputs:
|
||||||
|
OS::stack_id:
|
||||||
|
description: The OsNetConfigImpl resource.
|
||||||
|
value:
|
||||||
|
get_resource: OsNetConfigImpl
|
|
@ -0,0 +1,239 @@
|
||||||
|
heat_template_version: rocky
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
# Supernets
|
||||||
|
StorageSupernet:
|
||||||
|
type: string
|
||||||
|
StorageMgmtSupernet:
|
||||||
|
type: string
|
||||||
|
InternalApiSupernet:
|
||||||
|
type: string
|
||||||
|
TenantSupernet:
|
||||||
|
type: string
|
||||||
|
ExternalSupernet:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
# Default Routes
|
||||||
|
ControlPlaneDefaultRoute:
|
||||||
|
type: string
|
||||||
|
ControlPlaneEdge1DefaultRoute:
|
||||||
|
type: string
|
||||||
|
ControlPlaneEdge2DefaultRoute:
|
||||||
|
type: string
|
||||||
|
StorageInterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
StorageEdge1InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
StorageEdge2InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
StorageMgmtInterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
StorageMgmtEdge1InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
StorageMgmtEdge2InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
InternalApiInterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
InternalApiEdge1InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
InternalApiEdge2InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
TenantInterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
TenantEdge1InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
TenantEdge2InterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
ExternalInterfaceDefaultRoute:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
# IP subnets
|
||||||
|
StorageIpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
StorageEdge1IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
StorageEdge2IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
StorageMgmtIpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
StorageMgmtEdge1IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
StorageMgmtEdge2IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
InternalApiIpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
InternalApiEdge1IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
InternalApiEdge2IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
TenantIpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
TenantEdge1IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
TenantEdge2IpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
ExternalIpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
ManagementIpSubnet:
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
|
||||||
|
# VLAN IDs
|
||||||
|
StorageNetworkVlanID:
|
||||||
|
default: 121
|
||||||
|
type: number
|
||||||
|
StorageEdge1NetworkVlanID:
|
||||||
|
default: 131
|
||||||
|
type: number
|
||||||
|
StorageEdge2NetworkVlanID:
|
||||||
|
default: 141
|
||||||
|
type: number
|
||||||
|
StorageMgmtNetworkVlanID:
|
||||||
|
default: 122
|
||||||
|
type: number
|
||||||
|
StorageMgmtEdge1NetworkVlanID:
|
||||||
|
default: 132
|
||||||
|
type: number
|
||||||
|
StorageMgmtEdge2NetworkVlanID:
|
||||||
|
default: 142
|
||||||
|
type: number
|
||||||
|
InternalApiNetworkVlanID:
|
||||||
|
default: 123
|
||||||
|
type: number
|
||||||
|
InternalApiEdge1NetworkVlanID:
|
||||||
|
default: 133
|
||||||
|
type: number
|
||||||
|
InternalApiEdge2NetworkVlanID:
|
||||||
|
default: 143
|
||||||
|
type: number
|
||||||
|
TenantNetworkVlanID:
|
||||||
|
default: 124
|
||||||
|
type: number
|
||||||
|
TenantEdge1NetworkVlanID:
|
||||||
|
default: 134
|
||||||
|
type: number
|
||||||
|
TenantEdge2NetworkVlanID:
|
||||||
|
default: 144
|
||||||
|
type: number
|
||||||
|
ExternalNetworkVlanID:
|
||||||
|
default: 200
|
||||||
|
type: number
|
||||||
|
ManagementNetworkVlanID:
|
||||||
|
default: 300
|
||||||
|
type: number
|
||||||
|
|
||||||
|
# Subnet CIDR
|
||||||
|
ControlPlaneSubnetCidr:
|
||||||
|
type: string
|
||||||
|
ControlPlaneEdge1SubnetCidr:
|
||||||
|
type: string
|
||||||
|
ControlPlaneEdge2SubnetCidr:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
ControlPlaneIp:
|
||||||
|
type: string
|
||||||
|
DnsServers:
|
||||||
|
type: comma_delimited_list
|
||||||
|
|
||||||
|
# EC2 metadata server IPs
|
||||||
|
EC2MetadataIp:
|
||||||
|
type: string
|
||||||
|
Edge1EC2MetadataIp:
|
||||||
|
type: string
|
||||||
|
Edge2EC2MetadataIp:
|
||||||
|
type: string
|
||||||
|
|
||||||
|
resources:
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: /usr/share/openstack-tripleo-heat-templates/network/scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneEdge1SubnetCidr
|
||||||
|
routes:
|
||||||
|
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- default: true
|
||||||
|
next_hop:
|
||||||
|
get_param: ControlPlaneEdge1DefaultRoute
|
||||||
|
- - ip_netmask: 192.168.254.0/24
|
||||||
|
next_hop: 192.168.24.1
|
||||||
|
- - ip_netmask: 169.254.169.254/32
|
||||||
|
next_hop:
|
||||||
|
get_param: Edge1EC2MetadataIp
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: br-ex
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageEdge1NetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageEdge1IpSubnet
|
||||||
|
routes:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageSupernet
|
||||||
|
next_hop:
|
||||||
|
get_param: StorageEdge1InterfaceDefaultRoute
|
||||||
|
- type: vlan
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiEdge1NetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiEdge1IpSubnet
|
||||||
|
routes:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiSupernet
|
||||||
|
next_hop:
|
||||||
|
get_param: InternalApiEdge1InterfaceDefaultRoute
|
||||||
|
- type: vlan
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantEdge1NetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantEdge1IpSubnet
|
||||||
|
routes:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantSupernet
|
||||||
|
next_hop:
|
||||||
|
get_param: TenantEdge1InterfaceDefaultRoute
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
OS::stack_id:
|
||||||
|
description: The OsNetConfigImpl resource.
|
||||||
|
value:
|
||||||
|
get_resource: OsNetConfigImpl
|
|
@ -0,0 +1,280 @@
|
||||||
|
|
||||||
|
heat_template_version: rocky
|
||||||
|
description: >
|
||||||
|
Software Config to drive os-net-config to configure multiple interfaces for the Controller role.
|
||||||
|
parameters:
|
||||||
|
ControlPlaneIp:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the ctlplane network
|
||||||
|
type: string
|
||||||
|
ControlPlaneSubnetCidr:
|
||||||
|
default: ''
|
||||||
|
description: >
|
||||||
|
The subnet CIDR of the control plane network. (The parameter is
|
||||||
|
automatically resolved from the ctlplane subnet's cidr attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: The default route of the control plane network. (The parameter
|
||||||
|
is automatically resolved from the ctlplane subnet's gateway_ip attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneStaticRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the ctlplane network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ControlPlaneMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the network.
|
||||||
|
(The parameter is automatically resolved from the ctlplane network's mtu attribute.)
|
||||||
|
type: number
|
||||||
|
|
||||||
|
StorageIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage network
|
||||||
|
type: string
|
||||||
|
StorageMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Storage network.
|
||||||
|
type: number
|
||||||
|
StorageInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
StorageMgmtIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage_mgmt network
|
||||||
|
type: string
|
||||||
|
StorageMgmtMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
StorageMgmt network.
|
||||||
|
type: number
|
||||||
|
StorageMgmtInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage_mgmt network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
InternalApiIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the internal_api network
|
||||||
|
type: string
|
||||||
|
InternalApiMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
InternalApi network.
|
||||||
|
type: number
|
||||||
|
InternalApiInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the internal_api network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
TenantIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the tenant network
|
||||||
|
type: string
|
||||||
|
TenantMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Tenant network.
|
||||||
|
type: number
|
||||||
|
TenantInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the tenant network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ExternalIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the external network
|
||||||
|
type: string
|
||||||
|
ExternalMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
External network.
|
||||||
|
type: number
|
||||||
|
ExternalInterfaceDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: default route for the external network
|
||||||
|
type: string
|
||||||
|
ExternalInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the external network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
|
||||||
|
DnsServers: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
DNS servers to use for the Overcloud (2 max for some implementations).
|
||||||
|
If not set the nameservers configured in the ctlplane subnet's
|
||||||
|
dns_nameservers attribute will be used.
|
||||||
|
type: comma_delimited_list
|
||||||
|
DnsSearchDomains: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: A list of DNS search domains to be added (in order) to resolv.conf.
|
||||||
|
type: comma_delimited_list
|
||||||
|
resources:
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: ../../scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu:
|
||||||
|
get_param: ControlPlaneMtu
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
domain:
|
||||||
|
get_param: DnsSearchDomains
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneSubnetCidr
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ControlPlaneStaticRoutes
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMtu
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic2
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageInterfaceRoutes
|
||||||
|
- type: interface
|
||||||
|
name: nic5
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMgmtMtu
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic5
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMgmtMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageMgmtNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageMgmtIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageMgmtInterfaceRoutes
|
||||||
|
- type: interface
|
||||||
|
name: nic8
|
||||||
|
mtu:
|
||||||
|
get_param: InternalApiMtu
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic8
|
||||||
|
mtu:
|
||||||
|
get_param: InternalApiMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: InternalApiInterfaceRoutes
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: br-tenant
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic11
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
use_dhcp: false
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: TenantInterfaceRoutes
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic14
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
use_dhcp: false
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: ExternalNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: ExternalIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ExternalInterfaceRoutes
|
||||||
|
- - default: true
|
||||||
|
next_hop:
|
||||||
|
get_param: ExternalInterfaceDefaultRoute
|
||||||
|
outputs:
|
||||||
|
OS::stack_id:
|
||||||
|
description: The OsNetConfigImpl resource.
|
||||||
|
value:
|
||||||
|
get_resource: OsNetConfigImpl
|
|
@ -0,0 +1,51 @@
|
||||||
|
resources:
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: /usr/share/openstack-tripleo-heat-templates/network/scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
|
||||||
|
# NIC 1 - Provisioning
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
use_dhcp: false
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneSubnetCidr
|
||||||
|
|
||||||
|
# NIC 2 - Control Group
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic2
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiIpSubnet
|
||||||
|
|
||||||
|
# NIC 3 - Data Group
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic3
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantIpSubnet
|
|
@ -0,0 +1,285 @@
|
||||||
|
|
||||||
|
heat_template_version: rocky
|
||||||
|
description: >
|
||||||
|
Software Config to drive os-net-config to configure VLANs for the Controller role.
|
||||||
|
parameters:
|
||||||
|
ControlPlaneIp:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the ctlplane network
|
||||||
|
type: string
|
||||||
|
ControlPlaneSubnetCidr:
|
||||||
|
default: ''
|
||||||
|
description: >
|
||||||
|
The subnet CIDR of the control plane network. (The parameter is
|
||||||
|
automatically resolved from the ctlplane subnet's cidr attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: The default route of the control plane network. (The parameter
|
||||||
|
is automatically resolved from the ctlplane subnet's gateway_ip attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneStaticRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the ctlplane network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ControlPlaneMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the network.
|
||||||
|
(The parameter is automatically resolved from the ctlplane network's mtu attribute.)
|
||||||
|
type: number
|
||||||
|
|
||||||
|
StorageIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage network
|
||||||
|
type: string
|
||||||
|
StorageNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Storage network.
|
||||||
|
type: number
|
||||||
|
StorageInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
StorageMgmtIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage_mgmt network
|
||||||
|
type: string
|
||||||
|
StorageMgmtNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage_mgmt network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMgmtMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
StorageMgmt network.
|
||||||
|
type: number
|
||||||
|
StorageMgmtInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage_mgmt network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
InternalApiIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the internal_api network
|
||||||
|
type: string
|
||||||
|
InternalApiNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the internal_api network traffic.
|
||||||
|
type: number
|
||||||
|
InternalApiMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
InternalApi network.
|
||||||
|
type: number
|
||||||
|
InternalApiInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the internal_api network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
TenantIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the tenant network
|
||||||
|
type: string
|
||||||
|
TenantNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the tenant network traffic.
|
||||||
|
type: number
|
||||||
|
TenantMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Tenant network.
|
||||||
|
type: number
|
||||||
|
TenantInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the tenant network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ExternalIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the external network
|
||||||
|
type: string
|
||||||
|
ExternalNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the external network traffic.
|
||||||
|
type: number
|
||||||
|
ExternalMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
External network.
|
||||||
|
type: number
|
||||||
|
ExternalInterfaceDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: default route for the external network
|
||||||
|
type: string
|
||||||
|
ExternalInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the external network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
DnsServers: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
DNS servers to use for the Overcloud (2 max for some implementations).
|
||||||
|
If not set the nameservers configured in the ctlplane subnet's
|
||||||
|
dns_nameservers attribute will be used.
|
||||||
|
type: comma_delimited_list
|
||||||
|
DnsSearchDomains: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: A list of DNS search domains to be added (in order) to resolv.conf.
|
||||||
|
type: comma_delimited_list
|
||||||
|
|
||||||
|
resources:
|
||||||
|
|
||||||
|
MinViableMtu:
|
||||||
|
# This resource resolves the minimum viable MTU for interfaces, bonds and
|
||||||
|
# bridges that carry multiple VLANs. Each VLAN may have different MTU. The
|
||||||
|
# bridge, bond or interface must have an MTU to allow the VLAN with the
|
||||||
|
# largest MTU.
|
||||||
|
type: OS::Heat::Value
|
||||||
|
properties:
|
||||||
|
type: number
|
||||||
|
value:
|
||||||
|
yaql:
|
||||||
|
expression: $.data.max()
|
||||||
|
data:
|
||||||
|
- {get_param: ControlPlaneMtu}
|
||||||
|
- {get_param: StorageMtu}
|
||||||
|
- {get_param: StorageMgmtMtu}
|
||||||
|
- {get_param: InternalApiMtu}
|
||||||
|
- {get_param: TenantMtu}
|
||||||
|
- {get_param: ExternalMtu}
|
||||||
|
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: ../../scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
- type: linux_bridge
|
||||||
|
name: bridge_name
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
domain:
|
||||||
|
get_param: DnsSearchDomains
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneSubnetCidr
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ControlPlaneStaticRoutes
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: interface_name
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageNetworkVlanID
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMgmtMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageMgmtNetworkVlanID
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageMgmtIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageMgmtInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: InternalApiMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiNetworkVlanID
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: InternalApiInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantNetworkVlanID
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: TenantInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: ExternalNetworkVlanID
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: ExternalIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ExternalInterfaceRoutes
|
||||||
|
- - default: true
|
||||||
|
next_hop:
|
||||||
|
get_param: ExternalInterfaceDefaultRoute
|
||||||
|
outputs:
|
||||||
|
OS::stack_id:
|
||||||
|
description: The OsNetConfigImpl resource.
|
||||||
|
value:
|
||||||
|
get_resource: OsNetConfigImpl
|
|
@ -0,0 +1,281 @@
|
||||||
|
|
||||||
|
heat_template_version: rocky
|
||||||
|
description: >
|
||||||
|
Software Config to drive os-net-config to configure VLANs for the Controller role.
|
||||||
|
parameters:
|
||||||
|
ControlPlaneIp:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the ctlplane network
|
||||||
|
type: string
|
||||||
|
ControlPlaneSubnetCidr:
|
||||||
|
default: ''
|
||||||
|
description: >
|
||||||
|
The subnet CIDR of the control plane network. (The parameter is
|
||||||
|
automatically resolved from the ctlplane subnet's cidr attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: The default route of the control plane network. (The parameter
|
||||||
|
is automatically resolved from the ctlplane subnet's gateway_ip attribute.)
|
||||||
|
type: string
|
||||||
|
ControlPlaneStaticRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the ctlplane network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ControlPlaneMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the network.
|
||||||
|
(The parameter is automatically resolved from the ctlplane network's mtu attribute.)
|
||||||
|
type: number
|
||||||
|
|
||||||
|
StorageIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage network
|
||||||
|
type: string
|
||||||
|
StorageNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Storage network.
|
||||||
|
type: number
|
||||||
|
StorageInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
StorageMgmtIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the storage_mgmt network
|
||||||
|
type: string
|
||||||
|
StorageMgmtNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the storage_mgmt network traffic.
|
||||||
|
type: number
|
||||||
|
StorageMgmtMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
StorageMgmt network.
|
||||||
|
type: number
|
||||||
|
StorageMgmtInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the storage_mgmt network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
InternalApiIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the internal_api network
|
||||||
|
type: string
|
||||||
|
InternalApiNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the internal_api network traffic.
|
||||||
|
type: number
|
||||||
|
InternalApiMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
InternalApi network.
|
||||||
|
type: number
|
||||||
|
InternalApiInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the internal_api network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
TenantIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the tenant network
|
||||||
|
type: string
|
||||||
|
TenantNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the tenant network traffic.
|
||||||
|
type: number
|
||||||
|
TenantMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
Tenant network.
|
||||||
|
type: number
|
||||||
|
TenantInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the tenant network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
ExternalIpSubnet:
|
||||||
|
default: ''
|
||||||
|
description: IP address/subnet on the external network
|
||||||
|
type: string
|
||||||
|
ExternalNetworkVlanID:
|
||||||
|
default: 1
|
||||||
|
description: Vlan ID for the external network traffic.
|
||||||
|
type: number
|
||||||
|
ExternalMtu:
|
||||||
|
default: 1500
|
||||||
|
description: The maximum transmission unit (MTU) size(in bytes) that is
|
||||||
|
guaranteed to pass through the data path of the segments in the
|
||||||
|
External network.
|
||||||
|
type: number
|
||||||
|
ExternalInterfaceDefaultRoute:
|
||||||
|
default: ''
|
||||||
|
description: default route for the external network
|
||||||
|
type: string
|
||||||
|
ExternalInterfaceRoutes:
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
Routes for the external network traffic.
|
||||||
|
JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}]
|
||||||
|
Unless the default is changed, the parameter is automatically resolved
|
||||||
|
from the subnet host_routes attribute.
|
||||||
|
type: json
|
||||||
|
DnsServers: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: >
|
||||||
|
DNS servers to use for the Overcloud (2 max for some implementations).
|
||||||
|
If not set the nameservers configured in the ctlplane subnet's
|
||||||
|
dns_nameservers attribute will be used.
|
||||||
|
type: comma_delimited_list
|
||||||
|
DnsSearchDomains: # Override this via parameter_defaults
|
||||||
|
default: []
|
||||||
|
description: A list of DNS search domains to be added (in order) to resolv.conf.
|
||||||
|
type: comma_delimited_list
|
||||||
|
|
||||||
|
resources:
|
||||||
|
|
||||||
|
MinViableMtu:
|
||||||
|
# This resource resolves the minimum viable MTU for interfaces, bonds and
|
||||||
|
# bridges that carry multiple VLANs. Each VLAN may have different MTU. The
|
||||||
|
# bridge, bond or interface must have an MTU to allow the VLAN with the
|
||||||
|
# largest MTU.
|
||||||
|
type: OS::Heat::Value
|
||||||
|
properties:
|
||||||
|
type: number
|
||||||
|
value:
|
||||||
|
yaql:
|
||||||
|
expression: $.data.max()
|
||||||
|
data:
|
||||||
|
- {get_param: ControlPlaneMtu}
|
||||||
|
- {get_param: StorageMtu}
|
||||||
|
- {get_param: StorageMgmtMtu}
|
||||||
|
- {get_param: InternalApiMtu}
|
||||||
|
- {get_param: TenantMtu}
|
||||||
|
- {get_param: ExternalMtu}
|
||||||
|
|
||||||
|
OsNetConfigImpl:
|
||||||
|
type: OS::Heat::SoftwareConfig
|
||||||
|
properties:
|
||||||
|
group: script
|
||||||
|
config:
|
||||||
|
str_replace:
|
||||||
|
template:
|
||||||
|
get_file: ../../scripts/run-os-net-config.sh
|
||||||
|
params:
|
||||||
|
$network_config:
|
||||||
|
network_config:
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers:
|
||||||
|
get_param: DnsServers
|
||||||
|
domain:
|
||||||
|
get_param: DnsSearchDomains
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
list_join:
|
||||||
|
- /
|
||||||
|
- - get_param: ControlPlaneIp
|
||||||
|
- get_param: ControlPlaneSubnetCidr
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ControlPlaneStaticRoutes
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu:
|
||||||
|
get_attr: [MinViableMtu, value]
|
||||||
|
# force the MAC address of the bridge to this interface
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: StorageMgmtMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: StorageMgmtNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: StorageMgmtIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: StorageMgmtInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: InternalApiMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: InternalApiNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: InternalApiIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: InternalApiInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: TenantMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: TenantNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: TenantIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: TenantInterfaceRoutes
|
||||||
|
- type: vlan
|
||||||
|
mtu:
|
||||||
|
get_param: ExternalMtu
|
||||||
|
vlan_id:
|
||||||
|
get_param: ExternalNetworkVlanID
|
||||||
|
addresses:
|
||||||
|
- ip_netmask:
|
||||||
|
get_param: ExternalIpSubnet
|
||||||
|
routes:
|
||||||
|
list_concat_unique:
|
||||||
|
- get_param: ExternalInterfaceRoutes
|
||||||
|
- - default: true
|
||||||
|
next_hop:
|
||||||
|
get_param: ExternalInterfaceDefaultRoute
|
||||||
|
outputs:
|
||||||
|
OS::stack_id:
|
||||||
|
description: The OsNetConfigImpl resource.
|
||||||
|
value:
|
||||||
|
get_resource: OsNetConfigImpl
|
|
@ -0,0 +1,95 @@
|
||||||
|
---
|
||||||
|
{% set mtu_ctlplane_list = [ctlplane_mtu] %}
|
||||||
|
{% set mtu_dataplane_list = [] %}
|
||||||
|
{% for network in role_networks %}
|
||||||
|
{# This block resolves the minimum viable MTU for interfaces connected to #}
|
||||||
|
{# the dataplane network(s), which start by Tenant, and also bonds #}
|
||||||
|
{# and bridges that carry multiple VLANs. Each VLAN may have different MTU. #}
|
||||||
|
{# The bridge, bond or interface must have an MTU to allow the VLAN with the #}
|
||||||
|
{# largest MTU. #}
|
||||||
|
{% if network.startswith('Tenant') %}
|
||||||
|
{{ mtu_dataplane_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}
|
||||||
|
{# This block resolves the minimum viable MTU for interfaces connected to #}
|
||||||
|
{# the control plane network(s) (don't start by Tenant), and also bonds #}
|
||||||
|
{# and bridges that carry multiple VLANs. Each VLAN may have different MTU. #}
|
||||||
|
{# The bridge, bond or interface must have an MTU to allow the VLAN with the #}
|
||||||
|
{# largest MTU. #}
|
||||||
|
{% else %}
|
||||||
|
{{ mtu_ctlplane_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}
|
||||||
|
{%- endfor %}
|
||||||
|
{% set min_viable_mtu_ctlplane = mtu_ctlplane_list | max %}
|
||||||
|
{% set min_viable_mtu_dataplane = mtu_dataplane_list | max %}
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu: {{ ctlplane_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}
|
||||||
|
routes: {{ [ctlplane_host_routes] | flatten | unique }}
|
||||||
|
- type: linux_bond
|
||||||
|
name: bond_api
|
||||||
|
mtu: {{ min_viable_mtu_ctlplane }}
|
||||||
|
use_dhcp: false
|
||||||
|
bonding_options: {{ bond_interface_ovs_options }}
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
domain: {{ dns_search_domains }}
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
mtu: {{ min_viable_mtu_ctlplane }}
|
||||||
|
primary: true
|
||||||
|
- type: interface
|
||||||
|
name: nic3
|
||||||
|
mtu: {{ min_viable_mtu_ctlplane }}
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu: {{ storage_mtu }}
|
||||||
|
vlan_id: {{ storage_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_ip }}/{{ storage_cidr }}
|
||||||
|
routes: {{ [storage_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu: {{ storage_mgmt_mtu }}
|
||||||
|
vlan_id: {{ storage_mgmt_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_mgmt_ip }}/{{ storage_mgmt_cidr }}
|
||||||
|
routes: {{ [storage_mgmt_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu: {{ internal_api_mtu }}
|
||||||
|
vlan_id: {{ internal_api_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_api_ip }}/{{ internal_api_cidr }}
|
||||||
|
routes: {{ [internal_api_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
device: bond_api
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
vlan_id: {{ external_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ external_ip }}/{{ external_cidr }}
|
||||||
|
routes: {{ [external_host_routes, [{'default': True, 'next_hop': external_gateway_ip}]] | flatten | unique }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
members:
|
||||||
|
- type: linux_bond
|
||||||
|
name: bond-data
|
||||||
|
mtu: {{ min_viable_mtu_dataplane }}
|
||||||
|
bonding_options: {{ bond_interface_ovs_options }}
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic4
|
||||||
|
mtu: {{ min_viable_mtu_dataplane }}
|
||||||
|
primary: true
|
||||||
|
- type: interface
|
||||||
|
name: nic5
|
||||||
|
mtu: {{ min_viable_mtu_dataplane }}
|
||||||
|
- type: vlan
|
||||||
|
device: bond-data
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
vlan_id: {{ tenant_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenant_ip }}/{{ tenant_cidr }}
|
||||||
|
routes: {{ [tenant_host_routes] | flatten | unique }}
|
|
@ -0,0 +1,61 @@
|
||||||
|
---
|
||||||
|
{% set mtu_list = [ctlplane_mtu] %}
|
||||||
|
{% for network in role_networks %}
|
||||||
|
{{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}
|
||||||
|
{%- endfor %}
|
||||||
|
{% set min_viable_mtu = mtu_list | max %}
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu: {{ ctlplane_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}
|
||||||
|
routes: {{ [ctlplane_host_routes] | flatten | unique }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
domain: {{ dns_search_domains }}
|
||||||
|
members:
|
||||||
|
- type: ovs_bond
|
||||||
|
name: bond1
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
ovs_options: {{ bond_interface_ovs_options }}
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
primary: true
|
||||||
|
- type: interface
|
||||||
|
name: nic3
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ storage_mtu }}
|
||||||
|
vlan_id: {{ storage_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_ip }}/{{ storage_cidr }}
|
||||||
|
routes: {{ [storage_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ storage_mgmt_mtu }}
|
||||||
|
vlan_id: {{ storage_mgmt_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_mgmt_ip }}/{{ storage_mgmt_cidr }}
|
||||||
|
routes: {{ [storage_mgmt_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ internal_api_mtu }}
|
||||||
|
vlan_id: {{ internal_api_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_api_ip }}/{{ internal_api_cidr }}
|
||||||
|
routes: {{ [internal_api_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
vlan_id: {{ tenant_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenant_ip }}/{{ tenant_cidr }}
|
||||||
|
routes: {{ [tenant_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
vlan_id: {{ external_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ external_ip }}/{{ external_cidr }}
|
||||||
|
routes: {{ [external_host_routes, [{'default': True, 'next_hop': external_gateway_ip}]] | flatten | unique }}
|
|
@ -0,0 +1,48 @@
|
||||||
|
{# The values of the following custom heat parameters was hard-coded into this template:
|
||||||
|
* ControlPlaneEdge1SubnetCidr
|
||||||
|
* ControlPlaneEdge1DefaultRoute
|
||||||
|
* Edge1EC2MetadataIp
|
||||||
|
* StorageSupernet
|
||||||
|
* InternalApiSupernet
|
||||||
|
* TenantSupernet
|
||||||
|
To parameterize use the {{role.name}}ExtraGroupVars THT interface and update the template to use an ansible var.
|
||||||
|
#}
|
||||||
|
---
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/24{# NOTE! Custom parameter ControlPlaneEdge1SubnetCidr was hard-coded in the converted template. To parameterize use the {role.name}ExtraGroupVars THT interface and update the template to use an ansible var. #}
|
||||||
|
routes: {{ [{'default': True, 'next_hop': '172.16.1.201'}, [{'ip_netmask': '192.168.254.0/24',
|
||||||
|
'next_hop': '192.168.24.1'}], [{'ip_netmask': '169.254.169.254/32', 'next_hop': '172.16.1.201'}]]
|
||||||
|
| flatten | unique }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: br-ex
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ storageedge1_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storageedge1_ip }}/{{ storageedge1_cidr }}
|
||||||
|
routes:
|
||||||
|
- ip_netmask: 172.18.0.0/16{# NOTE! Custom parameter StorageSupernet was hard-coded in the converted template. To parameterize use the {role.name}ExtraGroupVars THT interface and update the template to use an ansible var. #}
|
||||||
|
next_hop: {{ storageedge1_gateway_ip }}
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ internal_apiedge1_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_apiedge1_ip }}/{{ internal_apiedge1_cidr }}
|
||||||
|
routes:
|
||||||
|
- ip_netmask: 172.20.0.0/16{# NOTE! Custom parameter InternalApiSupernet was hard-coded in the converted template. To parameterize use the {role.name}ExtraGroupVars THT interface and update the template to use an ansible var. #}
|
||||||
|
next_hop: {{ internal_apiedge1_gateway_ip }}
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ tenantedge1_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenantedge1_ip }}/{{ tenantedge1_cidr }}
|
||||||
|
routes:
|
||||||
|
- ip_netmask: 172.21.0.0/16{# NOTE! Custom parameter TenantSupernet was hard-coded in the converted template. To parameterize use the {role.name}ExtraGroupVars THT interface and update the template to use an ansible var. #}
|
||||||
|
next_hop: {{ tenantedge1_gateway_ip }}
|
|
@ -0,0 +1,39 @@
|
||||||
|
---
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/NEED MANUAL CONVERSION: {''get_param'': ''ControlPlaneEdge1SubnetCidr''}
|
||||||
|
routes: {{ [{'default': True, 'next_hop': "NEED MANUAL CONVERSION: {''get_param'': ''ControlPlaneEdge1DefaultRoute''}"}, [{'ip_netmask':
|
||||||
|
'192.168.254.0/24', 'next_hop': '192.168.24.1'}], [{'ip_netmask': '169.254.169.254/32', 'next_hop':
|
||||||
|
"NEED MANUAL CONVERSION: {''get_param'': ''Edge1EC2MetadataIp''}"}]] | flatten | unique }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: br-ex
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ storageedge1_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storageedge1_ip }}/{{ storageedge1_cidr }}
|
||||||
|
routes:
|
||||||
|
- ip_netmask: NEED MANUAL CONVERSION: {''get_param'': ''StorageSupernet''}
|
||||||
|
next_hop: {{ storageedge1_gateway_ip }}
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ internal_apiedge1_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_apiedge1_ip }}/{{ internal_apiedge1_cidr }}
|
||||||
|
routes:
|
||||||
|
- ip_netmask: NEED MANUAL CONVERSION: {''get_param'': ''InternalApiSupernet''}
|
||||||
|
next_hop: {{ internal_apiedge1_gateway_ip }}
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ tenantedge1_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenantedge1_ip }}/{{ tenantedge1_cidr }}
|
||||||
|
routes:
|
||||||
|
- ip_netmask: NEED MANUAL CONVERSION: {''get_param'': ''TenantSupernet''}
|
||||||
|
next_hop: {{ tenantedge1_gateway_ip }}
|
|
@ -0,0 +1,78 @@
|
||||||
|
---
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu: {{ ctlplane_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
domain: {{ dns_search_domains }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}
|
||||||
|
routes: {{ [ctlplane_host_routes] | flatten | unique }}
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
mtu: {{ storage_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic2
|
||||||
|
mtu: {{ storage_mtu }}
|
||||||
|
vlan_id: {{ storage_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_ip }}/{{ storage_cidr }}
|
||||||
|
routes: {{ [storage_host_routes] | flatten | unique }}
|
||||||
|
- type: interface
|
||||||
|
name: nic5
|
||||||
|
mtu: {{ storage_mgmt_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic5
|
||||||
|
mtu: {{ storage_mgmt_mtu }}
|
||||||
|
vlan_id: {{ storage_mgmt_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_mgmt_ip }}/{{ storage_mgmt_cidr }}
|
||||||
|
routes: {{ [storage_mgmt_host_routes] | flatten | unique }}
|
||||||
|
- type: interface
|
||||||
|
name: nic8
|
||||||
|
mtu: {{ internal_api_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic8
|
||||||
|
mtu: {{ internal_api_mtu }}
|
||||||
|
vlan_id: {{ internal_api_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_api_ip }}/{{ internal_api_cidr }}
|
||||||
|
routes: {{ [internal_api_host_routes] | flatten | unique }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: br-tenant
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic11
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
vlan_id: {{ tenant_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenant_ip }}/{{ tenant_cidr }}
|
||||||
|
routes: {{ [tenant_host_routes] | flatten | unique }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
use_dhcp: false
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic14
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
vlan_id: {{ external_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ external_ip }}/{{ external_cidr }}
|
||||||
|
routes: {{ [external_host_routes, [{'default': True, 'next_hop': external_gateway_ip}]] | flatten | unique }}
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
network_config:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
use_dhcp: false
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}
|
||||||
|
- type: interface
|
||||||
|
name: nic2
|
||||||
|
use_dhcp: false
|
||||||
|
- type: vlan
|
||||||
|
device: nic2
|
||||||
|
vlan_id: {{ internal_api_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_api_ip }}/{{ internal_api_cidr }}
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic3
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
vlan_id: {{ tenant_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenant_ip }}/{{ tenant_cidr }}
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
{% set mtu_list = [ctlplane_mtu] %}
|
||||||
|
{% for network in role_networks %}
|
||||||
|
{{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}
|
||||||
|
{%- endfor %}
|
||||||
|
{% set min_viable_mtu = mtu_list | max %}
|
||||||
|
network_config:
|
||||||
|
- type: linux_bridge
|
||||||
|
name: bridge_name
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
domain: {{ dns_search_domains }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}
|
||||||
|
routes: {{ [ctlplane_host_routes] | flatten | unique }}
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: interface_name
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ storage_mtu }}
|
||||||
|
vlan_id: {{ storage_vlan_id }}
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_ip }}/{{ storage_cidr }}
|
||||||
|
routes: {{ [storage_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ storage_mgmt_mtu }}
|
||||||
|
vlan_id: {{ storage_mgmt_vlan_id }}
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_mgmt_ip }}/{{ storage_mgmt_cidr }}
|
||||||
|
routes: {{ [storage_mgmt_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ internal_api_mtu }}
|
||||||
|
vlan_id: {{ internal_api_vlan_id }}
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_api_ip }}/{{ internal_api_cidr }}
|
||||||
|
routes: {{ [internal_api_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
vlan_id: {{ tenant_vlan_id }}
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenant_ip }}/{{ tenant_cidr }}
|
||||||
|
routes: {{ [tenant_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
vlan_id: {{ external_vlan_id }}
|
||||||
|
device: bridge_name
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ external_ip }}/{{ external_cidr }}
|
||||||
|
routes: {{ [external_host_routes, [{'default': True, 'next_hop': external_gateway_ip}]] | flatten | unique }}
|
|
@ -0,0 +1,51 @@
|
||||||
|
---
|
||||||
|
{% set mtu_list = [ctlplane_mtu] %}
|
||||||
|
{% for network in role_networks %}
|
||||||
|
{{ mtu_list.append(lookup('vars', networks_lower[network] ~ '_mtu')) }}
|
||||||
|
{%- endfor %}
|
||||||
|
{% set min_viable_mtu = mtu_list | max %}
|
||||||
|
network_config:
|
||||||
|
- type: ovs_bridge
|
||||||
|
name: bridge_name
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
use_dhcp: false
|
||||||
|
dns_servers: {{ ctlplane_dns_nameservers }}
|
||||||
|
domain: {{ dns_search_domains }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}
|
||||||
|
routes: {{ [ctlplane_host_routes] | flatten | unique }}
|
||||||
|
members:
|
||||||
|
- type: interface
|
||||||
|
name: nic1
|
||||||
|
mtu: {{ min_viable_mtu }}
|
||||||
|
primary: true
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ storage_mtu }}
|
||||||
|
vlan_id: {{ storage_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_ip }}/{{ storage_cidr }}
|
||||||
|
routes: {{ [storage_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ storage_mgmt_mtu }}
|
||||||
|
vlan_id: {{ storage_mgmt_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ storage_mgmt_ip }}/{{ storage_mgmt_cidr }}
|
||||||
|
routes: {{ [storage_mgmt_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ internal_api_mtu }}
|
||||||
|
vlan_id: {{ internal_api_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ internal_api_ip }}/{{ internal_api_cidr }}
|
||||||
|
routes: {{ [internal_api_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ tenant_mtu }}
|
||||||
|
vlan_id: {{ tenant_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ tenant_ip }}/{{ tenant_cidr }}
|
||||||
|
routes: {{ [tenant_host_routes] | flatten | unique }}
|
||||||
|
- type: vlan
|
||||||
|
mtu: {{ external_mtu }}
|
||||||
|
vlan_id: {{ external_vlan_id }}
|
||||||
|
addresses:
|
||||||
|
- ip_netmask: {{ external_ip }}/{{ external_cidr }}
|
||||||
|
routes: {{ [external_host_routes, [{'default': True, 'next_hop': external_gateway_ip}]] | flatten | unique }}
|
|
@ -0,0 +1,32 @@
|
||||||
|
- name: Storage
|
||||||
|
name_lower: storage
|
||||||
|
- name: StorageEdge1
|
||||||
|
name_lower: storageedge1
|
||||||
|
- name: StorageEdge2
|
||||||
|
name_lower: storageedge2
|
||||||
|
|
||||||
|
- name: StorageMgmt
|
||||||
|
name_lower: storage_mgmt
|
||||||
|
- name: StorageMgmtEdge1
|
||||||
|
name_lower: storage_mgmtedge1
|
||||||
|
- name: StorageMgmtEdge2
|
||||||
|
name_lower: storage_mgmtedge2
|
||||||
|
|
||||||
|
- name: InternalApi
|
||||||
|
name_lower: internal_api
|
||||||
|
- name: InternalApiEdge1
|
||||||
|
name_lower: internal_apiedge1
|
||||||
|
- name: InternalApiEdge2
|
||||||
|
name_lower: internal_apiedge2
|
||||||
|
|
||||||
|
- name: Tenant
|
||||||
|
name_lower: tenant
|
||||||
|
- name: TenantEdge1
|
||||||
|
name_lower: tenantedge1
|
||||||
|
- name: TenantEdge2
|
||||||
|
name_lower: tenantedge2
|
||||||
|
|
||||||
|
- name: External
|
||||||
|
name_lower: external
|
||||||
|
- name: Management
|
||||||
|
name_lower: management
|
|
@ -0,0 +1,4 @@
|
||||||
|
- name: InternalApi
|
||||||
|
name_lower: internal_api
|
||||||
|
- name: Tenant
|
||||||
|
name_lower: tenant
|
|
@ -0,0 +1,17 @@
|
||||||
|
parameters: {}
|
||||||
|
resource_registry: {}
|
||||||
|
parameter_defaults:
|
||||||
|
StorageSupernet: 172.18.0.0/16
|
||||||
|
StorageMgmtSupernet: 172.19.0.0/16
|
||||||
|
InternalApiSupernet: 172.20.0.0/16
|
||||||
|
TenantSupernet: 172.21.0.0/16
|
||||||
|
ExternalSupernet: 172.200.0.0/16
|
||||||
|
ControlPlaneDefaultRoute: 172.16.0.200
|
||||||
|
ControlPlaneSubnetCidr: '24'
|
||||||
|
ControlPlaneEdge1DefaultRoute: 172.16.1.201
|
||||||
|
ControlPlaneEdge1SubnetCidr: '24'
|
||||||
|
ControlPlaneEdge2DefaultRoute: 172.16.2.202
|
||||||
|
ControlPlaneEdge2SubnetCidr: '24'
|
||||||
|
EC2MetadataIp: 172.16.0.200
|
||||||
|
Edge1EC2MetadataIp: 172.16.1.201
|
||||||
|
Edge2EC2MetadataIp: 172.16.2.202
|
|
@ -0,0 +1,10 @@
|
||||||
|
parameters: {}
|
||||||
|
resource_registry: {}
|
||||||
|
parameter_defaults:
|
||||||
|
TestStringParameter: test_string
|
||||||
|
TestListParameter:
|
||||||
|
- test_list_element01
|
||||||
|
- test_list_element02
|
||||||
|
TestDictParameter:
|
||||||
|
test_key:
|
||||||
|
test_sub_key: test_value
|
|
@ -0,0 +1,303 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# 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 tempfile
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from oslotest import base
|
||||||
|
|
||||||
|
from tools import convert_heat_nic_config_to_ansible_j2 as converter
|
||||||
|
|
||||||
|
FAKE_PARAM_TO_VAR_MAP = {
|
||||||
|
'ControlPlaneDefaultRoute': '{{ ctlplane_gateway_ip }}',
|
||||||
|
'ControlPlaneIp': '{{ ctlplane_ip }}',
|
||||||
|
'ControlPlaneMtu': '{{ ctlplane_mtu }}',
|
||||||
|
'ControlPlaneStaticRoutes': '{{ ctlplane_host_routes }}',
|
||||||
|
'ControlPlaneSubnetCidr': '{{ ctlplane_subnet_cidr }}',
|
||||||
|
'DnsSearchDomains': '{{ dns_search_domains }}',
|
||||||
|
'DnsServers': '{{ ctlplane_dns_nameservers }}',
|
||||||
|
'InternalApiInterfaceDefaultRoute': '{{ internal_api_gateway_ip }}',
|
||||||
|
'InternalApiInterfaceRoutes': '{{ internal_api_host_routes }}',
|
||||||
|
'InternalApiIpSubnet': '{{ internal_api_ip }}/{{ internal_api_cidr }}',
|
||||||
|
'InternalApiMtu': '{{ internal_api_mtu }}',
|
||||||
|
'InternalApiNetworkVlanID': '{{ internal_api_vlan_id }}',
|
||||||
|
'NumDpdkInterfaceRxQueues': '{{ num_dpdk_interface_rx_queues }}',
|
||||||
|
'BondInterfaceOvsOptions': '{{ bond_interface_ovs_options }}',
|
||||||
|
'TenantInterfaceDefaultRoute': '{{ tenant_gateway_ip }}',
|
||||||
|
'TenantInterfaceRoutes': '{{ tenant_host_routes }}',
|
||||||
|
'TenantIpSubnet': '{{ tenant_ip }}/{{ tenant_cidr }}',
|
||||||
|
'TenantMtu': '{{ tenant_mtu }}',
|
||||||
|
'TenantNetworkVlanID': '{{ tenant_vlan_id }}',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ConvertToAnsibleJ2TestCase(base.BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ConvertToAnsibleJ2TestCase, self).setUp()
|
||||||
|
self.fake_param_to_var_map = FAKE_PARAM_TO_VAR_MAP
|
||||||
|
stack_env_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/stack_env_simple.yaml')
|
||||||
|
networks_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/networks_file_simple.yaml')
|
||||||
|
with open(stack_env_file, 'r') as f:
|
||||||
|
self.fake_stack_env = yaml.safe_load(f.read())
|
||||||
|
self.convert = converter.ConvertToAnsibleJ2(self.fake_stack_env,
|
||||||
|
networks_file)
|
||||||
|
|
||||||
|
def test_to_j2_var(self):
|
||||||
|
self.assertEqual('{{ some_var }}',
|
||||||
|
converter.ConvertToAnsibleJ2.to_j2_var('some_var'))
|
||||||
|
|
||||||
|
def test_to_j2_var_raises_on_unsupported_type(self):
|
||||||
|
for _type in [list(), dict(), int(), bool()]:
|
||||||
|
self.assertRaises(RuntimeError,
|
||||||
|
converter.ConvertToAnsibleJ2.to_j2_var,
|
||||||
|
_type)
|
||||||
|
|
||||||
|
def test_create_param_to_var_map(self):
|
||||||
|
networks_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/networks_file_simple.yaml')
|
||||||
|
param_to_var_map = self.convert.create_param_to_var_map(networks_file)
|
||||||
|
self.assertEqual(self.fake_param_to_var_map.keys(),
|
||||||
|
param_to_var_map.keys())
|
||||||
|
for key in param_to_var_map:
|
||||||
|
self.assertEqual(self.fake_param_to_var_map[key],
|
||||||
|
param_to_var_map[key])
|
||||||
|
|
||||||
|
def test_convert_get_param(self):
|
||||||
|
for k, v in self.fake_param_to_var_map.items():
|
||||||
|
old = {'get_param': k}
|
||||||
|
new = self.convert.convert_get_param(old)
|
||||||
|
self.assertEqual(v, new)
|
||||||
|
|
||||||
|
for k, v in self.fake_stack_env['parameter_defaults'].items():
|
||||||
|
old = {'get_param': k}
|
||||||
|
new = self.convert.convert_get_param(old)
|
||||||
|
if isinstance(v, str):
|
||||||
|
self.assertTrue(v in new)
|
||||||
|
self.assertTrue(new.startswith(converter.QUOTE_FIX + v))
|
||||||
|
elif isinstance(v, (bool, int, list, dict)):
|
||||||
|
self.assertEqual(v, new)
|
||||||
|
|
||||||
|
def test_convert_get_param_unable_param_not_defined(self):
|
||||||
|
old = {'get_param': 'UNKNOWN_PARAM'}
|
||||||
|
new = self.convert.convert_get_param(old)
|
||||||
|
self.assertEqual(converter.QUOTE_FIX
|
||||||
|
+ ('NEED MANUAL CONVERSION: {\'get_param\': '
|
||||||
|
'\'UNKNOWN_PARAM\'}') + converter.QUOTE_FIX, new)
|
||||||
|
|
||||||
|
def test_convert_get_param_comlex_data_struct_not_supported(self):
|
||||||
|
old = {'get_param': ['COMPLEX', 'DATA']}
|
||||||
|
new = self.convert.convert_get_param(old)
|
||||||
|
self.assertEqual(converter.QUOTE_FIX
|
||||||
|
+ ('NEED MANUAL CONVERSION: {\'get_param\': '
|
||||||
|
'[\'COMPLEX\', \'DATA\']}') + converter.QUOTE_FIX,
|
||||||
|
new)
|
||||||
|
|
||||||
|
def test_convert_get_attr(self):
|
||||||
|
old = {'get_attr': ['MinViableMtu', 'value']}
|
||||||
|
new = self.convert.convert_get_attr(old)
|
||||||
|
self.assertEqual('{{ min_viable_mtu }}', new)
|
||||||
|
|
||||||
|
def test_convert_get_attr_not_suported(self):
|
||||||
|
old = {'get_attr': ['UNSUPPORTED', 'value']}
|
||||||
|
new = self.convert.convert_get_attr(old)
|
||||||
|
self.assertEqual(('NEED MANUAL CONVERSION: '
|
||||||
|
'{\'get_attr\': [\'UNSUPPORTED\', \'value\']}'), new)
|
||||||
|
|
||||||
|
def test_convert_list_join(self):
|
||||||
|
list_join_attrs = ['/', ['foo', 'bar']]
|
||||||
|
new = self.convert.convert_list_join(list_join_attrs)
|
||||||
|
self.assertEqual('foo/bar', new)
|
||||||
|
|
||||||
|
def test_convert_list_concat(self):
|
||||||
|
list_concat_attrs = [['a_list', 'list_a'], ['list_b', 'b_list']]
|
||||||
|
new = self.convert.convert_list_concat(list_concat_attrs)
|
||||||
|
self.assertEqual(
|
||||||
|
("{{ [['%_fix_quote_%a_list%_fix_quote_%', "
|
||||||
|
"'%_fix_quote_%list_a%_fix_quote_%'], "
|
||||||
|
"['%_fix_quote_%list_b%_fix_quote_%', "
|
||||||
|
"'%_fix_quote_%b_list%_fix_quote_%']] "
|
||||||
|
"| flatten }}"), new)
|
||||||
|
|
||||||
|
def test_convert_list_concat_raise_if_not_list(self):
|
||||||
|
list_concat_attrs = 'NOT_A_LIST'
|
||||||
|
self.assertRaises(RuntimeError,
|
||||||
|
self.convert.convert_list_concat,
|
||||||
|
list_concat_attrs)
|
||||||
|
|
||||||
|
def test_convert_list_concat_unique(self):
|
||||||
|
convert_list_concat_unique = [['a_list', 'b_list'],
|
||||||
|
['list_b', 'b_list']]
|
||||||
|
new = self.convert.convert_list_concat_unique(
|
||||||
|
convert_list_concat_unique)
|
||||||
|
self.assertEqual(
|
||||||
|
("{{ [['%_fix_quote_%a_list%_fix_quote_%', "
|
||||||
|
"'%_fix_quote_%b_list%_fix_quote_%'], "
|
||||||
|
"['%_fix_quote_%list_b%_fix_quote_%', "
|
||||||
|
"'%_fix_quote_%b_list%_fix_quote_%']] "
|
||||||
|
"| flatten | unique }}"), new)
|
||||||
|
|
||||||
|
def test_convert_list_concat_unique_raise_if_not_list(self):
|
||||||
|
convert_list_concat_unique = 'NOT_A_LIST'
|
||||||
|
self.assertRaises(RuntimeError,
|
||||||
|
self.convert.convert_list_concat_unique,
|
||||||
|
convert_list_concat_unique)
|
||||||
|
|
||||||
|
def test_recursive_convert_str_bool_int_not_converted(self):
|
||||||
|
# old is a string
|
||||||
|
self.assertEqual('string', self.convert.recursive_convert('string'))
|
||||||
|
# old is a boolean
|
||||||
|
self.assertEqual(True, self.convert.recursive_convert(True))
|
||||||
|
# old is a number
|
||||||
|
self.assertEqual(1, self.convert.recursive_convert(1))
|
||||||
|
|
||||||
|
def test_recursive_convert_nothing_to_convert(self):
|
||||||
|
old = {'foo': 'bar', 'baz': ['a', 'b', {'c': 'd'}]}
|
||||||
|
self.assertEqual(old, self.convert.recursive_convert(old))
|
||||||
|
|
||||||
|
def test_recursive_convert_complex(self):
|
||||||
|
addresses = [
|
||||||
|
{'ip_netmask': {
|
||||||
|
'list_join': ['/',
|
||||||
|
[{'get_param': 'ControlPlaneIp'},
|
||||||
|
{'get_param': 'ControlPlaneSubnetCidr'}]
|
||||||
|
]}}]
|
||||||
|
old = {'type': 'interface', 'name': 'nic1', 'use_dhcp': 'false',
|
||||||
|
'addresses': addresses}
|
||||||
|
expected = {'name': 'nic1', 'type': 'interface', 'use_dhcp': 'false',
|
||||||
|
'addresses': [
|
||||||
|
{'ip_netmask':
|
||||||
|
'{{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}'}]}
|
||||||
|
self.assertEqual(expected, self.convert.recursive_convert(old))
|
||||||
|
|
||||||
|
def test_recursive_convert_unsupported_intrinsic_fn(self):
|
||||||
|
for fn in converter.UNSUPPORTED_HEAT_INTRINSIC_FUNCTIONS:
|
||||||
|
old = {'foo': 'bar', 'baz': ['a', 'b', {fn: 'd'}]}
|
||||||
|
unsupported_str = (
|
||||||
|
"UNSUPPORTED HEAT INTRINSIC FUNCTION {x} REQUIRES MANUAL "
|
||||||
|
"CONVERSION {{'{x}': 'd'}}".format(x=fn))
|
||||||
|
new = {'foo': 'bar', 'baz': ['a', 'b', unsupported_str]}
|
||||||
|
self.assertEqual(new, self.convert.recursive_convert(old))
|
||||||
|
|
||||||
|
def test_convert_template(self):
|
||||||
|
template_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/heat_templates/simple.yaml')
|
||||||
|
j2_config, mtu_header, j2_header = self.convert.convert_template(
|
||||||
|
template_file)
|
||||||
|
self.assertIsNone(mtu_header)
|
||||||
|
self.assertIsNone(j2_header)
|
||||||
|
expected = [
|
||||||
|
{'name': 'nic1',
|
||||||
|
'type': 'interface',
|
||||||
|
'use_dhcp': False,
|
||||||
|
'addresses': [{
|
||||||
|
'ip_netmask': '{{ ctlplane_ip }}/{{ ctlplane_subnet_cidr }}'}
|
||||||
|
]},
|
||||||
|
{'name': 'nic2',
|
||||||
|
'type': 'interface',
|
||||||
|
'use_dhcp': False},
|
||||||
|
{'type': 'vlan',
|
||||||
|
'device': 'nic2',
|
||||||
|
'vlan_id': '{{ internal_api_vlan_id }}',
|
||||||
|
'addresses': [{
|
||||||
|
'ip_netmask': '{{ internal_api_ip }}/{{ internal_api_cidr }}'}
|
||||||
|
]},
|
||||||
|
{'type': 'ovs_bridge',
|
||||||
|
'name': 'bridge_name',
|
||||||
|
'dns_servers': '{{ ctlplane_dns_nameservers }}',
|
||||||
|
'members': [
|
||||||
|
{'type': 'interface',
|
||||||
|
'name': 'nic3',
|
||||||
|
'primary': True},
|
||||||
|
{'type': 'vlan',
|
||||||
|
'vlan_id': '{{ tenant_vlan_id }}',
|
||||||
|
'addresses': [{
|
||||||
|
'ip_netmask': '{{ tenant_ip }}/{{ tenant_cidr }}'}
|
||||||
|
]},
|
||||||
|
]},
|
||||||
|
]
|
||||||
|
self.assertEqual(expected, j2_config['network_config'])
|
||||||
|
|
||||||
|
def convert_heat_to_ansible_j2(self, heat_template, j2_reference,
|
||||||
|
networks_file='network_file_complex.yaml',
|
||||||
|
stack_env='stack_env_simple.yaml'):
|
||||||
|
networks_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/' + networks_file)
|
||||||
|
template_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/heat_templates/' + heat_template)
|
||||||
|
reference_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/j2_references/' + j2_reference)
|
||||||
|
stack_env_file = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'nic_config_convert_samples/' + stack_env)
|
||||||
|
|
||||||
|
with open(stack_env_file, 'r') as f:
|
||||||
|
stack_env = yaml.safe_load(f.read())
|
||||||
|
convert = converter.ConvertToAnsibleJ2(stack_env, networks_file)
|
||||||
|
j2_config, mtu_header, j2_header = convert.convert_template(
|
||||||
|
template_file)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
j2_template = os.path.abspath(temp_dir) + '/j2_template.j2'
|
||||||
|
converter.write_j2_template(j2_template, j2_config, mtu_header,
|
||||||
|
j2_header)
|
||||||
|
with open(reference_file, 'r') as a:
|
||||||
|
with open(j2_template, 'r') as b:
|
||||||
|
reference = a.read()
|
||||||
|
result = b.read()
|
||||||
|
|
||||||
|
self.assertEqual(reference, result)
|
||||||
|
|
||||||
|
def test_convert_and_write_file_simple(self):
|
||||||
|
self.convert_heat_to_ansible_j2(
|
||||||
|
'simple.yaml', 'simple.j2',
|
||||||
|
networks_file='networks_file_simple.yaml')
|
||||||
|
|
||||||
|
def test_convert_and_write_file_complex01_incomplete(self):
|
||||||
|
self.convert_heat_to_ansible_j2('complex.yaml',
|
||||||
|
'complex_incomplete.j2')
|
||||||
|
|
||||||
|
def test_convert_and_write_file_complex01_complete(self):
|
||||||
|
self.convert_heat_to_ansible_j2('complex.yaml', 'complex_complete.j2',
|
||||||
|
stack_env='stack_env_complex.yaml')
|
||||||
|
|
||||||
|
def test_convert_2_linux_bonds_vlan_controller(self):
|
||||||
|
self.convert_heat_to_ansible_j2('2-linux-bonds-vlans-controller.yaml',
|
||||||
|
'2-linux-bonds-vlans-controller.j2')
|
||||||
|
|
||||||
|
def test_convert_bond_vlans_controller(self):
|
||||||
|
self.convert_heat_to_ansible_j2('bond-vlans-controller.yaml',
|
||||||
|
'bond-vlans-controller.j2')
|
||||||
|
|
||||||
|
def test_convert_multiple_nics_vlans_controller(self):
|
||||||
|
self.convert_heat_to_ansible_j2('multiple-nics-vlans-controller.yaml',
|
||||||
|
'multiple-nics-vlans-controller.j2')
|
||||||
|
|
||||||
|
def test_convert_single_nic_linux_bridge_vlans_controller(self):
|
||||||
|
self.convert_heat_to_ansible_j2(
|
||||||
|
'single-nic-linux-bridge-vlans-controller.yaml',
|
||||||
|
'single-nic-linux-bridge-vlans-controller.j2')
|
||||||
|
|
||||||
|
def test_convert_single_nic_vlans_controller(self):
|
||||||
|
self.convert_heat_to_ansible_j2('single-nic-vlans-controller.yaml',
|
||||||
|
'single-nic-vlans-controller.j2')
|
|
@ -1372,6 +1372,9 @@ for base_path in path_args:
|
||||||
dirs.remove('.tox')
|
dirs.remove('.tox')
|
||||||
for f in files:
|
for f in files:
|
||||||
file_path = os.path.join(subdir, f)
|
file_path = os.path.join(subdir, f)
|
||||||
|
if 'tools/tests/nic_config_convert_samples' in file_path:
|
||||||
|
continue
|
||||||
|
|
||||||
if 'environments/services-docker' in file_path:
|
if 'environments/services-docker' in file_path:
|
||||||
print("ERROR: environments/services-docker should not be "
|
print("ERROR: environments/services-docker should not be "
|
||||||
"used any more, use environments/services instead: "
|
"used any more, use environments/services instead: "
|
||||||
|
|
Loading…
Reference in New Issue