# -*- 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-lbaas-install", "PROMPT": "Should Packstack install Neutron LBaaS", "OPTION_LIST": ["y", "n"], "VALIDATORS": [validators.validate_options], "DEFAULT_VALUE": "n", "MASK_INPUT": False, "LOOSE_VALIDATION": False, "CONF_NAME": "CONFIG_LBAAS_INSTALL", "USE_DEFAULT": False, "NEED_CONFIRM": False, "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": "neutron-fwaas", "PROMPT": "Would you like to configure neutron FWaaS?", "OPTION_LIST": ["y", "n"], "VALIDATORS": [validators.validate_options], "DEFAULT_VALUE": "n", "MASK_INPUT": False, "LOOSE_VALIDATION": True, "CONF_NAME": "CONFIG_NEUTRON_FWAAS", "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 : " "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 : " "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 choosen OVN neutron backend. Note that this backend does not support LBaaS, VPNaaS or FWaaS services. " "Geneve will be used as 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, LBaaS and FWaaS are not supported with OVN config['CONFIG_NEUTRON_FWAAS'] = 'n' config['CONFIG_NEUTRON_VPNAAS'] = 'n' config['CONFIG_LBAAS_INSTALL'] = '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 LBaaS Agent entries', 'functions': [create_lbaas_manifests]}, {'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 config['CONFIG_LBAAS_INSTALL'] == 'y': lbaas_plugin = ('neutron_lbaas.services.loadbalancer.plugin.' 'LoadBalancerPluginv2') service_plugins.append(lbaas_plugin) lbaas_sp = ('LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.' 'plugin_driver.HaproxyOnHostPluginDriver:default') service_providers.append(lbaas_sp) 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_FWAAS'] == 'y': service_plugins.append('firewall') fwaas_sp = ('FIREWALL:Iptables:neutron.agent.linux.iptables_firewall.' 'OVSHybridIptablesFirewallDriver:default') service_providers.append(fwaas_sp) 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('[\.\-\:]', '_', 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_lbaas_manifests(config, messages): if use_ml2_with_ovn(config): return global network_hosts if not config['CONFIG_LBAAS_INSTALL'] == 'y': return for host in network_hosts: config['CONFIG_NEUTRON_LBAAS_INTERFACE_DRIVER'] = get_if_driver(config) 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'))