Update pve RustDesk GA sync scripts
This commit is contained in:
+100
-26
@@ -25,18 +25,50 @@ SHARE = os.environ.get('BLAIR_SHARE', '/tank/blair-share')
|
|||||||
REGISTRY = os.path.join(SHARE, 'fleet', 'registry.json')
|
REGISTRY = os.path.join(SHARE, 'fleet', 'registry.json')
|
||||||
NODE = os.environ.get('BLAIR_PVE_NODE', 'pve')
|
NODE = os.environ.get('BLAIR_PVE_NODE', 'pve')
|
||||||
DRY_RUN = os.environ.get('BLAIR_DRY_RUN', '') in ('1', 'true', 'yes')
|
DRY_RUN = os.environ.get('BLAIR_DRY_RUN', '') in ('1', 'true', 'yes')
|
||||||
|
VERBOSE = os.environ.get('BLAIR_VERBOSE', '') in ('1', 'true', 'yes')
|
||||||
VMIDS_ENV = os.environ.get('BLAIR_VMIDS', '').strip()
|
VMIDS_ENV = os.environ.get('BLAIR_VMIDS', '').strip()
|
||||||
|
|
||||||
RUSTDESK_CFG = (
|
GUEST_READ_PATHS = [
|
||||||
r'C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk2.toml'
|
r'C:\ProgramData\Blair\rustdesk-report.json',
|
||||||
)
|
r'C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk2.toml',
|
||||||
PS_GET_ID = (
|
r'C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk.toml',
|
||||||
r"$p='C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk2.toml'; "
|
r'C:\Windows\System32\config\systemprofile\AppData\Roaming\RustDesk\config\RustDesk2.toml',
|
||||||
r"if (-not (Test-Path -LiteralPath $p)) { exit 1 }; "
|
r'C:\ProgramData\RustDesk\config\RustDesk2.toml',
|
||||||
r"$t=Get-Content -Raw -LiteralPath $p; "
|
]
|
||||||
r"if ($t -match '(?m)^\s*id\s*=\s*''?(\d{6,12})') { Write-Output $Matches[1]; exit 0 }; "
|
|
||||||
r"exit 1"
|
PS_READ_ID = r'''
|
||||||
|
$paths = @(
|
||||||
|
'C:\ProgramData\Blair\rustdesk-report.json',
|
||||||
|
'C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk2.toml',
|
||||||
|
'C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk.toml',
|
||||||
|
'C:\Windows\System32\config\systemprofile\AppData\Roaming\RustDesk\config\RustDesk2.toml',
|
||||||
|
'C:\ProgramData\RustDesk\config\RustDesk2.toml'
|
||||||
)
|
)
|
||||||
|
foreach ($p in $paths) {
|
||||||
|
if (-not (Test-Path -LiteralPath $p)) { continue }
|
||||||
|
$t = Get-Content -Raw -LiteralPath $p
|
||||||
|
if ($p -like '*.json') {
|
||||||
|
try {
|
||||||
|
$j = $t | ConvertFrom-Json
|
||||||
|
if ($j.rustdesk_id -match '^\d{6,12}$') { Write-Output $j.rustdesk_id; exit 0 }
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
if ($t -match '(?m)^\s*id\s*=\s*[''"]?(\d{6,12})') { Write-Output $Matches[1]; exit 0 }
|
||||||
|
}
|
||||||
|
foreach ($rp in @(
|
||||||
|
'HKLM:\SOFTWARE\RustDesk\Host',
|
||||||
|
'HKLM:\SOFTWARE\RustDesk',
|
||||||
|
'HKLM:\SOFTWARE\WOW6432Node\RustDesk\Host',
|
||||||
|
'HKLM:\SOFTWARE\WOW6432Node\RustDesk'
|
||||||
|
)) {
|
||||||
|
if (-not (Test-Path $rp)) { continue }
|
||||||
|
foreach ($n in @('id', 'Id', 'rustdesk_id', 'peer_id')) {
|
||||||
|
$v = (Get-ItemProperty -Path $rp -Name $n -ErrorAction SilentlyContinue).$n
|
||||||
|
if ($v -match '^\d{6,12}$') { Write-Output $v; exit 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
def log(msg: str) -> None:
|
def log(msg: str) -> None:
|
||||||
@@ -142,40 +174,81 @@ def guest_exec_text(vmid: int, command: list[str], timeout: int = 90) -> tuple[s
|
|||||||
|
|
||||||
|
|
||||||
def guest_file_read(vmid: int, guest_path: str) -> tuple[str | None, str | None]:
|
def guest_file_read(vmid: int, guest_path: str) -> tuple[str | None, str | None]:
|
||||||
|
for path in {guest_path, guest_path.replace('\\', '/')}:
|
||||||
proc = subprocess.run(
|
proc = subprocess.run(
|
||||||
['pvesh', 'get', f'/nodes/{NODE}/qemu/{vmid}/agent/file-read', '--file', guest_path],
|
[
|
||||||
|
'pvesh', 'get', f'/nodes/{NODE}/qemu/{vmid}/agent/file-read',
|
||||||
|
'--file', path, '--output-format', 'json',
|
||||||
|
],
|
||||||
capture_output=True, text=True, check=False,
|
capture_output=True, text=True, check=False,
|
||||||
)
|
)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
msg = proc.stderr.strip() or proc.stdout.strip() or f'file-read rc={proc.returncode}'
|
continue
|
||||||
return None, msg
|
|
||||||
try:
|
try:
|
||||||
payload = json.loads(proc.stdout)
|
payload = json.loads(proc.stdout)
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return None, f'file-read json error: {proc.stdout[:160]!r}'
|
continue
|
||||||
data = payload.get('data', payload)
|
data = payload.get('data', payload)
|
||||||
content_b64 = data.get('content') if isinstance(data, dict) else None
|
content_b64 = data.get('content') if isinstance(data, dict) else None
|
||||||
if not content_b64:
|
if not content_b64:
|
||||||
return None, 'file-read empty content'
|
continue
|
||||||
return base64.b64decode(content_b64).decode('utf-8', errors='replace'), None
|
return base64.b64decode(content_b64).decode('utf-8', errors='replace'), None
|
||||||
|
return None, f'file-read failed for {guest_path}'
|
||||||
|
|
||||||
|
|
||||||
def parse_rustdesk_id_from_toml(text: str) -> str | None:
|
def parse_id_from_content(text: str, path: str) -> str | None:
|
||||||
match = re.search(r'(?m)^\s*id\s*=\s*["\']?(\d{6,12})', text)
|
if path.lower().endswith('.json'):
|
||||||
return match.group(1) if match else None
|
try:
|
||||||
|
rid = str(json.loads(text).get('rustdesk_id', '') or '').strip()
|
||||||
|
if re.fullmatch(r'\d{6,12}', rid):
|
||||||
|
return rid
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
for pattern in (
|
||||||
|
r'(?m)^\s*id\s*=\s*["\']?(\d{6,12})',
|
||||||
|
r'(?m)rustdesk_id\s*=\s*["\']?(\d{6,12})',
|
||||||
|
):
|
||||||
|
match = re.search(pattern, text)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def powershell_encoded(script: str) -> str:
|
||||||
|
return base64.b64encode(script.strip().encode('utf-16-le')).decode('ascii')
|
||||||
|
|
||||||
|
|
||||||
|
def guest_exec_powershell(vmid: int) -> tuple[str | None, str | None]:
|
||||||
|
enc = powershell_encoded(PS_READ_ID)
|
||||||
|
return guest_exec_text(
|
||||||
|
vmid,
|
||||||
|
['powershell.exe', '-NoProfile', '-EncodedCommand', enc],
|
||||||
|
timeout=120,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def read_rustdesk_id(vmid: int) -> tuple[str | None, str | None]:
|
def read_rustdesk_id(vmid: int) -> tuple[str | None, str | None]:
|
||||||
text, err = guest_file_read(vmid, RUSTDESK_CFG)
|
errors: list[str] = []
|
||||||
if text:
|
for path in GUEST_READ_PATHS:
|
||||||
rid = parse_rustdesk_id_from_toml(text)
|
text, err = guest_file_read(vmid, path)
|
||||||
|
if not text:
|
||||||
|
if VERBOSE:
|
||||||
|
errors.append(f'{path}: {err}')
|
||||||
|
continue
|
||||||
|
rid = parse_id_from_content(text, path)
|
||||||
if rid:
|
if rid:
|
||||||
|
if VERBOSE:
|
||||||
|
log(f'VM {vmid}: ID {rid} from file-read {path}')
|
||||||
return rid, None
|
return rid, None
|
||||||
err = 'id not found in RustDesk2.toml'
|
errors.append(f'{path}: no id in file')
|
||||||
return guest_exec_text(
|
|
||||||
vmid,
|
rid, err = guest_exec_powershell(vmid)
|
||||||
['powershell.exe', '-NoProfile', '-Command', PS_GET_ID],
|
if rid:
|
||||||
)
|
if VERBOSE:
|
||||||
|
log(f'VM {vmid}: ID {rid} from guest exec')
|
||||||
|
return rid, None
|
||||||
|
errors.append(f'exec: {err}')
|
||||||
|
return None, errors[-1] if errors else 'unknown'
|
||||||
|
|
||||||
|
|
||||||
def qm_description(vmid: int) -> str:
|
def qm_description(vmid: int) -> str:
|
||||||
@@ -224,7 +297,8 @@ def main() -> int:
|
|||||||
|
|
||||||
new_id, err = read_rustdesk_id(vmid)
|
new_id, err = read_rustdesk_id(vmid)
|
||||||
if not new_id:
|
if not new_id:
|
||||||
log(f'VM {vmid}: skip (could not read RustDesk ID: {err})')
|
hint = ' (try BLAIR_VERBOSE=1)' if not VERBOSE else ''
|
||||||
|
log(f'VM {vmid}: skip (could not read RustDesk ID: {err}){hint}')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
old_registry_id = registry_old_id(registry, vmid)
|
old_registry_id = registry_old_id(registry, vmid)
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ chmod 644 "$CRON"
|
|||||||
cat "$CRON"
|
cat "$CRON"
|
||||||
|
|
||||||
echo "=== dry run ==="
|
echo "=== dry run ==="
|
||||||
"$TARGET" --dry-run
|
BLAIR_VERBOSE=1 "$TARGET" --dry-run
|
||||||
|
|
||||||
echo "=== live run ==="
|
echo "=== live run ==="
|
||||||
"$TARGET"
|
"$TARGET"
|
||||||
|
|||||||
Reference in New Issue
Block a user