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 cmdatahandlers.api import utils
20 from serviceprofiles import profiles
23 class Config(config.Config):
24 def __init__(self, confman):
25 super(Config, self).__init__(confman)
26 self.ROOT = 'cloud.hosts'
29 self.update_service_profiles()
39 hosts = self.get_hosts()
40 except configerror.ConfigError:
44 utils.validate_list_items_unique(hosts)
47 self._validate_host(host)
49 def mask_sensitive_data(self):
50 for hostname in self.config[self.ROOT].keys():
51 self.config[self.ROOT][hostname]['hwmgmt']['password'] = self.MASK
52 self.config[self.ROOT][hostname]['hwmgmt']['snmpv2_trap_community_string'] = self.MASK
53 self.config[self.ROOT][hostname]['hwmgmt']['snmpv3_authpass'] = self.MASK
54 self.config[self.ROOT][hostname]['hwmgmt']['snmpv3_privpass'] = self.MASK
56 def _validate_host(self, hostname):
57 self._validate_hwmgmt(hostname)
58 self._validate_service_profiles(hostname)
59 self._validate_network_profiles(hostname)
60 self._validate_performance_profiles(hostname)
61 self._validate_storage_profiles(hostname)
63 def _validate_hwmgmt(self, hostname):
64 ip = self.get_hwmgmt_ip(hostname)
65 utils.validate_ipv4_address(ip)
66 self.get_hwmgmt_user(hostname)
67 self.get_hwmgmt_password(hostname)
68 netconf = self.confman.get_networking_config_handler()
72 hwmgmtnet = netconf.get_hwmgmt_network_name()
73 except configerror.ConfigError:
77 domain = self.get_host_network_domain(hostname)
78 cidr = netconf.get_network_cidr(hwmgmtnet, domain)
79 utils.validate_ip_in_network(ip, cidr)
81 def _validate_service_profiles(self, hostname):
82 node_profiles = self.get_service_profiles(hostname)
83 utils.validate_list_items_unique(node_profiles)
84 service_profiles_lib = profiles.Profiles()
85 serviceprofiles = service_profiles_lib.get_service_profiles()
86 for profile in node_profiles:
87 if profile not in serviceprofiles:
88 raise configerror.ConfigError('Invalid service profile %s specified for host %s' % (profile, hostname))
90 def _validate_network_profiles(self, hostname):
91 node_profiles = self.get_network_profiles(hostname)
92 utils.validate_list_items_unique(profiles)
93 netprofconf = self.confman.get_network_profiles_config_handler()
94 netprofiles = netprofconf.get_network_profiles()
95 for profile in node_profiles:
96 if profile not in netprofiles:
97 raise configerror.ConfigError('Invalid network profile %s specified for host %s' % (profile, hostname))
99 def _validate_performance_profiles(self, hostname):
100 node_performance_profiles = []
102 node_performance_profiles = self.get_performance_profiles(hostname)
103 except configerror.ConfigError:
106 if node_performance_profiles:
107 utils.validate_list_items_unique(node_performance_profiles)
108 perfprofconf = self.confman.get_performance_profiles_config_handler()
109 perfprofiles = perfprofconf.get_performance_profiles()
110 for profile in node_performance_profiles:
111 if profile not in perfprofiles:
112 raise configerror.ConfigError('Invalid performance profile %s specified for host %s' % (profile, hostname))
114 def _validate_storage_profiles(self, hostname):
115 node_storage_profiles = []
117 node_storage_profiles = self.get_storage_profiles(hostname)
118 except configerror.ConfigError:
121 if node_storage_profiles:
122 utils.validate_list_items_unique(node_storage_profiles)
123 storageprofconf = self.confman.get_storage_profiles_config_handler()
124 storageprofiles = storageprofconf.get_storage_profiles()
125 for profile in node_storage_profiles:
126 if profile not in storageprofiles:
127 raise configerror.ConfigError('Invalid storage profile %s specific for %s' % (profile, hostname))
130 """ get the list of hosts in the cloud
134 A sorted list of host names
138 ConfigError in-case of an error
142 return sorted(self.config[self.ROOT].keys())
144 def get_labels(self, hostname):
145 noderole_label = "node-role.kubernetes.io/{}".format(self.get_noderole(hostname))
147 {"nodetype": self.get_nodetype(hostname),
148 "nodeindex": self.get_nodeindex(hostname),
149 "nodename": self.get_nodename(hostname),
151 labels = self.config[self.ROOT][hostname].get('labels', {}).copy()
152 labels.update(mandatory_labels)
154 if self.is_sriov_enabled(hostname):
155 labels.update({"sriov": "enabled"})
157 black_list = ['name']
158 return {name: attributes
159 for name, attributes in labels.iteritems()
160 if name not in black_list}
162 def get_nodetype(self, hostname):
163 service_profiles_lib = profiles.Profiles()
164 service_profiles = self.get_service_profiles(hostname)
166 if service_profiles_lib.get_caasmaster_service_profile() in service_profiles:
167 return service_profiles_lib.get_caasmaster_service_profile()
168 if service_profiles_lib.get_caasworker_service_profile() in service_profiles:
169 return service_profiles_lib.get_caasworker_service_profile()
171 return service_profiles[0]
173 def get_nodeindex(self, hostname):
174 return re.search(r'[-_](\d+)$', hostname).group(1)
176 def get_nodename(self, hostname):
177 return "{}{}".format(self.get_nodetype(hostname), self.get_nodeindex(hostname))
179 def get_noderole(self, hostname):
180 service_profiles_lib = profiles.Profiles()
181 service_profiles = self.get_service_profiles(hostname)
183 if service_profiles_lib.get_caasmaster_service_profile() in service_profiles:
187 def is_sriov_enabled(self, hostname):
188 netprofs = self.get_network_profiles(hostname)
189 netprofconf = self.confman.get_network_profiles_config_handler()
190 for netprof in netprofs:
191 if 'sriov_provider_networks' in self.config[netprofconf.ROOT][netprof]:
195 def get_enabled_hosts(self):
196 """ get the list of enabled hosts in the cloud
204 ConfigError in-case of an error
207 hosts = self.get_hosts()
210 if self.is_host_enabled(host):
214 def get_hwmgmt_ip(self, hostname):
215 """get the hwmgmt ip address
219 hostname: The name of the node
223 The BMC ip address as a string
227 ConfigError in-case of an error
229 self._validate_hostname(hostname)
231 if 'hwmgmt' not in self.config[self.ROOT][hostname] or 'address' not in self.config[self.ROOT][hostname]['hwmgmt']:
232 raise configerror.ConfigError('No hwmgmt info defined for host')
234 return self.config[self.ROOT][hostname]['hwmgmt']['address']
236 def get_hwmgmt_user(self, hostname):
237 """get the hwmgmt user
241 hostname: The name of the node
249 ConfigError in-case of an error
251 self._validate_hostname(hostname)
253 if 'hwmgmt' not in self.config[self.ROOT][hostname] or 'user' not in self.config[self.ROOT][hostname]['hwmgmt']:
254 raise configerror.ConfigError('No hwmgmt info defined for host')
256 return self.config[self.ROOT][hostname]['hwmgmt']['user']
258 def get_hwmgmt_password(self, hostname):
259 """get the hwmgmt password
263 hostname: The name of the node
271 ConfigError in-case of an error
273 self._validate_hostname(hostname)
275 if 'hwmgmt' not in self.config[self.ROOT][hostname] or 'password' not in self.config[self.ROOT][hostname]['hwmgmt']:
276 raise configerror.ConfigError('No hwmgmt info defined for host')
278 return self.config[self.ROOT][hostname]['hwmgmt']['password']
280 def get_service_profiles(self, hostname):
281 """get the node service profiles
285 hostname: The name of the node
289 A list containing service profile names
293 ConfigError in-case of an error
295 self._validate_hostname(hostname)
297 if 'service_profiles' not in self.config[self.ROOT][hostname]:
298 raise configerror.ConfigError('No service profiles found')
300 return self.config[self.ROOT][hostname]['service_profiles']
302 def get_performance_profiles(self, hostname):
303 """ get the performance profiles
307 hostname: The name of the node
311 A list containing the perfromance profile names.
315 ConfigError in-case of an error
317 self._validate_hostname(hostname)
319 if 'performance_profiles' not in self.config[self.ROOT][hostname]:
320 raise configerror.ConfigError('No performance profiles found')
322 return self.config[self.ROOT][hostname]['performance_profiles']
324 def get_network_profiles(self, hostname):
325 """get the node network profiles
329 hostname: The name of the node
333 A list containing network profile names
337 ConfigError in-case of an error
339 self._validate_hostname(hostname)
341 if 'network_profiles' not in self.config[self.ROOT][hostname]:
342 raise configerror.ConfigError('No network profiles found')
344 return self.config[self.ROOT][hostname]['network_profiles']
346 def get_storage_profiles(self, hostname):
347 """get the node storage profiles
351 hostname: The name of the node
355 A list containing storage profile names
359 ConfigError in-case of an error
361 self._validate_hostname(hostname)
363 if 'storage_profiles' not in self.config[self.ROOT][hostname]:
364 raise configerror.ConfigError('No storage profiles found')
366 return self.config[self.ROOT][hostname]['storage_profiles']
368 def _validate_hostname(self, hostname):
369 if not self.is_valid_host(hostname):
370 raise configerror.ConfigError('Invalid hostname given %s' % hostname)
372 def is_valid_host(self, hostname):
373 """check if a host is valid
377 hostname: The name of the node
385 ConfigError in-case of an error
388 if hostname in self.config[self.ROOT]:
392 def get_service_profile_hosts(self, profile):
393 """ get hosts having some service profile
405 ConfigError in-case of an error
407 hosts = self.get_hosts()
410 node_profiles = self.get_service_profiles(host)
411 if profile in node_profiles:
416 def get_network_profile_hosts(self, profile):
417 """ get hosts having some network profile
429 ConfigError in-case of an error
431 hosts = self.get_hosts()
434 node_network_profiles = self.get_network_profiles(host)
435 if profile in node_network_profiles:
438 raise configerror.ConfigError('No hosts found for profile %s' % profile)
442 def get_performance_profile_hosts(self, profile):
443 """ get hosts having some performance profile
447 performance profile name
455 ConfigError in-case of an error
457 hosts = self.get_hosts()
460 node_performance_profiles = self.get_performance_profiles(host)
461 if profile in node_performance_profiles:
464 raise configerror.ConfigError('No hosts found for profile %s' % profile)
468 def get_storage_profile_hosts(self, profile):
469 """ get hosts having some storage profile
481 ConfigError in-case of an error
483 hosts = self.get_hosts()
487 node_storage_profiles = self.get_storage_profiles(host)
488 if profile in node_storage_profiles:
490 except configerror.ConfigError:
494 raise configerror.ConfigError('No hosts found for profile %s' % profile)
498 def get_host_network_interface(self, host, network):
499 """ get the host interface used for some network
513 ConfigError in-case of an error
515 node_network_profiles = self.get_network_profiles(host)
516 netprofconf = self.confman.get_network_profiles_config_handler()
517 for profile in node_network_profiles:
518 interfaces = netprofconf.get_profile_network_mapped_interfaces(profile)
519 for interface in interfaces:
520 networks = netprofconf.get_profile_interface_mapped_networks(profile, interface)
521 if network in networks:
524 raise configerror.ConfigError('No interfaces found for network %s in host %s' % (network, host))
526 def get_host_network_ip_holding_interface(self, host, network):
527 """ get the host ip holding interface some network
541 ConfigError in-case of an error
543 networkingconf = self.confman.get_networking_config_handler()
546 domain = self.get_host_network_domain(host)
547 vlan = networkingconf.get_network_vlan_id(network, domain)
548 except configerror.ConfigError as exp:
552 return 'vlan'+str(vlan)
554 return self.get_host_network_interface(host, network)
556 def get_host_networks(self, hostname):
557 """ get the host networks
565 A list of network names
569 ConfigError in-case of an error
571 node_network_profiles = self.get_network_profiles(hostname)
572 netprofconf = self.confman.get_network_profiles_config_handler()
574 for profile in node_network_profiles:
575 interfaces = netprofconf.get_profile_network_mapped_interfaces(profile)
576 for interface in interfaces:
577 networks = netprofconf.get_profile_interface_mapped_networks(profile, interface)
578 for network in networks:
579 if network not in result:
580 result.append(network)
582 raise configerror.ConfigError('No networks found for host %s' % hostname)
586 def get_host_having_hwmgmt_address(self, hwmgmtips):
587 """ get the node name matching an ipmi address
599 ConfigError in-case of an error
602 hosts = self.get_hosts()
604 ip = self.get_hwmgmt_ip(host)
605 for hwmgtip in hwmgmtips:
606 addr=ipaddress.ip_address(unicode(hwmgtip))
607 if addr.version == 6:
608 hwmgtip=addr.compressed
609 ip=ipaddress.ip_address(unicode(ip))
613 raise configerror.ConfigError('No hosts are matching the provided hw address %s' % hwmgmtips)
615 def set_installation_host(self, name):
616 """ set the installation node
620 The installation node name
624 ConfigError in-case of an error
626 self._validate_hostname(name)
628 self.config[self.ROOT][name]['installation_host'] = True
630 def is_installation_host(self, name):
631 """ get if the node is an installation node
639 True if installation node
643 ConfigError in-case of an error
645 self._validate_hostname(name)
647 if 'installation_host' in self.config[self.ROOT][name]:
648 return self.config[self.ROOT][name]['installation_host']
652 def get_installation_host(self):
653 """ get the name of the node used for installation
661 ConfigError in-case of an error
663 hosts = self.get_hosts()
665 if self.is_installation_host(host):
668 raise configerror.ConfigError('No installation host found')
670 def disable_host(self, host):
671 """ disable the hosts visible via configuration.
672 This can be used in bootstrapping phase.
680 ConfigError in-case if provided host is not valid
682 self._validate_hostname(host)
684 self.config[self.ROOT][host]['disabled'] = True
686 def enable_host(self, host):
687 """ enable the hosts visible via configuration.
688 This can be used in bootstrapping phase.
696 ConfigError in-case if provided host is not valid
698 self._validate_hostname(host)
700 self.config[self.ROOT][host]['disabled'] = False
702 def is_host_enabled(self, host):
703 """ is the host enabled
707 the host to be checked
711 ConfigError in-case if provided host is not valid
713 self._validate_hostname(host)
715 if 'disabled' in self.config[self.ROOT][host]:
716 return not self.config[self.ROOT][host]['disabled']
720 def get_mgmt_mac(self, host):
721 self._validate_hostname(host)
723 if 'mgmt_mac' in self.config[self.ROOT][host]:
724 return self.config[self.ROOT][host]['mgmt_mac']
727 def get_host_network_domain(self, host):
728 self._validate_hostname(host)
729 if 'network_domain' not in self.config[self.ROOT][host]:
730 raise configerror.ConfigError('Missing network domain for host %s' % host)
731 return self.config[self.ROOT][host]['network_domain']
733 def get_controllers_network_domain(self):
734 controllers = self.get_service_profile_hosts('controller')
736 for controller in controllers:
737 domains.add(self.get_host_network_domain(controller))
739 if len(domains) != 1:
740 raise configerror.ConfigError('Controllers in different networking domains not supported')
743 def get_managements_network_domain(self):
744 managements = self.get_service_profile_hosts('management')
746 for management in managements:
747 domains.add(self.get_host_network_domain(management))
748 if len(domains) != 1:
749 raise configerror.ConfigError('Management in different networking domains not supported')
752 def update_service_profiles(self):
753 profs = profiles.Profiles()
754 hosts = self.get_hosts()
757 current_profiles = self.config[self.ROOT][host]['service_profiles']
758 new_profiles = current_profiles
759 for profile in current_profiles:
760 included_profiles = profs.get_included_profiles(profile)
761 new_profiles = utils.add_lists(new_profiles, included_profiles)
762 self.config[self.ROOT][host]['service_profiles'] = new_profiles
764 def get_pre_allocated_ips(self, host, network):
765 ips_field = "pre_allocated_ips"
766 self._validate_hostname(host)
767 if (ips_field not in self.config[self.ROOT][host]
768 or network not in self.config[self.ROOT][host][ips_field]):
770 return self.config[self.ROOT][host][ips_field][network]
772 def allocate_port(self, host, base, name):
774 hosts = self.get_hosts()
776 if name in self.config[self.ROOT][node]:
777 used_ports.append(self.config[self.ROOT][node][name])
781 for port in range(base, base+1000):
782 if port not in used_ports:
787 raise configerror.ConfigError('No free ports available')
789 self.config[self.ROOT][host][name] = free_port
791 def add_vbmc_port(self, host):
792 base_vbmc_port = 61600
794 self._validate_hostname(host)
795 if name not in self.config[self.ROOT][host]:
796 self.allocate_port(host, base_vbmc_port, name)
798 def add_ipmi_terminal_port(self, host):
799 base_console_port = 61401
800 name = 'ipmi_terminal_port'
801 self._validate_hostname(host)
802 if name not in self.config[self.ROOT][host]:
803 self.allocate_port(host, base_console_port, name)
805 def get_ceph_osd_disks(self, host):
806 self._validate_hostname(host)
807 caas_disks = self.config[self.ROOT][host].get('caas_disks', [])
808 osd_disks = filter(lambda disk: disk.get('osd_disk', False), caas_disks)
809 return map(lambda disk: _get_path_for_virtio_id(disk), osd_disks)
812 def _get_path_for_virtio_id(disk):
813 disk_id = disk.get('id', '')
815 return "/dev/disk/by-id/virtio-{}".format(disk_id[:20])