diff --git a/apps/backend/agent/tools.py b/apps/backend/agent/tools.py index 481d3b7aa..52f857794 100644 --- a/apps/backend/agent/tools.py +++ b/apps/backend/agent/tools.py @@ -8,7 +8,7 @@ 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. """ - +import os import re import time from pathlib import Path @@ -22,6 +22,7 @@ from apps.node_man import constants, models from apps.node_man.models import aes_cipher from apps.utils.basic import suffix_slash +from apps.utils.encrypt import rsa class InstallationTools: @@ -29,7 +30,7 @@ def __init__( self, script_file_name: str, dest_dir: str, - win_commands: str, + win_commands: List[str], upstream_nodes: List[str], jump_server: models.Host, pre_commands: List[str], @@ -139,7 +140,7 @@ def gen_commands(host: models.Host, pipeline_id: str, is_uninstall: bool) -> Ins proxy 云区域所使用的代理, pre_commands 安装前命令, run_cmd 安装命令 """ proxies = [] - win_commands = [] + encrypted_password = "" ( jump_server, bt_file_servers, @@ -173,6 +174,15 @@ def gen_commands(host: models.Host, pipeline_id: str, is_uninstall: bool) -> Ins f'-k "{task_servers}"', ] + # 系统开启使用密码注册windows服务时,需额外传入用户名和加密密码参数,用于注册windows服务,详见setup_agent.bat脚本 + need_encrypted_password = settings.REGISTER_WIN_SERVICE_WITH_PASS and host.os_type == constants.OsType.WINDOWS + if need_encrypted_password: + # 系统开启使用密码注册windows服务时,需额外传入 -U -P参数,用于注册windows服务,详见setup_agent.bat脚本 + encrypted_password = rsa.RSAUtil( + public_extern_key_file=os.path.join(settings.BK_SCRIPTS_PATH, "gse_public_key"), + padding=rsa.CipherPadding.PKCS1_OAEP.value, + ).encrypt(host.identity.password) + check_run_commands(run_cmd_params) script_file_name = choose_script_file(host) @@ -208,14 +218,10 @@ def gen_commands(host: models.Host, pipeline_id: str, is_uninstall: bool) -> Ins f"-HPP '{settings.BK_NODEMAN_NGINX_PROXY_PASS_PORT}'", f"-HSN '{constants.SCRIPT_FILE_NAME_MAP[host.os_type]}'", f"-HS '{host_shell}'", - ] - ) - - run_cmd_params.extend( - [ f"-p '{install_path}'", f"-I {jump_server.inner_ip}", f"-o {gen_nginx_download_url(jump_server.inner_ip)}", + f"-HEP '{encrypted_password}'" if need_encrypted_password else "", "-R" if is_uninstall else "", ] ) @@ -231,7 +237,7 @@ def gen_commands(host: models.Host, pipeline_id: str, is_uninstall: bool) -> Ins if channel_proxy_address: run_cmd_params.extend([f"-CPA '{channel_proxy_address}'"]) - run_cmd = " ".join(run_cmd_params) + run_cmd = " ".join(list(filter(None, run_cmd_params))) download_cmd = ( f"if [ ! -e {dest_dir}{script_file_name} ] || " @@ -251,20 +257,17 @@ def gen_commands(host: models.Host, pipeline_id: str, is_uninstall: bool) -> Ins "-R" if is_uninstall else "", ] ) - - run_cmd = format_run_cmd_by_os_type(host.os_type, f"{dest_dir}{script_file_name} {' '.join(run_cmd_params)}") - if host.os_type == constants.OsType.WINDOWS: - # WINDOWS 下的 Agent 安装 - win_remove_cmd = ( - f"del /q /s /f {dest_dir}{script_file_name} " - f"{dest_dir}{constants.SetupScriptFileName.GSECTL_BAT.value}" - ) - win_download_cmd = ( - f"{dest_dir}curl.exe {host.ap.package_inner_url}/{script_file_name}" - f" -o {dest_dir}{script_file_name} -sSf" + if need_encrypted_password: + run_cmd_params.extend( + [ + f"-U {host.identity.account}", + f'-P "{encrypted_password}"', + ] ) - win_commands = [win_remove_cmd, win_download_cmd, run_cmd] + run_cmd = format_run_cmd_by_os_type( + host.os_type, f"{dest_dir}{script_file_name} {' '.join(list(filter(None, run_cmd_params)))}" + ) download_cmd = f"curl {package_url}/{script_file_name} -o {dest_dir}{script_file_name} --connect-timeout 5 -sSf" chmod_cmd = f"chmod +x {dest_dir}{script_file_name}" pre_commands = [ @@ -275,7 +278,16 @@ def gen_commands(host: models.Host, pipeline_id: str, is_uninstall: bool) -> Ins pre_commands.insert(0, f"mkdir -p {dest_dir}") return InstallationTools( - script_file_name, dest_dir, win_commands, upstream_nodes, jump_server, pre_commands, run_cmd + script_file_name, + dest_dir, + [ + f"{dest_dir}curl.exe {host.ap.package_inner_url}/{script_file_name} -o {dest_dir}{script_file_name} -sSf", + run_cmd, + ], + upstream_nodes, + jump_server, + pre_commands, + run_cmd, ) diff --git a/apps/backend/tests/components/collections/agent/test_install.py b/apps/backend/tests/components/collections/agent/test_install.py index 87b853df1..fbed27732 100644 --- a/apps/backend/tests/components/collections/agent/test_install.py +++ b/apps/backend/tests/components/collections/agent/test_install.py @@ -12,7 +12,7 @@ import time from django.conf import settings -from django.test import TestCase +from django.test import TestCase, override_settings from mock import patch from apps.backend.agent.tools import gen_commands @@ -84,7 +84,7 @@ def test_gen_agent_command(self): f" -r http://127.0.0.1/backend -l http://127.0.0.1/download" f" -c {token}" f' -O 48668 -E 58925 -A 58625 -V 58930 -B 10020 -S 60020 -Z 60030 -K 10030 -e "" -a "" -k ""' - f" -i 0 -I 127.0.0.1 -N SERVER -p /usr/local/gse -T /tmp/ &" + f" -i 0 -I 127.0.0.1 -N SERVER -p /usr/local/gse -T /tmp/ &" ) self.assertEqual(installation_tool.run_cmd, run_cmd) @@ -139,7 +139,7 @@ def test_gen_win_command(self): f"C:\\tmp\\setup_agent.bat -s {utils.JOB_TASK_PIPELINE_ID}" f" -r http://127.0.0.1/backend -l http://127.0.0.1/download -c {token}" f' -O 48668 -E 58925 -A 58625 -V 58930 -B 10020 -S 60020 -Z 60030 -K 10030 -e "" -a "" -k ""' - f" -i 0 -I 127.0.0.1 -N SERVER -p c:\\gse -T C:\\tmp\\ " + f" -i 0 -I 127.0.0.1 -N SERVER -p c:\\gse -T C:\\tmp\\" ) self.assertEqual(installation_tool.run_cmd, run_cmd) @@ -152,6 +152,25 @@ def tearDown(self): ) +@override_settings(REGISTER_WIN_SERVICE_WITH_PASS=True) +class InstallWindowsAgentWithEncryptedPasswordSuccessTest(InstallWindowsAgentSuccessTest): + def setUp(self): + super().setUp() + + def test_gen_win_command(self): + host = models.Host.objects.get(bk_host_id=utils.BK_HOST_ID) + installation_tool = gen_commands(host, utils.JOB_TASK_PIPELINE_ID, is_uninstall=False) + token = re.match(r"(.*) -c (.*?) -O", installation_tool.run_cmd).group(2) + run_cmd = ( + f"C:\\tmp\\setup_agent.bat -s {utils.JOB_TASK_PIPELINE_ID}" + f" -r http://127.0.0.1/backend -l http://127.0.0.1/download -c {token}" + f' -O 48668 -E 58925 -A 58625 -V 58930 -B 10020 -S 60020 -Z 60030 -K 10030 -e "" -a "" -k ""' + f" -i 0 -I 127.0.0.1 -N SERVER -p c:\\gse -T C:\\tmp\\ -U root -P " + ) + # RSA每次加密的结果都不一样,因此只要保证startswith即可 + self.assertTrue(installation_tool.run_cmd.startswith(run_cmd)) + + class InstallWindowsPasswordAuthOverdueTest(TestCase, ComponentTestMixin): EXECUTE_CMD_MOCK_PATH = "apps.backend.components.collections.agent.execute_cmd" PUT_FILE_MACK_PATH = "apps.backend.components.collections.agent.put_file" @@ -331,7 +350,7 @@ def test_gen_pagent_command(self): f" -HOT linux -HDD '/tmp/'" f" -HPP '17981' -HSN 'setup_agent.sh' -HS 'bash'" f" -p '/usr/local/gse' -I 1.1.1.1" - f" -o http://1.1.1.1:{settings.BK_NODEMAN_NGINX_DOWNLOAD_PORT}/ " + f" -o http://1.1.1.1:{settings.BK_NODEMAN_NGINX_DOWNLOAD_PORT}/" ) self.assertEqual(installation_tool.run_cmd, run_cmd) @@ -532,7 +551,7 @@ def test_gen_install_channel_agent_command(self): f" -HOT linux -HDD '/tmp/'" f" -HPP '17981' -HSN 'setup_agent.sh' -HS 'bash'" f" -p '/usr/local/gse' -I 1.1.1.1" - f" -o http://1.1.1.1:{settings.BK_NODEMAN_NGINX_DOWNLOAD_PORT}/ " + f" -o http://1.1.1.1:{settings.BK_NODEMAN_NGINX_DOWNLOAD_PORT}/" f" -ADP 'True' -CPA 'http://127.0.0.1:17981'" ) self.assertEqual(installation_tool.run_cmd, run_cmd) @@ -545,3 +564,27 @@ def tearDown(self): models.JobTask.objects.filter(bk_host_id=utils.BK_HOST_ID, current_step__endswith=DESCRIPTION).exists() ) self.job_client_v2.stop() + + +@override_settings(REGISTER_WIN_SERVICE_WITH_PASS=True) +class InstallWindowsPAgentWithEncryptedPasswordSuccessTest(InstallPAgentSuccessTest): + def setUp(self): + super().setUp() + models.Host.objects.filter(bk_host_id=utils.BK_HOST_ID).update(os_type=constants.OsType.WINDOWS) + + def test_gen_pagent_command(self): + host = models.Host.objects.get(bk_host_id=utils.BK_HOST_ID) + installation_tool = gen_commands(host, utils.JOB_TASK_PIPELINE_ID, is_uninstall=False) + token = re.match(r"(.*) -c (.*?) -O", installation_tool.run_cmd).group(2) + run_cmd = ( + f"-s {utils.JOB_TASK_PIPELINE_ID} -r http://127.0.0.1/backend -l http://127.0.0.1/download" + f" -c {token}" + f" -O 48668 -E 58925 -A 58625 -V 58930 -B 10020 -S 60020 -Z 60030 -K 10030" + f' -e "1.1.1.1" -a "1.1.1.1" -k "1.1.1.1" -L /data/bkee/public/bknodeman/download' + f" -HLIP 127.0.0.1 -HIIP 127.0.0.1 -HA root -HP 22 -HI 'aes_str:::H4MFaqax' -HC 0 -HNT PAGENT" + f" -HOT windows -HDD 'C:\\tmp\\'" + f" -HPP '17981' -HSN 'setup_agent.bat' -HS 'bash'" + f" -p 'c:\\gse' -I 1.1.1.1" + f" -o http://1.1.1.1:{settings.BK_NODEMAN_NGINX_DOWNLOAD_PORT}/ -HEP" + ) + self.assertTrue(installation_tool.run_cmd.startswith(run_cmd)) diff --git a/apps/node_man/apps.py b/apps/node_man/apps.py index 66c8614f9..3b15aeed5 100644 --- a/apps/node_man/apps.py +++ b/apps/node_man/apps.py @@ -105,3 +105,8 @@ def init_settings(self): ), ) settings.HEAD_PLUGINS = obj.v_json + + obj, created = GlobalSettings.objects.get_or_create( + key=GlobalSettings.KeyEnum.REGISTER_WIN_SERVICE_WITH_PASS.value, defaults=dict(v_json=False) + ) + settings.REGISTER_WIN_SERVICE_WITH_PASS = obj.v_json diff --git a/apps/node_man/models.py b/apps/node_man/models.py index 3b0a4b484..fd8af88ae 100644 --- a/apps/node_man/models.py +++ b/apps/node_man/models.py @@ -81,6 +81,7 @@ class KeyEnum(Enum): """枚举全局配置KEY,避免散落在各处难以维护""" USE_TJJ = "USE_TJJ" # 是否启用TJJ + REGISTER_WIN_SERVICE_WITH_PASS = "REGISTER_WIN_SERVICE_WITH_PASS" # 是否使用密码注册windows服务 CONFIG_POLICY_BY_SOPS = "CONFIG_POLICY_BY_SOPS" # 是否使用标准运维自动开通网络策略 CONFIG_POLICY_BY_TENCENT_VPC = "CONFIG_POLICY_BY_TENCENT_VPC" # 是否使用腾讯云SDK自动开通网络策略 APIGW_PUBLIC_KEY = "APIGW_PUBLIC_KEY" # APIGW公钥,从PaaS接口获取或直接配到settings中 diff --git a/apps/utils/encrypt/rsa.py b/apps/utils/encrypt/rsa.py index cdbcc6eb7..67c1557de 100644 --- a/apps/utils/encrypt/rsa.py +++ b/apps/utils/encrypt/rsa.py @@ -10,9 +10,12 @@ """ import base64 +from enum import Enum +from functools import wraps from typing import Any, List, Optional, Tuple, Union from Cryptodome import Util +from Cryptodome.Cipher import PKCS1_OAEP from Cryptodome.Cipher import PKCS1_v1_5 as PKCS1_v1_5_cipher from Cryptodome.Hash import SHA1 from Cryptodome.PublicKey import RSA @@ -22,6 +25,39 @@ ENCODING = "utf-8" +class CipherPadding(Enum): + """填充标志""" + + PKCS1 = "PKCS1" + PKCS1_OAEP = "PKCS1_OAEP" + + +class KeyObjType(Enum): + """密钥对象类型""" + + PRIVATE_KEY_OBJ = "private_key_obj" + PUBLIC_KEY_OBJ = "public_key_obj" + + +def key_obj_checker(key_obj_type: str): + """ + 密钥对象检查器 + :param key_obj_type: KeyObjType + :return: + """ + + def decorate(func): + @wraps(func) + def wrapper(self, *args, **kwargs): + if not getattr(self, key_obj_type): + raise ValueError(f"{key_obj_type} must be set if you want to call {func.__name__}") + return func(self, *args, **kwargs) + + return wrapper + + return decorate + + def generate_keys() -> Tuple[str, str]: """ 生成公私钥 @@ -39,11 +75,13 @@ def generate_keys() -> Tuple[str, str]: class RSAUtil: - public_key_obj: RSA.RsaKey = None - private_key_obj: RSA.RsaKey = None + public_key_obj: Optional[RSA.RsaKey] = None + private_key_obj: Optional[RSA.RsaKey] = None @staticmethod - def load_key(extern_key: Optional[Union[str, bytes]] = None, extern_key_file: Optional[str] = None) -> RSA.RsaKey: + def load_key( + extern_key: Optional[Union[str, bytes]] = None, extern_key_file: Optional[str] = None + ) -> Optional[RSA.RsaKey]: """ 导入rsa密钥 :param extern_key: 密钥内容 @@ -51,7 +89,7 @@ def load_key(extern_key: Optional[Union[str, bytes]] = None, extern_key_file: Op :return: """ if not (extern_key or extern_key_file): - raise ValueError("key or key_file need to provide at least one.") + return None if extern_key_file: try: @@ -93,10 +131,16 @@ def __init__( private_extern_key: Optional[Union[str, bytes]] = None, public_extern_key_file: Optional[str] = None, private_extern_key_file: Optional[str] = None, + padding: str = CipherPadding.PKCS1.value, ): self.public_key_obj = self.load_key(public_extern_key, public_extern_key_file) self.private_key_obj = self.load_key(private_extern_key, private_extern_key_file) + if padding == CipherPadding.PKCS1_OAEP.value: + self.cipher_method = PKCS1_OAEP + else: + self.cipher_method = PKCS1_v1_5_cipher + @key_obj_checker(KeyObjType.PUBLIC_KEY_OBJ.value) def encrypt(self, message: str) -> str: """ 加密 @@ -106,12 +150,13 @@ def encrypt(self, message: str) -> str: message_bytes = message.encode(encoding=ENCODING) encrypt_message_bytes = b"" block_size = self.get_block_size(self.public_key_obj) - cipher = PKCS1_v1_5_cipher.new(self.public_key_obj) + cipher = self.cipher_method.new(self.public_key_obj) for block in self.block_list(message_bytes, block_size): encrypt_message_bytes += cipher.encrypt(block) encrypt_message = base64.b64encode(encrypt_message_bytes) return encrypt_message.decode(encoding=ENCODING) + @key_obj_checker(KeyObjType.PRIVATE_KEY_OBJ.value) def decrypt(self, encrypt_message: str) -> str: """ 解密 @@ -121,11 +166,12 @@ def decrypt(self, encrypt_message: str) -> str: decrypt_message_bytes = b"" encrypt_message_bytes = base64.b64decode(encrypt_message) block_size = self.get_block_size(self.private_key_obj, is_encrypt=False) - cipher = PKCS1_v1_5_cipher.new(self.private_key_obj) + cipher = self.cipher_method.new(self.private_key_obj) for block in self.block_list(encrypt_message_bytes, block_size): decrypt_message_bytes += cipher.decrypt(block, "") return decrypt_message_bytes.decode(encoding=ENCODING) + @key_obj_checker(KeyObjType.PRIVATE_KEY_OBJ.value) def sign(self, message: str) -> bytes: """ 根据私钥和需要发送的信息生成签名 @@ -137,6 +183,7 @@ def sign(self, message: str) -> bytes: signature = cipher.sign(sha) return base64.b64encode(signature) + @key_obj_checker(KeyObjType.PUBLIC_KEY_OBJ.value) def verify(self, message: str, signature: bytes): """ 使用公钥验证签名 diff --git a/apps/utils/tests/test_encrypt/test_rsa.py b/apps/utils/tests/test_encrypt/test_rsa.py index 1a404b941..1553952ba 100644 --- a/apps/utils/tests/test_encrypt/test_rsa.py +++ b/apps/utils/tests/test_encrypt/test_rsa.py @@ -31,3 +31,6 @@ def test_rsa_util__verify(self): message = "验证私钥签名,如果验证结果为True,表明该消息从私钥拥有方发出,没有被修改" signature = rsa_util.sign(message=message) self.assertTrue(rsa_util.verify(message=message, signature=signature)) + + def test_key_obj_check_failed(self): + self.assertRaises(ValueError, rsa.RSAUtil().encrypt, "test") diff --git a/config/default.py b/config/default.py index c2431a263..e92d0f468 100644 --- a/config/default.py +++ b/config/default.py @@ -405,6 +405,9 @@ class StorageType(Enum): # 下载文件路径 EXPORT_PATH = os.path.join(PUBLIC_PATH, "export") +# 脚本工具存放位置 +BK_SCRIPTS_PATH = os.path.join(PROJECT_ROOT, "script_tools") + # ============================================================================== # 后台配置 # ============================================================================== @@ -509,7 +512,6 @@ def get_standard_redis_mode(cls, config_redis_mode: str, default: Optional[str] } } BK_OFFICIAL_PLUGINS_INIT_PATH = os.path.join(PROJECT_ROOT, "official_plugin") - BK_SCRIPTS_PATH = os.path.join(PROJECT_ROOT, "script_tools") REST_FRAMEWORK["DEFAULT_AUTHENTICATION_CLASSES"] = [ "apps.utils.drf.CsrfExemptSessionAuthentication", ] diff --git a/dev_log/2.1.356/durant_202112081505.yaml b/dev_log/2.1.356/durant_202112081505.yaml new file mode 100644 index 000000000..bddaa7a39 --- /dev/null +++ b/dev_log/2.1.356/durant_202112081505.yaml @@ -0,0 +1,3 @@ +--- +feature: + - "Windows Agent安装支持用administrator用户注册服务(close #277)" diff --git a/script_tools/gse_public_key b/script_tools/gse_public_key new file mode 100644 index 000000000..7edcaf9bb --- /dev/null +++ b/script_tools/gse_public_key @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDM7NP/GYXJUURUemBdA +DUMWj8XKXq9UMfJFs2gWVpICW/A2/VqcgJbeVCauoy5hQ3og0/FqMOFsUrKakT8r +Kz5MPMDix9+5dCjEZEHz4Oxd+/gX77S1sMPIjlDnyj0AuwKAQ0hN+oPCrRp5wzVM +e11R+9VQxuEWCScXeEmcs39AFqQZHTXl6Ao3l/NXE2lsYuDB+AQiy276nnEkgmch +O7BgundCL3pvq9yZblEkTI3v1sSMYZaMU81YUOOZuO24YIqPwN/ZEYf7I4UkwO+w +MM8OozzsHzhJymI/oM9C6VvaecwY3L6fPTe9WWMqH84uOOaH6QuTXQ8jH2Ge8J7K +PwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/script_tools/setup_agent.bat b/script_tools/setup_agent.bat index f52dc7479..4ce39fd57 100644 --- a/script_tools/setup_agent.bat +++ b/script_tools/setup_agent.bat @@ -35,13 +35,21 @@ if "%1" EQU "-B" (set BT_PORT=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-S" (set BT_PORT_START=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-Z" (set BT_PORT_END=%~2) && shift && shift && goto CheckOpts if "%1" EQU "-K" (set TRACKER_PORT=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-U" (set INSTALL_USER=%~2) && shift && shift && goto CheckOpts +if "%1" EQU "-P" (set INSTALL_PASSWORD=%~2) && shift && shift && goto CheckOpts if "%1" NEQ "" echo Invalid option: "%1" && goto :EOF && exit /B 1 if not defined UPSTREAM_TYPE (set UPSTREAM_TYPE=SERVER) else (set UPSTREAM_TYPE=%UPSTREAM_TYPE%) if not defined HTTP_PROXY (set HTTP_PROXY=) else (set HTTP_PROXY=%HTTP_PROXY%) +if not defined INSTALL_USER (set INSTALL_USER=) else (set INSTALL_USER=%INSTALL_USER%) +if not defined INSTALL_PASSWORD (set INSTALL_PASSWORD=) else (set INSTALL_PASSWORD=%INSTALL_PASSWORD%) if "%PROCESSOR_ARCHITECTURE%" == "x86" (set PKG_NAME=gse_client-windows-x86.tgz) else (set PKG_NAME=gse_client-windows-x86_64.tgz) if "%PROCESSOR_ARCHITECTURE%" == "x86" (set CPU_ARCH=x86) else (set CPU_ARCH=x86_64) if "%CLOUD_ID%" == "0" (set NODE_TYPE=agent) else (set NODE_TYPE=pagent) +set gse_winagent_home=%AGENT_SETUP_PATH% +set service_id=%gse_winagent_home:~3,20% +if %service_id%=="gse" (set _service_id=) else (set _service_id=_%service_id%) +set gse_winagent_home=%gse_winagent_home:\=\\% set report_line_num=3 set tmp_json_resp=%TMP_DIR%\nm.setup_agent.bat.%TASK_ID% @@ -347,18 +355,6 @@ goto :EOF ) goto :EOF -:start_agent - if exist %AGENT_SETUP_PATH% ( - cd /d %AGENT_SETUP_PATH%\agent\bin && .\gsectl start 1>nul 2>&1 - ping -n 3 127.0.0.1 1>nul 2>&1 - cd /d %TMP_DIR% - call :is_process_start_ok - ) else ( - call :print FAIL start_agent FAILED "%AGENT_SETUP_PATH% not exist , ERROR" - call :multi_report_step_status - ) -goto :EOF - :stop_agent if exist %AGENT_SETUP_PATH% ( cd /d %AGENT_SETUP_PATH%\agent\bin && .\gsectl stop 1>nul 2>&1 @@ -457,8 +453,10 @@ goto :EOF if not exist %GSE_AGENT_DATA_DIR% (md %GSE_AGENT_DATA_DIR%) if not exist %GSE_AGENT_LOG_DIR% (md %GSE_AGENT_LOG_DIR%) - call :start_agent + call :quit_legacy_agent + call :install_gse_agent_service_with_user_special ping -n 3 127.0.0.1 >nul 2>&1 + call :print INFO setup_agent DONE "agent setup successfully" goto :EOF @@ -668,7 +666,7 @@ goto :EOF for /f "tokens=1* delims=:" %%i in ('type %tmp_check_deploy_result_files% ^|findstr /n "."') do (set ret=%%i) echo %ret% ---------------------------------------------------------------------------------------------------------------------Final - if %ret% GEQ 4 ( + if %ret% GEQ 2 ( rem DEL /F /S /Q %tmp_json_resp% %TMP_DIR%\nm.setup_agent.bat.%TASK_ID% %TMP_DIR%\nm.test.XXXXXXXX %TMP_DIR%\nm.test.ZZZZZZZ call :print INFO check_deploy_result DONE "gse agent has been deployed successfully" rem call :multi_report_step_status @@ -837,6 +835,35 @@ goto :EOF ) goto :EOF +:install_gse_agent_service_with_user_special + if %INSTALL_USER% == "" ( + %gse_winagent_home%\\agent\\bin\\gse_agent_daemon.exe -f %gse_winagent_home%\\agent\\etc\\agent.conf --name gse_agent_daemon_%service_id% + if %errorlevel% equ 0 ( + call :print INFO setup_agent DONE "create gse_agent service without special user succeed" + ) else ( + call :print FAIL setup_agent DONE "create gse_agent service without special user failed" + ) + ) else ( + %gse_winagent_home%\\agent\\bin\\gse_agent_daemon.exe -f %gse_winagent_home%\\agent\\etc\\agent.conf --name gse_agent_daemon_%service_id% --user .\\%INSTALL_USER% --pwd %INSTALL_PASSWORD% --encode + if %errorlevel% equ 0 ( + call :print INFO setup_agent DONE "create gse_agent service with special user: %INSTALL_USER%, pwd: %INSTALL_PASSWORD% succeed" + ) else ( + call :print FAIL setup_agent DONE "create gse_agent service with special user %INSTALL_USER% failed" + ) + ) + %gse_winagent_home%\\agent\\bin\\gse_agent_daemon.exe --start --name gse_agent_daemon_%service_id% +goto :EOF + +:quit_legacy_agent + rem 兼容性处理,停用并删除老版本agent + sc stop gse_agent_daemon_%service_id% + sc delete gse_agent_daemon_%service_id% + sc stop gseDaemon + sc delete gseDaemon + cd C: + RD /S /Q C:\gse\gseagentw +goto :EOF + :help echo usage: setup_agent.bat -i CLOUD_ID -l URL -i CLOUD_ID -I LAN_IP [OPTIONS] echo for example: setup_agent.bat -i 0 -I gse_ethernet_ip -s task_id -l DOWNLOAD_URL -p C:\gse -r CALLBACK_URL -n GSE_SERVER_IP -N SERVER -T Temp_folder diff --git a/script_tools/setup_pagent.py b/script_tools/setup_pagent.py index 638306685..33b405eca 100644 --- a/script_tools/setup_pagent.py +++ b/script_tools/setup_pagent.py @@ -44,39 +44,27 @@ def arg_parser() -> argparse.ArgumentParser: """Commandline argument parser""" parser = argparse.ArgumentParser(description="p-agent setup scripts") parser.add_argument("-R", "--remove", action="store_true", default=None, help="uninstall agent") - parser.add_argument("-f", "--config", type=str, help="a file contain p-agent hosts info") - parser.add_argument( "-j", "--json", type=str, help="a file contain p-agent hosts info in json format", ) - parser.add_argument("-I", "--lan-eth-ip", type=str, help="local ip address of proxy") - parser.add_argument( "-l", "--download-url", type=str, help="a url for downloading gse agent packages (without filename)", ) - parser.add_argument("-s", "--task-id", type=str, help="task id generated by nodeman, optional") - parser.add_argument("-r", "--callback-url", type=str, help="api for report step and task status") - parser.add_argument("-c", "--token", type=str, help="token for request callback api") - parser.add_argument("-p", "--install-path", type=str, help="install path for gse agent") - parser.add_argument("-e", "--btfile-server-ip", type=str, help="comma seperated btfile server ip list") parser.add_argument("-a", "--data-server-ip", type=str, help="comma seperated data server ip list") parser.add_argument("-k", "--task-server-ip", type=str, help="comma seperated task server ip list") - - parser.add_argument("-P", "--parallel", type=int, help="max process in parallel") - parser.add_argument( "-q", "--quite", @@ -85,15 +73,7 @@ def arg_parser() -> argparse.ArgumentParser: default=False, help="discard remote output, run in silent and keep no persistent connections", ) - - parser.add_argument( - "-u", - "--upgrade", - action="store_true", - default=False, - help="upgrade agent version", - ) - + parser.add_argument("-u", "--upgrade", action="store_true", default=False, help="upgrade agent version") parser.add_argument( "-T", "--temp_dir", @@ -101,81 +81,27 @@ def arg_parser() -> argparse.ArgumentParser: default=False, help="directory to save downloaded scripts and temporary files", ) - parser.add_argument( "-o", "--package_url", type=str, help="url for pagent to download package and dependency", ) - - parser.add_argument( - "-O", - "--io-port", - type=int, - help="IO_PORT", - ) - - parser.add_argument( - "-E", - "--file-svr-port", - type=int, - help="FILE_SVR_PORT", - ) - - parser.add_argument( - "-A", - "--data-port", - type=int, - help="DATA_PORT", - ) - - parser.add_argument( - "-V", - "--btsvr-thrift-port", - type=int, - help="BTSVR_THRIFT_PORT", - ) - - parser.add_argument( - "-B", - "--bt-port", - type=int, - help="BT_PORT", - ) - - parser.add_argument( - "-S", - "--bt-port-start", - type=int, - help="BT_PORT_START", - ) - - parser.add_argument( - "-Z", - "--bt-port-end", - type=int, - help="BT_PORT_END", - ) - - parser.add_argument( - "-K", - "--tracker-port", - type=int, - help="TRACKER_PORT", - ) - - parser.add_argument( - "-L", - "--download-path", - type=str, - help="Tool kit storage path", - ) + parser.add_argument("-O", "--io-port", type=int, help="IO_PORT") + parser.add_argument("-E", "--file-svr-port", type=int, help="FILE_SVR_PORT") + parser.add_argument("-A", "--data-port", type=int, help="DATA_PORT") + parser.add_argument("-V", "--btsvr-thrift-port", type=int, help="BTSVR_THRIFT_PORT") + parser.add_argument("-B", "--bt-port", type=int, help="BT_PORT") + parser.add_argument("-S", "--bt-port-start", type=int, help="BT_PORT_START") + parser.add_argument("-Z", "--bt-port-end", type=int, help="BT_PORT_END") + parser.add_argument("-K", "--tracker-port", type=int, help="TRACKER_PORT") + parser.add_argument("-L", "--download-path", type=str, help="Tool kit storage path") # 主机信息 parser.add_argument("-HLIP", "--host-login-ip", type=str, help="Host Login IP") parser.add_argument("-HIIP", "--host-inner-ip", type=str, help="Host Inner IP") parser.add_argument("-HA", "--host-account", type=str, help="Host Account") + parser.add_argument("-HEP", "--host-encrypted-password", type=str, help="Host Encrypted Password") parser.add_argument("-HP", "--host-port", type=str, help="Host Port") parser.add_argument("-HI", "--host-identity", type=str, help="Host Identity") parser.add_argument("-HC", "--host-cloud", type=str, help="Host Cloud") @@ -435,6 +361,7 @@ def main() -> None: user = args.host_account port = args.host_port identity = args.host_identity + host_encrypted_password = args.host_encrypted_password cloud_id = args.host_cloud _os = args.host_os_type tmp_dir = args.host_dest_dir @@ -495,7 +422,7 @@ def main() -> None: cmd.append( "{dest_dir}{script_name} -T {dest_dir} -i {} -I {} -s {} -c {} -l {} -r {} -p {} " - '-e "{}" -a "{}" -k "{}" -x {} -N PROXY {} -O {} -E {} -A {} -V {} -B {} -S {} -Z {} -K {}'.format( + '-e "{}" -a "{}" -k "{}" -x {} -N PROXY {} -O {} -E {} -A {} -V {} -B {} -S {} -Z {} -K {} {}'.format( cloud_id, lan_eth_ip, args.task_id, @@ -516,6 +443,9 @@ def main() -> None: args.bt_port_start, args.bt_port_end, args.tracker_port, + # 需要加密时,传入-U -P参数,用于windows服务注册 + # 注意-P参数是base64,其中的 等号(=) 会被吃掉,需要添加 双引号("") 来规避此问题 + '-U {} -P "{}"'.format(user, host_encrypted_password) if host_encrypted_password else "", script_name=script_name, dest_dir=tmp_dir, )