summaryrefslogtreecommitdiffstats
path: root/apex/network
diff options
context:
space:
mode:
authorTim Rozet <trozet@redhat.com>2017-06-25 21:25:36 -0400
committerTim Rozet <trozet@redhat.com>2017-08-23 08:59:54 -0400
commitf4d388ea508ba00771e43a219ac64e0d430b73bd (patch)
tree4f61a89664474154c3d6f7adecfbb0396617199c /apex/network
parent807fad268c90649f2901c5f5c4cdeb788a0308e0 (diff)
Migrates Apex to Python
Removes all bash libraries and converts almost all of the code to a mixture of Python and Ansible. utils.sh and clean.sh still exist. clean.sh will be migrated fully to clean.py in another patch. The Apex Python package is now built into the opnfv-apex-common RPM. To install locally do 'pip3 install .'. To deploy: opnfv-deploy -d <file> -n <file> --image-dir /root/apex/.build -v --debug Non-python files (THT yaml, settings files, ansible playbooks) are all installed into /usr/share/opnfv-apex/. The RPM will copy settings files into /etc/opnfv-apex/. JIRA: APEX-317 Change-Id: I3232f0329bcd13bce5a28da6a8c9c84d0b048024 Signed-off-by: Tim Rozet <trozet@redhat.com>
Diffstat (limited to 'apex/network')
-rw-r--r--apex/network/__init__.py0
-rw-r--r--apex/network/ip_utils.py230
-rw-r--r--apex/network/jumphost.py172
-rw-r--r--apex/network/network_environment.py218
4 files changed, 620 insertions, 0 deletions
diff --git a/apex/network/__init__.py b/apex/network/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/apex/network/__init__.py
diff --git a/apex/network/ip_utils.py b/apex/network/ip_utils.py
new file mode 100644
index 00000000..ae60b705
--- /dev/null
+++ b/apex/network/ip_utils.py
@@ -0,0 +1,230 @@
+##############################################################################
+# Copyright (c) 2016 Feng Pan (fpan@redhat.com) and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+
+import ipaddress
+import subprocess
+import re
+import logging
+
+
+def get_ip_range(start_offset=None, count=None, end_offset=None,
+ cidr=None, interface=None):
+ """
+ Generate IP range for a network (cidr) or an interface.
+
+ If CIDR is provided, it will take precedence over interface. In this case,
+ The entire CIDR IP address space is considered usable. start_offset will be
+ calculated from the network address, and end_offset will be calculated from
+ the last address in subnet.
+
+ If interface is provided, the interface IP will be used to calculate
+ offsets:
+ - If the interface IP is in the first half of the address space,
+ start_offset will be calculated from the interface IP, and end_offset
+ will be calculated from end of address space.
+ - If the interface IP is in the second half of the address space,
+ start_offset will be calculated from the network address in the address
+ space, and end_offset will be calculated from the interface IP.
+
+ 2 of start_offset, end_offset and count options must be provided:
+ - If start_offset and end_offset are provided, a range from
+ start_offset to end_offset will be returned.
+ - If count is provided, a range from either start_offset to
+ (start_offset+count) or (end_offset-count) to end_offset will be
+ returned. The IP range returned will be of size <count>.
+ Both start_offset and end_offset must be greater than 0.
+
+ Returns IP range in the format of "first_addr,second_addr" or exception
+ is raised.
+ """
+ if cidr:
+ if count and start_offset and not end_offset:
+ start_index = start_offset
+ end_index = start_offset + count - 1
+ elif count and end_offset and not start_offset:
+ end_index = -1 - end_offset
+ start_index = -1 - end_index - count + 1
+ elif start_offset and end_offset and not count:
+ start_index = start_offset
+ end_index = -1 - end_offset
+ else:
+ raise IPUtilsException("Argument error: must pass in exactly 2 of"
+ " start_offset, end_offset and count")
+
+ start_ip = cidr[start_index]
+ end_ip = cidr[end_index]
+ network = cidr
+ elif interface:
+ network = interface.network
+ number_of_addr = network.num_addresses
+ if interface.ip < network[int(number_of_addr / 2)]:
+ if count and start_offset and not end_offset:
+ start_ip = interface.ip + start_offset
+ end_ip = start_ip + count - 1
+ elif count and end_offset and not start_offset:
+ end_ip = network[-1 - end_offset]
+ start_ip = end_ip - count + 1
+ elif start_offset and end_offset and not count:
+ start_ip = interface.ip + start_offset
+ end_ip = network[-1 - end_offset]
+ else:
+ raise IPUtilsException(
+ "Argument error: must pass in exactly 2 of"
+ " start_offset, end_offset and count")
+ else:
+ if count and start_offset and not end_offset:
+ start_ip = network[start_offset]
+ end_ip = start_ip + count - 1
+ elif count and end_offset and not start_offset:
+ end_ip = interface.ip - end_offset
+ start_ip = end_ip - count + 1
+ elif start_offset and end_offset and not count:
+ start_ip = network[start_offset]
+ end_ip = interface.ip - end_offset
+ else:
+ raise IPUtilsException(
+ "Argument error: must pass in exactly 2 of"
+ " start_offset, end_offset and count")
+
+ else:
+ raise IPUtilsException("Must pass in cidr or interface to generate"
+ "ip range")
+
+ range_result = _validate_ip_range(start_ip, end_ip, network)
+ if range_result:
+ ip_range = "{},{}".format(start_ip, end_ip)
+ return ip_range
+ else:
+ raise IPUtilsException("Invalid IP range: {},{} for network {}"
+ .format(start_ip, end_ip, network))
+
+
+def get_ip(offset, cidr=None, interface=None):
+ """
+ Returns an IP in a network given an offset.
+
+ Either cidr or interface must be provided, cidr takes precedence.
+
+ If cidr is provided, offset is calculated from network address.
+ If interface is provided, offset is calculated from interface IP.
+
+ offset can be positive or negative, but the resulting IP address must also
+ be contained in the same subnet, otherwise an exception will be raised.
+
+ returns a IP address object.
+ """
+ if cidr:
+ ip = cidr[0 + offset]
+ network = cidr
+ elif interface:
+ ip = interface.ip + offset
+ network = interface.network
+ else:
+ raise IPUtilsException("Must pass in cidr or interface to generate IP")
+
+ if ip not in network:
+ raise IPUtilsException("IP {} not in network {}".format(ip, network))
+ else:
+ return str(ip)
+
+
+def get_interface(nic, address_family=4):
+ """
+ Returns interface object for a given NIC name in the system
+
+ Only global address will be returned at the moment.
+
+ Returns interface object if an address is found for the given nic,
+ otherwise returns None.
+ """
+ if not nic.strip():
+ logging.error("empty nic name specified")
+ return None
+ output = subprocess.getoutput("/usr/sbin/ip -{} addr show {} scope global"
+ .format(address_family, nic))
+ if address_family == 4:
+ pattern = re.compile("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d{1,2}")
+ elif address_family == 6:
+ pattern = re.compile("([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}/\d{1,3}")
+ else:
+ raise IPUtilsException("Invalid address family: {}"
+ .format(address_family))
+ match = re.search(pattern, output)
+ if match:
+ logging.info("found interface {} ip: {}".format(nic, match.group()))
+ return ipaddress.ip_interface(match.group())
+ else:
+ logging.info("interface ip not found! ip address output:\n{}"
+ .format(output))
+ return None
+
+
+def find_gateway(interface):
+ """
+ Validate gateway on the system
+
+ Ensures that the provided interface object is in fact configured as default
+ route on the system.
+
+ Returns gateway IP (reachable from interface) if default route is found,
+ otherwise returns None.
+ """
+
+ address_family = interface.version
+ output = subprocess.getoutput("/usr/sbin/ip -{} route".format(
+ address_family))
+
+ pattern = re.compile("default\s+via\s+(\S+)\s+")
+ match = re.search(pattern, output)
+
+ if match:
+ gateway_ip = match.group(1)
+ reverse_route_output = subprocess.getoutput("/usr/sbin/ip route get {}"
+ .format(gateway_ip))
+ pattern = re.compile("{}.+src\s+{}".format(gateway_ip, interface.ip))
+ if not re.search(pattern, reverse_route_output):
+ logging.warning("Default route doesn't match interface specified: "
+ "{}".format(reverse_route_output))
+ return None
+ else:
+ return gateway_ip
+ else:
+ logging.warning("Can't find gateway address on system")
+ return None
+
+
+def _validate_ip_range(start_ip, end_ip, cidr):
+ """
+ Validates an IP range is in good order and the range is part of cidr.
+
+ Returns True if validation succeeds, False otherwise.
+ """
+ ip_range = "{},{}".format(start_ip, end_ip)
+ if end_ip <= start_ip:
+ logging.warning("IP range {} is invalid: end_ip should be greater "
+ "than starting ip".format(ip_range))
+ return False
+ if start_ip not in ipaddress.ip_network(cidr):
+ logging.warning('start_ip {} is not in network {}'
+ .format(start_ip, cidr))
+ return False
+ if end_ip not in ipaddress.ip_network(cidr):
+ logging.warning('end_ip {} is not in network {}'.format(end_ip, cidr))
+ return False
+
+ return True
+
+
+class IPUtilsException(Exception):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return self.value
diff --git a/apex/network/jumphost.py b/apex/network/jumphost.py
new file mode 100644
index 00000000..81562c7a
--- /dev/null
+++ b/apex/network/jumphost.py
@@ -0,0 +1,172 @@
+##############################################################################
+# Copyright (c) 2017 Tim Rozet (trozet@redhat.com) and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import logging
+import os
+import re
+import shutil
+import subprocess
+
+from apex.common.exceptions import ApexDeployException
+from apex.network import ip_utils
+
+NET_MAP = {
+ 'admin': 'br-admin',
+ 'tenant': 'br-tenant',
+ 'external': 'br-external',
+ 'storage': 'br-storage',
+ 'api': 'br-api'
+}
+
+
+def configure_bridges(ns):
+ """
+ Configures IP on jumphost bridges
+ :param ns: network_settings
+ :return: None
+ """
+ bridge_networks = ['admin']
+ if 'external' in ns.enabled_network_list:
+ bridge_networks.append('external')
+ for network in bridge_networks:
+ if network == 'external':
+ net_config = ns['networks'][network][0]
+ else:
+ net_config = ns['networks'][network]
+ cidr = net_config['cidr']
+ interface = ip_utils.get_interface(NET_MAP[network], cidr.version)
+
+ if interface:
+ logging.info("Bridge {} already configured with IP: {}".format(
+ NET_MAP[network], interface.ip))
+ else:
+ logging.info("Will configure IP for {}".format(NET_MAP[network]))
+ ovs_ip = net_config['overcloud_ip_range'][1]
+ if cidr.version == 6:
+ ipv6_br_path = "/proc/sys/net/ipv6/conf/{}/disable_" \
+ "ipv6".format(NET_MAP[network])
+ try:
+ subprocess.check_call('echo', 0, '>', ipv6_br_path)
+ except subprocess.CalledProcessError:
+ logging.error("Unable to enable ipv6 on "
+ "bridge {}".format(NET_MAP[network]))
+ raise
+ try:
+ ip_prefix = "{}/{}".format(ovs_ip, cidr.prefixlen)
+ subprocess.check_call(['ip', 'addr', 'add', ip_prefix, 'dev',
+ NET_MAP[network]])
+ subprocess.check_call(['ip', 'link', 'set', 'up', NET_MAP[
+ network]])
+ logging.info("IP configured: {} on bridge {}".format(ovs_ip,
+ NET_MAP[network]))
+ except subprocess.CalledProcessError:
+ logging.error("Unable to configure IP address on "
+ "bridge {}".format(NET_MAP[network]))
+
+
+def attach_interface_to_ovs(bridge, interface, network):
+ """
+ Attaches jumphost interface to OVS for baremetal deployments
+ :param bridge: bridge to attach to
+ :param interface: interface to attach to bridge
+ :param network: Apex network type for these interfaces
+ :return: None
+ """
+
+ net_cfg_path = '/etc/sysconfig/network-scripts'
+ if_file = os.path.join(net_cfg_path, "ifcfg-{}".format(interface))
+ ovs_file = os.path.join(net_cfg_path, "ifcfg-{}".format(bridge))
+
+ logging.info("Attaching interface: {} to bridge: {} on network {}".format(
+ bridge, interface, network
+ ))
+
+ try:
+ output = subprocess.check_output(['ovs-vsctl', 'list-ports', bridge],
+ stderr=subprocess.STDOUT)
+ if bridge in output:
+ logging.debug("Interface already attached to bridge")
+ return
+ except subprocess.CalledProcessError as e:
+ logging.error("Unable to dump ports for bridge: {}".format(bridge))
+ logging.error("Error output: {}".format(e.output))
+ raise
+
+ if not os.path.isfile(if_file):
+ logging.error("Interface ifcfg not found: {}".format(if_file))
+ raise FileNotFoundError("Interface file missing: {}".format(if_file))
+
+ ifcfg_params = {
+ 'IPADDR': '',
+ 'NETMASK': '',
+ 'GATEWAY': '',
+ 'METRIC': '',
+ 'DNS1': '',
+ 'DNS2': '',
+ 'PREFIX': ''
+ }
+ with open(if_file, 'r') as fh:
+ interface_output = fh.read()
+
+ for param in ifcfg_params.keys():
+ match = re.search("{}=(.*)\n".format(param), interface_output)
+ if match:
+ ifcfg_params[param] = match.group(1)
+
+ if not ifcfg_params['IPADDR']:
+ logging.error("IPADDR missing in {}".format(if_file))
+ raise ApexDeployException("IPADDR missing in {}".format(if_file))
+ if not (ifcfg_params['NETMASK'] or ifcfg_params['PREFIX']):
+ logging.error("NETMASK/PREFIX missing in {}".format(if_file))
+ raise ApexDeployException("NETMASK/PREFIX missing in {}".format(
+ if_file))
+ if network == 'external' and not ifcfg_params['GATEWAY']:
+ logging.error("GATEWAY is required to be in {} for external "
+ "network".format(if_file))
+ raise ApexDeployException("GATEWAY is required to be in {} for "
+ "external network".format(if_file))
+
+ shutil.move(if_file, "{}.orig".format(if_file))
+ if_content = """DEVICE={}
+DEVICETYPE=ovs
+TYPE=OVSPort
+PEERDNS=no
+BOOTPROTO=static
+NM_CONTROLLED=no
+ONBOOT=yes
+OVS_BRIDGE={}
+PROMISC=yes""".format(interface, bridge)
+
+ bridge_content = """DEVICE={}
+DEVICETYPE=ovs
+BOOTPROTO=static
+ONBOOT=yes
+TYPE=OVSBridge
+PROMISC=yes""".format(bridge)
+ peer_dns = 'no'
+ for param, value in ifcfg_params.items():
+ if value:
+ bridge_content += "\n{}={}".format(param, value)
+ if param == 'DNS1' or param == 'DNS2':
+ peer_dns = 'yes'
+ bridge_content += "\n{}={}".format('PEERDNS', peer_dns)
+
+ logging.debug("New interface file content:\n{}".format(if_content))
+ logging.debug("New bridge file content:\n{}".format(bridge_content))
+ with open(if_file, 'w') as fh:
+ fh.write(if_content)
+ with open(ovs_file, 'w') as fh:
+ fh.write(bridge_content)
+ logging.info("New network ifcfg files written")
+ logging.info("Restarting Linux networking")
+ try:
+ subprocess.check_call(['systemctl', 'restart', 'network'])
+ except subprocess.CalledProcessError:
+ logging.error("Failed to restart Linux networking")
+ raise
diff --git a/apex/network/network_environment.py b/apex/network/network_environment.py
new file mode 100644
index 00000000..c2e9991a
--- /dev/null
+++ b/apex/network/network_environment.py
@@ -0,0 +1,218 @@
+##############################################################################
+# Copyright (c) 2016 Tim Rozet (trozet@redhat.com) and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+import re
+
+import yaml
+
+from apex.settings.network_settings import NetworkSettings
+from apex.common.constants import (
+ CONTROLLER,
+ COMPUTE,
+ ADMIN_NETWORK,
+ TENANT_NETWORK,
+ STORAGE_NETWORK,
+ EXTERNAL_NETWORK,
+ API_NETWORK
+)
+
+HEAT_NONE = 'OS::Heat::None'
+PORTS = '/ports'
+# Resources defined by <resource name>: <prefix>
+EXTERNAL_RESOURCES = {'OS::TripleO::Network::External': None,
+ 'OS::TripleO::Network::Ports::ExternalVipPort': PORTS,
+ 'OS::TripleO::Controller::Ports::ExternalPort': PORTS,
+ 'OS::TripleO::Compute::Ports::ExternalPort': PORTS}
+TENANT_RESOURCES = {'OS::TripleO::Network::Tenant': None,
+ 'OS::TripleO::Controller::Ports::TenantPort': PORTS,
+ 'OS::TripleO::Compute::Ports::TenantPort': PORTS}
+STORAGE_RESOURCES = {'OS::TripleO::Network::Storage': None,
+ 'OS::TripleO::Network::Ports::StorageVipPort': PORTS,
+ 'OS::TripleO::Controller::Ports::StoragePort': PORTS,
+ 'OS::TripleO::Compute::Ports::StoragePort': PORTS}
+API_RESOURCES = {'OS::TripleO::Network::InternalApi': None,
+ 'OS::TripleO::Network::Ports::InternalApiVipPort': PORTS,
+ 'OS::TripleO::Controller::Ports::InternalApiPort': PORTS,
+ 'OS::TripleO::Compute::Ports::InternalApiPort': PORTS}
+
+# A list of flags that will be set to true when IPv6 is enabled
+IPV6_FLAGS = ["NovaIPv6", "MongoDbIPv6", "CorosyncIPv6", "CephIPv6",
+ "RabbitIPv6", "MemcachedIPv6"]
+
+reg = 'resource_registry'
+param_def = 'parameter_defaults'
+
+
+class NetworkEnvironment(dict):
+ """
+ This class creates a Network Environment to be used in TripleO Heat
+ Templates.
+
+ The class builds upon an existing network-environment file and modifies
+ based on a NetworkSettings object.
+ """
+ def __init__(self, net_settings, filename, compute_pre_config=False,
+ controller_pre_config=False):
+ """
+ Create Network Environment according to Network Settings
+ """
+ init_dict = {}
+ if isinstance(filename, str):
+ with open(filename, 'r') as net_env_fh:
+ init_dict = yaml.safe_load(net_env_fh)
+
+ super().__init__(init_dict)
+ if not isinstance(net_settings, NetworkSettings):
+ raise NetworkEnvException('Invalid Network Settings object')
+
+ self._set_tht_dir()
+
+ nets = net_settings['networks']
+
+ admin_cidr = nets[ADMIN_NETWORK]['cidr']
+ admin_prefix = str(admin_cidr.prefixlen)
+ self[param_def]['ControlPlaneSubnetCidr'] = admin_prefix
+ self[param_def]['ControlPlaneDefaultRoute'] = \
+ nets[ADMIN_NETWORK]['installer_vm']['ip']
+ self[param_def]['EC2MetadataIp'] = \
+ nets[ADMIN_NETWORK]['installer_vm']['ip']
+ self[param_def]['DnsServers'] = net_settings['dns_servers']
+
+ if EXTERNAL_NETWORK in net_settings.enabled_network_list:
+ external_cidr = net_settings.get_network(EXTERNAL_NETWORK)['cidr']
+ self[param_def]['ExternalNetCidr'] = str(external_cidr)
+ external_vlan = self._get_vlan(net_settings.get_network(
+ EXTERNAL_NETWORK))
+ if isinstance(external_vlan, int):
+ self[param_def]['NeutronExternalNetworkBridge'] = '""'
+ self[param_def]['ExternalNetworkVlanID'] = external_vlan
+ external_range = net_settings.get_network(EXTERNAL_NETWORK)[
+ 'overcloud_ip_range']
+ self[param_def]['ExternalAllocationPools'] = \
+ [{'start': str(external_range[0]),
+ 'end': str(external_range[1])}]
+ self[param_def]['ExternalInterfaceDefaultRoute'] = \
+ net_settings.get_network(EXTERNAL_NETWORK)['gateway']
+
+ if external_cidr.version == 6:
+ postfix = '/external_v6.yaml'
+ else:
+ postfix = '/external.yaml'
+ else:
+ postfix = '/noop.yaml'
+
+ # apply resource registry update for EXTERNAL_RESOURCES
+ self._config_resource_reg(EXTERNAL_RESOURCES, postfix)
+
+ if TENANT_NETWORK in net_settings.enabled_network_list:
+ tenant_range = nets[TENANT_NETWORK]['overcloud_ip_range']
+ self[param_def]['TenantAllocationPools'] = \
+ [{'start': str(tenant_range[0]),
+ 'end': str(tenant_range[1])}]
+ tenant_cidr = nets[TENANT_NETWORK]['cidr']
+ self[param_def]['TenantNetCidr'] = str(tenant_cidr)
+ if tenant_cidr.version == 6:
+ postfix = '/tenant_v6.yaml'
+ # set overlay_ip_version option in Neutron ML2 config
+ self[param_def]['NeutronOverlayIPVersion'] = "6"
+ else:
+ postfix = '/tenant.yaml'
+
+ tenant_vlan = self._get_vlan(nets[TENANT_NETWORK])
+ if isinstance(tenant_vlan, int):
+ self[param_def]['TenantNetworkVlanID'] = tenant_vlan
+ else:
+ postfix = '/noop.yaml'
+
+ # apply resource registry update for TENANT_RESOURCES
+ self._config_resource_reg(TENANT_RESOURCES, postfix)
+
+ if STORAGE_NETWORK in net_settings.enabled_network_list:
+ storage_range = nets[STORAGE_NETWORK]['overcloud_ip_range']
+ self[param_def]['StorageAllocationPools'] = \
+ [{'start': str(storage_range[0]),
+ 'end': str(storage_range[1])}]
+ storage_cidr = nets[STORAGE_NETWORK]['cidr']
+ self[param_def]['StorageNetCidr'] = str(storage_cidr)
+ if storage_cidr.version == 6:
+ postfix = '/storage_v6.yaml'
+ else:
+ postfix = '/storage.yaml'
+ storage_vlan = self._get_vlan(nets[STORAGE_NETWORK])
+ if isinstance(storage_vlan, int):
+ self[param_def]['StorageNetworkVlanID'] = storage_vlan
+ else:
+ postfix = '/noop.yaml'
+
+ # apply resource registry update for STORAGE_RESOURCES
+ self._config_resource_reg(STORAGE_RESOURCES, postfix)
+
+ if API_NETWORK in net_settings.enabled_network_list:
+ api_range = nets[API_NETWORK]['overcloud_ip_range']
+ self[param_def]['InternalApiAllocationPools'] = \
+ [{'start': str(api_range[0]),
+ 'end': str(api_range[1])}]
+ api_cidr = nets[API_NETWORK]['cidr']
+ self[param_def]['InternalApiNetCidr'] = str(api_cidr)
+ if api_cidr.version == 6:
+ postfix = '/internal_api_v6.yaml'
+ else:
+ postfix = '/internal_api.yaml'
+ api_vlan = self._get_vlan(nets[API_NETWORK])
+ if isinstance(api_vlan, int):
+ self[param_def]['InternalApiNetworkVlanID'] = api_vlan
+ else:
+ postfix = '/noop.yaml'
+
+ # apply resource registry update for API_RESOURCES
+ self._config_resource_reg(API_RESOURCES, postfix)
+
+ # Set IPv6 related flags to True. Not that we do not set those to False
+ # when IPv4 is configured, we'll use the default or whatever the user
+ # may have set.
+ if net_settings.get_ip_addr_family() == 6:
+ for flag in IPV6_FLAGS:
+ self[param_def][flag] = True
+
+ def _get_vlan(self, network):
+ if isinstance(network['nic_mapping'][CONTROLLER]['vlan'], int):
+ return network['nic_mapping'][CONTROLLER]['vlan']
+ elif isinstance(network['nic_mapping'][COMPUTE]['vlan'], int):
+ return network['nic_mapping'][COMPUTE]['vlan']
+ else:
+ return 'native'
+
+ def _set_tht_dir(self):
+ self.tht_dir = None
+ for key, prefix in TENANT_RESOURCES.items():
+ if prefix is None:
+ prefix = ''
+ m = re.split('%s/\w+\.yaml' % prefix, self[reg][key])
+ if m is not None and len(m) > 1:
+ self.tht_dir = m[0]
+ break
+ if not self.tht_dir:
+ raise NetworkEnvException('Unable to parse THT Directory')
+
+ def _config_resource_reg(self, resources, postfix):
+ for key, prefix in resources.items():
+ if prefix is None:
+ if postfix == '/noop.yaml':
+ self[reg][key] = HEAT_NONE
+ continue
+ prefix = ''
+ self[reg][key] = self.tht_dir + prefix + postfix
+
+
+class NetworkEnvException(Exception):
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return self.value