build/google-cloud-sql-server-agent-install.ps1 (229 lines of code) (raw):
#Requires -Version 5
#Requires -RunAsAdministrator
#Requires -Modules ScheduledTasks
<#
.SYNOPSIS
Google Cloud Agent for SQL installation script.
.DESCRIPTION
This powershell script is used to install the Google Cloud Agent for SQL
on the system and a Task Scheduler entry: google-cloud-sql-agent-monitor (runs every min),
.
#>
$ErrorActionPreference = 'Stop'
$INSTALL_DIR = "$Env:Programfiles\Google\google-cloud-sql-server-agent"
$SVC_NAME = 'google-cloud-sql-server-agent'
# The google-cloud-sql-agent-service.exe is a Windows Service Wrapper for google-cloud-sql-server-agent.exe
$SVC_NAME_EXE = 'google-cloud-sql-server-agent.exe'
$MONITOR_TASK = 'google-cloud-sql-server-agent-monitor'
$LOGS_DIR = "$INSTALL_DIR\logs"
$LOG_FILE ="$LOGS_DIR\google-cloud-sql-server-agent-install.log"
function Log-Write {
#.DESCRIPTION
# Writes to log file.
param (
[string] $log_message
)
Write-Host $log_message
if (-not (Test-Path $LOGS_DIR)) {
return
}
$time_stamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
$logFileSize = $(Get-Item $LOG_FILE -ErrorAction Ignore).Length/1kb
if ($logFileSize -ge 1024) {
Write-Host "Logfilesize: $logFileSize kb, rotating"
Move-Item -Force $LOG_FILE "$LOG_FILE.1"
}
Add-Content -Value ("$time_stamp - $log_message") -path $LOG_FILE
}
function CreateItem-IfNotExists {
param (
[string] $PathToCreate,
[string] $TypeToCreate
)
if (-not (Test-Path $PathToCreate)) {
Log-Write "Creating folder/contents: $PathToCreate"
New-Item -ItemType $TypeToCreate -Path $PathToCreate
}
}
function RenameFile-IfNotExists {
param (
[string] $SourceFile,
[string] $TargetFile
)
if (-not (Test-Path $TargetFile)) {
Log-Write "Renaming [$SourceFile] to [$TargetFile]"
Rename-Item -Path $SourceFile -NewName $TargetFile
}
else {
Log-Write "Skipping file copy as the file [$TargetFile] already exists."
}
}
function RemoveItem-IfExists {
param (
[string] $PathToRemove
)
if (Test-Path $PathToRemove) {
Log-Write "Cleaning up prior folder/contents: $PathToRemove"
# Left Overs, cleanup
Remove-Item -Recurse -Force $PathToRemove
}
}
function CreateInstall-Artifacts {
# Using -Force flag will not complain if the folder already exists.
CreateItem-IfNotExists $INSTALL_DIR 'Directory'
CreateItem-IfNotExists $LOGS_DIR 'Directory'
if (-not (Test-Path "$INSTALL_DIR\configuration.json") -And
(Test-Path "$INSTALL_DIR\config.json")
) {
RenameFile-IfNotExists "$INSTALL_DIR\config.json" "$INSTALL_DIR\configuration.json"
}
else {
RenameFile-IfNotExists "$INSTALL_DIR\config-default.json" "$INSTALL_DIR\configuration.json"
}
RemoveItem-IfExists "$INSTALL_DIR\config-default.json"
}
function Update-Configuration {
$date = Get-Date -Format 'MMddyyyy'
$backup = "$INSTALL_DIR\config-$date.bak"
Copy-Item "$INSTALL_DIR\configuration.json" $backup
$save = $false
$config = Get-Content $backup | ConvertFrom-Json
foreach ($cred in $config.credential_configuration) {
if ($cred.windows_authentication -ne $null) {
$save = $true
$cred.PSObject.Properties.Remove('windows_authentication')
}
if (![string]::IsNullOrEmpty($cred.domain)) {
$save = $true
$cred.user_name = '{0}\{1}' -f $cred.domain,$cred.user_name
if ($cred.guest_user_name -ne $null) {
$cred.guest_user_name = '{0}\{1}' -f $cred.domain,$cred.guest_user_name
}
$cred.PSObject.Properties.Remove('domain')
}
if ($cred.sql_configurations -eq $null) {
$save = $true
Add-Member -InputObject $cred -MemberType NoteProperty -Name 'sql_configurations' -Value @(
$(New-Object PSObject -Property $([ordered]@{
'host' = $cred.host
'user_name' = $cred.user_name
'secret_name' = $cred.secret_name
'port_number' = $cred.port_number
}))
) -Force
if ([string]::isNullOrEmpty($config.remote_collection) -or ($config.remote_collection -eq $false)) {
Add-Member -InputObject $cred -MemberType NoteProperty -Name 'local_collection' -Value $true -Force
}
elseif ([string]::isNullOrEmpty($cred.linux_remote) -or ($cred.linux_remote -eq $false)) {
Add-Member -InputObject $cred -MemberType NoteProperty -Name 'remote_win' -Value $(New-Object PSObject -Property $([ordered]@{
'server_name' = $cred.server_name
'guest_user_name' = $cred.guest_user_name
'guest_secret_name' = $cred.guest_secret_name
})
) -Force
}
else {
Add-Member -InputObject $cred -MemberType NoteProperty -Name 'remote_linux' -Value $(New-Object PSObject -Property $([ordered]@{
'server_name' = $cred.server_name
'guest_user_name' = $cred.guest_user_name
'guest_port_number' = $cred.guest_port_number
'linux_ssh_private_key_path' = $cred.linux_ssh_private_key_path
})
) -Force
}
$cred.PSObject.Properties.Remove('host')
$cred.PSObject.Properties.Remove('user_name')
$cred.PSObject.Properties.Remove('secret_name')
$cred.PSObject.Properties.Remove('port_number')
$cred.PSObject.Properties.Remove('server_name')
$cred.PSObject.Properties.Remove('guest_user_name')
$cred.PSObject.Properties.Remove('guest_secret_name')
$cred.PSObject.Properties.Remove('guest_port_number')
$cred.PSObject.Properties.Remove('linux_remote')
$cred.PSObject.Properties.Remove('linux_ssh_private_key_path')
}
}
if ($save) {
$config | ConvertTo-Json -Depth 4 | Out-File "$INSTALL_DIR\configuration.json" -Encoding ASCII
}
else {
RemoveItem-IfExists $backup
}
}
function ConfigureAgentWindows-Service {
if ($(Get-Service -Name $SVC_NAME -ErrorAction SilentlyContinue).Status) {
& "$INSTALL_DIR\$SVC_NAME_EXE" --action=uninstall
}
& "$INSTALL_DIR\$SVC_NAME_EXE" --action=install
}
function AddMonitor-Task {
if ($(Get-ScheduledTask $MONITOR_TASK -ErrorAction Ignore).TaskName) {
Log-Write "Scheduled task exists: $MONITOR_TASK"
Unregister-ScheduledTask -TaskName $MONITOR_TASK -Confirm:$false
}
Log-Write "Adding scheduled task: $MONITOR_TASK"
$action = New-ScheduledTaskAction `
-Execute 'Powershell.exe' `
-Argument "-File `"$INSTALL_DIR\google-cloud-sql-server-agent-monitor.ps1`" -WindowStyle Hidden" `
-WorkingDirectory $INSTALL_DIR
$trigger = New-ScheduledTaskTrigger `
-Once `
-At (Get-Date) `
-RepetitionInterval (New-TimeSpan -Minutes 10) `
-RepetitionDuration (New-TimeSpan -Days (365 * 20))
Register-ScheduledTask -Action $action -Trigger $trigger `
-TaskName $MONITOR_TASK `
-Description $MONITOR_TASK -User 'System'
Log-Write "Added scheduled task: $MONITOR_TASK"
}
function StopService-AndTasks {
if ($(Get-ScheduledTask $MONITOR_TASK -ErrorAction Ignore).TaskName) {
Disable-ScheduledTask $MONITOR_TASK
}
$service = Get-Service -Name $SVC_NAME -ErrorAction Ignore
if ($service.Status -and $service.Status -ne 'Stopped') {
Stop-Service $SVC_NAME
$service.WaitForStatus('Stopped', (New-TimeSpan -Minutes 5))
}
}
function StartService-AndTasks {
Start-Service $SVC_NAME -ErrorAction Ignore
Enable-ScheduledTask $MONITOR_TASK
}
$Success = $false
$Processing=$false
try {
Log-Write 'Installing the Google Cloud Agent for SQL'
CreateInstall-Artifacts
$Processing = $true;
Log-Write 'Updating the configuration'
Update-Configuration
Log-Write 'Stopping agent services...'
StopService-AndTasks
Log-Write 'Stopped agent services'
Log-Write 'Configuring Windows service...'
ConfigureAgentWindows-Service
Log-Write 'Windows service configured'
Log-Write 'Adding monitor task...'
AddMonitor-Task
Log-Write 'Monitor task added'
Log-Write 'Starting agent services...'
StartService-AndTasks
Log-Write 'Started agent services'
$Success = $true
Log-Write 'Successuflly installed the Google Cloud Agent for SQL'
}
catch {
Log-Write $_.Exception|Format-List -force | Out-String
break
}
Finally {
# Try to start service and tasks again to make sure we are not leaving things inconsistent.
try {
if ($Processing -and !$Success) {
StartService-AndTasks
}
}
Finally {
}
}