Files
Inv_web/installer/initialize_inventera_database.ps1
2026-07-26 14:54:21 +03:00

180 lines
5.2 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$PsqlPath,
[Parameter(Mandatory = $true)]
[string]$AdminUser,
[Parameter(Mandatory = $true)]
[string]$AdminPassword,
[Parameter(Mandatory = $true)]
[ValidateRange(1, 65535)]
[int]$PostgreSqlPort,
[Parameter(Mandatory = $true)]
[string]$DatabaseName,
[Parameter(Mandatory = $true)]
[string]$DatabaseUser,
[Parameter(Mandatory = $true)]
[string]$DatabasePassword,
[Parameter(Mandatory = $true)]
[ValidateRange(1, 65535)]
[int]$ApplicationPort,
[Parameter(Mandatory = $true)]
[string]$ConfigPath
)
$ErrorActionPreference = 'Stop'
trap {
$logDirectory = Split-Path -Parent $ConfigPath
New-Item -ItemType Directory -Path $logDirectory -Force -ErrorAction SilentlyContinue | Out-Null
$_ | Out-String | Set-Content -LiteralPath (Join-Path $logDirectory 'install-error.log') -Encoding UTF8
$env:PGPASSWORD = $null
exit 1
}
function Assert-SafeIdentifier {
param([string]$Value, [string]$Label)
if ($Value -notmatch '^[A-Za-z_][A-Za-z0-9_]*$') {
throw "$Label содержит недопустимые символы."
}
}
function Quote-Identifier {
param([string]$Value)
return '"' + $Value.Replace('"', '""') + '"'
}
function Quote-Literal {
param([string]$Value)
return "'" + $Value.Replace("'", "''") + "'"
}
function Invoke-Psql {
param(
[string]$Database,
[string]$Sql,
[switch]$Capture
)
$arguments = @(
'--host', '127.0.0.1',
'--port', [string]$PostgreSqlPort,
'--username', $AdminUser,
'--dbname', $Database,
'--no-password',
'--set', 'ON_ERROR_STOP=1',
'--tuples-only',
'--no-align',
'--command', $Sql
)
if ($Capture) {
$output = & $PsqlPath @arguments 2>&1
if ($LASTEXITCODE -ne 0) {
throw ($output -join [Environment]::NewLine)
}
return ($output -join [Environment]::NewLine).Trim()
}
& $PsqlPath @arguments
if ($LASTEXITCODE -ne 0) {
throw "psql завершился с кодом $LASTEXITCODE."
}
}
if (-not (Test-Path -LiteralPath $PsqlPath -PathType Leaf)) {
throw "Не найден psql.exe: $PsqlPath"
}
Assert-SafeIdentifier -Value $AdminUser -Label 'Логин администратора PostgreSQL'
Assert-SafeIdentifier -Value $DatabaseName -Label 'Имя базы данных'
Assert-SafeIdentifier -Value $DatabaseUser -Label 'Логин пользователя базы данных'
$env:PGPASSWORD = $AdminPassword
$connected = $false
$lastConnectionError = $null
for ($attempt = 1; $attempt -le 45; $attempt++) {
try {
Invoke-Psql -Database 'postgres' -Sql 'SELECT 1;' | Out-Null
$connected = $true
break
}
catch {
$lastConnectionError = $_
Start-Sleep -Seconds 2
}
}
if (-not $connected) {
throw "Не удалось подключиться к PostgreSQL на порту $PostgreSqlPort. $lastConnectionError"
}
$databaseIdentifier = Quote-Identifier $DatabaseName
$databaseLiteral = Quote-Literal $DatabaseName
$userIdentifier = Quote-Identifier $DatabaseUser
$userLiteral = Quote-Literal $DatabaseUser
$passwordLiteral = Quote-Literal $DatabasePassword
$roleExists = Invoke-Psql -Database 'postgres' -Sql "SELECT 1 FROM pg_roles WHERE rolname = $userLiteral;" -Capture
if ($roleExists -eq '1') {
Invoke-Psql -Database 'postgres' -Sql "ALTER ROLE $userIdentifier WITH LOGIN PASSWORD $passwordLiteral;"
}
else {
Invoke-Psql -Database 'postgres' -Sql "CREATE ROLE $userIdentifier WITH LOGIN PASSWORD $passwordLiteral;"
}
$databaseExists = Invoke-Psql -Database 'postgres' -Sql "SELECT 1 FROM pg_database WHERE datname = $databaseLiteral;" -Capture
if ($databaseExists -ne '1') {
Invoke-Psql -Database 'postgres' -Sql "CREATE DATABASE $databaseIdentifier OWNER $userIdentifier ENCODING 'UTF8';"
}
else {
Invoke-Psql -Database 'postgres' -Sql "ALTER DATABASE $databaseIdentifier OWNER TO $userIdentifier;"
}
Invoke-Psql -Database 'postgres' -Sql "GRANT ALL PRIVILEGES ON DATABASE $databaseIdentifier TO $userIdentifier;"
$env:PGPASSWORD = $DatabasePassword
$testArguments = @(
'--host', '127.0.0.1',
'--port', [string]$PostgreSqlPort,
'--username', $DatabaseUser,
'--dbname', $DatabaseName,
'--no-password',
'--set', 'ON_ERROR_STOP=1',
'--command', 'SELECT 1;'
)
& $PsqlPath @testArguments | Out-Null
if ($LASTEXITCODE -ne 0) {
throw 'Не удалось проверить подключение с учётными данными приложения.'
}
$configDirectory = Split-Path -Parent $ConfigPath
New-Item -ItemType Directory -Path $configDirectory -Force | Out-Null
$config = [ordered]@{
database = [ordered]@{
host = '127.0.0.1'
port = $PostgreSqlPort
name = $DatabaseName
user = $DatabaseUser
password = $DatabasePassword
}
application = [ordered]@{
host = '0.0.0.0'
port = $ApplicationPort
}
}
$config | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $ConfigPath -Encoding UTF8
$env:PGPASSWORD = $null
Write-Host "База данных $DatabaseName и конфигурация Inventera подготовлены."