diff --git a/component/DevKitWeb/devkit_installer/devkit_installer.py b/component/DevKitWeb/devkit_installer/devkit_installer.py new file mode 100644 index 0000000000000000000000000000000000000000..06036dd92c709eb99f00289fc98e30f0d26c161a --- /dev/null +++ b/component/DevKitWeb/devkit_installer/devkit_installer.py @@ -0,0 +1,71 @@ +import logging +import sys + +from user_manage import UserManage +from devkit_machine import DevKitMachine +from installer_log import config_logging +from installer_command_line import process_command_line, CommandLine + +LOGGER = logging.getLogger("devkit_installer") + + +class DevKitInstaller: + def __init__(self): + self.server_ip = CommandLine.ip + self.user = CommandLine.user + self.pkey = CommandLine.pkey + self.package_path = CommandLine.package_path + self.package_name = CommandLine.package_name + self.admin_username = CommandLine.admin_username + self.admin_password = CommandLine.admin_password + self.install_path = CommandLine.install_path + self.machine = DevKitMachine(ip=self.server_ip, user=self.user, pkey=self.pkey) + self.user_manage = UserManage(server_ip=self.server_ip) + + def pre_install(self): + LOGGER.info("Install DevKit start!") + decompress_result = self.machine.decompress_package( + package_path=self.package_path, + package_name=self.package_name, + ) + if not decompress_result: + LOGGER.error("Decompress package failed.") + exit(1) + LOGGER.info("Decompress package success.") + + def install_java_perf(self): + install_result = self.machine.devkit_install_by_cmd(server_ip=self.server_ip, + server_port="8086", + http_port="8002", + install_path=self.install_path, + plugin="java_perf", + rpc_port=50051) + if not install_result: + LOGGER.error(f"Install DevKit failed.") + exit(1) + LOGGER.info(f"Install DevKit success.") + + def set_up_password(self): + # 初始化管理员密码 + result_dict = self.user_manage.first_login(username=self.admin_username, password=self.admin_password) + if not result_dict: + exit(1) + LOGGER.info("DevKitInstaller executive success.") + + +if __name__ == '__main__': + try: + if not process_command_line(program="devkit_installer", description="devkit-pipeline devkit_installer", + class_list=[CommandLine]): + print("[ERROR] Command line params incomplete!") + sys.exit(1) + config_logging(CommandLine.debug) + + installer = DevKitInstaller() + installer.pre_install() + installer.install_java_perf() + installer.set_up_password() + + except (KeyboardInterrupt, Exception) as e: + print(f"[warning] Program Exited. {str(e)}") + sys.exit(1) diff --git a/component/DevKitWeb/devkit_installer/devkit_machine.py b/component/DevKitWeb/devkit_installer/devkit_machine.py new file mode 100644 index 0000000000000000000000000000000000000000..0ff751dc6b02ec7a40f4f6088b4ca282a1a685ae --- /dev/null +++ b/component/DevKitWeb/devkit_installer/devkit_machine.py @@ -0,0 +1,162 @@ +import logging +import os +import socket +import time +import timeout_decorator + +import paramiko + +LOGGER = logging.getLogger("devkit_installer") + + +class DevKitMachine: + def __init__(self, ip, user, pkey): + self.ip = ip + self.user = user + self.pkey = pkey + self.install_path = "/opt" + self.install_dir = "" + self.install_file = "install.sh" + + def ssh_client(self): + try: + ssh = paramiko.SSHClient() + ssh._transport = self.transport_connect(self.user, self.pkey) + except (OSError, IOError, Exception) as e: + LOGGER.error(f"Unable to connect to {self.ip}. Error occurs: {str(e)}") + return None + return ssh + + def transport_connect(self, user, pkey_path, password=None): + try: + # 指定本地的RSA私钥文件。如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数 + pkey = paramiko.RSAKey.from_private_key_file(pkey_path, password=password) + except (IOError,) as e: + LOGGER.error(f"Pkey file not exists. {str(e)}") + raise IOError() + except (paramiko.ssh_exception.PasswordRequiredException, paramiko.ssh_exception.AuthenticationException) as e: + LOGGER.warning(f"Pkey password is required. {str(e)}") + raise IOError(str(e)) + except (paramiko.ssh_exception.SSHException,) as e: + LOGGER.error(f"Connect remote {self.ip} failed because of wrong pkey. {str(e)}") + raise IOError() + + try: + transport = self.transport_connect_with_timeout(user, pkey) + except (paramiko.ssh_exception.AuthenticationException, + paramiko.ssh_exception.SSHException, + timeout_decorator.TimeoutError, + socket.gaierror, + socket.timeout, + socket.error) as e: + LOGGER.error(f"Connect remote {self.ip} failed. {str(e)}") + raise IOError() + return transport + + @timeout_decorator.timeout(10) + def transport_connect_with_timeout(self, user, pkey): + transport = paramiko.Transport((self.ip, 22)) + transport.connect(username=user, pkey=pkey) + return transport + + @staticmethod + def channel_create(ssh_client): + chan = ssh_client.invoke_shell() + time.sleep(3) + chan.recv(65535) + return chan + + def decompress_package(self, package_path, package_name): + ssh_client = self.ssh_client() + if not ssh_client: + return False + ret = self.decompress_package_handle(ssh_client, package_path, package_name) + ssh_client.close() + return ret + + def decompress_package_handle(self, ssh_client, package_dir, package_name): + package_file = os.path.join(package_dir, package_name) + stdin, stdout, stderr = ssh_client.exec_command(f"ls {package_file}") + stdout_output = stdout.read().decode().strip() + if stdout_output != package_file: + LOGGER.error(f"DevKit install package not exists: {package_file}") + return False + + cmd = f"cd {package_dir} && tar -zxf {package_name}" + stdin, stdout, stderr = ssh_client.exec_command(cmd) + exit_status = stdout.channel.recv_exit_status() + if exit_status == 0: + LOGGER.info(f"Remote machine {self.ip} exec '{cmd}' success.") + else: + LOGGER.error(f"Remote machine {self.ip} exec '{cmd}' failed.") + return False + + package_name_trim = package_name.replace(".tar.gz", "") + install_abs_path = os.path.join(package_dir, package_name_trim, "install.sh") + stdin, stdout, stderr = ssh_client.exec_command(f"ls {install_abs_path}") + stdout_output = stdout.read().decode().strip() + if stdout_output != install_abs_path: + LOGGER.error(f"DevKit install file not exists: {install_abs_path}") + return False + + self.install_dir = str(os.path.join(package_dir, package_name_trim)) + LOGGER.info(f"DevKit install_dir: {self.install_dir}") + return True + + def devkit_install_by_cmd(self, server_ip, server_port="8086", http_port="8002", install_path="/opt", + plugin="java_perf", rpc_port=50051, all_plugins=False): + if all_plugins: + plugin_param = "-a" + else: + plugin_param = f"--plugin={plugin}" + + cmd = (f"cd {self.install_dir} && yes | head -1 | ./{self.install_file} {plugin_param} -d={install_path} " + f"--ip={server_ip} --map_ip={server_ip} -p={server_port} --http_port={http_port} " + f"--rpc_ip={server_ip} --rpc_port={rpc_port} --normal-install=1") + LOGGER.info(f"cmd: {cmd}") + + special_end = f"https://{server_ip}:{server_port}" + environment_check = ("Do you want to " + "authorize the tool to handle the items failed in the installation environment check") + + ssh_client = self.ssh_client() + if not ssh_client: + return False + channel = DevKitMachine.channel_create(ssh_client) + result = self.channel_send_cmd(chan=channel, cmd=cmd, special_end=special_end, + error_special_end=[environment_check], timeout=300) + if not result or environment_check in result: + # 授权工具处理环境检查失败项 + result = self.channel_send_cmd(chan=channel, cmd="y\n", special_end=special_end, timeout=240) + if special_end in result: + ssh_client.close() + return True + ssh_client.close() + return False + + def channel_send_cmd(self, chan, cmd, special_end="", error_special_end=None, timeout=60): + if error_special_end is None: + error_special_end = [] + try: + chan.settimeout(timeout) + if not cmd.endswith('\n'): + cmd = cmd + '\n' + chan.send(cmd) + + while True: + time.sleep(5) + buff = chan.recv(65535) + buff_decode = buff.decode("utf8", errors='ignore') + if special_end in buff_decode: + break + for error_end in error_special_end: + if error_end in buff_decode: + break + + result = buff.decode("utf8", errors="ignore") + LOGGER.info("result: {}".format(result.split('\n')[-2])) + return result + except Exception as e: + LOGGER.info(f"Exec '{cmd}' error occurs: {str(e)}") + return "" + diff --git a/component/DevKitWeb/devkit_installer/installer_command_line.py b/component/DevKitWeb/devkit_installer/installer_command_line.py new file mode 100644 index 0000000000000000000000000000000000000000..9ea38bc51cb2e13cfdd2b67a16258da874fd891b --- /dev/null +++ b/component/DevKitWeb/devkit_installer/installer_command_line.py @@ -0,0 +1,62 @@ +import argparse + +PACKAGE_NAME = "DevKit-All-24.0.RC1-Linux-Kunpeng.tar.gz" + + +class CommandLine: + ip = "" + user = "" + pkey = "" + package_path = "/opt" + package_name = PACKAGE_NAME + admin_username = "devadmin" + admin_password = "devkit123" + install_path = "/opt" + debug = False + + @classmethod + def add_options(cls, parser): + parser.add_argument("-i", "--ip", action="store", dest="ip", + help="Assign IP to install DevKit.") + parser.add_argument("-u", "--user", action="store", dest="user", + help="Assign USER configured password-free.") + parser.add_argument("-p", "--pkey", action="store", dest="pkey", + help="Assign PKEY used for password-free.") + parser.add_argument("-papath", "--package-path", action="store", dest="package_path", default="/opt", + help="Assign DevKit package store path. Default DevKit package store path is '/opt'.") + parser.add_argument("-paname", "--package-name", action="store", dest="package_name", default=PACKAGE_NAME, + help=f"Assign DevKit package name. Default DevKit package name is '{PACKAGE_NAME}'.") + parser.add_argument("-aduser", "--admin-username", action="store", dest="admin_username", default="devadmin", + help="Assign DevKit admin username. Default admin username is 'devadmin'.") + parser.add_argument("-adpass", "--admin-password", action="store", dest="admin_password", default="devkit123", + help="Assign DevKit admin password. Default admin password is 'devkit123'.") + parser.add_argument("-inpath", "--install-path", action="store", dest="install_path", default="/opt", + help="Assign DevKit install path. Default DevKit install path is '/opt'.") + parser.add_argument("--debug", action="store_true", dest="debug", default=False, help=argparse.SUPPRESS) + + @classmethod + def process_args(cls, args): + cls.ip = args.ip + cls.user = args.user + cls.pkey = args.pkey + cls.package_path = args.package_path + cls.package_name = args.package_name + cls.admin_username = args.admin_username + cls.admin_password = args.admin_password + cls.install_path = args.install_path + cls.debug = args.debug + return (cls.ip and cls.user and cls.pkey + and cls.package_path and cls.package_name + and cls.admin_username and cls.admin_password and cls.install_path) + + +def process_command_line(program, description, class_list): + parser = argparse.ArgumentParser(prog=program, description=description, add_help=True) + for klass in class_list: + klass.add_options(parser) + + args = parser.parse_args() + for klass in class_list: + if not klass.process_args(args): + return False + return True diff --git a/component/DevKitWeb/devkit_installer/installer_log.py b/component/DevKitWeb/devkit_installer/installer_log.py new file mode 100644 index 0000000000000000000000000000000000000000..1e45266cbb92fc68105ea5e70a54b22e7e24d27f --- /dev/null +++ b/component/DevKitWeb/devkit_installer/installer_log.py @@ -0,0 +1,18 @@ +import logging +import sys + + +def config_logging(debug=False): + logger = logging.getLogger("devkit_installer") + logger.setLevel(logging.DEBUG) + + formatter = logging.Formatter( + "[%(asctime)s] [%(levelname)s] [processID:%(process)d]" + " [%(threadName)s] [%(module)s:%(funcName)s:%(lineno)d]" + " %(message)s") + + handler = logging.StreamHandler(sys.stdout) + handler.setLevel(logging.DEBUG if debug else logging.INFO) + handler.setFormatter(formatter) + + logger.addHandler(handler) diff --git a/component/DevKitWeb/devkit_installer/user_manage.py b/component/DevKitWeb/devkit_installer/user_manage.py new file mode 100644 index 0000000000000000000000000000000000000000..ccf2850918e9c4676369d21eb126ee0b4b47a24d --- /dev/null +++ b/component/DevKitWeb/devkit_installer/user_manage.py @@ -0,0 +1,38 @@ +import logging +import requests +import urllib3 + +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + +SERVER_PORT = "8086" +DEVKIT_VERSION = "v1.0" +FRAMEWORK_URL = "https://{}:{}/framework/api/{}" +LOGGER = logging.getLogger("devkit_installer") +NO_PROXY = {"http": None, "https": None} + + +class UserManage: + def __init__(self, server_ip): + self.server_ip = server_ip + self.frame_url = FRAMEWORK_URL.format(self.server_ip, SERVER_PORT, DEVKIT_VERSION) + + def first_login(self, username, password): + url = f"{self.frame_url}/users/admin-password/" + response_body = {"username": username, "password": password, "confirm_password": password} + try: + result = requests.post(url=url, json=response_body, verify=False, timeout=10, proxies=NO_PROXY) + except (requests.exceptions.ConnectionError, + requests.exceptions.Timeout, + requests.exceptions.HTTPError, + requests.exceptions.ProxyError, + requests.exceptions.TooManyRedirects, + requests.exceptions.RequestException, + urllib3.exceptions.MaxRetryError, + OSError, Exception) as e: + LOGGER.info("Admin first_login failed.") + return {} + LOGGER.info(f"POST Request result: {result.text}") + result_dict = result.json() + LOGGER.info("Admin first_login success.") + return result_dict diff --git a/tools/install_dependency/src/download/download_command_line.py b/tools/install_dependency/src/download/download_command_line.py index d4b1cc88ad6e18d08d2f803d905e63dcf07ba516..ce22c776226f70ca530a153948a8d43821ec2fb6 100644 --- a/tools/install_dependency/src/download/download_command_line.py +++ b/tools/install_dependency/src/download/download_command_line.py @@ -47,6 +47,7 @@ class CommandLine: @classmethod def process_args(cls, args): + cls.yaml_path = args.yaml_path if args.yaml_path and args.yaml_path != "./" else DEFAULT_YAML_PATH cls.download_iso = args.download_iso return cls.download_iso diff --git a/tools/install_dependency/src/utils.py b/tools/install_dependency/src/utils.py index 501928ac2effe0a00cb77f532a400e8e66c51862..b16c3aca3773d592c4c43ac290c1b2da95fb3833 100644 --- a/tools/install_dependency/src/utils.py +++ b/tools/install_dependency/src/utils.py @@ -30,14 +30,6 @@ def base_path(path): return os.path.join(base_dir, path) -def available_role(role_list, data): - list_after_verification = [] - for role in role_list: - if role in data: - list_after_verification.append(role) - return list_after_verification - - def read_yaml_file(yaml_path): try: with open(yaml_path, "r") as file: