1 ##############################################################################
2 # Copyright (c) 2016 Feng Pan (fpan@redhat.com) and others.
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
13 from . import ip_utils
14 from .common import constants, utils
17 class NetworkSettings:
19 This class parses APEX network settings yaml file into an object. It
20 generates or detects all missing fields for deployment.
22 The resulting object will be used later to generate network environment file
23 as well as configuring post deployment networks.
25 Currently the parsed object is dumped into a bash global definition file
26 for deploy.sh consumption. This object will later be used directly as
27 deployment script move to python.
29 def __init__(self, filename, network_isolation):
30 with open(filename, 'r') as network_settings_file:
31 self.settings_obj = yaml.load(network_settings_file)
32 self.network_isolation = network_isolation
33 self.enabled_network_list = []
34 self._validate_input()
36 def _validate_input(self):
38 Validates the network settings file and populates all fields.
40 NetworkSettingsException will be raised if validation fails.
42 if constants.ADMIN_NETWORK not in self.settings_obj or \
43 not utils.str2bool(self.settings_obj[constants.ADMIN_NETWORK].get(
45 raise NetworkSettingsException("You must enable admin_network "
46 "and configure it explicitly or "
48 if self.network_isolation and \
49 (constants.PUBLIC_NETWORK not in self.settings_obj or not
50 utils.str2bool(self.settings_obj[constants.PUBLIC_NETWORK].get(
52 raise NetworkSettingsException("You must enable public_network "
53 "and configure it explicitly or "
56 for network in constants.OPNFV_NETWORK_TYPES:
57 if network in self.settings_obj:
58 if utils.str2bool(self.settings_obj[network].get('enabled')):
59 logging.info("{} enabled".format(network))
60 self._config_required_settings(network)
61 self._config_ip_range(network=network,
62 setting='usable_ip_range',
63 start_offset=21, end_offset=21)
64 self._config_optional_settings(network)
65 self.enabled_network_list.append(network)
67 logging.info("{} disabled, will collapse with "
68 "admin_network".format(network))
70 logging.info("{} is not in specified, will collapse with "
71 "admin_network".format(network))
73 def _config_required_settings(self, network):
75 Configures either CIDR or bridged_interface setting
77 cidr takes precedence if both cidr and bridged_interface are specified
80 When using bridged_interface, we will detect network setting on the
81 given NIC in the system. The resulting config in settings object will
82 be an ipaddress.network object, replacing the NIC name.
84 cidr = self.settings_obj[network].get('cidr')
85 nic_name = self.settings_obj[network].get('bridged_interface')
88 cidr = ipaddress.ip_network(self.settings_obj[network]['cidr'])
89 self.settings_obj[network]['cidr'] = cidr
90 logging.info("{}_cidr: {}".format(network, cidr))
93 # If cidr is not specified, we need to know if we should find
94 # IPv6 or IPv4 address on the interface
95 if utils.str2bool(self.settings_obj[network].get('ipv6')):
99 nic_interface = ip_utils.get_interface(nic_name, address_family)
101 self.settings_obj[network]['bridged_interface'] = nic_interface
102 logging.info("{}_bridged_interface: {}".
103 format(network, nic_interface))
106 raise NetworkSettingsException("Auto detection failed for {}: "
107 "Unable to find valid ip for "
109 .format(network, nic_name))
112 raise NetworkSettingsException("Auto detection failed for {}: "
113 "either bridge_interface or cidr "
117 def _config_ip_range(self, network, setting, start_offset=None,
118 end_offset=None, count=None):
120 Configures IP range for a given setting.
122 If the setting is already specified, no change will be made.
124 The spec for start_offset, end_offset and count are identical to
125 ip_utils.get_ip_range.
127 ip_range = self.settings_obj[network].get(setting)
128 interface = self.settings_obj[network].get('bridged_interface')
131 cidr = self.settings_obj[network].get('cidr')
132 ip_range = ip_utils.get_ip_range(start_offset=start_offset,
133 end_offset=end_offset,
137 self.settings_obj[network][setting] = ip_range
139 logging.info("{}_{}: {}".format(network, setting, ip_range))
141 def _config_ip(self, network, setting, offset):
143 Configures IP for a given setting.
145 If the setting is already specified, no change will be made.
147 The spec for offset is identical to ip_utils.get_ip
149 ip = self.settings_obj[network].get(setting)
150 interface = self.settings_obj[network].get('bridged_interface')
153 cidr = self.settings_obj[network].get('cidr')
154 ip = ip_utils.get_ip(offset, cidr, interface)
155 self.settings_obj[network][setting] = ip
157 logging.info("{}_{}: {}".format(network, setting, ip))
159 def _config_optional_settings(self, network):
161 Configures optional settings:
165 - introspection_range
171 if network == constants.ADMIN_NETWORK:
172 self._config_ip(network, 'provisioner_ip', 1)
173 self._config_ip_range(network=network, setting='dhcp_range',
174 start_offset=2, count=9)
175 self._config_ip_range(network=network,
176 setting='introspection_range',
177 start_offset=11, count=9)
178 elif network == constants.PUBLIC_NETWORK:
179 self._config_ip(network, 'provisioner_ip', 1)
180 self._config_ip_range(network=network,
181 setting='floating_ip',
182 end_offset=2, count=20)
183 self._config_gateway(network)
185 def _config_gateway(self, network):
187 Configures gateway setting for a given network.
189 If cidr is specified, we always use the first address in the address
190 space for gateway. Otherwise, we detect the system gateway.
192 gateway = self.settings_obj[network].get('gateway')
193 interface = self.settings_obj[network].get('bridged_interface')
196 cidr = self.settings_obj[network].get('cidr')
198 gateway = ip_utils.get_ip(1, cidr)
200 gateway = ip_utils.find_gateway(interface)
203 self.settings_obj[network]['gateway'] = gateway
205 raise NetworkSettingsException("Failed to set gateway")
207 logging.info("{}_gateway: {}".format(network, gateway))
209 def dump_bash(self, path=None):
211 Prints settings for bash consumption.
213 If optional path is provided, bash string will be written to the file
217 for network in self.enabled_network_list:
218 for key, value in self.settings_obj[network].items():
219 bash_str += "{}_{}={}\n".format(network, key, value)
220 bash_str += "enabled_network_list='{}'\n" \
221 .format(' '.join(self.enabled_network_list))
222 bash_str += "ip_addr_family={}\n".format(self.get_ip_addr_family())
224 with open(path, 'w') as file:
229 def get_ip_addr_family(self):
231 Returns IP address family for current deployment.
233 If any enabled network has IPv6 CIDR, the deployment is classified as
236 for network in self.enabled_network_list:
237 cidr = ipaddress.ip_network(self.settings_obj[network]['cidr'])
238 if cidr.version == 6:
243 def get_network_settings(self):
245 Getter for network settings
246 :return: network settings dictionary
248 return self.settings_obj
250 def get_enabled_networks(self):
252 Getter for enabled network list
253 :return: list of enabled networks
255 return self.enabled_network_list
258 class NetworkSettingsException(Exception):
259 def __init__(self, value):