# coding: utf-8 # OceanBase Deploy. # Copyright (C) 2021 OceanBase # # This file is part of OceanBase Deploy. # # OceanBase Deploy is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # OceanBase Deploy is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with OceanBase Deploy. If not, see . import uuid import tempfile from service.handler.base_handler import BaseHandler from service.model.components import Component, ComponentInfo, ConfigParameter, ParameterMeta from service.common import log from _mirror import MirrorRepositoryType from _plugin import PluginType from _repository import Repository from singleton_decorator import singleton from collections import defaultdict from _rpm import Version from service.common import const def map_to_config_parameter(param, is_cn): log.get_logger().info("param {0} type: {1}".format(param.name, param._param_type.__name__)) config_parameter = ConfigParameter() config_parameter.auto = False config_parameter.name = param.name config_parameter.is_essential = param.essential config_parameter.require = param.require config_parameter.type = param._param_type.__name__ config_parameter.default = str(param.default) if param.default is not None else "" config_parameter.min_value = str(param.min_value) if param.min_value is not None else "" config_parameter.max_value = str(param.max_value) if param.max_value is not None else "" config_parameter.modify_limit = param.modify_limit.__name__ config_parameter.need_restart = param.need_restart config_parameter.need_redeploy = param.need_redeploy config_parameter.need_reload = param.need_reload config_parameter.section = param.section config_parameter.description = param.description_local if is_cn else param.description_en return config_parameter @singleton class ComponentHandler(BaseHandler): def __get_all_components(self, component_filter=const.VERSION_FILTER): local_packages = self.obd.mirror_manager.local_mirror.get_all_pkg_info() remote_packages = list() remote_mirrors = self.obd.mirror_manager.get_remote_mirrors() for mirror in remote_mirrors: remote_packages.extend(mirror.get_all_pkg_info()) local_packages.sort() remote_packages.sort() local_pkg_idx = len(local_packages) - 1 remote_pkg_idx = len(remote_packages) - 1 component_dict = defaultdict(list) while local_pkg_idx >= 0 and remote_pkg_idx >= 0: local_pkg = local_packages[local_pkg_idx] remote_pkg = remote_packages[remote_pkg_idx] if local_pkg >= remote_pkg: component_dict[local_pkg.name].append( ComponentInfo(version=local_pkg.version, md5=local_pkg.md5, release=local_pkg.release, arch=local_pkg.arch, type=MirrorRepositoryType.LOCAL.value, estimated_size=const.PKG_ESTIMATED_SIZE[local_pkg.name])) local_pkg_idx -= 1 else: if len(component_dict[remote_pkg.name]) > 0 and component_dict[remote_pkg.name][-1].md5 == remote_pkg.md5: log.get_logger().debug("already found local package %s", remote_pkg) else: component_dict[remote_pkg.name].append( ComponentInfo(version=remote_pkg.version, md5=remote_pkg.md5, release=remote_pkg.release, arch=remote_pkg.arch, type=MirrorRepositoryType.REMOTE.value, estimated_size=const.PKG_ESTIMATED_SIZE[remote_pkg.name])) remote_pkg_idx -= 1 if local_pkg_idx >= 0: for pkg in local_packages[local_pkg_idx::-1]: component_dict[pkg.name].append( ComponentInfo(version=pkg.version, md5=pkg.md5, release=pkg.release, arch=pkg.arch, type=MirrorRepositoryType.LOCAL.value, estimated_size=const.PKG_ESTIMATED_SIZE[pkg.name])) if remote_pkg_idx >= 0: for pkg in remote_packages[remote_pkg_idx::-1]: component_dict[pkg.name].append( ComponentInfo(version=pkg.version, md5=pkg.md5, release=pkg.release, arch=pkg.arch, type=MirrorRepositoryType.REMOTE.value, estimated_size=const.PKG_ESTIMATED_SIZE[pkg.name])) for component, version in component_filter.items(): if component in component_dict.keys(): log.get_logger().info("filter component: {0} above version: {1}".format(component, version)) log.get_logger().info("original components: {0}".format(component_dict[component])) component_dict[component] = list(filter(lambda c: Version(c.version) >= Version(version), component_dict[component])) log.get_logger().info("filtered components: {0}".format(component_dict[component])) return component_dict def list_components(self): if self.context['mirror']['remote_mirror_info_status'] != const.FINISHED: raise Exception("startup event mirror update still not finished") component_list = list() component_dict = self.__get_all_components() for componentInfo in component_dict[const.OCEANBASE_CE]: componentInfo.version_type = const.CE for componentInfo in component_dict[const.OCEANBASE]: componentInfo.version_type = const.BUSINESS for componentInfo in component_dict[const.OBPROXY_CE]: componentInfo.version_type = const.CE for componentInfo in component_dict[const.OBPROXY]: componentInfo.version_type = const.BUSINESS if const.OCEANBASE in component_dict.keys() and const.OCEANBASE_CE in component_dict.keys(): component_dict[const.OCEANBASE].extend(component_dict[const.OCEANBASE_CE]) component_dict.pop(const.OCEANBASE_CE) component_dict[const.OCEANBASE].sort(key=lambda x: x.version, reverse=True) elif const.OCEANBASE_CE in component_dict.keys(): component_dict[const.OCEANBASE] = component_dict[const.OCEANBASE_CE] component_dict.pop(const.OCEANBASE_CE) if const.OBPROXY in component_dict.keys() and const.OBPROXY_CE in component_dict.keys(): component_dict[const.OBPROXY].extend(component_dict[const.OBPROXY_CE]) component_dict.pop(const.OBPROXY_CE) component_dict[const.OBPROXY].sort(key=lambda x: x.version, reverse=True) elif const.OBPROXY_CE in component_dict.keys(): component_dict[const.OBPROXY] = component_dict[const.OBPROXY_CE] component_dict.pop(const.OBPROXY_CE) for name, info in component_dict.items(): component_list.append(Component(name=name, info=info)) return component_list def get_component(self, component_name): if self.context['mirror']['remote_mirror_info_status'] != const.FINISHED: raise Exception("startup event mirror update still not finished") component = None component_dict = self.__get_all_components() if component_name in component_dict.keys(): component = Component(name=component_name, info=component_dict[component_name]) return component def list_component_parameters(self, parameter_request, accept_language): parameter_metas = list() for parameter_filter in parameter_request.filters: name=uuid.uuid4().hex # generate minimal deploy config_path = '' log.get_logger().info('dump config') with tempfile.NamedTemporaryFile(prefix="obd", suffix="yaml", mode="w", encoding="utf-8") as f: f.write(const.MINIMAL_CONFIG.format(parameter_filter.component)) f.flush() config_path = f.name deploy = self.obd.deploy_manager.create_deploy_config(name, config_path) if deploy is None: raise Exception("create temp deployment failed") self.obd.set_deploy(deploy) spacename = "{0}_parameter".format(parameter_filter.component) gen_config_plugin = self.obd.plugin_manager.get_best_py_script_plugin("generate_config", parameter_filter.component, parameter_filter.version) repository = Repository(parameter_filter.component, "") self.obd.set_repositories([repository]) ret = self.obd.call_plugin(gen_config_plugin, repository, return_generate_keys=True, generate_consistent_config=True, spacename=spacename, clients={}) del(self.obd.namespaces[spacename]) if not ret: self.obd.deploy_manager.remove_deploy_config(name) raise Exception("genconfig failed for compoennt: {0}".format(parameter_filter.component)) else: auto_keys = ret.get_return("generate_keys") log.get_logger().info("auto keys for comopnent %s are %s", parameter_filter.component, auto_keys) parameter_plugin = self.obd.plugin_manager.get_best_plugin(PluginType.PARAM, parameter_filter.component, parameter_filter.version) ## use plugin.params to generate parameter meta config_parameters = list() is_cn = 'zh-CN' in accept_language for param in parameter_plugin.params.values(): config_parameter = map_to_config_parameter(param, is_cn) if config_parameter.name in auto_keys: config_parameter.auto = True if config_parameter.is_essential or not parameter_filter.is_essential_only: config_parameters.append(config_parameter) parameter_metas.append(ParameterMeta(component=parameter_filter.component, version=parameter_filter.version, config_parameters=config_parameters)) self.obd.deploy_manager.remove_deploy_config(name) return parameter_metas