bootstrap ircs-prod gitops config
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
param(
|
||||
[string]$OldNamespace = "ircs-system",
|
||||
[string]$NewNamespace = "ircs-prod",
|
||||
[string]$OldApplication = "ircs-app",
|
||||
[string]$ArgoNamespace = "argocd",
|
||||
[switch]$Execute
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
if (-not $Execute) {
|
||||
Write-Host "Dry run only. Planned actions:"
|
||||
Write-Host "1. Patch ArgoCD application $OldApplication to disable automated sync."
|
||||
Write-Host "2. Apply ircs-prod/edge-cutover HTTPRoutes."
|
||||
Write-Host "3. Delete old $OldNamespace huawai-route and ircs-route to avoid hostname/path conflicts."
|
||||
Write-Host "4. Wait for new routes to be Accepted and ResolvedRefs."
|
||||
Write-Host "Add -Execute to perform cutover."
|
||||
exit 0
|
||||
}
|
||||
|
||||
kubectl -n $ArgoNamespace patch application $OldApplication --type merge -p '{"spec":{"syncPolicy":null}}' | Out-Null
|
||||
kubectl apply -k ircs-prod/edge-cutover | Out-Null
|
||||
kubectl -n $OldNamespace delete httproute huawai-route ircs-route --ignore-not-found | Out-Null
|
||||
kubectl -n $NewNamespace wait --for=condition=Accepted httproute/huawai-route --timeout=120s
|
||||
kubectl -n $NewNamespace wait --for=condition=Accepted httproute/ircs-route --timeout=120s
|
||||
kubectl -n $NewNamespace get httproute huawai-route ircs-route
|
||||
@@ -0,0 +1,54 @@
|
||||
param(
|
||||
[string]$OldNamespace = "ircs-system",
|
||||
[string]$NewNamespace = "ircs-prod",
|
||||
[string]$Database = "ircs",
|
||||
[switch]$Execute,
|
||||
[switch]$TruncateTarget
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$tables = @(
|
||||
'actors', 'collection_tasks', 'cover_images', 'data_sources', 'directors', 'episodes',
|
||||
'failed_messages', 'magnet_links', 'magnet_provider_runs', 'magnet_providers', 'magnet_search_jobs',
|
||||
'member_favorites', 'member_watch_histories', 'members', 'playlists', 'raw_areas', 'raw_category',
|
||||
'raw_genres', 'raw_languages', 'raw_video_unified_video', 'raw_videos', 'request_audit_logs',
|
||||
'search_sync_tasks', 'source_domains', 'standard_areas', 'standard_category', 'standard_genre',
|
||||
'standard_languages', 'sys_credentials', 'system_configs', 'unified_video_actors',
|
||||
'unified_video_directors', 'unified_video_genres', 'unified_video_standard_areas',
|
||||
'unified_video_standard_languages', 'unified_videos', 'user_messages', 'video_actors',
|
||||
'video_directors', 'video_raw_areas', 'video_raw_genres', 'video_raw_languages',
|
||||
'video_resolver_sources'
|
||||
)
|
||||
|
||||
function Invoke-Postgres($Namespace, $Sql) {
|
||||
$escapedSql = $Sql.Replace("'", "'\''")
|
||||
kubectl -n $Namespace exec statefulset/postgres -- sh -lc "PGPASSWORD=\`$POSTGRES_PASSWORD psql -U postgres -d $Database -Atc '$escapedSql'"
|
||||
}
|
||||
|
||||
Write-Host "Compatible business tables planned for migration: $($tables.Count)"
|
||||
Write-Host "Excluded tables: databasechangelog, databasechangeloglock, V3 runtime audit/outbox/maintenance derived tables."
|
||||
|
||||
$oldTables = Invoke-Postgres $OldNamespace "select tablename from pg_tables where schemaname='public' order by tablename"
|
||||
$newTables = Invoke-Postgres $NewNamespace "select tablename from pg_tables where schemaname='public' order by tablename"
|
||||
$missingOld = $tables | Where-Object { $_ -notin $oldTables }
|
||||
$missingNew = $tables | Where-Object { $_ -notin $newTables }
|
||||
if ($missingOld) { throw "Old namespace is missing expected tables: $($missingOld -join ', ')" }
|
||||
if ($missingNew) { throw "New namespace is missing expected tables. Run ircs-prod core migrator first: $($missingNew -join ', ')" }
|
||||
|
||||
if (-not $Execute) {
|
||||
Write-Host "Dry run only. Add -Execute to stream data from $OldNamespace to $NewNamespace."
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($TruncateTarget) {
|
||||
$quoted = ($tables | ForEach-Object { 'public."' + $_ + '"' }) -join ', '
|
||||
Invoke-Postgres $NewNamespace "truncate table $quoted restart identity cascade" | Out-Null
|
||||
}
|
||||
|
||||
$tableArgs = ($tables | ForEach-Object { "--table=public.$_" }) -join ' '
|
||||
$dumpCmd = "PGPASSWORD=\`$POSTGRES_PASSWORD pg_dump -U postgres -d $Database --data-only --column-inserts --disable-triggers $tableArgs"
|
||||
$loadCmd = "PGPASSWORD=\`$POSTGRES_PASSWORD psql -U postgres -d $Database -v ON_ERROR_STOP=1"
|
||||
|
||||
kubectl -n $OldNamespace exec statefulset/postgres -- sh -lc $dumpCmd | kubectl -n $NewNamespace exec -i statefulset/postgres -- sh -lc $loadCmd
|
||||
Write-Host "Compatible data migration stream finished."
|
||||
@@ -0,0 +1,62 @@
|
||||
param(
|
||||
[string]$OldNamespace = "ircs-system",
|
||||
[string]$NewNamespace = "ircs-prod",
|
||||
[string]$OldSecret = "ircs-backend-secrets",
|
||||
[string]$NewSecret = "ircs-prod-secrets",
|
||||
[string]$OldPullSecret = "harbor-secret",
|
||||
[string]$NewPullSecret = "harbor-secret"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function New-Base64SecretValue([int]$Bytes = 48) {
|
||||
$buffer = [byte[]]::new($Bytes)
|
||||
[System.Security.Cryptography.RandomNumberGenerator]::Fill($buffer)
|
||||
return [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes([Convert]::ToBase64String($buffer)))
|
||||
}
|
||||
|
||||
kubectl get namespace $NewNamespace *> $null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
kubectl create namespace $NewNamespace | Out-Null
|
||||
}
|
||||
|
||||
$old = kubectl -n $OldNamespace get secret $OldSecret -o json | ConvertFrom-Json
|
||||
$data = @{}
|
||||
foreach ($prop in $old.data.PSObject.Properties) {
|
||||
$data[$prop.Name] = $prop.Value
|
||||
}
|
||||
|
||||
foreach ($key in @('APP_IDENTITY_JWT_SECRET', 'INTERNAL_CREDENTIAL_TOKEN', 'SERVICE_CREDENTIAL_TOKEN', 'SERVICE_SEARCH_TOKEN')) {
|
||||
if (-not $data.ContainsKey($key)) {
|
||||
$data[$key] = New-Base64SecretValue 48
|
||||
}
|
||||
}
|
||||
|
||||
$secret = [ordered]@{
|
||||
apiVersion = 'v1'
|
||||
kind = 'Secret'
|
||||
metadata = [ordered]@{
|
||||
name = $NewSecret
|
||||
namespace = $NewNamespace
|
||||
labels = [ordered]@{
|
||||
'app.kubernetes.io/part-of' = 'ircs'
|
||||
environment = 'prod'
|
||||
}
|
||||
}
|
||||
type = 'Opaque'
|
||||
data = $data
|
||||
}
|
||||
|
||||
$secret | ConvertTo-Json -Depth 20 | kubectl apply -f - | Out-Null
|
||||
|
||||
$pull = kubectl -n $OldNamespace get secret $OldPullSecret -o json | ConvertFrom-Json
|
||||
$pull.metadata.namespace = $NewNamespace
|
||||
$pull.metadata.name = $NewPullSecret
|
||||
$pull.metadata.PSObject.Properties.Remove('creationTimestamp')
|
||||
$pull.metadata.PSObject.Properties.Remove('resourceVersion')
|
||||
$pull.metadata.PSObject.Properties.Remove('uid')
|
||||
$pull.metadata.PSObject.Properties.Remove('managedFields')
|
||||
$pull.metadata.PSObject.Properties.Remove('annotations')
|
||||
$pull | ConvertTo-Json -Depth 20 | kubectl apply -f - | Out-Null
|
||||
|
||||
Write-Host "Prepared namespace, runtime secret, and image pull secret for $NewNamespace. Secret values were not printed."
|
||||
Reference in New Issue
Block a user