## vRealize Suite Operations 8.10
vROPS에서 Guest OS 내부를 모니터링하기 위해 telegraf agent를 사용할 수 있습니다.
telegraf agent를 설치하기 위해서는 cloud proxy가 필요한데, 정상적으로 telegraf agent가 설치되지 않는 케이스가 있어 이에 대해 공유 드립니다.
[구성 환경]
vRealize Operations
vRealize Operations Cloud Proxy
Windows Server(Korean Language)
[문제 증상]
우선, telegraf agent가 vRealize Operations Manager UI를 통해 설치가 실패한 후, Windows Server에서 telegraf agent를 수동으로 설치할 때, 다음과 같은 오류가 발생합니다.
PS C:\> powershell -file .\download.ps1 -o install -v 192.168.1.31 -u admin -p P@ssw0rd -d c:\temp -c 192.168.1.32 디렉터리: C:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2022-12-16 오전 8:43 arc_install_tmp_dir Executing install operation... install agents failed at FAILED - runBootstrapOrch. please check logs for more detail. |
수동 설치 방법은 아래 링크를 참조하시면 됩니다.
Install/Uninstall an Agent Using a Script on a Windows Platform
[분석 내용]
1. 우선, 설치 과정의 로그를 확인하기 위해 agent 설치 파일 다운로드 경로에 있는 uaf_bootstrap.log 파일을 살펴봐야 합니다.
최초 설치 시작은 powershell을 통해 download.ps1을 실행하는데, 실제로는 download.ps1 내에서 uaf-bootstrap.bat 배치 파일을 호출하기 때문에 uaf_bootstrap.log 파일을 확인하면 됩니다.
download.ps1 #################### # Parameter Check #################### $OPERATION=$o $VROPS_IP=$v $VROPS_USER=$u $VROPS_USER_PASSWORD=$p $BOOTSTRAP_DIR=$d $SLEEP_TIME=$s $COLLECTOR_IP=$c $INPUT_IPS=$i if( $BOOTSTRAP_DIR -eq $null) { $BOOTSTRAP_DIR = $pwd.ToString() + "\" + "arc_${OPERATION}_tmp_dir" } else { $BOOTSTRAP_DIR = $BOOTSTRAP_DIR + "\" + "arc_${OPERATION}_tmp_dir" } #Execute bootstrap operation Write-Host "Executing $OPERATION operation..." #add remotedir key to grains Add-Content $BOOTSTRAP_DIR/grains "remotedir: $BOOTSTRAP_DIR" $GRAINS_PATH="C:\VMware\UCP\salt\conf\grains" if ( $OPERATION -eq "uninstall" -and (Test-Path $GRAINS_PATH -PathType Leaf)) { $ARC_INSTALL_TMP_DIR=Select-String -path $GRAINS_PATH -Pattern "remotedir: (.*)" |Foreach-Object {$_.Matches}|Foreach-Object {$_.Groups[1].Value} } elseif ( $OPERATION -eq "uninstall" ) { $ARC_INSTALL_TMP_DIR=$BOOTSTRAP_DIR.Replace('arc_uninstall_tmp_dir','arc_install_tmp_dir') } $VC_ID=Select-String -path $BOOTSTRAP_DIR/grains -Pattern "vc_id: (.*)" |Foreach-Object {$_.Matches}|Foreach-Object {$_.Groups[1].Value} $VM_ID=Select-String -path $BOOTSTRAP_DIR/grains -Pattern "vm_id: (.*)" |Foreach-Object {$_.Matches}|Foreach-Object {$_.Groups[1].Value} $VM_NAME=Select-String -path $BOOTSTRAP_DIR/grains -Pattern "vm_name: (.*)" |Foreach-Object {$_.Matches}|Foreach-Object {$_.Groups[1].Value} $SALT_FQDN=Select-String -path $BOOTSTRAP_DIR/grains -Pattern "salt_master_fqdn: (.*)" |Foreach-Object {$_.Matches}|Foreach-Object {$_.Groups[1].Value} $DL_URL=Select-String -path $BOOTSTRAP_DIR/grains -Pattern "dl_url: (.*)" |Foreach-Object {$_.Matches}|Foreach-Object {$_.Groups[1].Value} & $BOOTSTRAP_DIR\uaf-bootstrap.bat $OPERATION $VC_ID $VM_ID $VM_NAME $SALT_FQDN $DL_URL download_job $BOOTSTRAP_DIR 2>&1 | Out-File -FilePath $BOOTSTRAP_DIR/uaf_bootstrap.log -Append |
2. 설치 과정의 마지막 오류 메시지가 "install agents failed at FAILED - runBootstrapOrch" 였기 때문에, runBootstrapOrch가 무엇인지를 우선 확인해야 합니다.
uaf-bootstrap.bat 파일을 살펴보면, 몇 가지 단계를 나누어서 구성되어 있는 것을 알 수 있습니다.
대략적으로 정리해보면, 설치할 파일들을 download하고, "Salt Minion"과 "Ucp Minion"을 설치 및 등록한 후 마지막으로 runBootstrapOrch 단계를 실행합니다.
즉, 마지막 단계인 runBootstrapOrch 에서 문제가 발생했음을 추측할 수 있습니다.
uaf-bootstrap.bat :install call :logMesg INFO "Starting Installation..." :: 1. Download required components :: 2. Install Salt Minion :: 3. Install Ucp Minion call :initializeVars call :runBootstrapStages downloadAll,installSaltMinion,registerSaltMinionService,installUcpMinion,registerUcpMinionService,runBootstrapOrch exit /b %errorlevel% ... ... ... :runBootstrapOrch set FETCH_ARTIFACTS_AND_RETRY=false :: Setup Bootstrap Orch Environment call:logMesg INFO "Setup Bootstrap Orch Environment..." %CONFIG_UTILS_CMD% unzip "%PROGDIR%\ucp-minion.zip" "%PROGDIR%" set _exitStatus=!errorlevel! ... ... ... |
3. 이제 설치 과정 시 생성된 uaf_bootstrap.log 파일을 확인해보겠습니다.
downloadAll > installSaltMinion > registerSaltMinionService > installUcpMinion > registerUcpMinionService 단계가 순서대로 완료된 후 runBootstrapOrch 단계에서 config-utils.py 내부의 status_windows 함수를 호출할 때, decode 관련 오류가 기록되어 있습니다.
uaf_bootstrap.log C:\Users\system-mgr.pub>call :logMesg INFO "Starting Installation..." C:\Users\system-mgr.pub>call :initializeVars C:\Users\system-mgr.pub>call :runBootstrapStages downloadAll,installSaltMinion,registerSaltMinionService,installUcpMinion,registerUcpMinionService,runBootstrapOrch C:\Users\system-mgr.pub>echo [2022-11-22,10:06:25.70] - INFO - 2. Execution the stage 'install - reinstall install downloadAll' [2022-11-22,10:06:25.70] - INFO - 2. Execution the stage 'install - reinstall install downloadAll' C:\Users\system-mgr.pub>echo [2022-11-22,10:06:26.64] - INFO - 2. Execution the stage 'install - reinstall install installSaltMinion' [2022-11-22,10:06:26.64] - INFO - 2. Execution the stage 'install - reinstall install installSaltMinion' C:\Users\system-mgr.pub>echo [2022-11-22,10:06:31.57] - INFO - 2. Execution the stage 'install - reinstall install registerSaltMinionService' [2022-11-22,10:06:31.57] - INFO - 2. Execution the stage 'install - reinstall install registerSaltMinionService' C:\Users\system-mgr.pub>echo [2022-11-22,10:06:31.67] - INFO - 2. Execution the stage 'install - reinstall install installUcpMinion' [2022-11-22,10:06:31.67] - INFO - 2. Execution the stage 'install - reinstall install installUcpMinion' C:\Users\system-mgr.pub>echo [2022-11-22,10:06:32.01] - INFO - 2. Execution the stage 'install - reinstall install registerUcpMinionService' [2022-11-22,10:06:32.01] - INFO - 2. Execution the stage 'install - reinstall install registerUcpMinionService' C:\Users\system-mgr.pub>echo [2022-11-22,10:06:32.12] - INFO - 2. Execution the stage 'install - reinstall install runBootstrapOrch' [2022-11-22,10:06:32.12] - INFO - 2. Execution the stage 'install - reinstall install runBootstrapOrch' C:\Users\system-mgr.pub>echo [2022-11-22,10:06:32.14] - INFO - Setup Bootstrap Orch Environment... [2022-11-22,10:06:32.14] - INFO - Setup Bootstrap Orch Environment... C:\Users\system-mgr.pub>echo [2022-11-22,10:06:32.45] - INFO - Running Bootstrap Orchestration... [2022-11-22,10:06:32.45] - INFO - Running Bootstrap Orchestration... 2022-11-22 10:06:32 - INFO - root - Running action: reinstall, run_dependent_action: install 2022-11-22 10:06:32 - INFO - root - Running the stage: SETUP_BOOTSTRAP_ENV configure_uaf_infra verify_configure_uaf_infra Setup Bootstrap Environment 2022-11-22 10:06:32 - INFO - root - Stage action run info - action=install_salt_minion ret=True stage_status=SUCCESS Traceback (most recent call last): File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 1199, in <module> exit_status = 0 if u.run_orchestration() else 1 File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 396, in run_orchestration stage_status = self.run_stage(stage) File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 444, in run_stage stage_status = self.run_stage_action(stage, action, verify) File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 460, in run_stage_action ret = verify_cb() File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 725, in is_salt_minion_installed return SvcStatus.NOT_INSTALLED != ServiceControl(SvcNames.SALT_MINION).status()['STATUS'] File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 137, in status return self.status_windows() File "C:\Users\system-mgr.pub\arc_install_tmp_dir\config-utils.py", line 209, in status_windows strStdout = strStdout.decode().replace("\r\n", "\n").replace("\r", "\n") UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc1 in position 42: invalid start byte C:\Users\system-mgr.pub>exit /b 1 C:\Users\system-mgr.pub>echo Run Bootstrap Orch _exitStatus=!_exitStatus! Run Bootstrap Orch _exitStatus=1 C:\Users\system-mgr.pub>call:exitHandler C:\Users\system-mgr.pub>if "" == "" (call:setActionCurrentStatusMesg "FAILED - runBootstrapOrch" ) C:\Users\system-mgr.pub>set ACTION_CURRENT_STATUS_MESG=FAILED - runBootstrapOrch |
4. 그렇다면, 다음으로 config-utils.py 파일에서 status_windows 함수를 찾아봐야 합니다.
문제가 생기기 전까지의 코드를 살펴보면, "sc query service_name"을 이용해서 서비스의 상태를 확인하고, 이 결과값을 읽어들인 후 이 값을 decode 하는 과정을 수행합니다.
def status_windows(self): status_dict = {'STATE': 'NA'} state_found = False cmd = "sc query \"%s\"" %(self.service_name) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) retval = proc.wait() if retval == 0: strStdout = proc.stdout.read() + proc.stderr.read() strStdout = strStdout.decode().replace("\r\n", "\n").replace("\r", "\n") ## an error occurs here lines = [] for line in strStdout.split("\n"): keyval = line.split(":") if len(keyval) < 2: continue lines.append(line) key = keyval[0].strip() val = keyval[1].strip() status_dict[key] = val if key == 'STATE': state_found = True ## i18N/G11N case - STATE, TYPE keys are locale strings if not state_found and retval == 0 and len(lines) >= 3: key, val = (k.strip() for k in lines[1].split(':')) status_dict['TYPE'] = val key, val = (k.strip() for k in lines[2].split(':')) status_dict['STATE'] = val status_dict['STATUS'] = status_dict['STATE'] if status_dict['STATE'] == 'NA': status_dict['STATUS'] = SvcStatus.NOT_INSTALLED if status_dict['STATE'].endswith('STOPPED'): status_dict['STATUS'] = SvcStatus.STOPPED if status_dict['STATE'].endswith('RUNNING'): status_dict['STATUS'] = SvcStatus.RUNNING if status_dict['STATE'].endswith('PAUSED'): status_dict['STATUS'] = SvcStatus.PAUSED return status_dict |
5. 위 과정을 Sample Code로 작성하여, 다음과 같이 테스트를 진행하였습니다.
Sample Code를 이용해서 테스트를 해보면, 실제로 설치 과정과 동일한 오류가 발생하는 것을 알 수 있습니다.
test.py import subprocess cmd = "sc query \"ucp-salt-minion\"" proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) retval = proc.wait() strStdout = proc.stdout.read() + proc.stderr.read() strStdout = strStdout.decode().replace("\r\n", "\n").replace("\r", "\n") C:\Temp\arc_install_tmp_dir>"%PYTHON_BIN%" C:\Temp\arc_install_tmp_dir\test.py Traceback (most recent call last): File "C:\Temp\arc_install_tmp_dir\test.py", line 7, in <module> strStdout = strStdout.decode().replace("\r\n", "\n").replace("\r", "\n") UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc1 in position 42: invalid start byte |
6. 그렇다면, 왜 해당 과정에서 오류가 발생하는지를 알아봐야 합니다.
이를 위해서 Python의 pdb를 이용하여 Sample Code가 실행될 때 어떤 값이 Return 되는지를 확인해봤습니다.
아래 결과를 보시면 "strStdout = proc.stdout.read() + proc.stderr.read()" 과정에서 strStdout 은 byte class로 "sc query" 결과값을 전달받은 것을 볼 수 있습니다.
C:\Temp\arc_install_tmp_dir>"%PYTHON_BIN%" -m pdb C:\Temp\arc_install_tmp_dir\test.py > c:\temp\arc_install_tmp_dir\test.py(1)<module>() -> import subprocess (Pdb) n > c:\temp\arc_install_tmp_dir\test.py(3)<module>() -> cmd = "sc query \"ucp-salt-minion\"" (Pdb) n > c:\temp\arc_install_tmp_dir\test.py(4)<module>() -> proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) (Pdb) n > c:\temp\arc_install_tmp_dir\test.py(5)<module>() -> retval = proc.wait() (Pdb) n > c:\temp\arc_install_tmp_dir\test.py(6)<module>() -> strStdout = proc.stdout.read() + proc.stderr.read() (Pdb) n > c:\temp\arc_install_tmp_dir\test.py(7)<module>() -> strStdout = strStdout.decode().replace("\r\n", "\n").replace("\r", "\n") (Pdb) print(type(strStdout)) <class 'bytes'> (Pdb) print(strStdout) b'\r\nSERVICE_NAME: ucp-salt-minion \r\n \xc1\xbe\xb7\xf9 : 10 WIN32_OWN_PROCESS \r\n \xbb\xf3\xc5\xc2 : 1 STOPPED \r\n WIN32_EXIT_CODE : 1077 (0x435)\r\n SERVICE_EXIT_CODE : 0 (0x0)\r\n \xb0\xcb\xbb\xe7\xc1\xa1 : 0x0\r\n WAIT_HINT : 0x0\r\n' (Pdb) n UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc1 in position 42: invalid start byte > c:\temp\arc_install_tmp_dir\test.py(7)<module>() -> strStdout = strStdout.decode().replace("\r\n", "\n").replace("\r", "\n") |
7. strStdout 변수가 가지고 있는 값을 확인해보면, 실제 "sc query" 명령어의 결과에서 한글로 표현된 글자가 encoding된 값으로 표시되는 것을 알 수 있습니다.
C:\Temp\arc_install_tmp_dir>sc query ucp-salt-minion SERVICE_NAME: ucp-salt-minion 종류 : 10 WIN32_OWN_PROCESS 상태 : 1 STOPPED WIN32_EXIT_CODE : 1077 (0x435) SERVICE_EXIT_CODE : 0 (0x0) 검사점 : 0x0 WAIT_HINT : 0x0 (Pdb) print(strStdout) b'\r\nSERVICE_NAME: ucp-salt-minion \r\n \xc1\xbe\xb7\xf9 : 10 WIN32_OWN_PROCESS \r\n \xbb\xf3\xc5\xc2 : 1 STOPPED \r\n WIN32_EXIT_CODE : 1077 (0x435)\r\n SERVICE_EXIT_CODE : 0 (0x0)\r\n \xb0\xcb\xbb\xe7\xc1\xa1 : 0x0\r\n WAIT_HINT : 0x0\r\n' |
8. 문제는 해당 글자가 encoding된 방식이 UTF가 아닌 euc-kr 이라는 것입니다. 이는 Windows Server에서 기본적으로 제공하는 완성형 방식의 글자이며, 개별 글자의 encode 값은 다음과 같이 정리해 볼 수 있습니다.
종류 종 \xc1\xbe 류 \xb7\xf9 상태 상 \xbb\xf3 태 \xc5\xc2 검사점 검 \xb0\xcb 사 \xbb\xe7 점 \xc1\xa1 |
9. 비교를 위해서 동일한 글자를 UTF-8로 encoding 하면 다음과 같은 값으로 결과를 확인할 수 있습니다.
대충봐도 확연히 다른 값들인 것을 알 수 있습니다.
종류 \xec\xa2\x85\xeb\xa5\x98 상태 \xec\x83\x81\xed\x83\x9c 검사점 \xEA\xB2\x80\xEC\x82\xAC\xEC\xA0\x90 |
10. 위 내용에서 문제가 발생한 부분은 strStdout 변수의 class가 byte인 경우 해당 class에서 decode() 함수를 호출할 때 별도의 argument를 지정하지 않으면, 기본적으로 UTF-8을 사용하여 decode를 하는데요. 실제로 strStdout 변수에 담겨있던 값 중 한글은 UTF-8이 아닌 euc-kr로 되어 있었기 때문에 올바르게 decoding이 되지 않던 현상이었습니다.
완성형 방식이 아닌 경우에는 위와 같은 문제가 발생하지는 않는 것으로 확인하였으며, 현재 해당 문제는 개발팀에서 수정 및 테스트를 진행하고 있는 단계입니다.
본 케이스를 통해서 Windows Server의 다국어 지원 시 어떤 방식으로 글자를 encoding 하는지를 확인할 수 있었으며, Python을 테스트 할 때 PDB라는 도구를 이용하여 변수를 확인해가면서 Debugging을 할 수 있던 기회였습니다.
'Management' 카테고리의 다른 글
[Automation] Unable to unregister that machine, unless you remove the disk (0) | 2023.06.30 |
---|---|
[Automation] How to debug with worfklow (0) | 2023.06.30 |
[LogInsight] How to configure AVI compatible with Syslog RFC (0) | 2022.10.27 |
[Automation] How to unregister the specific resource from the deployment (0) | 2022.10.07 |
[Automation] How to login vRealize Automation API Server (0) | 2022.09.30 |