Skip to content

Commit a65992c

Browse files
chore: Automate restore of logical DB backup
1 parent d5a4e39 commit a65992c

File tree

1 file changed

+240
-0
lines changed

1 file changed

+240
-0
lines changed

admin/restore-db-logical.ps1

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
<#PSScriptInfo
2+
.VERSION 1.1.0
3+
.GUID 356b42ed-f2ab-47ed-af57-57a5411c3723
4+
.AUTHOR Synopsys
5+
#>
6+
7+
<#
8+
.DESCRIPTION
9+
This script automates the process of restoring the MariaDB master database with
10+
a logical backup generated by mysqldump:
11+
12+
mysqldump --host=127.0.0.1 --port=3306 --user=root -p codedx > /bitnami/mariadb/dump-codedx.sql
13+
14+
Note: This does not work with a physical backup generated with mariabackup.
15+
#>
16+
17+
param (
18+
[string] $backupToRestore, # logical backup file (dump.sql) or tar gzipped file (dump.tgz containing a dump.sql file)
19+
[string] $rootPwd,
20+
[string] $replicationPwd,
21+
[string] $namespace = 'cdx-app',
22+
[string] $releaseName = 'codedx',
23+
[int] $waitSeconds = 600,
24+
[switch] $skipWebRestart
25+
)
26+
27+
$ErrorActionPreference = 'Stop'
28+
$VerbosePreference = 'Continue'
29+
30+
Set-PSDebug -Strict
31+
32+
$global:PSNativeCommandArgumentPassing='Legacy'
33+
34+
'../.install-guided-setup-module.ps1' | ForEach-Object {
35+
$path = join-path $PSScriptRoot $_
36+
if (-not (Test-Path $path)) {
37+
Write-Error "Unable to find file script dependency at $path. Please download the entire GitHub repository and rerun the downloaded copy of this script."
38+
}
39+
. $path
40+
}
41+
42+
function New-DatabaseFromLogicalBackup([string] $namespace,
43+
[string] $podName,
44+
[string] $containerName,
45+
[string] $rootPwd,
46+
[string] $databaseName,
47+
[string] $databaseDump,
48+
[switch] $skipDropDatabase) {
49+
50+
if (-not $skipDropDatabase) {
51+
Remove-Database $namespace $podName $containerName $rootPwd $databaseName
52+
}
53+
54+
$cmd = "CREATE DATABASE $databaseName"
55+
56+
kubectl -n $namespace exec -c $containerName $podName -- mysql -uroot --password=$rootPwd -e $cmd
57+
if (0 -ne $LASTEXITCODE) {
58+
Write-Error "Unable to create database, kubectl exited with exit code $LASTEXITCODE."
59+
}
60+
61+
if (-not (Test-Path $databaseDump -PathType Leaf)) {
62+
Write-Error "Unable to find database dump file at $databaseDump."
63+
}
64+
65+
$databaseDumpFilename = Split-Path $databaseDump -Leaf
66+
67+
$importPath = "/bitnami/mariadb/$databaseDumpFilename"
68+
Copy-K8sItem $namespace $databaseDump $podName $containerName $importPath
69+
70+
$databaseDumpFileExtension = [IO.Path]::GetExtension($databaseDumpFilename)
71+
if ($databaseDumpFileExtension -eq '.tgz') {
72+
73+
# a tar gzip file should expand to a file of the same name with a .sql extension
74+
# for example, tar cvzf dump.tgz dump.sql
75+
kubectl -n $namespace exec -c $containerName $podName -- tar xvf $importPath -C '/bitnami/mariadb'
76+
if (0 -ne $LASTEXITCODE) {
77+
Write-Error "Unable to extract $importPath, kubectl exited with exit code $LASTEXITCODE."
78+
}
79+
$importPath = [IO.Path]::ChangeExtension($importPath, '.sql')
80+
}
81+
82+
kubectl -n $namespace exec -c $containerName $podName -- bash -c "mysql -uroot --password=""$rootPwd"" $databaseName < $importPath"
83+
if (0 -ne $LASTEXITCODE) {
84+
Write-Error "Unable to import database dump, kubectl exited with exit code $LASTEXITCODE."
85+
}
86+
}
87+
88+
if (-not (Test-HelmRelease $namespace $releaseName)) {
89+
Write-Error "Unable to find Helm release named $releaseName in namespace $namespace."
90+
}
91+
92+
$deployment = Get-HelmChartFullname $releaseName 'codedx'
93+
$statefulSetMariaDBMaster = "$releaseName-mariadb-master"
94+
$statefulSetMariaDBSlave = "$releaseName-mariadb-slave"
95+
96+
$statefulSetMariaDBSlaveCount = (Get-HelmValues $namespace $releaseName).mariadb.slave.replicas
97+
if ($statefulSetMariaDBSlaveCount -eq 0) {
98+
$statefulSetMariaDBMaster = "$releaseName-mariadb"
99+
$statefulSetMariaDBSlave = ''
100+
}
101+
102+
$mariaDbSecretName = "$releaseName-mariadb-pd"
103+
$mariaDbMasterServiceName = "$releaseName-mariadb"
104+
105+
if (-not (Test-Deployment $namespace $deployment)) {
106+
Write-Error "Unable to find Deployment named $deployment in namespace $namespace."
107+
}
108+
109+
if (-not (Test-StatefulSet $namespace $statefulSetMariaDBMaster)) {
110+
Write-Error "Unable to find StatefulSet named $statefulSetMariaDBMaster in namespace $namespace."
111+
}
112+
113+
if ($statefulSetMariaDBSlaveCount -ne 0 -and (-not (Test-StatefulSet $namespace $statefulSetMariaDBSlave))) {
114+
Write-Error "Unable to find StatefulSet named $statefulSetMariaDBSlave in namespace $namespace."
115+
}
116+
117+
if (-not (Test-Secret $namespace $mariaDbSecretName)) {
118+
# it could be a default DB resource
119+
Write-Error "Unable to find Secret named $mariaDbSecretName in namespace $namespace."
120+
}
121+
122+
if (-not (Test-Service $namespace $mariaDbMasterServiceName)) {
123+
Write-Error "Unable to find Service named $mariaDbMasterServiceName in namespace $namespace."
124+
}
125+
126+
$mariaDBServiceAccount = Get-ServiceAccountName $namespace 'statefulset' $statefulSetMariaDBMaster
127+
128+
Write-Host @"
129+
130+
Using the following configuration:
131+
132+
Deployment Name: $deployment
133+
MariaDB Master StatefulSet Name: $statefulSetMariaDBMaster
134+
MariaDB Slave StatefulSet Name: $statefulSetMariaDBSlave
135+
MariaDB Slave Replica Count: $statefulSetMariaDBSlaveCount
136+
MariaDB Secret Name: $mariaDbSecretName
137+
MariaDB Master Service Name: $mariaDbMasterServiceName
138+
MariaDB Service Account: $mariaDBServiceAccount
139+
"@
140+
141+
if ($backupToRestore -eq '') {
142+
$backupToRestore = Read-HostText 'Enter the db backup to restore (backup.sql)' 1
143+
}
144+
145+
if (-not (Test-Path $backupToRestore -PathType Leaf)) {
146+
Write-Error "The '$backupToRestore' file does not exist."
147+
}
148+
if ('.sql','.tgz' -notcontains ([io.path]::GetExtension($backupToRestore))) {
149+
Write-Error "The '$backupToRestore' file does not have a .sql or .tgz file extension."
150+
}
151+
if ($backupToRestore.Contains(":")) {
152+
Write-Error "Unable to continue because the '$backupToRestore' path contains a colon that will disrupt a required kubectl cp command - specify an alternate, relative path instead."
153+
}
154+
155+
if ($rootPwd -eq '') {
156+
$rootPwd = Read-HostSecureText 'Enter the password for the MariaDB root user' 1
157+
}
158+
159+
if ($replicationPwd -eq '') {
160+
$replicationPwd = Read-HostSecureText 'Enter the password for the MariaDB replication user' 1
161+
}
162+
163+
Write-Verbose 'Restarting database...'
164+
& (join-path $PSScriptRoot 'restart-db.ps1') -namespace $namespace -releaseName $releaseName -waitSeconds $waitSeconds -skipWebRestart
165+
166+
Write-Verbose 'Searching for MariaDB slave pods...'
167+
$podFullNamesSlaves = kubectl -n $namespace get pod -l component=slave -o name
168+
if (0 -ne $LASTEXITCODE) {
169+
Write-Error "Unable to fetch slave pods, kubectl exited with exit code $LASTEXITCODE."
170+
}
171+
172+
$podNamesSlaves = @()
173+
$podFullNamesSlaves | ForEach-Object {
174+
175+
$podName = $_ -replace 'pod/',''
176+
$podNamesSlaves = $podNamesSlaves + $podName
177+
}
178+
179+
Write-Verbose 'Searching for web pod...'
180+
$podName = kubectl -n $namespace get pod -l component=web -o name
181+
if (0 -ne $LASTEXITCODE) {
182+
Write-Error "Unable to find web pod, kubectl exited with exit code $LASTEXITCODE."
183+
}
184+
$podName = $podName -replace 'pod/',''
185+
186+
Write-Verbose 'Searching for MariaDB master pod...'
187+
$podNameMaster = kubectl -n $namespace get pod -l component=master -o name
188+
if (0 -ne $LASTEXITCODE) {
189+
Write-Error "Unable to find MariaDB master pod, kubectl exited with exit code $LASTEXITCODE."
190+
}
191+
192+
if ([string]::IsNullOrEmpty($podNameMaster)) {
193+
Write-Error "Unable to find primary database pod. Is it running?"
194+
}
195+
$podNameMaster = $podNameMaster -replace 'pod/',''
196+
197+
Write-Verbose "Stopping deployment named $deployment..."
198+
Set-DeploymentReplicas $namespace $deployment 0 $waitSeconds
199+
200+
Write-Verbose 'Stopping slave database instances...'
201+
$podNamesSlaves | ForEach-Object {
202+
Write-Verbose "Stopping slave named $_..."
203+
Stop-SlaveDB $namespace $_ 'mariadb' $rootPwd
204+
}
205+
206+
Write-Verbose "Restoring database backup on pod $podNameMaster..."
207+
New-DatabaseFromLogicalBackup $namespace $podNameMaster 'mariadb' $rootPwd 'codedx' $backupToRestore
208+
$podNamesSlaves | ForEach-Object {
209+
Write-Verbose "Restoring database backup on pod $_..."
210+
New-DatabaseFromLogicalBackup $namespace $_ 'mariadb' $rootPwd 'codedx' $backupToRestore
211+
}
212+
213+
Write-Verbose "Starting $statefulSetMariaDBMaster statefulset replica..."
214+
Set-StatefulSetReplicas $namespace $statefulSetMariaDBMaster 1 $waitSeconds
215+
216+
if ($statefulSetMariaDBSlaveCount -ne 0) {
217+
218+
Write-Verbose "Starting $statefulSetMariaDBSlave statefulset replica(s)..."
219+
Set-StatefulSetReplicas $namespace $statefulSetMariaDBSlave $statefulSetMariaDBSlaveCount $waitSeconds
220+
221+
Write-Verbose 'Resetting master database...'
222+
$filePos = Get-MasterFilePosAfterReset $namespace 'mariadb' $podNameMaster $rootPwd
223+
224+
Write-Verbose 'Connecting slave database(s)...'
225+
$podNamesSlaves | ForEach-Object {
226+
Write-Verbose "Restoring slave database pod $_..."
227+
Stop-SlaveDB $namespace $_ 'mariadb' $rootPwd
228+
Start-SlaveDB $namespace $_ 'mariadb' 'replicator' $replicationPwd $rootPwd $mariaDbMasterServiceName $filePos
229+
}
230+
}
231+
232+
if ($skipWebRestart) {
233+
Write-Verbose "Skipping Restart..."
234+
Write-Verbose " To restart, run: kubectl -n $namespace scale --replicas=1 deployment/$deployment"
235+
} else {
236+
Write-Verbose "Starting deployment named $deployment..."
237+
Set-DeploymentReplicas $namespace $deployment 1 $waitSeconds
238+
}
239+
240+
Write-Host 'Done'

0 commit comments

Comments
 (0)