blob: 0962f88babb892ee3ec9746241a50c5d53a005e5 [file] [log] [blame]
Martin Polreichf7a1bb02018-12-05 11:12:23 +01001/**
2 * Verify and restore Galera cluster
3 *
4 * Expected parameters:
5 * SALT_MASTER_CREDENTIALS Credentials to the Salt API.
6 * SALT_MASTER_URL Full Salt API address [http://10.10.10.1:8000].
Sergey6579de62019-01-15 17:27:59 +04007 * ASK_CONFIRMATION Ask confirmation for restore
Martin Polreich721b7252019-01-21 14:42:48 +01008 * CHECK_TIME_SYNC Set to true to check time synchronization accross selected nodes.
Martin Polreichf7889b52019-02-01 14:46:10 +01009 * VERIFICATION_RETRIES Number of restries to verify the restoration.
Martin Polreichddfdb612019-03-21 15:12:15 +010010 * RESTORE_TYPE Sets restoration method
Martin Polreichf7a1bb02018-12-05 11:12:23 +010011 *
12**/
13
14def common = new com.mirantis.mk.Common()
15def salt = new com.mirantis.mk.Salt()
Martin Polreich208c4872019-02-15 10:09:10 +010016def galera = new com.mirantis.mk.Galera()
Martin Polreichf7a1bb02018-12-05 11:12:23 +010017def python = new com.mirantis.mk.Python()
Martin Polreichf7a1bb02018-12-05 11:12:23 +010018def pepperEnv = "pepperEnv"
19def resultCode = 99
Martin Polreichddfdb612019-03-21 15:12:15 +010020def restoreType = env.RESTORE_TYPE
21def runRestoreDb = false
22def runBackupDb = false
Denis Egorenkoafc43442019-08-12 18:17:02 +040023def restartCluster = false
Martin Polreichf7a1bb02018-12-05 11:12:23 +010024
Sergey6579de62019-01-15 17:27:59 +040025askConfirmation = (env.getProperty('ASK_CONFIRMATION') ?: true).toBoolean()
Martin Polreich721b7252019-01-21 14:42:48 +010026checkTimeSync = (env.getProperty('CHECK_TIME_SYNC') ?: true).toBoolean()
Martin Polreich49f16c02019-02-04 13:14:01 +010027if (common.validInputParam('VERIFICATION_RETRIES') && VERIFICATION_RETRIES.isInteger()) {
Martin Polreichf7889b52019-02-01 14:46:10 +010028 verificationRetries = VERIFICATION_RETRIES.toInteger()
29} else {
30 verificationRetries = 5
31}
Martin Polreichddfdb612019-03-21 15:12:15 +010032if (restoreType.equals("BACKUP_AND_RESTORE") || restoreType.equals("ONLY_RESTORE")) {
33 runRestoreDb = true
34}
35if (restoreType.equals("BACKUP_AND_RESTORE")) {
36 runBackupDb = true
37}
Denis Egorenkoafc43442019-08-12 18:17:02 +040038if (restoreType.equals("RESTART_CLUSTER")) {
39 restartCluster = true
40}
Sergey6579de62019-01-15 17:27:59 +040041
Martin Polreichf7a1bb02018-12-05 11:12:23 +010042timeout(time: 12, unit: 'HOURS') {
43 node() {
44 stage('Setup virtualenv for Pepper') {
45 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
46 }
Denis Egorenkoafc43442019-08-12 18:17:02 +040047
48 def galeraStatus = [:]
Martin Polreichddfdb612019-03-21 15:12:15 +010049 stage('Verify status') {
Ivan Berezovskiy844da962019-07-24 15:30:54 +040050 def sysstatTargets = 'I@xtrabackup:client or I@xtrabackup:server'
51 def sysstatTargetsNodes = salt.getMinions(pepperEnv, sysstatTargets)
52 try {
53 if (!salt.isPackageInstalled(['saltId': pepperEnv, 'target': sysstatTargets, 'packageName': 'sysstat', 'output': false])) {
54 if (askConfirmation) {
55 input message: "Do you want to install 'sysstat' package on targeted nodes: ${sysstatTargetsNodes}? Click to confirm"
56 }
57 salt.runSaltProcessStep(pepperEnv, sysstatTargets, 'pkg.install', ['sysstat'])
58 }
59 } catch (Exception e) {
60 common.errorMsg("Unable to determine status of sysstat package on target nodes: ${sysstatTargetsNodes}.")
Martin Polreich42767c32019-08-07 18:07:57 +020061 common.errorMsg(e.getMessage())
Ivan Berezovskiy844da962019-07-24 15:30:54 +040062 if (askConfirmation) {
63 input message: "Do you want to continue? Click to confirm"
64 }
65 }
Denis Egorenkoafc43442019-08-12 18:17:02 +040066 galeraStatus = galera.verifyGaleraStatus(pepperEnv, checkTimeSync)
67
68 switch (galeraStatus.error) {
69 case 128:
70 common.errorMsg("Unable to obtain Galera members minions list. Without fixing this issue, pipeline cannot continue in verification, backup and restoration. This may be caused by wrong Galera configuration or corrupted pillar data.")
Martin Polreichf7a1bb02018-12-05 11:12:23 +010071 currentBuild.result = "FAILURE"
Martin Polreichf7889b52019-02-01 14:46:10 +010072 return
Denis Egorenkoafc43442019-08-12 18:17:02 +040073 case 130:
Martin Polreich42767c32019-08-07 18:07:57 +020074 common.errorMsg("Neither master or slaves are reachable. Without fixing this issue, pipeline cannot continue in verification, backup and restoration. Is at least one member of the Galera cluster up and running?")
Martin Polreichf7a1bb02018-12-05 11:12:23 +010075 currentBuild.result = "FAILURE"
Martin Polreichf7889b52019-02-01 14:46:10 +010076 return
Denis Egorenkoafc43442019-08-12 18:17:02 +040077 case 131:
78 common.errorMsg("Time desynced - Please fix this issue and rerun the pipeline.")
79 currentBuild.result = "FAILURE"
Ivan Berezovskiy64824112019-07-26 15:55:24 +040080 return
Denis Egorenkoafc43442019-08-12 18:17:02 +040081 case 140..141:
82 common.errorMsg("Disk utilization check failed - Please fix this issue and rerun the pipeline.")
83 currentBuild.result = "FAILURE"
84 return
85 case 1:
86 if (askConfirmation) {
87 input message: "There was a problem with parsing the status output or with determining it. Do you want to run a next action: ${restoreType}?"
88 } else {
89 common.warningMsg("There was a problem with parsing the status output or with determining it. Trying to perform action: ${restoreType}.")
90 }
91 break
92 case 0:
93 if (askConfirmation) {
94 input message: "There seems to be everything alright with the cluster, do you still want to continue with next action: ${restoreType}?"
95 break
96 } else {
97 common.warningMsg("There seems to be everything alright with the cluster, no backup and no restoration will be done.")
98 currentBuild.result = "SUCCESS"
99 return
100 }
101 default:
102 if (askConfirmation) {
103 input message: "There's something wrong with the cluster, do you want to continue with action: ${restoreType}?"
104 } else {
105 common.warningMsg("There's something wrong with the cluster, trying to perform action: ${restoreType}")
106 }
107 break
Martin Polreichf7a1bb02018-12-05 11:12:23 +0100108 }
Martin Polreich0f3b85d2019-04-02 14:22:11 +0200109 }
110 if (runBackupDb) {
Ivan Berezovskiy64824112019-07-26 15:55:24 +0400111 if (askConfirmation) {
112 input message: "Are you sure you want to run a backup? Click to confirm"
113 }
Martin Polreich0f3b85d2019-04-02 14:22:11 +0200114 stage('Backup') {
Ivan Berezovskiy64824112019-07-26 15:55:24 +0400115 deployBuild = build(job: 'galera_backup_database', parameters: [
116 [$class: 'StringParameterValue', name: 'SALT_MASTER_URL', value: SALT_MASTER_URL],
117 [$class: 'StringParameterValue', name: 'SALT_MASTER_CREDENTIALS', value: SALT_MASTER_CREDENTIALS],
118 [$class: 'StringParameterValue', name: 'OVERRIDE_BACKUP_NODE', value: "none"],
119 ]
Martin Polreich0f3b85d2019-04-02 14:22:11 +0200120 )
121 }
122 }
Denis Egorenkoafc43442019-08-12 18:17:02 +0400123 if (runRestoreDb || restartCluster) {
124 if (runRestoreDb) {
125 stage('Restore') {
126 if (askConfirmation) {
127 input message: "Are you sure you want to run a restore? Click to confirm"
Ivan Berezovskiy64824112019-07-26 15:55:24 +0400128 }
Denis Egorenkoafc43442019-08-12 18:17:02 +0400129 try {
130 if ((!askConfirmation && resultCode > 0) || askConfirmation) {
131 galera.restoreGaleraCluster(pepperEnv, galeraStatus)
132 }
133 } catch (Exception e) {
134 common.errorMsg("Restoration process has failed.")
135 common.errorMsg(e.getMessage())
136 }
137 }
138 }
139 if (restartCluster) {
140 stage('Restart cluster') {
141 if (askConfirmation) {
142 input message: "Are you sure you want to run a restart? Click to confirm"
143 }
144 try {
145 if ((!askConfirmation && resultCode > 0) || askConfirmation) {
146 galera.restoreGaleraCluster(pepperEnv, galeraStatus, false)
147 }
148 } catch (Exception e) {
149 common.errorMsg("Restart process has failed.")
150 common.errorMsg(e.getMessage())
151 }
Ivan Berezovskiy64824112019-07-26 15:55:24 +0400152 }
Martin Polreichf7a1bb02018-12-05 11:12:23 +0100153 }
Ivan Berezovskiy64824112019-07-26 15:55:24 +0400154 stage('Verify restoration result') {
155 common.retry(verificationRetries, 15) {
Denis Egorenkoafc43442019-08-12 18:17:02 +0400156 def status = galera.verifyGaleraStatus(pepperEnv, false)
157 if (status.error >= 1) {
Ivan Berezovskiy64824112019-07-26 15:55:24 +0400158 error("Verification attempt finished with an error. This may be caused by cluster not having enough time to come up or to sync. Next verification attempt in 5 seconds.")
159 } else {
160 common.infoMsg("Restoration procedure seems to be successful. See verification report to be sure.")
161 currentBuild.result = "SUCCESS"
162 }
Martin Polreichf7889b52019-02-01 14:46:10 +0100163 }
Martin Polreich7bc654c2019-01-18 14:17:52 +0100164 }
165 }
Martin Polreichf7a1bb02018-12-05 11:12:23 +0100166 }
167}