blob: 3faedc7f81c7f4d711c98546658e87143bfe8e35 [file] [log] [blame]
Martin Polreichaae1b9d2018-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].
Martin Polreich0d538262019-02-01 14:46:10 +01007 * ASK_CONFIRMATION Ask confirmation for restore
Martin Polreich0d538262019-02-01 14:46:10 +01008 * VERIFICATION_RETRIES Number of restries to verify the restoration.
Martin Polreich2aa74402019-01-21 14:42:48 +01009 * CHECK_TIME_SYNC Set to true to check time synchronization accross selected nodes.
Martin Polreich7ba33592019-03-21 15:12:15 +010010 * RESTORE_TYPE Sets restoration method
Martin Polreichaae1b9d2018-12-05 11:12:23 +010011 *
12**/
13
14def common = new com.mirantis.mk.Common()
15def salt = new com.mirantis.mk.Salt()
Martin Polreich71a08db2019-02-15 10:09:10 +010016def galera = new com.mirantis.mk.Galera()
Martin Polreichaae1b9d2018-12-05 11:12:23 +010017def python = new com.mirantis.mk.Python()
Martin Polreichaae1b9d2018-12-05 11:12:23 +010018def pepperEnv = "pepperEnv"
19def resultCode = 99
Martin Polreich7ba33592019-03-21 15:12:15 +010020def restoreType = env.RESTORE_TYPE
21def runRestoreDb = false
22def runBackupDb = false
Martin Polreichaae1b9d2018-12-05 11:12:23 +010023
Martin Polreich0d538262019-02-01 14:46:10 +010024askConfirmation = (env.getProperty('ASK_CONFIRMATION') ?: true).toBoolean()
Martin Polreich2aa74402019-01-21 14:42:48 +010025checkTimeSync = (env.getProperty('CHECK_TIME_SYNC') ?: true).toBoolean()
Sergeyc8a8a792019-01-15 17:27:59 +040026
Martin Polreich0d538262019-02-01 14:46:10 +010027if (common.validInputParam(VERIFICATION_RETRIES) && VERIFICATION_RETRIES.isInteger()) {
28 verificationRetries = VERIFICATION_RETRIES.toInteger()
29} else {
30 verificationRetries = 5
31}
Martin Polreich7ba33592019-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}
Martin Polreich0d538262019-02-01 14:46:10 +010038
Martin Polreichaae1b9d2018-12-05 11:12:23 +010039timeout(time: 12, unit: 'HOURS') {
40 node() {
41 stage('Setup virtualenv for Pepper') {
42 python.setupPepperVirtualenv(pepperEnv, SALT_MASTER_URL, SALT_MASTER_CREDENTIALS)
43 }
Martin Polreich7ba33592019-03-21 15:12:15 +010044 stage('Verify status') {
Ivan Berezovskiyb6d18d52019-07-24 15:30:54 +040045 def sysstatTargets = 'I@xtrabackup:client or I@xtrabackup:server'
46 def sysstatTargetsNodes = salt.getMinions(pepperEnv, sysstatTargets)
47 try {
48 if (!salt.isPackageInstalled(['saltId': pepperEnv, 'target': sysstatTargets, 'packageName': 'sysstat', 'output': false])) {
49 if (askConfirmation) {
50 input message: "Do you want to install 'sysstat' package on targeted nodes: ${sysstatTargetsNodes}? Click to confirm"
51 }
52 salt.runSaltProcessStep(pepperEnv, sysstatTargets, 'pkg.install', ['sysstat'])
53 }
54 } catch (Exception e) {
55 common.errorMsg("Unable to determine status of sysstat package on target nodes: ${sysstatTargetsNodes}.")
Martin Polreich63b40fc2019-08-07 18:07:57 +020056 common.errorMsg(e.getMessage())
Ivan Berezovskiyb6d18d52019-07-24 15:30:54 +040057 if (askConfirmation) {
58 input message: "Do you want to continue? Click to confirm"
59 }
60 }
Martin Polreich71a08db2019-02-15 10:09:10 +010061 resultCode = galera.verifyGaleraStatus(pepperEnv, false, checkTimeSync)
Martin Polreichaae1b9d2018-12-05 11:12:23 +010062 if (resultCode == 128) {
63 common.errorMsg("Unable to connect to Galera Master. Trying slaves...")
Martin Polreich71a08db2019-02-15 10:09:10 +010064 resultCode = galera.verifyGaleraStatus(pepperEnv, true, checkTimeSync)
Martin Polreichaae1b9d2018-12-05 11:12:23 +010065 if (resultCode == 129) {
Martin Polreich63b40fc2019-08-07 18:07:57 +020066 common.errorMsg("Unable to obtain Galera slave 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 Polreichaae1b9d2018-12-05 11:12:23 +010067 currentBuild.result = "FAILURE"
Martin Polreich0d538262019-02-01 14:46:10 +010068 return
Martin Polreichaae1b9d2018-12-05 11:12:23 +010069 } else if (resultCode == 130) {
Martin Polreich63b40fc2019-08-07 18:07:57 +020070 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 Polreichaae1b9d2018-12-05 11:12:23 +010071 currentBuild.result = "FAILURE"
Martin Polreich0d538262019-02-01 14:46:10 +010072 return
Martin Polreichaae1b9d2018-12-05 11:12:23 +010073 }
74 }
Martin Polreich2aa74402019-01-21 14:42:48 +010075 if (resultCode == 131) {
Martin Polreich323ffde2019-05-07 15:56:38 +020076 common.errorMsg("Time desynced - Please fix this issue and rerun the pipeline.")
Martin Polreich2aa74402019-01-21 14:42:48 +010077 currentBuild.result = "FAILURE"
Martin Polreich323ffde2019-05-07 15:56:38 +020078 return
79 }
80 if (resultCode == 140 || resultCode == 141) {
81 common.errorMsg("Disk utilization check failed - Please fix this issue and rerun the pipeline.")
82 currentBuild.result = "FAILURE"
83 return
Martin Polreich2aa74402019-01-21 14:42:48 +010084 }
Martin Polreichaae1b9d2018-12-05 11:12:23 +010085 if (resultCode == 1) {
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +040086 if (askConfirmation) {
87 input message: "There was a problem with parsing the status output or with determining it. Do you want to run a restore?"
Sergeyc8a8a792019-01-15 17:27:59 +040088 } else {
89 common.warningMsg("There was a problem with parsing the status output or with determining it. Try to restore.")
90 }
Martin Polreichaae1b9d2018-12-05 11:12:23 +010091 } else if (resultCode > 1) {
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +040092 if (askConfirmation) {
93 input message: "There's something wrong with the cluster, do you want to continue with backup and/or restore?"
Sergeyc8a8a792019-01-15 17:27:59 +040094 } else {
Martin Polreich7ba33592019-03-21 15:12:15 +010095 common.warningMsg("There's something wrong with the cluster, try to backup and/or restore.")
Sergeyc8a8a792019-01-15 17:27:59 +040096 }
Martin Polreichaae1b9d2018-12-05 11:12:23 +010097 } else {
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +040098 if (askConfirmation) {
99 input message: "There seems to be everything alright with the cluster, do you still want to continue with backup and/or restore?"
Sergeyc8a8a792019-01-15 17:27:59 +0400100 } else {
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400101 common.warningMsg("There seems to be everything alright with the cluster, no backup and no restoration will be done.")
102 currentBuild.result = "SUCCESS"
103 return
Sergeyc8a8a792019-01-15 17:27:59 +0400104 }
Martin Polreichaae1b9d2018-12-05 11:12:23 +0100105 }
Martin Polreich7ba33592019-03-21 15:12:15 +0100106 }
107 if (runBackupDb) {
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400108 if (askConfirmation) {
109 input message: "Are you sure you want to run a backup? Click to confirm"
110 }
Martin Polreich7ba33592019-03-21 15:12:15 +0100111 stage('Backup') {
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400112 deployBuild = build(job: 'galera_backup_database', parameters: [
113 [$class: 'StringParameterValue', name: 'SALT_MASTER_URL', value: SALT_MASTER_URL],
114 [$class: 'StringParameterValue', name: 'SALT_MASTER_CREDENTIALS', value: SALT_MASTER_CREDENTIALS],
115 [$class: 'StringParameterValue', name: 'OVERRIDE_BACKUP_NODE', value: "none"],
116 ]
Martin Polreich7ba33592019-03-21 15:12:15 +0100117 )
118 }
119 }
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400120 if (runRestoreDb) {
121 stage('Restore') {
122 if (askConfirmation) {
123 input message: "Are you sure you want to run a restore? Click to confirm"
Sergeyc8a8a792019-01-15 17:27:59 +0400124 }
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400125 try {
126 if ((!askConfirmation && resultCode > 0) || askConfirmation) {
127 galera.restoreGaleraCluster(pepperEnv, runRestoreDb)
128 }
129 } catch (Exception e) {
130 common.errorMsg("Restoration process has failed.")
Martin Polreich63b40fc2019-08-07 18:07:57 +0200131 common.errorMsg(e.getMessage())
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400132 }
Martin Polreichaae1b9d2018-12-05 11:12:23 +0100133 }
Ivan Berezovskiy6ef32f02019-07-26 15:55:24 +0400134 stage('Verify restoration result') {
135 common.retry(verificationRetries, 15) {
136 exitCode = galera.verifyGaleraStatus(pepperEnv, false, false)
137 if (exitCode >= 1) {
138 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.")
139 } else {
140 common.infoMsg("Restoration procedure seems to be successful. See verification report to be sure.")
141 currentBuild.result = "SUCCESS"
142 }
Martin Polreich0d538262019-02-01 14:46:10 +0100143 }
Martin Polreichc9466c72019-01-18 14:17:52 +0100144 }
145 }
Martin Polreichaae1b9d2018-12-05 11:12:23 +0100146 }
147}