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 ##############################################################################
14 from . import ip_utils
17 ADMIN_NETWORK = 'admin_network'
18 PRIVATE_NETWORK = 'private_network'
19 PUBLIC_NETWORK = 'public_network'
20 STORAGE_NETWORK = 'storage_network'
21 API_NETWORK = 'api_network'
22 OPNFV_NETWORK_TYPES = [ADMIN_NETWORK, PRIVATE_NETWORK, PUBLIC_NETWORK,
23 STORAGE_NETWORK, API_NETWORK]
26 class NetworkSettings:
28 This class parses APEX network settings yaml file into an object. It
29 generates or detects all missing fields for deployment.
31 The resulting object will be used later to generate network environment file
32 as well as configuring post deployment networks.
34 Currently the parsed object is dumped into a bash global definition file
35 for deploy.sh consumption. This object will later be used directly as
36 deployment script move to python.
38 def __init__(self, filename, network_isolation):
39 with open(filename, 'r') as network_settings_file:
40 self.settings_obj = yaml.load(network_settings_file)
41 self.network_isolation = network_isolation
42 self.enabled_network_list = []
43 self._validate_input()
45 def _validate_input(self):
47 Validates the network settings file and populates all fields.
49 NetworkSettingsException will be raised if validation fails.
51 if ADMIN_NETWORK not in self.settings_obj or \
52 self.settings_obj[ADMIN_NETWORK].get('enabled') != True:
53 raise NetworkSettingsException("You must enable admin_network "
54 "and configure it explicitly or "
56 if self.network_isolation and \
57 (PUBLIC_NETWORK not in self.settings_obj or
58 self.settings_obj[PUBLIC_NETWORK].get('enabled') != True):
59 raise NetworkSettingsException("You must enable public_network "
60 "and configure it explicitly or "
63 for network in OPNFV_NETWORK_TYPES:
64 if network in self.settings_obj:
65 if self.settings_obj[network].get('enabled') == True:
66 logging.info("{} enabled".format(network))
67 self._config_required_settings(network)
68 self._config_ip_range(network=network,
69 setting='usable_ip_range',
70 start_offset=21, end_offset=21)
71 self._config_optional_settings(network)
72 self.enabled_network_list.append(network)
74 logging.info("{} disabled, will collapse with "
75 "admin_network".format(network))
77 logging.info("{} is not in specified, will collapse with "
78 "admin_network".format(network))
80 def _config_required_settings(self, network):
82 Configures either CIDR or bridged_interface setting
84 cidr takes precedence if both cidr and bridged_interface are specified
87 When using bridged_interface, we will detect network setting on the
88 given NIC in the system. The resulting config in settings object will
89 be an ipaddress.network object, replacing the NIC name.
91 cidr = self.settings_obj[network].get('cidr')
92 nic_name = self.settings_obj[network].get('bridged_interface')
95 cidr = ipaddress.ip_network(self.settings_obj[network]['cidr'])
96 self.settings_obj[network]['cidr'] = cidr
97 logging.info("{}_cidr: {}".format(network, cidr))
100 # If cidr is not specified, we need to know if we should find
101 # IPv6 or IPv4 address on the interface
102 if self.settings_obj[network].get('ipv6') == True:
106 nic_interface = ip_utils.get_interface(nic_name, address_family)
108 self.settings_obj[network]['bridged_interface'] = nic_interface
109 logging.info("{}_bridged_interface: {}".
110 format(network, nic_interface))
113 raise NetworkSettingsException("Auto detection failed for {}: "
114 "Unable to find valid ip for "
116 .format(network, nic_name))
119 raise NetworkSettingsException("Auto detection failed for {}: "
120 "either bridge_interface or cidr "
124 def _config_ip_range(self, network, setting, start_offset=None,
125 end_offset=None, count=None):
127 Configures IP range for a given setting.
129 If the setting is already specified, no change will be made.
131 The spec for start_offset, end_offset and count are identical to
132 ip_utils.get_ip_range.
134 ip_range = self.settings_obj[network].get(setting)
135 interface = self.settings_obj[network].get('bridged_interface')
138 cidr = self.settings_obj[network].get('cidr')
139 ip_range = ip_utils.get_ip_range(start_offset=start_offset,
140 end_offset=end_offset,
144 self.settings_obj[network][setting] = ip_range
146 logging.info("{}_{}: {}".format(network, setting, ip_range))
148 def _config_ip(self, network, setting, offset):
150 Configures IP for a given setting.
152 If the setting is already specified, no change will be made.
154 The spec for offset is identical to ip_utils.get_ip
156 ip = self.settings_obj[network].get(setting)
157 interface = self.settings_obj[network].get('bridged_interface')
160 cidr = self.settings_obj[network].get('cidr')
161 ip = ip_utils.get_ip(offset, cidr, interface)
162 self.settings_obj[network][setting] = ip
164 logging.info("{}_{}: {}".format(network, setting, ip))
166 def _config_optional_settings(self, network):
168 Configures optional settings:
172 - introspection_range
178 if network == ADMIN_NETWORK:
179 self._config_ip(network, 'provisioner_ip', 1)
180 self._config_ip_range(network=network, setting='dhcp_range',
181 start_offset=2, count=9)
182 self._config_ip_range(network=network,
183 setting='introspection_range',
184 start_offset=11, count=9)
185 elif network == PUBLIC_NETWORK:
186 self._config_ip(network, 'provisioner_ip', 1)
187 self._config_ip_range(network=network,
188 setting='floating_ip',
189 end_offset=2, count=20)
190 self._config_gateway(network)
192 def _config_gateway(self, network):
194 Configures gateway setting for a given network.
196 If cidr is specified, we always use the first address in the address
197 space for gateway. Otherwise, we detect the system gateway.
199 gateway = self.settings_obj[network].get('gateway')
200 interface = self.settings_obj[network].get('bridged_interface')
203 cidr = self.settings_obj[network].get('cidr')
205 gateway = ip_utils.get_ip(1, cidr)
207 gateway = ip_utils.find_gateway(interface)
210 self.settings_obj[network]['gateway'] = gateway
212 raise NetworkSettingsException("Failed to set gateway")
214 logging.info("{}_gateway: {}".format(network, gateway))
217 def dump_bash(self, path=None):
219 Prints settings for bash consumption.
221 If optional path is provided, bash string will be written to the file
225 for network in self.enabled_network_list:
226 for key, value in self.settings_obj[network].items():
227 bash_str += "{}_{}={}\n".format(network, key, value)
228 bash_str += "enabled_network_list='{}'\n" \
229 .format(' '.join(self.enabled_network_list))
230 bash_str += "ip_addr_family={}\n".format(self.get_ip_addr_family())
232 with open(path, 'w') as file:
237 def get_ip_addr_family(self):
239 Returns IP address family for current deployment.
241 If any enabled network has IPv6 CIDR, the deployment is classified as
244 for network in self.enabled_network_list:
245 cidr = ipaddress.ip_network(self.settings_obj[network]['cidr'])
246 if cidr.version == 6:
251 class NetworkSettingsException(Exception):
252 def __init__(self, value):