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
24 ['infra_external', 'infra_storage_cluster', 'infra_hw_management', 'infra_internal', 'cloud_tenant', 'infra_access']
26 NETWORK_DOMAINS = 'network_domains'
28 class Config(config.Config):
29 def __init__(self, confman):
30 super(Config, self).__init__(confman)
31 self.ROOT = 'cloud.networking'
32 self.DOMAIN = 'networking'
34 self.external_vip = None
37 if self.ROOT not in self.config:
40 # a mapping between network and free IPSet
42 for network in self.config[self.ROOT].keys():
43 if network in VALID_NETWORKS:
44 if NETWORK_DOMAINS not in self.config[self.ROOT][network]:
45 raise configerror.ConfigError('No network domains for network %s' % network)
47 self.freepool[network] = {}
48 for domain in self.config[self.ROOT][network][NETWORK_DOMAINS].keys():
49 self.freepool[network][domain] = self._get_free_set(network, domain)
51 except configerror.ConfigError:
54 except Exception as exp:
55 raise configerror.ConfigError(str(exp))
57 def _validate_network(self, network, domain=None):
58 networks = self.get_networks()
59 if network not in networks:
60 raise configerror.ConfigError('Invalid network name %s' % network)
62 if NETWORK_DOMAINS not in self.config[self.ROOT][network]:
63 raise configerror.ConfigError('No network domains for network %s' % network)
65 if domain and domain not in self.config[self.ROOT][network][NETWORK_DOMAINS]:
66 raise configerror.ConfigError('Invalid network domain name %s' % domain)
68 def _get_free_set(self, network, domain):
69 ip_range_start = self.get_network_ip_range_start(network, domain)
70 ip_range_end = self.get_network_ip_range_end(network, domain)
71 select_range = IPRange(ip_range_start, ip_range_end)
72 netset = IPSet(select_range)
73 if (network == self.get_infra_external_network_name() and
74 domain == self._get_vip_domain()):
75 iterator = netset.__iter__()
76 self.external_vip = str(iterator.next())
77 netset.remove(self.external_vip)
79 # check for the IP(s) taken by the nodes
81 hostsconfig = self.confman.get_hosts_config_handler()
82 hosts = hostsconfig.get_hosts()
85 hostip = self.get_host_ip(host, network)
87 except configerror.ConfigError:
89 except configerror.ConfigError:
92 service_profiles_lib = profiles.Profiles()
94 # check for the IP(s) taken as VIPs
95 if network == self.get_infra_internal_network_name() and domain == self._get_vip_domain():
96 vips = self.get_net_vips(network)
97 for _, vip in vips.iteritems():
100 except configerror.ConfigError:
106 """ get the list of dns servers
110 A list of dns servers
114 ConfigError is raised in-case of an error
117 if 'dns' not in self.config[self.ROOT]:
118 raise configerror.ConfigError('dns not found!')
120 return self.config[self.ROOT]['dns']
123 """ get the mtu value
127 A number representing the mtu size
131 ConfigError is raised in-case of an error
134 if 'mtu' not in self.config['cloud.networking']:
135 raise configerror.ConfigError('mtu not found!')
136 return self.config[self.ROOT]['mtu']
138 def get_networks(self):
139 """ get the list of network names
143 A list of network names
147 ConfigError is raised in-case of an error
151 for entry in self.config[self.ROOT]:
152 if entry in VALID_NETWORKS:
153 networks.append(entry)
156 def allocate_ip(self, network, domain):
157 """ get a new free ip in some network
171 ConfigError in-case of an error
173 self._validate_network(network, domain)
176 iterator = self.freepool[network][domain].__iter__()
177 ip = str(iterator.next())
178 self.freepool[network][domain].remove(ip)
181 raise configerror.ConfigError('Failed to allocate ip for network %s in %s' % (network, domain))
183 def allocate_static_ip(self, ip, network, domain=None):
184 """ allocate the given ip in some network
196 The allocated ip address
200 ConfigError in-case of an error
202 self._validate_network(network, domain)
205 self.freepool[network][domain].remove(ip)
208 raise configerror.ConfigError('Failed to allocate %s for network %s in %s' % (ip, network, domain))
210 def allocate_vip(self, network):
211 return self.allocate_ip(network, self._get_vip_domain())
213 def get_network_domains(self, network):
214 self._validate_network(network)
215 return self.config[self.ROOT][network][NETWORK_DOMAINS].keys()
217 def get_network_cidr(self, network, domain):
218 """ get the network cidr
232 ConfigError in-case of an error
234 self._validate_network(network, domain)
236 if 'cidr' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
237 raise configerror.ConfigError('No CIDR for network %s in %s' % (network, domain))
239 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['cidr']
241 def get_vip_network_cidr(self, network):
242 return self.get_network_cidr(network, self._get_vip_domain())
244 def get_network_mask(self, network, domain):
245 """ get the network mask
255 A number representing the mask
259 ConfigError in-case of an error
261 cidr = self.get_network_cidr(network, domain)
263 mask = cidr.split('/')[1]
265 except Exception as exp:
266 raise configerror.ConfigError('Invalid network mask in %s: %s' % (cidr, str(exp)))
268 def get_vip_network_mask(self, network):
269 return self.get_network_mask(network, self._get_vip_domain())
271 def get_network_gateway(self, network, domain):
272 """ get the network gateway
286 ConfigError in-case of an error
288 self._validate_network(network, domain)
290 if 'gateway' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
291 raise configerror.ConfigError('No gateway configured for network %s in %s' % (network, domain))
293 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['gateway']
295 def get_network_routes(self, network, domain):
296 self._validate_network(network, domain)
298 if 'routes' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
299 raise configerror.ConfigError('No routes configured for network %s in %s' % (network, domain))
301 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['routes']
303 def get_network_ip_range_start(self, network, domain):
304 """ get the network allocation range start
314 The starting allocation range
318 ConfigError in-case of an error
320 net = IPNetwork(self.get_network_cidr(network, domain))
322 if 'ip_range_start' in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
323 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['ip_range_start']
327 def get_network_ip_range_end(self, network, domain):
328 """ get the network allocation range end
338 The end of the allocation range
342 ConfigError in-case of an error
344 net = IPNetwork(self.get_network_cidr(network, domain))
346 if 'ip_range_end' in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
347 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['ip_range_end']
351 def get_network_vlan_id(self, network, domain):
352 """ get the network vlan id
366 ConfigError in-case of an error
368 self._validate_network(network, domain)
370 if 'vlan' not in self.config[self.ROOT][network][NETWORK_DOMAINS][domain]:
371 raise configerror.ConfigError('No vlan specified for %s in %s' % (network, domain))
373 return self.config[self.ROOT][network][NETWORK_DOMAINS][domain]['vlan']
375 def get_vip_network_vlan_id(self, network):
376 return self.get_network_vlan_id(network, self._get_vip_domain())
378 def get_network_mtu(self, network):
379 """ get the network mtu
387 The mtu of the network
391 ConfigError in-case of an error
393 self._validate_network(network)
395 if 'mtu' not in self.config[self.ROOT][network]:
396 raise configerror.ConfigError('No mtu specified for %s' % network)
398 return self.config[self.ROOT][network]['mtu']
400 def get_host_ip(self, host, network):
401 """ get the host ip allocated from a specific network
405 hostname: The name of the host
406 networkname: The name of the network
410 The ip address assigned for the host
414 ConfigError in-case of an error
416 self._validate_network(network)
418 hostnetconfigkey = host + '.' + self.DOMAIN
419 if hostnetconfigkey not in self.config:
420 raise configerror.ConfigError('No network configuration available for %s' % host)
422 if network not in self.config[hostnetconfigkey]:
423 raise configerror.ConfigError('No network configuration available for %s' % host)
425 if 'ip' not in self.config[hostnetconfigkey][network]:
426 raise configerror.ConfigError('No IP assigned for %s in network %s' % (host, network))
428 return self.config[hostnetconfigkey][network]['ip']
430 def _get_vip_domain(self):
431 return self.confman.get_hosts_config_handler().get_managements_network_domain()
434 def get_infra_external_network_name():
435 """ get the network name for the external network
439 The external network name
443 ConfigError in-case the network is not configured
445 return 'infra_external'
448 def get_infra_storage_cluster_network_name():
449 """ get the infra storage cluster network name
453 The infra stroage cluster network name
457 ConfigError in-case the network is not configured
459 return 'infra_storage_cluster'
462 def get_hwmgmt_network_name():
463 """ get the hwmgmt network name
467 The hwmgmt network name
471 ConfigError in-case the network is not defined
473 return 'infra_hw_management'
476 def get_infra_internal_network_name():
477 """ get the infra management network name
481 The infra management network name
485 ConfigError in-case the network is not defined
487 return 'infra_internal'
489 def get_cloud_tenant_network_name(self):
490 """ get the network name for the cloud tenant network
494 The cloud tenant network name
498 ConfigError in-case the network is not configured
500 return 'cloud_tenant'
502 def get_infra_access_network_name(self):
503 """ get the network name for the infra access network
507 The infra access network name
511 ConfigError in-case the network is not configured
513 return 'infra_access'
515 def add_host_networks(self, host):
516 """ add host network data
524 ConfigError in-case of an error
526 hostsconf = self.confman.get_hosts_config_handler()
527 networks = hostsconf.get_host_networks(host)
528 domain = hostsconf.get_host_network_domain(host)
529 for network in networks:
531 ip = self.get_host_ip(host, network)
533 except configerror.ConfigError:
536 static_ip = hostsconf.get_pre_allocated_ips(host, network)
538 ip = self.allocate_static_ip(static_ip, network, domain)
540 ip = self.allocate_ip(network, domain)
541 interface = hostsconf.get_host_network_ip_holding_interface(host, network)
542 netmask = self.get_network_mask(network, domain)
543 networkdata = {'ip': ip, 'interface': interface, 'mask': netmask}
546 vlan = self.get_network_vlan_id(network, domain)
547 networkdata['vlan'] = vlan
548 except configerror.ConfigError:
552 gw = self.get_network_gateway(network, domain)
553 networkdata['gateway'] = gw
554 except configerror.ConfigError:
558 routes = self.get_network_routes(network, domain)
559 networkdata['routes'] = routes
560 except configerror.ConfigError:
563 key = host + '.' + self.DOMAIN
564 if key not in self.config:
565 self.config[key] = {}
566 if network not in self.config[key]:
567 self.config[key][network] = {}
569 self.config[key][network] = networkdata
571 def delete_host_networks(self, host):
572 """ delete host network data
578 key = '{}.{}'.format(host, self.DOMAIN)
579 if key in self.config:
582 def get_networking_hosts(self):
583 """ get hosts with networking data
587 List of host names with existing networking data
590 match = r'^[^.]*\.networking$'
591 for key in self.config.keys():
592 if key != self.ROOT and re.match(match, key):
593 hosts.append(key.split('.')[0])
596 def get_host_interface(self, host, network):
597 """ get the host interface allocated from a specific network
601 hostname: The name of the host
602 networkname: The name of the network
606 The interface for the host
610 ConfigError in-case of an error
612 self._validate_network(network)
614 hostnetconfigkey = host + '.' + self.DOMAIN
615 if hostnetconfigkey not in self.config:
616 raise configerror.ConfigError('No network configuration available for %s' % host)
618 if network not in self.config[hostnetconfigkey]:
619 raise configerror.ConfigError('No network configuration available for %s' % host)
621 if 'interface' not in self.config[hostnetconfigkey][network]:
622 raise configerror.ConfigError(
623 'No interface assigned for %s in network %s' % (host, network))
625 return self.config[hostnetconfigkey][network]['interface']
627 def get_host_mask(self, host, network):
628 """ get the network mask for the host
632 hostname: The name of the host
633 networkname: The name of the network
641 ConfigError in-case of an error
643 self._validate_network(network)
645 hostnetconfigkey = host + '.' + self.DOMAIN
646 if hostnetconfigkey not in self.config:
647 raise configerror.ConfigError('No network configuration available for %s' % host)
649 if network not in self.config[hostnetconfigkey]:
650 raise configerror.ConfigError('No network configuration available for %s' % host)
652 if 'mask' not in self.config[hostnetconfigkey][network]:
653 raise configerror.ConfigError('No mask assigned for %s in network %s' % (host, network))
655 return self.config[hostnetconfigkey][network]['mask']
658 def get_external_vip(self):
659 """ get the external vip ip, this is always the first ip in the range
661 return self.external_vip
664 def get_provider_networks(self):
666 Get provider network names
669 A list of provider network names
672 ConfigError in-case of an error
674 if 'provider_networks' not in self.config[self.ROOT]:
675 raise configerror.ConfigError('No provider networks configured')
677 return self.config[self.ROOT]['provider_networks'].keys()
679 def is_shared_provider_network(self, network):
681 Is shared provider network
684 Provider network name
687 True if given provider network is shared, False otherwise
690 ConfigError in-case of an error
692 networks = self.get_provider_networks()
693 if network not in networks:
694 raise configerror.ConfigError('Missing configuration for provider network %s' % network)
696 return (self.config[self.ROOT]['provider_networks'][network].get('shared') is True)
698 def get_provider_network_vlan_ranges(self, network):
700 Get vlan ranges for the given provider network
703 Provider network name
706 Vlan ranges for the provider network
709 ConfigError in-case of an error
711 networks = self.get_provider_networks()
712 if network not in networks:
713 raise configerror.ConfigError('Missing configuration for provider network %s' % network)
715 if 'vlan_ranges' not in self.config[self.ROOT]['provider_networks'][network]:
716 raise configerror.ConfigError(
717 'Missing vlan ranges configuration for provider network %s' % network)
719 return self.config[self.ROOT]['provider_networks'][network]['vlan_ranges']
722 def get_provider_network_mtu(self, network):
724 Get mtu for the given provider network
727 Provider network name
730 mtu for the provider network
733 ConfigError in-case of an error
735 networks = self.get_provider_networks()
736 if network not in networks:
737 raise configerror.ConfigError('Missing configuration for provider network %s' % network)
739 if 'mtu' not in self.config[self.ROOT]['provider_networks'][network]:
740 raise configerror.ConfigError(
741 'Missing mtu configuration for provider network %s' % network)
743 return self.config[self.ROOT]['provider_networks'][network]['mtu']
745 def is_l3_ha_enabled(self):
750 True if L3 HA is enabled, False otherwise
752 return True if 'l3_ha' in self.config[self.ROOT] else False
754 def _get_l3_ha_config(self):
755 if 'l3_ha' not in self.config[self.ROOT]:
756 raise configerror.ConfigError('Missing L3 HA configuration')
758 return self.config[self.ROOT]['l3_ha']
760 def get_l3_ha_provider_network(self):
761 """ get L3 HA provider network
765 L3 HA provider network name
769 ConfigError in-case of an error
771 conf = self._get_l3_ha_config()
772 if 'provider_network' not in conf:
773 raise configerror.ConfigError('Missing L3 HA provider network configuration')
775 return conf['provider_network']
777 def get_l3_ha_cidr(self):
786 ConfigError in-case of an error
788 conf = self._get_l3_ha_config()
789 if 'cidr' not in conf:
790 raise configerror.ConfigError('Missing L3 HA CIDR configuration')
794 def add_ovs_config_defaults(self, host):
795 """ Add Openvswitch default config """
797 ovs_defaults = { 'tx-flush-interval': 0, 'rxq-rebalance': 0 }
800 if key not in self.config:
801 self.config[key] = {}
802 if 'ovs_config' not in self.config[key]:
803 self.config[key]['ovs_config'] = {}
804 if host not in self.config[key]['ovs_config']:
805 self.config[key]['ovs_config'][host] = {}
807 self.config[key]['ovs_config'][host] = ovs_defaults
809 def del_ovs_config(self, host):
810 """ Delete Openvswitch config """
811 if host in self.config[self.ROOT]['ovs_config']:
812 self.config[self.ROOT]['ovs_config'].pop(host, None)
814 def get_ovs_config(self, host):
815 return self.config[self.ROOT]['ovs_config'].get(host, None)
817 def _validate_ovs_config_args(self, host, args):
818 ovs_conf = self.config[self.ROOT]['ovs_config']
820 if args.get('tx_flush_interval') is not None:
821 if int(args['tx_flush_interval']) >= 0 and int(args['tx_flush_interval']) <= 1000000:
822 ovs_conf[host]['tx-flush-interval'] = int(args['tx_flush_interval'])
824 raise ValueError("tx-flush-interval value must be 0..1000000")
826 if args.get('rxq_rebalance_interval') is not None:
827 if int(args['rxq_rebalance_interval']) >= 0 and int(args['rxq_rebalance_interval']) <= 1000000:
828 ovs_conf[host]['rxq-rebalance'] = int(args['rxq_rebalance_interval'])
830 raise ValueError("rxq_rebalance_interval value must be 0..1000000")
832 def update_ovs_config(self, host, args):
833 if self.config[self.ROOT]['ovs_config'].get(host, None) is None:
835 self._validate_ovs_config_args(host, args)
836 return self.config[self.ROOT]
838 def get_ovs_config_hosts(self):
839 return [host for host in self.config[self.ROOT]['ovs_config']]
841 def add_vip(self, network, name, ip):
842 if 'vips' not in self.config[self.ROOT]:
843 self.config[self.ROOT]['vips'] = {}
845 if network not in self.config[self.ROOT]['vips']:
846 self.config[self.ROOT]['vips'][network] = {}
848 self.config[self.ROOT]['vips'][network][name] = ip
850 def add_external_vip(self):
851 external_vip = self.get_external_vip()
852 self.add_vip('infra_external', 'external_vip', external_vip)
854 def add_internal_vip(self):
855 internal_vip = self.allocate_vip('infra_internal')
856 self.add_vip('infra_internal', 'internal_vip', internal_vip)
858 def get_internal_vip(self):
860 return self.config[self.ROOT]['vips']['infra_internal']['internal_vip']
861 except KeyError as exp:
862 raise configerror.ConfigError('Internal vip not found')
865 if 'vips' not in self.config[self.ROOT]:
868 return self.config[self.ROOT]['vips']
870 def get_net_vips(self, net):
871 if 'vips' not in self.config[self.ROOT]:
874 if net not in self.config[self.ROOT]['vips']:
877 return self.config[self.ROOT]['vips'][net]
879 return self.config[self.ROOT]['vips']