3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 from cmdatahandlers.api import configerror
18 from cmdatahandlers.api import config
19 from serviceprofiles import profiles
20 from netaddr import IPNetwork, IPSet, IPRange
29 'infra_hw_management',
30 'infra_storage_cluster',
33 NETWORK_DOMAINS = 'network_domains'
36 class Config(config.Config):
37 def __init__(self, confman):
38 super(Config, self).__init__(confman)
39 self.ROOT = 'cloud.networking'
40 self.DOMAIN = 'networking'
42 self.external_vip = None
45 if self.ROOT not in self.config:
48 # a mapping between network and free IPSet
50 for network in self.config[self.ROOT].keys():
51 if network in VALID_NETWORKS:
52 if NETWORK_DOMAINS not in self.config[self.ROOT][network]:
53 raise configerror.ConfigError('No network domains for network %s' % network)
55 self.freepool[network] = {}
56 for domain in self.config[self.ROOT][network][NETWORK_DOMAINS].keys():
57 self.freepool[network][domain] = self._get_free_set(network, domain)
59 except configerror.ConfigError:
62 except Exception as exp:
63 raise configerror.ConfigError(str(exp))
65 def _validate_network(self, network, domain=None):
66 networks = self.get_networks()
67 if network not in networks:
68 raise configerror.ConfigError('Invalid network name %s' % network)
70 if NETWORK_DOMAINS not in self.config[self.ROOT][network]:
71 raise configerror.ConfigError('No network domains for network %s' % network)
73 if domain and domain not in self.config[self.ROOT][network][NETWORK_DOMAINS]:
74 raise configerror.ConfigError('Invalid network domain name %s' % domain)
76 def _get_free_set(self, network, domain):
77 ip_range_start = self.get_network_ip_range_start(network, domain)
78 ip_range_end = self.get_network_ip_range_end(network, domain)
79 select_range = IPRange(ip_range_start, ip_range_end)
80 netset = IPSet(select_range)
81 if (network == self.get_infra_external_network_name() and
82 domain == self._get_vip_domain()):
83 iterator = netset.__iter__()
84 self.external_vip = str(iterator.next())
85 netset.remove(self.external_vip)
87 # check for the IP(s) taken by the nodes
89 hostsconfig = self.confman.get_hosts_config_handler()
90 hosts = hostsconfig.get_hosts()
93 hostip = self.get_host_ip(host, network)
95 except configerror.ConfigError:
97 except configerror.ConfigError:
100 service_profiles_lib = profiles.Profiles()
102 # check for the IP(s) taken as VIPs
103 if network == self.get_infra_internal_network_name() and domain == self._get_vip_domain():
104 vips = self.get_net_vips(network)
105 for _, vip in vips.iteritems():
108 except configerror.ConfigError:
114 """ get the list of dns servers
118 A list of dns servers
122 ConfigError is raised in-case of an error
125 if 'dns' not in self.config[self.ROOT]:
126 raise configerror.ConfigError('dns not found!')
128 return self.config[self.ROOT]['dns']
131 """ get the mtu value
135 A number representing the mtu size
139 ConfigError is raised in-case of an error
142 if 'mtu' not in self.config['cloud.networking']:
143 raise configerror.ConfigError('mtu not found!')
144 return self.config[self.ROOT]['mtu']
146 def get_networks(self):
147 """ get the list of network names
151 A list of network names
155 ConfigError is raised in-case of an error
159 for entry in self.config[self.ROOT]:
160 if entry in VALID_NETWORKS:
161 networks.append(entry)
164 def allocate_ip(self, network, domain):
165 """ get a new free ip in some network
179 ConfigError in-case of an error
181 self._validate_network(network, domain)
184 iterator = self.freepool[network][domain].__iter__()
185 ip = str(iterator.next())
186 self.freepool[network][domain].remove(ip)
189 raise configerror.ConfigError('Failed to allocate ip for network %s in %s' % (network, domain))
191 def allocate_static_ip(self, ip, network, domain=None):
192 """ allocate the given ip in some network
204 The allocated ip address
208 ConfigError in-case of an error
210 self._validate_network(network, domain)
213 self.freepool[network][domain].remove(ip)
216 raise configerror.ConfigError('Failed to allocate %s for network %s in %s' % (ip, network, domain))
218 def allocate_vip(self, network):
219 return self.allocate_ip(network, self._get_vip_domain())
221 def get_network_domains(self, network):
222 self._validate_network(network)
223 return self.config[self.ROOT][network][NETWORK_DOMAINS].keys()
225 def get_network_cidr(self, network, domain):
226 """ get the network cidr
240 ConfigError in-case of an error
242 self._validate_network(network, domain)
244 if 'cidr' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
245 raise configerror.ConfigError('No CIDR for network %s in %s' % (network, domain))
247 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['cidr']
249 def get_vip_network_cidr(self, network):
250 return self.get_network_cidr(network, self._get_vip_domain())
252 def get_network_mask(self, network, domain):
253 """ get the network mask
263 A number representing the mask
267 ConfigError in-case of an error
269 cidr = self.get_network_cidr(network, domain)
271 mask = cidr.split('/')[1]
273 except Exception as exp:
274 raise configerror.ConfigError('Invalid network mask in %s: %s' % (cidr, str(exp)))
276 def get_vip_network_mask(self, network):
277 return self.get_network_mask(network, self._get_vip_domain())
279 def get_network_gateway(self, network, domain):
280 """ get the network gateway
294 ConfigError in-case of an error
296 self._validate_network(network, domain)
298 if 'gateway' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
299 raise configerror.ConfigError('No gateway configured for network %s in %s' % (network, domain))
301 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['gateway']
303 def get_network_routes(self, network, domain):
304 self._validate_network(network, domain)
306 if 'routes' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
307 raise configerror.ConfigError('No routes configured for network %s in %s' % (network, domain))
309 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['routes']
311 def get_network_ip_range_start(self, network, domain):
312 """ get the network allocation range start
322 The starting allocation range
326 ConfigError in-case of an error
328 net = IPNetwork(self.get_network_cidr(network, domain))
330 if 'ip_range_start' in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
331 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['ip_range_start']
335 def get_network_ip_range_end(self, network, domain):
336 """ get the network allocation range end
346 The end of the allocation range
350 ConfigError in-case of an error
352 net = IPNetwork(self.get_network_cidr(network, domain))
354 if 'ip_range_end' in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
355 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['ip_range_end']
359 def get_network_vlan_id(self, network, domain):
360 """ get the network vlan id
374 ConfigError in-case of an error
376 self._validate_network(network, domain)
378 if 'vlan' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
379 raise configerror.ConfigError('No vlan specified for %s in %s' % (network, domain))
381 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['vlan']
383 def get_vip_network_vlan_id(self, network):
384 return self.get_network_vlan_id(network, self._get_vip_domain())
386 def get_network_mtu(self, network):
387 """ get the network mtu
395 The mtu of the network
399 ConfigError in-case of an error
401 self._validate_network(network)
403 if 'mtu' not in self.config[self.ROOT][network]:
404 raise configerror.ConfigError('No mtu specified for %s' % network)
406 return self.config[self.ROOT][network]['mtu']
408 def get_host_ip(self, host, network):
409 """ get the host ip allocated from a specific network
413 hostname: The name of the host
414 networkname: The name of the network
418 The ip address assigned for the host
422 ConfigError in-case of an error
424 self._validate_network(network)
426 hostnetconfigkey = host + '.' + self.DOMAIN
427 if hostnetconfigkey not in self.config:
428 raise configerror.ConfigError('No network configuration available for %s' % host)
430 if network not in self.config[hostnetconfigkey]:
431 raise configerror.ConfigError('No network configuration available for %s' % host)
433 if 'ip' not in self.config[hostnetconfigkey][network]:
434 raise configerror.ConfigError('No IP assigned for %s in network %s' % (host, network))
436 return self.config[hostnetconfigkey][network]['ip']
438 def _get_vip_domain(self):
439 return self.confman.get_hosts_config_handler().get_managements_network_domain()
442 def get_infra_external_network_name():
443 """ get the network name for the external network
447 The external network name
451 ConfigError in-case the network is not configured
453 return 'infra_external'
456 def get_infra_storage_cluster_network_name():
457 """ get the infra storage cluster network name
461 The infra stroage cluster network name
465 ConfigError in-case the network is not configured
467 return 'infra_storage_cluster'
470 def get_hwmgmt_network_name():
471 """ get the hwmgmt network name
475 The hwmgmt network name
479 ConfigError in-case the network is not defined
481 return 'infra_hw_management'
484 def get_infra_internal_network_name():
485 """ get the infra management network name
489 The infra management network name
493 ConfigError in-case the network is not defined
495 return 'infra_internal'
498 def get_caas_oam_network_name():
499 """ get the CaaS OAM network name
503 The CaaS OAM network name
510 def get_cloud_tenant_network_name(self):
511 """ get the network name for the cloud tenant network
515 The cloud tenant network name
519 ConfigError in-case the network is not configured
521 return 'cloud_tenant'
523 def get_infra_access_network_name(self):
524 """ get the network name for the infra access network
528 The infra access network name
532 ConfigError in-case the network is not configured
534 return 'infra_access'
536 def add_host_networks(self, host):
537 """ add host network data
545 ConfigError in-case of an error
547 hostsconf = self.confman.get_hosts_config_handler()
548 networks = hostsconf.get_host_networks(host)
549 domain = hostsconf.get_host_network_domain(host)
550 for network in networks:
552 ip = self.get_host_ip(host, network)
554 except configerror.ConfigError:
557 static_ip = hostsconf.get_pre_allocated_ips(host, network)
559 ip = self.allocate_static_ip(static_ip, network, domain)
561 ip = self.allocate_ip(network, domain)
562 interface = hostsconf.get_host_network_ip_holding_interface(host, network)
563 netmask = self.get_network_mask(network, domain)
564 networkdata = {'ip': ip, 'interface': interface, 'mask': netmask}
567 vlan = self.get_network_vlan_id(network, domain)
568 networkdata['vlan'] = vlan
569 except configerror.ConfigError:
573 gw = self.get_network_gateway(network, domain)
574 networkdata['gateway'] = gw
575 except configerror.ConfigError:
579 routes = self.get_network_routes(network, domain)
580 networkdata['routes'] = routes
581 except configerror.ConfigError:
585 cidr = self.get_network_cidr(network, domain)
586 networkdata['cidr'] = cidr
587 except configerror.ConfigError:
590 key = host + '.' + self.DOMAIN
591 if key not in self.config:
592 self.config[key] = {}
593 if network not in self.config[key]:
594 self.config[key][network] = {}
596 self.config[key][network] = networkdata
598 def delete_host_networks(self, host):
599 """ delete host network data
605 key = '{}.{}'.format(host, self.DOMAIN)
606 if key in self.config:
609 def get_networking_hosts(self):
610 """ get hosts with networking data
614 List of host names with existing networking data
617 match = r'^[^.]*\.networking$'
618 for key in self.config.keys():
619 if key != self.ROOT and re.match(match, key):
620 hosts.append(key.split('.')[0])
623 def get_host_interface(self, host, network):
624 """ get the host interface allocated from a specific network
628 hostname: The name of the host
629 networkname: The name of the network
633 The interface for the host
637 ConfigError in-case of an error
639 self._validate_network(network)
641 hostnetconfigkey = host + '.' + self.DOMAIN
642 if hostnetconfigkey not in self.config:
643 raise configerror.ConfigError('No network configuration available for %s' % host)
645 if network not in self.config[hostnetconfigkey]:
646 raise configerror.ConfigError('No network configuration available for %s' % host)
648 if 'interface' not in self.config[hostnetconfigkey][network]:
649 raise configerror.ConfigError(
650 'No interface assigned for %s in network %s' % (host, network))
652 return self.config[hostnetconfigkey][network]['interface']
654 def get_host_mask(self, host, network):
655 """ get the network mask for the host
659 hostname: The name of the host
660 networkname: The name of the network
668 ConfigError in-case of an error
670 self._validate_network(network)
672 hostnetconfigkey = host + '.' + self.DOMAIN
673 if hostnetconfigkey not in self.config:
674 raise configerror.ConfigError('No network configuration available for %s' % host)
676 if network not in self.config[hostnetconfigkey]:
677 raise configerror.ConfigError('No network configuration available for %s' % host)
679 if 'mask' not in self.config[hostnetconfigkey][network]:
680 raise configerror.ConfigError('No mask assigned for %s in network %s' % (host, network))
682 return self.config[hostnetconfigkey][network]['mask']
684 def get_external_vip(self):
685 """ get the external vip ip, this is always the first ip in the range
687 return self.external_vip
689 def get_provider_networks(self):
691 Get provider network names
694 A list of provider network names
697 ConfigError in-case of an error
699 if 'provider_networks' not in self.config[self.ROOT]:
700 raise configerror.ConfigError('No provider networks configured')
702 return self.config[self.ROOT]['provider_networks'].keys()
704 def is_shared_provider_network(self, network):
706 Is shared provider network
709 Provider network name
712 True if given provider network is shared, False otherwise
715 ConfigError in-case of an error
717 networks = self.get_provider_networks()
718 if network not in networks:
719 raise configerror.ConfigError('Missing configuration for provider network %s' % network)
721 return (self.config[self.ROOT]['provider_networks'][network].get('shared') is True)
723 def get_provider_network_vlan_ranges(self, network):
725 Get vlan ranges for the given provider network
728 Provider network name
731 Vlan ranges for the provider network
734 ConfigError in-case of an error
736 networks = self.get_provider_networks()
737 if network not in networks:
738 raise configerror.ConfigError('Missing configuration for provider network %s' % network)
740 if 'vlan_ranges' not in self.config[self.ROOT]['provider_networks'][network]:
741 raise configerror.ConfigError(
742 'Missing vlan ranges configuration for provider network %s' % network)
744 return self.config[self.ROOT]['provider_networks'][network]['vlan_ranges']
746 def get_provider_network_mtu(self, network):
748 Get mtu for the given provider network
751 Provider network name
754 mtu for the provider network
757 ConfigError in-case of an error
759 networks = self.get_provider_networks()
760 if network not in networks:
761 raise configerror.ConfigError('Missing configuration for provider network %s' % network)
763 if 'mtu' not in self.config[self.ROOT]['provider_networks'][network]:
764 raise configerror.ConfigError(
765 'Missing mtu configuration for provider network %s' % network)
767 return self.config[self.ROOT]['provider_networks'][network]['mtu']
769 def is_l3_ha_enabled(self):
774 True if L3 HA is enabled, False otherwise
776 return True if 'l3_ha' in self.config[self.ROOT] else False
778 def _get_l3_ha_config(self):
779 if 'l3_ha' not in self.config[self.ROOT]:
780 raise configerror.ConfigError('Missing L3 HA configuration')
782 return self.config[self.ROOT]['l3_ha']
784 def get_l3_ha_provider_network(self):
785 """ get L3 HA provider network
789 L3 HA provider network name
793 ConfigError in-case of an error
795 conf = self._get_l3_ha_config()
796 if 'provider_network' not in conf:
797 raise configerror.ConfigError('Missing L3 HA provider network configuration')
799 return conf['provider_network']
801 def get_l3_ha_cidr(self):
810 ConfigError in-case of an error
812 conf = self._get_l3_ha_config()
813 if 'cidr' not in conf:
814 raise configerror.ConfigError('Missing L3 HA CIDR configuration')
818 def add_ovs_config_defaults(self, host):
819 """ Add Openvswitch default config """
821 ovs_defaults = { 'tx-flush-interval': 0, 'rxq-rebalance': 0 }
824 if key not in self.config:
825 self.config[key] = {}
826 if 'ovs_config' not in self.config[key]:
827 self.config[key]['ovs_config'] = {}
828 if host not in self.config[key]['ovs_config']:
829 self.config[key]['ovs_config'][host] = {}
831 self.config[key]['ovs_config'][host] = ovs_defaults
833 def del_ovs_config(self, host):
834 """ Delete Openvswitch config """
835 if host in self.config[self.ROOT]['ovs_config']:
836 self.config[self.ROOT]['ovs_config'].pop(host, None)
838 def get_ovs_config(self, host):
839 return self.config[self.ROOT]['ovs_config'].get(host, None)
841 def _validate_ovs_config_args(self, host, args):
842 ovs_conf = self.config[self.ROOT]['ovs_config']
844 if args.get('tx_flush_interval') is not None:
845 if int(args['tx_flush_interval']) >= 0 and int(args['tx_flush_interval']) <= 1000000:
846 ovs_conf[host]['tx-flush-interval'] = int(args['tx_flush_interval'])
848 raise ValueError("tx-flush-interval value must be 0..1000000")
850 if args.get('rxq_rebalance_interval') is not None:
851 if int(args['rxq_rebalance_interval']) >= 0 and int(args['rxq_rebalance_interval']) <= 1000000:
852 ovs_conf[host]['rxq-rebalance'] = int(args['rxq_rebalance_interval'])
854 raise ValueError("rxq_rebalance_interval value must be 0..1000000")
856 def update_ovs_config(self, host, args):
857 if self.config[self.ROOT]['ovs_config'].get(host, None) is None:
859 self._validate_ovs_config_args(host, args)
860 return self.config[self.ROOT]
862 def get_ovs_config_hosts(self):
863 return [host for host in self.config[self.ROOT]['ovs_config']]
865 def add_vip(self, network, name, ip):
866 if 'vips' not in self.config[self.ROOT]:
867 self.config[self.ROOT]['vips'] = {}
869 if network not in self.config[self.ROOT]['vips']:
870 self.config[self.ROOT]['vips'][network] = {}
872 self.config[self.ROOT]['vips'][network][name] = ip
874 def add_external_vip(self):
875 external_vip = self.get_external_vip()
876 self.add_vip('infra_external', 'external_vip', external_vip)
878 def add_internal_vip(self):
879 internal_vip = self.allocate_vip('infra_internal')
880 self.add_vip('infra_internal', 'internal_vip', internal_vip)
882 def get_internal_vip(self):
884 return self.config[self.ROOT]['vips']['infra_internal']['internal_vip']
885 except KeyError as exp:
886 raise configerror.ConfigError('Internal vip not found')
889 if 'vips' not in self.config[self.ROOT]:
892 return self.config[self.ROOT]['vips']
894 def get_net_vips(self, net):
895 if 'vips' not in self.config[self.ROOT]:
898 if net not in self.config[self.ROOT]['vips']:
901 return self.config[self.ROOT]['vips'][net]
903 return self.config[self.ROOT]['vips']