packstack/packstack/plugins/neutron_350.py

1001 lines
40 KiB
Python

# -*- coding: utf-8 -*-
# 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.
"""
Installs and configures Neutron
"""
import re
from packstack.installer import basedefs
from packstack.installer import utils
from packstack.installer import validators
from packstack.installer import processors
from packstack.installer import output_messages
from packstack.installer.utils import split_hosts
from packstack.modules import common
from packstack.modules.documentation import update_params_usage
from packstack.modules.ospluginutils import generate_ssl_cert
# ------------- Neutron Packstack Plugin Initialization --------------
PLUGIN_NAME = "OS-Neutron"
PLUGIN_NAME_COLORED = utils.color_text(PLUGIN_NAME, 'blue')
def initConfig(controller):
conf_params = {
"NEUTRON": [
{"CMD_OPTION": "os-neutron-ks-password",
"PROMPT": "Enter the password for Neutron Keystone access",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_not_empty],
"DEFAULT_VALUE": "PW_PLACEHOLDER",
"PROCESSORS": [processors.process_password],
"MASK_INPUT": True,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_NEUTRON_KS_PW",
"USE_DEFAULT": False,
"NEED_CONFIRM": True,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-db-password",
"PROMPT": "Enter the password for Neutron DB access",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_not_empty],
"DEFAULT_VALUE": "PW_PLACEHOLDER",
"PROCESSORS": [processors.process_password],
"MASK_INPUT": True,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_NEUTRON_DB_PW",
"USE_DEFAULT": False,
"NEED_CONFIRM": True,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-l3-ext-bridge",
"PROMPT": ("Enter the ovs bridge the Neutron L3 agent will use "
"for external traffic, or 'provider' if using "
"provider networks."),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "br-ex",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_L3_EXT_BRIDGE",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-metadata-pw",
"PROMPT": "Enter Neutron metadata agent password",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_not_empty],
"DEFAULT_VALUE": "PW_PLACEHOLDER",
"PROCESSORS": [processors.process_password],
"MASK_INPUT": True,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_NEUTRON_METADATA_PW",
"USE_DEFAULT": False,
"NEED_CONFIRM": True,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-metering-agent-install",
"PROMPT": ("Should Packstack install Neutron L3 Metering agent"),
"OPTION_LIST": ["y", "n"],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": "y",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_NEUTRON_METERING_AGENT_INSTALL",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-vpnaas-install",
"PROMPT": "Would you like to configure neutron VPNaaS?",
"OPTION_LIST": ["y", "n"],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": "n",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_VPNAAS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_LB_AGENT": [
{"CMD_OPTION": "os-neutron-lb-interface-mappings",
"PROMPT": ("Enter a comma separated list of interface mappings "
"for the Neutron linuxbridge plugin"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_LB_INTERFACE_MAPPINGS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_OVS_AGENT": [
{"CMD_OPTION": "os-neutron-ovs-bridge-mappings",
"PROMPT": ("Enter a comma separated list of bridge mappings for "
"the Neutron openvswitch plugin"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "extnet:br-ex",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovs-bridge-interfaces",
"PROMPT": ("Enter a comma separated list of OVS bridge:interface "
"pairs for the Neutron openvswitch plugin"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVS_BRIDGE_IFACES",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovs-bridges-compute",
"PROMPT": ("Enter a comma separated list of bridges for the "
"Neutron OVS plugin in compute nodes. They must "
"be included in os-neutron-ovs-bridge-mappings and "
"os-neutron-ovs-bridge-interfaces."),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVS_BRIDGES_COMPUTE",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovs-external-physnet",
"PROMPT": ("Enter the name of the physical external network as"
"defined in bridge mappings"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "extnet",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVS_EXTERNAL_PHYSNET",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_OVS_AGENT_TUNNEL": [
{"CMD_OPTION": "os-neutron-ovs-tunnel-if",
"PROMPT": ("Enter interface with IP to override the default "
"tunnel local_ip"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVS_TUNNEL_IF",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovs-tunnel-subnets",
"PROMPT": ("Enter comma separated list of subnets used for "
"tunneling to make them allowed by IP filtering."),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVS_TUNNEL_SUBNETS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_OVS_AGENT_VXLAN": [
{"CMD_OPTION": "os-neutron-ovs-vxlan-udp-port",
"CONF_NAME": "CONFIG_NEUTRON_OVS_VXLAN_UDP_PORT",
"PROMPT": "Enter VXLAN UDP port number",
"OPTION_LIST": [],
"VALIDATORS": [validators.validate_port],
"DEFAULT_VALUE": 4789,
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_OVN_AGENT": [
{"CMD_OPTION": "os-neutron-ovn-bridge-mappings",
"PROMPT": ("Enter a comma separated list of bridge mappings for "
"the Neutron Open Virtual Network plugin"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "extnet:br-ex",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVN_BRIDGE_MAPPINGS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovn-bridge-interfaces",
"PROMPT": ("Enter a comma separated list of OVS bridge:interface "
"pairs for the Neutron Open Virtual Network plugin"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVN_BRIDGE_IFACES",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovn-bridges-compute",
"PROMPT": ("Enter a comma separated list of bridges for the "
"Neutron Open Virtual Network plugin in compute nodes."
"They must be included in os-neutron-ovs-bridge-mappings "
"and os-neutron-ovs-bridge-interfaces."),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVN_BRIDGES_COMPUTE",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovn-external-physnet",
"PROMPT": ("Enter the name of the physical external network as"
"defined in bridge mappings"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "extnet",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVN_EXTERNAL_PHYSNET",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_OVN_AGENT_TUNNEL": [
{"CMD_OPTION": "os-neutron-ovn-tunnel-if",
"PROMPT": ("Enter interface with IP to override the default "
"tunnel local IP"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVN_TUNNEL_IF",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ovn-tunnel-subnets",
"PROMPT": ("Enter comma separated list of subnets used for "
"tunneling to make them allowed by IP filtering."),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_OVN_TUNNEL_SUBNETS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
"NEUTRON_ML2_PLUGIN": [
{"CMD_OPTION": "os-neutron-ml2-type-drivers",
"CONF_NAME": "CONFIG_NEUTRON_ML2_TYPE_DRIVERS",
"PROMPT": ("Enter a comma separated list of network type driver "
"entrypoints"),
"OPTION_LIST": ["local", "flat", "vlan", "gre", "vxlan", "geneve"],
"VALIDATORS": [validators.validate_multi_options],
"DEFAULT_VALUE": "geneve,flat",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-tenant-network-types",
"CONF_NAME": "CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES",
"PROMPT": ("Enter a comma separated ordered list of "
"network_types to allocate as tenant networks"),
"OPTION_LIST": ["local", "vlan", "gre", "vxlan", "geneve"],
"VALIDATORS": [validators.validate_multi_options],
"DEFAULT_VALUE": "geneve",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-mechanism-drivers",
"CONF_NAME": "CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS",
"PROMPT": ("Enter a comma separated ordered list of networking "
"mechanism driver entrypoints"),
"OPTION_LIST": ["logger", "test", "linuxbridge", "openvswitch",
"hyperv", "ncs", "arista", "cisco_nexus",
"mlnx", "l2population", "sriovnicswitch", "ovn"],
"VALIDATORS": [validators.validate_multi_options],
"DEFAULT_VALUE": "ovn",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-flat-networks",
"CONF_NAME": "CONFIG_NEUTRON_ML2_FLAT_NETWORKS",
"PROMPT": ("Enter a comma separated list of physical_network "
"names with which flat networks can be created"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "*",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-vlan-ranges",
"CONF_NAME": "CONFIG_NEUTRON_ML2_VLAN_RANGES",
"PROMPT": ("Enter a comma separated list of physical_network "
"names usable for VLAN"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-tunnel-id-ranges",
"CONF_NAME": "CONFIG_NEUTRON_ML2_TUNNEL_ID_RANGES",
"PROMPT": ("Enter a comma separated list of <tun_min>:<tun_max> "
"tuples enumerating ranges of GRE tunnel IDs that "
"are available for tenant network allocation"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-vxlan-group",
"CONF_NAME": "CONFIG_NEUTRON_ML2_VXLAN_GROUP",
"PROMPT": "Enter a multicast group for VXLAN",
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
{"CMD_OPTION": "os-neutron-ml2-vni-ranges",
"CONF_NAME": "CONFIG_NEUTRON_ML2_VNI_RANGES",
"PROMPT": ("Enter a comma separated list of <vni_min>:<vni_max> "
"tuples enumerating ranges of VXLAN VNI IDs that are "
"available for tenant network allocation"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "10:100",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
# We need to ask for this only in case of ML2 plugins
{"CMD_OPTION": "os-neutron-l2-agent",
"PROMPT": ("Enter the name of the L2 agent to be used "
"with Neutron"),
"OPTION_LIST": ["linuxbridge", "openvswitch", "ovn"],
"VALIDATORS": [validators.validate_options],
"DEFAULT_VALUE": "ovn",
"MASK_INPUT": False,
"LOOSE_VALIDATION": False,
"CONF_NAME": "CONFIG_NEUTRON_L2_AGENT",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False,
"MESSAGE": ("You have chosen OVN Neutron backend. Note that this backend does not support the VPNaaS plugin. "
"Geneve will be used as the encapsulation method for tenant networks"),
"MESSAGE_VALUES": ["ovn"]},
{"CMD_OPTION": "os-neutron-ml2-sriov-interface-mappings",
"PROMPT": ("Enter a comma separated list of interface mappings "
"for the Neutron ML2 sriov agent"),
"OPTION_LIST": [],
"VALIDATORS": [],
"DEFAULT_VALUE": "",
"MASK_INPUT": False,
"LOOSE_VALIDATION": True,
"CONF_NAME": "CONFIG_NEUTRON_ML2_SRIOV_INTERFACE_MAPPINGS",
"USE_DEFAULT": False,
"NEED_CONFIRM": False,
"CONDITION": False},
],
}
update_params_usage(basedefs.PACKSTACK_DOC, conf_params)
conf_groups = [
{"GROUP_NAME": "NEUTRON",
"DESCRIPTION": "Neutron config",
"PRE_CONDITION": "CONFIG_NEUTRON_INSTALL",
"PRE_CONDITION_MATCH": "y",
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_ML2_PLUGIN",
"DESCRIPTION": "Neutron ML2 plugin config",
"PRE_CONDITION": neutron_install,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_LB_AGENT",
"DESCRIPTION": "Neutron LB agent config",
"PRE_CONDITION": use_ml2_with_linuxbridge,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_OVS_AGENT",
"DESCRIPTION": "Neutron OVS agent config",
"PRE_CONDITION": use_ml2_with_ovs,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_OVS_AGENT_TUNNEL",
"DESCRIPTION": "Neutron OVS agent config for tunnels",
"PRE_CONDITION": use_ml2_with_ovs,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_OVS_AGENT_VXLAN",
"DESCRIPTION": "Neutron OVS agent config for VXLAN",
"PRE_CONDITION": use_openvswitch_vxlan,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_OVN_AGENT",
"DESCRIPTION": "Neutron OVN agent config",
"PRE_CONDITION": use_ml2_with_ovn,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
{"GROUP_NAME": "NEUTRON_OVN_AGENT_TUNNEL",
"DESCRIPTION": "Neutron OVN agent config for tunnels",
"PRE_CONDITION": use_ml2_with_ovn,
"PRE_CONDITION_MATCH": True,
"POST_CONDITION": False,
"POST_CONDITION_MATCH": True},
]
for group in conf_groups:
params = conf_params[group["GROUP_NAME"]]
controller.addGroup(group, params)
def initSequences(controller):
config = controller.CONF
if config['CONFIG_NEUTRON_INSTALL'] != 'y':
return
if config['CONFIG_IRONIC_INSTALL'] == 'y':
config['CONFIG_NEUTRON_ML2_TYPE_DRIVERS'] += ', flat'
config['CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES'] += ', flat'
if 'openvswitch' not in config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS']:
config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS'] += ', openvswitch'
config['CONFIG_NEUTRON_ML2_FLAT_NETWORKS'] = 'extnet'
if use_ml2_with_sriovnicswitch(config):
if ('openvswitch' not in config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS']
and 'linuxbridge' not in
config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS']):
config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS'] += ', openvswitch'
if use_ml2_with_ovn(config):
if ('ovn' not in config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS']):
config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS'] = 'ovn'
# OVN only supports geneve encapsulation
if ('geneve' not in config['CONFIG_NEUTRON_ML2_TYPE_DRIVERS']):
config['CONFIG_NEUTRON_ML2_TYPE_DRIVERS'] += ', geneve'
config['CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES'] = 'geneve'
# VPNaaS is not supported with OVN
config['CONFIG_NEUTRON_VPNAAS'] = 'n'
config['CONFIG_NEUTRON_METERING_AGENT_INSTALL'] = 'n'
# When using OVN we need to create the same L2 infrastucture as
# for OVS, so I'm copying value for required variables and use
# the same logic
ovs_tunnel_sub = 'CONFIG_NEUTRON_OVS_TUNNEL_SUBNETS'
ovn_tunnel_sub = 'CONFIG_NEUTRON_OVN_TUNNEL_SUBNETS'
config[ovs_tunnel_sub] = config[ovn_tunnel_sub]
ovs_tunnel_if = 'CONFIG_NEUTRON_OVS_TUNNEL_IF'
ovn_tunnel_if = 'CONFIG_NEUTRON_OVN_TUNNEL_IF'
config[ovs_tunnel_if] = config[ovn_tunnel_if]
ovs_mappings = 'CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS'
ovn_mappings = 'CONFIG_NEUTRON_OVN_BRIDGE_MAPPINGS'
config[ovs_mappings] = config[ovn_mappings]
ovs_ifaces = 'CONFIG_NEUTRON_OVS_BRIDGE_IFACES'
ovn_ifaces = 'CONFIG_NEUTRON_OVN_BRIDGE_IFACES'
config[ovs_ifaces] = config[ovn_ifaces]
ovs_compute = 'CONFIG_NEUTRON_OVS_BRIDGES_COMPUTE'
ovn_compute = 'CONFIG_NEUTRON_OVN_BRIDGES_COMPUTE'
config[ovs_compute] = config[ovn_compute]
ovs_external = 'CONFIG_NEUTRON_OVS_EXTERNAL_PHYSNET'
ovn_external = 'CONFIG_NEUTRON_OVN_EXTERNAL_PHYSNET'
config[ovs_external] = config[ovn_external]
elif use_ml2_with_ovs(config):
if ('openvswitch' not in config[
'CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS']):
config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS'] = 'openvswitch'
plugin_db = 'neutron'
plugin_path = 'neutron.plugins.ml2.plugin.Ml2Plugin'
# values modification
for key in ('CONFIG_NEUTRON_ML2_TYPE_DRIVERS',
'CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES',
'CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS',
'CONFIG_NEUTRON_ML2_FLAT_NETWORKS',
'CONFIG_NEUTRON_ML2_VLAN_RANGES',
'CONFIG_NEUTRON_ML2_TUNNEL_ID_RANGES',
'CONFIG_NEUTRON_ML2_VNI_RANGES'):
if config[key] == '':
config[key] = []
else:
config[key] = [i.strip() for i in config[key].split(',') if i]
key = 'CONFIG_NEUTRON_ML2_VXLAN_GROUP'
config[key] = "%s" % config[key] if config[key] else ''
config['CONFIG_NEUTRON_L2_DBNAME'] = plugin_db
config['CONFIG_NEUTRON_CORE_PLUGIN'] = plugin_path
global api_hosts, network_hosts, compute_hosts, q_hosts
api_hosts = split_hosts(config['CONFIG_CONTROLLER_HOST'])
network_hosts = split_hosts(config['CONFIG_NETWORK_HOSTS'])
compute_hosts = set()
if config['CONFIG_NOVA_INSTALL'] == 'y':
compute_hosts = split_hosts(config['CONFIG_COMPUTE_HOSTS'])
q_hosts = api_hosts | network_hosts | compute_hosts
neutron_steps = [
{'title': 'Preparing Neutron API entries',
'functions': [create_manifests]},
{'title': 'Preparing Neutron L3 entries',
'functions': [create_l3_manifests]},
{'title': 'Preparing Neutron L2 Agent entries',
'functions': [create_l2_agent_manifests]},
{'title': 'Preparing Neutron DHCP Agent entries',
'functions': [create_dhcp_manifests]},
{'title': 'Preparing Neutron Metering Agent entries',
'functions': [create_metering_agent_manifests]},
{'title': 'Checking if NetworkManager is enabled and running',
'functions': [check_nm_status]},
]
controller.addSequence("Installing OpenStack Neutron", [], [],
neutron_steps)
# ------------------------- helper functions -------------------------
def neutron_install(config):
return config['CONFIG_NEUTRON_INSTALL'] == 'y'
def use_ml2_with_linuxbridge(config):
ml2_used = (neutron_install(config) and
config["CONFIG_NEUTRON_L2_AGENT"] == 'linuxbridge')
return ml2_used
def use_ml2_with_ovs(config):
return (neutron_install(config) and
config["CONFIG_NEUTRON_L2_AGENT"] == 'openvswitch')
def use_ml2_with_ovn(config):
return (neutron_install(config) and
config["CONFIG_NEUTRON_L2_AGENT"] == 'ovn')
def use_openvswitch_vxlan(config):
ml2_vxlan = (
use_ml2_with_ovs(config) and
'vxlan' in config['CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES']
)
return ml2_vxlan
def use_openvswitch_gre(config):
ml2_vxlan = (
use_ml2_with_ovs(config) and
'gre' in config['CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES']
)
return ml2_vxlan
def use_ovn_geneve(config):
ml2_vxlan = (
use_ml2_with_ovn(config) and
'geneve' in config['CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES']
)
return ml2_vxlan
def use_ml2_with_sriovnicswitch(config):
ml2_sriovnic = (
use_ml2_with_ovs(config) and
'sriovnicswitch' in config['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS']
)
return ml2_sriovnic
def get_if_driver(config):
agent = config['CONFIG_NEUTRON_L2_AGENT']
if agent == "openvswitch":
return 'neutron.agent.linux.interface.OVSInterfaceDriver'
elif agent == 'linuxbridge':
return 'neutron.agent.linux.interface.BridgeInterfaceDriver'
else:
# OVN does not provides a interface driver
return ''
def find_mapping(haystack, needle):
return needle in [x.split(':')[1].strip() for x in get_values(haystack)]
def get_values(val):
return [x.strip() for x in val.split(',')] if val else []
def tunnel_fw_details(config, host, src, fw_details):
key = "neutron_tunnel_%s_%s" % (host, src)
fw_details.setdefault(key, {})
fw_details[key]['host'] = "%s" % src
fw_details[key]['service_name'] = "neutron tunnel port"
fw_details[key]['chain'] = "INPUT"
if use_openvswitch_vxlan(config):
fw_details[key]['proto'] = 'udp'
tun_port = ("%s" % config['CONFIG_NEUTRON_OVS_VXLAN_UDP_PORT'])
elif use_ovn_geneve(config):
fw_details[key]['proto'] = 'udp'
tun_port = "6081"
else:
fw_details[key]['proto'] = 'gre'
tun_port = None
fw_details[key]['ports'] = tun_port
# -------------------------- step functions --------------------------
def create_manifests(config, messages):
global q_hosts
service_plugins = ['qos', 'trunk']
service_providers = []
if use_ml2_with_ovn(config):
service_plugins.append('ovn-router')
else:
# ML2 uses the L3 Router service plugin to implement l3 agent for linuxbridge and ovs
service_plugins.append('router')
if config['CONFIG_NEUTRON_METERING_AGENT_INSTALL'] == 'y':
service_plugins.append('metering')
if config['CONFIG_NEUTRON_VPNAAS'] == 'y':
service_plugins.append('vpnaas')
vpnaas_sp = ('VPN:libreswan:neutron_vpnaas.services.vpn.'
'service_drivers.ipsec.IPsecVPNDriver:default')
service_providers.append(vpnaas_sp)
config['SERVICE_PLUGINS'] = (service_plugins if service_plugins
else 'undef')
config['SERVICE_PROVIDERS'] = (service_providers if service_providers
else [])
config['FIREWALL_DRIVER'] = ("neutron.agent.linux.iptables_firewall."
"OVSHybridIptablesFirewallDriver")
plugin_manifest = 'neutron_ml2_plugin'
if config['CONFIG_AMQP_ENABLE_SSL'] == 'y':
ssl_cert_file = config['CONFIG_NEUTRON_SSL_CERT'] = (
'/etc/pki/tls/certs/ssl_amqp_neutron.crt'
)
ssl_key_file = config['CONFIG_NEUTRON_SSL_KEY'] = (
'/etc/pki/tls/private/ssl_amqp_neutron.key'
)
service = 'neutron'
for host in q_hosts:
if config['CONFIG_AMQP_ENABLE_SSL'] == 'y':
generate_ssl_cert(config, host, service, ssl_key_file,
ssl_cert_file)
if host in api_hosts:
# Firewall
fw_details = dict()
key = "neutron_server_%s" % host
fw_details.setdefault(key, {})
fw_details[key]['host'] = "ALL"
fw_details[key]['service_name'] = "neutron server"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = ['9696']
fw_details[key]['proto'] = "tcp"
if use_ml2_with_ovn(config):
key = "ovn_northd_%s" % host
fw_details.setdefault(key, {})
fw_details[key]['host'] = "ALL"
fw_details[key]['service_name'] = "ovn northd"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = ['6641']
fw_details[key]['proto'] = "tcp"
key = "ovn_southd_%s" % host
fw_details.setdefault(key, {})
fw_details[key]['host'] = "ALL"
fw_details[key]['service_name'] = "ovn southd"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = ['6642']
fw_details[key]['proto'] = "tcp"
config['FIREWALL_NEUTRON_SERVER_RULES'] = fw_details
# We also need to open VXLAN/GRE port for agent
if (use_openvswitch_vxlan(config) or use_openvswitch_gre(config) or
use_ovn_geneve(config)):
if config['CONFIG_IP_VERSION'] == 'ipv6':
msg = output_messages.WARN_IPV6_OVS
messages.append(utils.color_text(msg % host, 'red'))
fw_details = dict()
if (config['CONFIG_NEUTRON_OVS_TUNNEL_SUBNETS']):
tunnel_subnets = map(
str.strip,
config['CONFIG_NEUTRON_OVS_TUNNEL_SUBNETS'].split(',')
)
cf_fw_nt_key = ("FIREWALL_NEUTRON_TUNNEL_RULES_%s" %
host.replace('.', '_'))
for subnet in tunnel_subnets:
tunnel_fw_details(config, host, subnet, fw_details)
config[cf_fw_nt_key] = fw_details
else:
cf_fw_nt_key = ("FIREWALL_NEUTRON_TUNNEL_RULES_%s" %
host.replace('.', '_'))
for n_host in network_hosts | compute_hosts:
if config['CONFIG_NEUTRON_OVS_TUNNEL_IF']:
if config['CONFIG_USE_SUBNETS'] == 'y':
iface = common.cidr_to_ifname(
config['CONFIG_NEUTRON_OVS_TUNNEL_IF'],
n_host, config)
else:
iface = config['CONFIG_NEUTRON_OVS_TUNNEL_IF']
ifip = ("ipaddress_%s" % iface)
ifip = re.sub(r'[\.\-\:]', '_', ifip)
try:
src_host = config['HOST_DETAILS'][n_host][ifip]
except KeyError:
raise KeyError('Couldn\'t detect ipaddress of '
'interface %s on node %s' %
(iface, n_host))
else:
src_host = n_host
tunnel_fw_details(config, host, src_host, fw_details)
config[cf_fw_nt_key] = fw_details
def create_l3_manifests(config, messages):
global network_hosts
if config['CONFIG_NEUTRON_L3_EXT_BRIDGE'] == 'provider':
config['CONFIG_NEUTRON_L3_EXT_BRIDGE'] = ''
for host in network_hosts:
config['CONFIG_NEUTRON_L3_HOST'] = host
config['CONFIG_NEUTRON_L3_INTERFACE_DRIVER'] = get_if_driver(config)
if (config['CONFIG_NEUTRON_L2_AGENT'] == 'openvswitch' or
config['CONFIG_NEUTRON_L2_AGENT'] == 'ovn'):
ext_bridge = config['CONFIG_NEUTRON_L3_EXT_BRIDGE']
mapping = find_mapping(
config['CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS'],
ext_bridge) if ext_bridge else None
if (ext_bridge and not mapping):
config['CONFIG_NEUTRON_OVS_BRIDGE'] = ext_bridge
config['CONFIG_NEUTRON_OVS_BRIDGE_CREATE'] = 'y'
else:
config['CONFIG_NEUTRON_OVS_BRIDGE_CREATE'] = 'n'
else:
config['CONFIG_NEUTRON_OVS_BRIDGE_CREATE'] = 'n'
def create_dhcp_manifests(config, messages):
if use_ml2_with_ovn(config):
return
global network_hosts
for host in network_hosts:
config["CONFIG_NEUTRON_DHCP_HOST"] = host
config['CONFIG_NEUTRON_DHCP_INTERFACE_DRIVER'] = get_if_driver(config)
# Firewall Rules for dhcp in
fw_details = dict()
key = "neutron_dhcp_in_%s" % host
fw_details.setdefault(key, {})
fw_details[key]['host'] = "ALL"
fw_details[key]['service_name'] = "neutron dhcp in"
fw_details[key]['chain'] = "INPUT"
fw_details[key]['ports'] = ['67']
fw_details[key]['proto'] = "udp"
config['FIREWALL_NEUTRON_DHCPIN_RULES'] = fw_details
# Firewall Rules for dhcp out
fw_details = dict()
key = "neutron_dhcp_out_%s" % host
fw_details.setdefault(key, {})
fw_details[key]['host'] = "ALL"
fw_details[key]['service_name'] = "neutron dhcp out"
fw_details[key]['chain'] = "OUTPUT"
fw_details[key]['ports'] = ['68']
fw_details[key]['proto'] = "udp"
config['FIREWALL_NEUTRON_DHCPOUT_RULES'] = fw_details
def create_metering_agent_manifests(config, messages):
if use_ml2_with_ovn(config):
return
global network_hosts
if not config['CONFIG_NEUTRON_METERING_AGENT_INSTALL'] == 'y':
return
for host in network_hosts:
config['CONFIG_NEUTRON_METERING_IFCE_DRIVER'] = get_if_driver(config)
def create_l2_agent_manifests(config, messages):
global network_hosts, compute_hosts
agent = config["CONFIG_NEUTRON_L2_AGENT"]
# CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS will be available only for ML2
# plugin deployment, but we need CONFIG_NEUTRON_USE_L2POPULATION also
# for other plugin template generation
if ('l2population' in
config.get('CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS', [])):
config['CONFIG_NEUTRON_USE_L2POPULATION'] = True
else:
config['CONFIG_NEUTRON_USE_L2POPULATION'] = False
if agent in ["openvswitch", "ovn"]:
ovs_type = 'CONFIG_NEUTRON_ML2_TYPE_DRIVERS'
ovs_type = config.get(ovs_type, 'local')
tunnel_types = set(ovs_type) & set(['gre', 'vxlan'])
config["CONFIG_NEUTRON_OVS_TUNNEL_TYPES"] = list(tunnel_types)
bm_arr = get_values(config["CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS"])
iface_arr = get_values(config["CONFIG_NEUTRON_OVS_BRIDGE_IFACES"])
# The CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS parameter contains a
# comma-separated list of bridge mappings. Since the puppet module
# expects this parameter to be an array, this parameter must be
# properly formatted by packstack, then consumed by the puppet module.
# For example, the input string 'A, B' should formatted as '['A','B']'.
config["CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS"] = bm_arr
config["CONFIG_NEUTRON_OVS_BRIDGE_IFACES"] = []
# Bridge configuration and mappings for compute nodes can be different.
# Parameter CONFIG_NEUTRON_OVS_BRIDGES_COMPUTE contains the list of
# bridge names, included in bridge mappings and bridge interfaces, that
# must be created in compute nodes.
brd_arr_cmp = get_values(config["CONFIG_NEUTRON_OVS_BRIDGES_COMPUTE"])
if_arr_cmp = []
mapp_arr_cmp = []
for brd in brd_arr_cmp:
if_arr_cmp.append(common.find_pair_with(iface_arr, brd, 0))
mapp_arr_cmp.append(common.find_pair_with(bm_arr, brd, 1))
config["CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS_COMPUTE"] = mapp_arr_cmp
config["CONFIG_NEUTRON_OVS_BRIDGE_IFACES_COMPUTE"] = []
no_local_types = set(ovs_type) & set(['gre', 'vxlan', 'vlan', 'flat'])
no_tunnel_types = set(ovs_type) & set(['vlan', 'flat'])
elif agent == "linuxbridge":
host_var = 'CONFIG_NEUTRON_LB_HOST'
else:
raise KeyError("Unknown layer2 agent")
for host in network_hosts | compute_hosts:
# NICs connected to OVS bridges can be required in network nodes if
# vlan, flat, vxlan or gre are enabled. For compute nodes, they are
# only required if vlan or flat are enabled.
if (
agent in ["openvswitch", "ovn"] and (
(host in network_hosts and no_local_types)
or no_tunnel_types)
):
if config['CONFIG_USE_SUBNETS'] == 'y':
iface_arr = [
common.cidr_to_ifname(i, host, config) for i in iface_arr
]
if_arr_cmp = [
common.cidr_to_ifname(i, host, config) for i in if_arr_cmp
]
config["CONFIG_NEUTRON_OVS_BRIDGE_IFACES"] = iface_arr
config["CONFIG_NEUTRON_OVS_BRIDGE_IFACES_COMPUTE"] = if_arr_cmp
config['CREATE_BRIDGES'] = 'y'
else:
config['CREATE_BRIDGES'] = 'n'
def check_nm_status(config, messages):
hosts_with_nm = []
for host in common.filtered_hosts(config):
server = utils.ScriptRunner(host)
server.append("systemctl")
rc, out = server.execute(can_fail=False)
server.clear()
if rc < 1:
server.append("systemctl is-enabled NetworkManager")
rc, is_enabled = server.execute(can_fail=False)
is_enabled = is_enabled.strip("\n ")
server.clear()
server.append("systemctl is-active NetworkManager")
rc, is_active = server.execute(can_fail=False)
is_active = is_active.strip("\n ")
if is_enabled == "enabled" or is_active == "active":
hosts_with_nm.append(host)
else:
server.clear()
server.append("service NetworkManager status")
rc, out = server.execute(can_fail=False)
if rc < 1:
hosts_with_nm.append(host)
server.clear()
if hosts_with_nm:
hosts_list = ', '.join("%s" % x for x in hosts_with_nm)
msg = output_messages.WARN_NM_ENABLED
messages.append(utils.color_text(msg % hosts_list, 'yellow'))