Merge "tool: convert heat network-config to ansible j2"
This commit is contained in:
commit
c72909b35a
0
tools/__init__.py
Normal file
0
tools/__init__.py
Normal file
512
tools/convert_heat_nic_config_to_ansible_j2.py
Normal file
512
tools/convert_heat_nic_config_to_ansible_j2.py
Normal file
@ -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
tools/tests/__init__.py
Normal file
0
tools/tests/__init__.py
Normal file
@ -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
|
10
tools/tests/nic_config_convert_samples/stack_env_simple.yaml
Normal file
10
tools/tests/nic_config_convert_samples/stack_env_simple.yaml
Normal file
@ -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
|
303
tools/tests/test_convert_heat_nic_config_to_ansible_j2.py
Normal file
303
tools/tests/test_convert_heat_nic_config_to_ansible_j2.py
Normal file
@ -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')
|
@ -1371,6 +1371,9 @@ for base_path in path_args:
|
||||
dirs.remove('.tox')
|
||||
for f in files:
|
||||
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:
|
||||
print("ERROR: environments/services-docker should not be "
|
||||
"used any more, use environments/services instead: "
|
||||
|
Loading…
Reference in New Issue
Block a user