From 8646b8d62cf4ca7b6bccae537a0c9e72ba45eab3 Mon Sep 17 00:00:00 2001 From: Harry Huang Date: Fri, 17 Nov 2017 14:53:44 +0800 Subject: Merge compass-tasks-osa and compass-tasks-k8s JIRA: COMPASS-568 rename compass-tasks to compass-tasks-base. add both osa and k8s support in compass-tasks Change-Id: I438f5b17e509d4cb751ced0ffe640ec70899882f Signed-off-by: Harry Huang --- .../deployment/installers/config_manager.py | 527 +++++++++++++++++++++ 1 file changed, 527 insertions(+) create mode 100644 compass-tasks-base/deployment/installers/config_manager.py (limited to 'compass-tasks-base/deployment/installers/config_manager.py') diff --git a/compass-tasks-base/deployment/installers/config_manager.py b/compass-tasks-base/deployment/installers/config_manager.py new file mode 100644 index 0000000..597c3a6 --- /dev/null +++ b/compass-tasks-base/deployment/installers/config_manager.py @@ -0,0 +1,527 @@ +# Copyright 2014 Huawei Technologies Co. Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +__author__ = "baigk baiguoku@huawei.com)" + +from collections import defaultdict +from copy import deepcopy +import json +import logging +import netaddr + +from compass.deployment.utils import constants as const + +ip_generator_map = {} + + +def get_ip_addr(ip_ranges): + def _get_ip_addr(): + for ip_range in ip_ranges: + for ip in netaddr.iter_iprange(*ip_range): + yield str(ip) + + s = json.dumps(ip_ranges) + if s not in ip_generator_map: + ip_generator_map[s] = _get_ip_addr() + return ip_generator_map[s] + else: + return ip_generator_map[s] + + +class AdapterInfo(object): + def __init__(self, adapter_info): + self.adapter_info = adapter_info + self.name = self.adapter_info.get(const.NAME) + self.dist_system_name = self.name + self.health_check_cmd = self.adapter_info.get(const.HEALTH_CHECK_CMD) + + self.os_installer = self.adapter_info.setdefault( + const.OS_INSTALLER, {} + ) + self.os_installer.setdefault(const.INSTALLER_SETTINGS, {}) + + self.package_installer = self.adapter_info.setdefault( + const.PK_INSTALLER, {} + ) + self.package_installer.setdefault(const.INSTALLER_SETTINGS, {}) + + self.metadata = self.adapter_info.setdefault(const.METADATA, {}) + self.os_metadata = self.metadata.setdefault(const.OS_CONFIG, {}) + self.package_metadata = self.metadata.setdefault(const.PK_CONFIG, {}) + + self.flavors = dict([(f[const.FLAVOR_NAME], f) + for f in self.adapter_info.get(const.FLAVOR, [])]) + + @property + def flavor_list(self): + return self.flavors.values() + + def get_flavor(self, flavor_name): + return self.flavors.get(flavor_name) + + +class ClusterInfo(object): + def __init__(self, cluster_info): + self.cluster_info = cluster_info + self.id = self.cluster_info.get(const.ID) + self.name = self.cluster_info.get(const.NAME) + self.os_version = self.cluster_info.get(const.OS_VERSION) + self.flavor = self.cluster_info.setdefault( + const.FLAVOR, {} + ) + self.os_config = self.cluster_info.setdefault( + const.OS_CONFIG, {} + ) + self.package_config = self.cluster_info.setdefault( + const.PK_CONFIG, {} + ) + self.deployed_os_config = self.cluster_info.setdefault( + const.DEPLOYED_OS_CONFIG, {} + ) + self.deployed_package_config = self.cluster_info.setdefault( + const.DEPLOYED_PK_CONFIG, {} + ) + self.network_mapping = self.package_config.setdefault( + const.NETWORK_MAPPING, {} + ) + + os_config_general = self.os_config.setdefault( + const.OS_CONFIG_GENERAL, {} + ) + self.domain = os_config_general.setdefault(const.DOMAIN, None) + self.hosts = [] + + def add_host(self, host): + self.hosts.append(host) + + @property + def roles_mapping(self): + deploy_config = self.deployed_package_config + return deploy_config.setdefault( + const.ROLES_MAPPING, self._get_cluster_roles_mapping() + ) + + def _get_cluster_roles_mapping(self): + """The ouput format will be as below, for example: + + { + "controller": [{ + "hostname": "xxx", + "management": { + "interface": "eth0", + "ip": "192.168.1.10", + "netmask": "255.255.255.0", + "subnet": "192.168.1.0/24", + "is_mgmt": True, + "is_promiscuous": False + }, + ... + }], + ... + } + """ + mapping = defaultdict(list) + for host in self.hosts: + for role, value in host.roles_mapping.iteritems(): + mapping[role].append(value) + + return dict(mapping) + + def _get_cluster_patched_roles_mapping(self): + mapping = defaultdict(list) + for host in self.hosts: + for role, value in host.patched_roles_mapping.iteritems(): + mapping[role].append(value) + + return dict(mapping) + + @property + def base_info(self): + return { + const.ID: self.id, + const.NAME: self.name, + const.OS_VERSION: self.os_version + } + + +class HostInfo(object): + def __init__(self, host_info, cluster_info): + self.host_info = host_info + self.cluster_info = cluster_info + self.id = self.host_info.get(const.ID) + self.name = self.host_info.get(const.NAME) + self.mac = self.host_info.get(const.MAC_ADDR) + self.hostname = self.host_info.get(const.HOSTNAME) + self.networks = self.host_info.setdefault(const.NETWORKS, {}) + self.os_config = self.host_info.setdefault(const.OS_CONFIG, {}) + + self.package_config = self.host_info.setdefault(const.PK_CONFIG, {}) + self.roles = self.host_info.setdefault(const.ROLES, []) + self.patched_roles = self.host_info.setdefault(const.PATCHED_ROLES, []) + self.ipmi = deepcopy(self.host_info.setdefault(const.IPMI, {})) + self.reinstall_os_flag = self.host_info.get(const.REINSTALL_OS_FLAG) + self.deployed_os_config = self.host_info.setdefault( + const.DEPLOYED_OS_CONFIG, {} + ) + self.deployed_package_config = self.host_info.setdefault( + const.DEPLOYED_PK_CONFIG, {} + ) + + os_general_config = self.os_config.setdefault( + const.OS_CONFIG_GENERAL, {} + ) + domain = os_general_config.setdefault(const.DOMAIN, None) + if domain is None: + self.domain = self.cluster_info.domain + else: + self.domain = domain + + if const.DNS in host_info: + self.dns = host_info[const.DNS] + else: + self.dns = '.'.join((self.hostname, self.domain)) + + if const.NETWORK_MAPPING not in self.package_config: + self.network_mapping = self.cluster_info.network_mapping + else: + self.network_mapping = self.package_config[const.NETWORK_MAPPING] + + if const.ROLES_MAPPING not in self.deployed_package_config: + self.roles_mapping = self._get_host_roles_mapping() + self.deployed_package_config[ + const.ROLES_MAPPING + ] = self.roles_mapping + else: + self.roles_mapping = \ + self.deployed_package_config[const.ROLES_MAPPING] + + self.patched_roles_mapping = self._get_host_patched_roles_mapping() + + self.cluster_info.add_host(self) + + def valid_interface(self, interface): + if interface not in self.networks: + raise RuntimeError("interface %s is invalid" % interface) + + def get_interface(self, interface): + self.valid_interface(interface) + return self.networks[interface] + + def get_interface_ip(self, interface): + return self.get_interface(interface).get(const.IP_ADDR) + + def get_interface_netmask(self, interface): + return self.get_interface(interface).get(const.NETMASK) + + def get_interface_subnet(self, interface): + return self.get_interface(interface).get(const.SUBNET) + + def is_interface_promiscuous(self, interface): + return self.get_interface(interface).get(const.PROMISCUOUS_FLAG) + + def is_interface_mgmt(self, interface): + return self.get_interface(interface).get(const.MGMT_NIC_FLAG) + + def _get_host_roles_mapping(self): + if not self.network_mapping: + return {} + + net_info = {const.HOSTNAME: self.hostname} + for k, v in self.network_mapping.items(): + try: + net_info[k] = self.networks[v[const.NIC]] + net_info[k][const.NIC] = v[const.NIC] + except Exception: + pass + + mapping = {} + for role in self.roles: + role = role.replace("-", "_") + mapping[role] = net_info + + return mapping + + def _get_host_patched_roles_mapping(self): + if not self.network_mapping: + return {} + + net_info = {const.HOSTNAME: self.hostname} + for k, v in self.network_mapping.items(): + try: + net_info[k] = self.networks[v[const.NIC]] + net_info[k][const.NIC] = v[const.NIC] + except Exception: + pass + + mapping = {} + for role in self.patched_roles: + role = role['name'].replace("-", "_") + mapping[role] = net_info + + return mapping + + @property + def baseinfo(self): + return { + const.REINSTALL_OS_FLAG: self.reinstall_os_flag, + const.MAC_ADDR: self.mac, + const.NAME: self.name, + const.HOSTNAME: self.hostname, + const.DNS: self.dns, + const.NETWORKS: deepcopy(self.networks) + } + + +class BaseConfigManager(object): + def __init__(self, adapter_info={}, cluster_info={}, hosts_info={}): + assert(adapter_info and isinstance(adapter_info, dict)) + assert(cluster_info and isinstance(cluster_info, dict)) + assert(hosts_info and isinstance(hosts_info, dict)) + + self.adapter_info = AdapterInfo(adapter_info) + self.cluster_info = ClusterInfo(cluster_info) + self.hosts_info = dict([(k, HostInfo(v, self.cluster_info)) + for k, v in hosts_info.iteritems()]) + + def get_adapter_name(self): + return self.adapter_info.name + + def get_dist_system_name(self): + return self.adapter_info.dist_system_name + + def get_adapter_health_check_cmd(self): + return self.adapter_info.health_check_cmd + + def get_os_installer_settings(self): + return self.adapter_info.os_installer[const.INSTALLER_SETTINGS] + + def get_pk_installer_settings(self): + return self.adapter_info.package_installer[const.INSTALLER_SETTINGS] + + def get_os_config_metadata(self): + return self.adapter_info.metadata[const.OS_CONFIG] + + def get_pk_config_meatadata(self): + return self.adapter_info.metadata[const.PK_CONFIG] + + def get_adapter_all_flavors(self): + return self.adapter_info.flavor_list + + def get_adapter_flavor(self, flavor_name): + return self.adapter_info.get_flavor(flavor_name) + + def get_cluster_id(self): + return self.cluster_info.id + + def get_clustername(self): + return self.cluster_info.name + + def get_os_version(self): + return self.cluster_info.os_version + + def get_cluster_os_config(self): + return self.cluster_info.os_config + + def get_cluster_baseinfo(self): + return self.cluster_info.base_info + + def get_cluster_flavor_name(self): + return self.cluster_info.flavor.get(const.FLAVOR_NAME) + + def get_cluster_flavor_roles(self): + return self.cluster_info.flavor.get(const.ROLES, []) + + def get_cluster_flavor_template(self): + return self.cluster_info.flavor.get(const.TMPL) + + def get_cluster_package_config(self): + return self.cluster_info.package_config + + def get_cluster_network_mapping(self): + mapping = self.cluster_info.network_mapping + logging.info("Network mapping in the config is '%s'!", mapping) + return mapping + + def get_cluster_deployed_os_config(self): + return self.cluster_info.deployed_os_config + + def get_cluster_deployed_package_config(self): + return self.cluster_info.deployed_package_config + + def get_cluster_roles_mapping(self): + return self.cluster_info.roles_mapping + + def get_cluster_patched_roles_mapping(self): + return self.cluster_info._get_cluster_patched_roles_mapping() + + def validate_host(self, host_id): + if host_id not in self.hosts_info: + raise RuntimeError("host_id %s is invalid" % host_id) + + def get_host_id_list(self): + return self.hosts_info.keys() + + def get_hosts_id_list_for_os_installation(self): + """Get info of hosts which need to install/reinstall OS.""" + return [ + id for id, info in self.hosts_info.items() + if info.reinstall_os_flag + ] + + def get_server_credentials(self): + cluster_os_config = self.get_cluster_os_config() + if not cluster_os_config: + logging.info("cluster os_config is None!") + return () + + username = cluster_os_config[const.SERVER_CREDS][const.USERNAME] + password = cluster_os_config[const.SERVER_CREDS][const.PASSWORD] + return (username, password) + + def _get_host_info(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id] + + def get_host_baseinfo(self, host_id): + self.validate_host(host_id) + host_info = self.hosts_info[host_id] + return host_info.baseinfo + + def get_host_fullname(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].name + + def get_host_dns(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].dns + + def get_host_mac_address(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].mac + + def get_hostname(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].hostname + + def get_host_networks(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].networks + + def get_host_interfaces(self, host_id): + # get interface names + return self.get_host_networks(host_id).keys() + + def get_host_interface_ip(self, host_id, interface): + self.validate_host(host_id) + return self.hosts_info[host_id].get_interface_ip(interface) + + def get_host_interface_netmask(self, host_id, interface): + self.validate_host(host_id) + return self.hosts_info[host_id].get_interface_netmask(interface) + + def get_host_interface_subnet(self, host_id, interface): + self.validate_host(host_id) + return self.hosts_info[host_id].get_interface_subnet(interface) + + def is_interface_promiscuous(self, host_id, interface): + self.validate_host(host_id) + return self.hosts_info[host_id].is_interface_promiscuous(interface) + + def is_interface_mgmt(self, host_id, interface): + self.validate_host(host_id) + return self.hosts_info[host_id].is_interface_mgmt(interface) + + def get_host_os_config(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].os_config + + def get_host_domain(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].domain + + def get_host_network_mapping(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].network_mapping + + def get_host_package_config(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].package_config + + def get_host_deployed_os_config(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].deployed_os_config + + def get_host_deployed_package_config(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].deployed_package_config + + def get_host_roles(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].roles + + def get_all_hosts_roles(self, hosts_id_list=None): + roles = [] + for host_id, host_info in self.hosts_info.iteritems(): + roles.extend(host_info.roles) + + return list(set(roles)) + + def get_hosts_ip_settings(self, ip_settings, sys_intf_mappings): + logging.info( + "get_hosts_ip_settings:ip_settings=%s, sys_intf_mappings=%s" % + (ip_settings, sys_intf_mappings) + ) + + intf_alias = {} + for m in sys_intf_mappings: + if "vlan_tag" in m: + intf_alias[m["name"]] = m["name"] + else: + intf_alias[m["name"]] = m["interface"] + + mappings = {} + hosts_id_list = self.get_host_id_list() + for host_id in hosts_id_list: + hostname = self.get_hostname(host_id) + mappings[hostname] = [] + for ip_info in ip_settings: + logging.info("ip_info=%s" % ip_info) + new_ip_info = deepcopy(ip_info) + del new_ip_info["ip_ranges"] + + ip_ranges = ip_info["ip_ranges"] + new_ip_info["netmask"] = netaddr.IPNetwork( + ip_info["cidr"] + ).netmask.bin.count("1") + new_ip_info["ip"] = get_ip_addr(ip_ranges).next() + new_ip_info["alias"] = intf_alias[ip_info["name"]] + mappings[hostname].append(new_ip_info) + + return {"ip_settings": mappings} + + def get_host_roles_mapping(self, host_id): + self.validate_host(host_id) + return self.hosts_info[host_id].roles_mapping + + def get_host_ipmi_info(self, host_id): + self.validate_host(host_id) + if self.hosts_info[host_id].ipmi: + return ( + self.hosts_info[host_id].ipmi[const.IP_ADDR], + self.hosts_info[host_id].ipmi + [const.IPMI_CREDS][const.USERNAME], + self.hosts_info[host_id].ipmi + [const.IPMI_CREDS][const.USERNAME]) + else: + return (None, None, None) -- cgit 1.2.3-korg