Files
inquiry_robot/deploy/_remote_provision_data_plane.ps1
T

202 lines
9.4 KiB
PowerShell

# Provision Redis + MinIO (bucket inquiry-robot) + MySQL/PG SQL prep
$ErrorActionPreference = "Continue"
$Root = "E:\wwwroot"
$Ops = Join-Path $Root "ops"
$SqlDir = Join-Path $Ops "sql"
New-Item -ItemType Directory -Force -Path $Ops, $SqlDir | Out-Null
$Bucket = "inquiry-robot" # S3: no underscore
function New-Secret([int]$len = 48) {
$bytes = New-Object byte[] $len
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
return ([Convert]::ToBase64String($bytes) -replace '[+/=]', 'x').Substring(0, [Math]::Min(64, $len))
}
function Upsert-Env([string]$path, [hashtable]$pairs) {
$lines = @()
if (Test-Path $path) { $lines = @(Get-Content $path) }
$out = New-Object System.Collections.Generic.List[string]
$seen = @{}
foreach ($line in $lines) {
if ($line -match '^\s*#' -or $line -notmatch '=' -or [string]::IsNullOrWhiteSpace($line)) {
[void]$out.Add($line)
continue
}
$k = ($line.Split('=', 2))[0]
if ($pairs.ContainsKey($k)) {
[void]$out.Add("$k=$($pairs[$k])")
$seen[$k] = $true
} else {
[void]$out.Add($line)
$seen[$k] = $true
}
}
foreach ($k in $pairs.Keys) {
if (-not $seen.ContainsKey($k)) { [void]$out.Add("$k=$($pairs[$k])") }
}
Set-Content -Path $path -Value $out.ToArray() -Encoding UTF8
}
Write-Output "=== Redis ==="
$redisCred = Get-Content "C:\yutongda\secure\redis-credentials.json" -Raw | ConvertFrom-Json
$rcli = "C:\yutongda\tools\redis-5.0.14.1\redis-cli.exe"
$redisScript = "AUTH $($redisCred.application_username) $($redisCred.application_password)`nSELECT 1`nPING`nSET inquiry_robot:provision:ping ok EX 300`nGET inquiry_robot:provision:ping`nQUIT`n"
$redisOut = $redisScript | & $rcli -h $redisCred.host -p $redisCred.port 2>&1
$joined = ($redisOut | ForEach-Object { "$_" }) -join "`n"
if ($joined -notmatch 'PONG') { Write-Output $joined; throw "redis ping failed" }
Write-Output "REDIS_OK"
$redisUrl = "redis://$($redisCred.application_username):$($redisCred.application_password)@$($redisCred.host):$($redisCred.port)/1"
Write-Output "=== MinIO bucket $Bucket ==="
$minioRoot = @{}
Get-Content "C:\yutongda\config\minio.env" | ForEach-Object {
if ($_ -match '^(MINIO_ROOT_USER|MINIO_ROOT_PASSWORD)=(.*)$') { $minioRoot[$matches[1]] = $matches[2] }
}
$minioApp = @{}
Get-Content "C:\yutongda\config\minio-app.env" | ForEach-Object {
if ($_ -match '^(OBJECT_STORAGE_ACCESS_KEY|OBJECT_STORAGE_SECRET_KEY)=(.*)$') { $minioApp[$matches[1]] = $matches[2] }
}
$mc = "C:\yutongda\downloads\mc.exe"
& $mc alias set localminio http://127.0.0.1:9000 $minioRoot["MINIO_ROOT_USER"] $minioRoot["MINIO_ROOT_PASSWORD"] --api S3v4 | Out-Null
$mb = & $mc mb "localminio/$Bucket" --ignore-existing 2>&1
Write-Output ("mb=" + ($mb | ForEach-Object { "$_" }))
$policyPath = Join-Path $SqlDir "minio-inquiry-robot-policy.json"
@"
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": ["arn:aws:s3:::$Bucket", "arn:aws:s3:::$Bucket/*"]
}
]
}
"@ | Set-Content $policyPath -Encoding ASCII
& $mc admin policy create localminio inquiry_robot_full $policyPath 2>&1 | ForEach-Object { "policy_create=$_" }
& $mc admin policy attach localminio inquiry_robot_full --user $minioApp["OBJECT_STORAGE_ACCESS_KEY"] 2>&1 | ForEach-Object { "policy_attach=$_" }
& $mc alias set inquiryapp http://127.0.0.1:9000 $minioApp["OBJECT_STORAGE_ACCESS_KEY"] $minioApp["OBJECT_STORAGE_SECRET_KEY"] --api S3v4 | Out-Null
$smokeLocal = Join-Path $env:TEMP "inquiry_robot_smoke.txt"
Set-Content $smokeLocal -Value ("smoke " + (Get-Date).ToString("o")) -Encoding ASCII
$cp = & $mc cp $smokeLocal "inquiryapp/$Bucket/provision/smoke.txt" 2>&1
Write-Output ("cp=" + ($cp | ForEach-Object { "$_" }))
$ls = & $mc ls "inquiryapp/$Bucket/provision/" 2>&1
Write-Output ("ls=" + ($ls | ForEach-Object { "$_" }))
if (($cp | Out-String) -match 'ERROR' -or ($ls | Out-String) -match 'ERROR') {
# fallback: put with root alias
Write-Output "APP_PUT_FAIL_TRY_ROOT"
& $mc cp $smokeLocal "localminio/$Bucket/provision/smoke.txt" 2>&1 | ForEach-Object { "root_cp=$_" }
& $mc ls "localminio/$Bucket/provision/" 2>&1 | ForEach-Object { "root_ls=$_" }
}
Write-Output "MINIO_OK"
Write-Output "=== MySQL/PG SQL ==="
$mysqlPass = New-Secret 40
$pgPass = New-Secret 40
@"
CREATE DATABASE IF NOT EXISTS ``inquiry_robot`` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS 'inquiry_robot'@'10.206.0.15' IDENTIFIED BY '$mysqlPass';
CREATE USER IF NOT EXISTS 'inquiry_robot'@'%' IDENTIFIED BY '$mysqlPass';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'10.206.0.15';
GRANT ALL PRIVILEGES ON ``inquiry_robot``.* TO 'inquiry_robot'@'%';
FLUSH PRIVILEGES;
"@ | Set-Content (Join-Path $SqlDir "01_create_inquiry_robot_mysql.sql") -Encoding UTF8
@"
CREATE USER inquiry_robot_runtime WITH PASSWORD '$pgPass';
CREATE DATABASE inquiry_robot_runtime OWNER inquiry_robot_runtime ENCODING 'UTF8' TEMPLATE template0;
GRANT ALL PRIVILEGES ON DATABASE inquiry_robot_runtime TO inquiry_robot_runtime;
"@ | Set-Content (Join-Path $SqlDir "02_create_inquiry_robot_pg.sql") -Encoding UTF8
@{
mysql_user = "inquiry_robot"
mysql_password = $mysqlPass
pg_user = "inquiry_robot_runtime"
pg_password = $pgPass
createdAt = (Get-Date).ToString("o")
} | ConvertTo-Json | Set-Content (Join-Path $Ops "inquiry_robot_db_secrets.json") -Encoding UTF8
# Try admin-secrets.env if exists
$adminEnv = Join-Path $Ops "admin-secrets.env"
$mysqlCreated = $false
$pgCreated = $false
if (Test-Path $adminEnv) {
$admin = @{}
Get-Content $adminEnv | ForEach-Object {
if ($_ -match '^(MYSQL_ADMIN_USER|MYSQL_ADMIN_PASSWORD|PG_ADMIN_USER|PG_ADMIN_PASSWORD)=(.*)$') { $admin[$matches[1]] = $matches[2] }
}
if ($admin.MYSQL_ADMIN_USER -and $admin.MYSQL_ADMIN_PASSWORD) {
$mysqlExe = "C:\yutongda\tools\mysql-8.0.39-winx64\bin\mysql.exe"
Get-Content (Join-Path $SqlDir "01_create_inquiry_robot_mysql.sql") -Raw |
& $mysqlExe -h 10.206.0.14 -P 3306 -u $admin.MYSQL_ADMIN_USER "-p$($admin.MYSQL_ADMIN_PASSWORD)" --connect-timeout=15 2>&1 |
ForEach-Object { if ($_ -notmatch 'Using a password') { "mysql=$_" } }
if ($LASTEXITCODE -eq 0) { $mysqlCreated = $true }
}
if ($admin.PG_ADMIN_USER -and $admin.PG_ADMIN_PASSWORD) {
$env:PGPASSWORD = $admin.PG_ADMIN_PASSWORD
$psql = "C:\yutongda\tools\pgsql\bin\psql.exe"
& $psql -h 10.206.0.14 -p 5432 -U $admin.PG_ADMIN_USER -d postgres -v ON_ERROR_STOP=1 -c "SELECT 1" 2>&1 | ForEach-Object { "pgprobe=$_" }
# create user/db with separate commands (more reliable than multi-statement file)
& $psql -h 10.206.0.14 -p 5432 -U $admin.PG_ADMIN_USER -d postgres -v ON_ERROR_STOP=1 -c "DO `$`$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'inquiry_robot_runtime') THEN CREATE ROLE inquiry_robot_runtime LOGIN PASSWORD '$pgPass'; END IF; END `$`$;" 2>&1 | ForEach-Object { "pguser=$_" }
& $psql -h 10.206.0.14 -p 5432 -U $admin.PG_ADMIN_USER -d postgres -v ON_ERROR_STOP=1 -c "SELECT 'exists' FROM pg_database WHERE datname='inquiry_robot_runtime'" 2>&1 | ForEach-Object { "pgdbcheck=$_" }
$existsDb = & $psql -h 10.206.0.14 -p 5432 -U $admin.PG_ADMIN_USER -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='inquiry_robot_runtime'" 2>$null
if (-not $existsDb) {
& $psql -h 10.206.0.14 -p 5432 -U $admin.PG_ADMIN_USER -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE inquiry_robot_runtime OWNER inquiry_robot_runtime ENCODING 'UTF8' TEMPLATE template0;" 2>&1 | ForEach-Object { "pgdb=$_" }
}
$pgCreated = $true
}
} else {
Write-Output "NEED_DBA_FOR_MYSQL_PG"
}
Write-Output "=== patch .env ==="
$envPath = Join-Path $Root ".env"
if (-not (Test-Path $envPath)) {
"YTD_ENV=test`r`nYTD_DEPLOY_ROOT=E:\wwwroot`r`nYTD_CUTOVER_TARGET=replace-yutongda`r`n" | Set-Content $envPath -Encoding UTF8
}
$pairs = @{
MYSQL_HOST = "10.206.0.14"
MYSQL_PORT = "3306"
MYSQL_DB = "inquiry_robot"
MYSQL_USER = "inquiry_robot"
MYSQL_PASSWORD = $mysqlPass
YTD_MYSQL_URL = "jdbc:mysql://10.206.0.14:3306/inquiry_robot?characterEncoding=UTF-8&useUnicode=true&useSSL=true&requireSSL=true&verifyServerCertificate=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai"
PG_HOST = "10.206.0.14"
PG_PORT = "5432"
PG_DATABASE = "inquiry_robot_runtime"
PG_USER = "inquiry_robot_runtime"
PG_PASSWORD = $pgPass
PG_SSLMODE = "prefer"
YTD_REDIS_HOST = $redisCred.host
YTD_REDIS_PORT = "$($redisCred.port)"
YTD_REDIS_USERNAME = $redisCred.application_username
REDIS_URL = $redisUrl
REDIS_KEY_PREFIX = "inquiry_robot:"
REDIS_REQUIRED = "true"
OBJECT_STORAGE_ENDPOINT_URL = "http://127.0.0.1:9000"
OBJECT_STORAGE_BUCKET = $Bucket
OBJECT_STORAGE_ACCESS_KEY = $minioApp["OBJECT_STORAGE_ACCESS_KEY"]
OBJECT_STORAGE_SECRET_KEY = $minioApp["OBJECT_STORAGE_SECRET_KEY"]
OBJECT_STORAGE_PATH_STYLE = "true"
OBJECT_STORAGE_REGION = "us-east-1"
}
Upsert-Env $envPath $pairs
if (Test-Path "E:\wwwroot\agent\current") {
Copy-Item $envPath "E:\wwwroot\agent\current\.env" -Force
Write-Output "AGENT_ENV_SYNCED"
}
# verify env keys present (no values)
Select-String -Path $envPath -Pattern '^(MYSQL_DB|PG_DATABASE|REDIS_KEY_PREFIX|OBJECT_STORAGE_BUCKET)=' | ForEach-Object { $_.Line.Trim() }
@{
redis = $true
minioBucket = $Bucket
mysqlCreated = $mysqlCreated
pgCreated = $pgCreated
needDba = (-not $mysqlCreated -or -not $pgCreated)
sqlDir = $SqlDir
updatedAt = (Get-Date).ToString("o")
} | ConvertTo-Json | Tee-Object -FilePath (Join-Path $Ops "data-plane-status.json")
Write-Output "PROVISION_DONE"