Skip to content

Commit 05f3b82

Browse files
committed
cli backup-restore: small refactoring to remove code dup
Change-Id: I109453bb4a63f5188be0abf0edb83c43c45a338f
1 parent 9ef5607 commit 05f3b82

File tree

3 files changed

+73
-128
lines changed

3 files changed

+73
-128
lines changed

cli/cmd/backup.go

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
controllers "github.com/softwarefactory-project/sf-operator/controllers"
3030
"github.com/spf13/cobra"
3131
"gopkg.in/yaml.v3"
32-
"k8s.io/client-go/kubernetes"
32+
apiv1 "k8s.io/api/core/v1"
3333
ctrl "sigs.k8s.io/controller-runtime"
3434
)
3535

@@ -64,29 +64,15 @@ var SecretsToBackup = []string{
6464
"zuul-auth-secret",
6565
}
6666

67-
func prepareBackup(kmd *cobra.Command, backupDir string) (string, *kubernetes.Clientset, string) {
68-
69-
cliCtx, err := cliutils.GetCLIContext(kmd)
70-
if err != nil {
71-
ctrl.Log.Error(err, "Error initializing CLI:")
72-
os.Exit(1)
73-
}
74-
75-
cliutils.CreateDirectory(backupDir, 0755)
76-
77-
kubeContext := cliCtx.KubeContext
78-
_, kubeClientSet := cliutils.GetClientset(kubeContext)
79-
return cliCtx.Namespace, kubeClientSet, kubeContext
80-
}
81-
82-
func createSecretBackup(ns string, backupDir string, kubeClientSet *kubernetes.Clientset) {
67+
func createSecretBackup(backupDir string, env cliutils.ENV) {
8368
ctrl.Log.Info("Creating secrets backup...")
8469

8570
secretsDir := backupDir + "/" + SecretsBackupPath
8671
cliutils.CreateDirectory(secretsDir, 0755)
8772

88-
for _, sec := range SecretsToBackup {
89-
secret := cliutils.GetSecretByName(sec, ns, kubeClientSet)
73+
for _, secName := range SecretsToBackup {
74+
secret := apiv1.Secret{}
75+
cliutils.GetMOrDie(&env, secName, &secret)
9076

9177
// convert secret content to string (was bytes)
9278
strMap := cliutils.ConvertMapOfBytesToMapOfStrings(secret.Data)
@@ -115,12 +101,12 @@ func createSecretBackup(ns string, backupDir string, kubeClientSet *kubernetes.C
115101
ctrl.Log.Info("Finished doing secret backup!")
116102
}
117103

118-
func createZuulKeypairBackup(ns string, backupDir string, kubeClientSet *kubernetes.Clientset,
119-
kubeContext string) {
104+
func createZuulKeypairBackup(backupDir string, kubeContext string, env cliutils.ENV) {
120105

121106
ctrl.Log.Info("Doing Zuul keys backup...")
122107

123-
pod := cliutils.GetPodByName(zuulBackupPod, ns, kubeClientSet)
108+
pod := apiv1.Pod{}
109+
cliutils.GetMOrDie(&env, zuulBackupPod, &pod)
124110

125111
// https://zuul-ci.org/docs/zuul/latest/client.html
126112
zuulBackupPath := backupDir + "/" + ZuulBackupPath
@@ -141,22 +127,21 @@ func createZuulKeypairBackup(ns string, backupDir string, kubeClientSet *kuberne
141127
}
142128

143129
// Execute command for backup
144-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, backupZuulCMD)
130+
cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.ZuulSchedulerIdent, backupZuulCMD)
145131

146132
// Take output of the backup
147-
commandBuffer := cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, backupZuulPrintCMD)
133+
commandBuffer := cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.ZuulSchedulerIdent, backupZuulPrintCMD)
148134

149135
// write stdout to file
150136
cliutils.WriteContentToFile(zuulBackupPath, commandBuffer.Bytes(), 0640)
151137

152138
// Remove key file from the pod
153-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, backupZuulRemoveCMD)
139+
cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.ZuulSchedulerIdent, backupZuulRemoveCMD)
154140

155141
ctrl.Log.Info("Finished doing Zuul private keys backup!")
156142
}
157143

158-
func createMySQLBackup(ns string, backupDir string, kubeClientSet *kubernetes.Clientset,
159-
kubeContext string) {
144+
func createMySQLBackup(backupDir string, kubeContext string, env cliutils.ENV) {
160145
ctrl.Log.Info("Doing DB backup...")
161146

162147
// create MariaDB dir
@@ -165,7 +150,8 @@ func createMySQLBackup(ns string, backupDir string, kubeClientSet *kubernetes.Cl
165150

166151
cliutils.CreateDirectory(mariaDBBackupDir, 0755)
167152

168-
pod := cliutils.GetPodByName(dbBackupPod, ns, kubeClientSet)
153+
pod := apiv1.Pod{}
154+
cliutils.GetMOrDie(&env, dbBackupPod, &pod)
169155

170156
// NOTE: We use option: --single-transaction to avoid error:
171157
// "The user specified as a definer ('mariadb.sys'@'localhost') does not exist" when using LOCK TABLES
@@ -177,7 +163,7 @@ func createMySQLBackup(ns string, backupDir string, kubeClientSet *kubernetes.Cl
177163
}
178164

179165
// just create Zuul DB backup
180-
commandBuffer := cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.MariaDBIdent, backupZuulCMD)
166+
commandBuffer := cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.MariaDBIdent, backupZuulCMD)
181167

182168
// write stdout to file
183169
cliutils.WriteContentToFile(mariadbBackupPath, commandBuffer.Bytes(), 0640)
@@ -192,24 +178,25 @@ func backupCmd(kmd *cobra.Command, args []string) {
192178
os.Exit(1)
193179
}
194180

195-
// prepare to make backup
196-
ns, kubeClientSet, kubeContext := prepareBackup(kmd, backupDir)
181+
cliutils.CreateDirectory(backupDir, 0755)
182+
183+
kubeContext, env := cliutils.GetCLIENV(kmd)
197184

198-
if ns == "" {
185+
if env.Ns == "" {
199186
ctrl.Log.Error(errors.New("no namespace set"), "You need to specify the namespace!")
200187
os.Exit(1)
201188
}
202189

203-
ctrl.Log.Info("Starting backup process for services in namespace: " + ns)
190+
ctrl.Log.Info("Starting backup process for services in namespace: " + env.Ns)
204191

205192
// create secret backup
206-
createSecretBackup(ns, backupDir, kubeClientSet)
193+
createSecretBackup(backupDir, env)
207194

208195
// create zuul backup
209-
createZuulKeypairBackup(ns, backupDir, kubeClientSet, kubeContext)
196+
createZuulKeypairBackup(backupDir, kubeContext, env)
210197

211198
// create DB backup
212-
createMySQLBackup(ns, backupDir, kubeClientSet, kubeContext)
199+
createMySQLBackup(backupDir, kubeContext, env)
213200

214201
}
215202

cli/cmd/restore.go

Lines changed: 29 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ package cmd
2121
*/
2222

2323
import (
24-
"context"
2524
"errors"
2625
"fmt"
2726
"os"
@@ -33,39 +32,19 @@ import (
3332
"github.com/spf13/cobra"
3433

3534
appsv1 "k8s.io/api/apps/v1"
36-
corev1 "k8s.io/api/core/v1"
35+
apiv1 "k8s.io/api/core/v1"
3736
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38-
"k8s.io/client-go/kubernetes"
3937
ctrl "sigs.k8s.io/controller-runtime"
4038
)
4139

42-
func prepareRestore(kmd *cobra.Command) (string, *kubernetes.Clientset, string) {
43-
44-
cliCtx, err := cliutils.GetCLIContext(kmd)
45-
if err != nil {
46-
ctrl.Log.Error(err, "Error initializing CLI:")
47-
os.Exit(1)
48-
}
49-
50-
kubeContext := cliCtx.KubeContext
51-
_, kubeClientSet := cliutils.GetClientset(kubeContext)
52-
return cliCtx.Namespace, kubeClientSet, kubeContext
53-
}
54-
55-
func restoreSecret(ns string, backupDir string, kubeContext string) {
40+
func restoreSecret(backupDir string, env cliutils.ENV) {
5641
ctrl.Log.Info("Restoring secrets...")
5742

58-
env := cliutils.ENV{
59-
Cli: cliutils.CreateKubernetesClientOrDie(kubeContext),
60-
Ctx: context.TODO(),
61-
Ns: ns,
62-
}
63-
6443
for _, sec := range SecretsToBackup {
6544
pathToSecret := backupDir + "/" + SecretsBackupPath + "/" + sec + ".yaml"
6645
secretContent := cliutils.ReadYAMLToMapOrDie(pathToSecret)
6746

68-
var secret corev1.Secret
47+
secret := apiv1.Secret{}
6948
if cliutils.GetMOrDie(&env, sec, &secret) {
7049
secretMap := secretContent["data"].(map[string]interface{})
7150
for key, value := range secretMap {
@@ -88,16 +67,17 @@ func restoreSecret(ns string, backupDir string, kubeContext string) {
8867

8968
}
9069

91-
func restoreDB(ns string, backupDir string, kubeClientSet *kubernetes.Clientset, kubeContext string) {
70+
func restoreDB(backupDir string, kubeContext string, env cliutils.ENV) {
9271
ctrl.Log.Info("Restoring DB...")
93-
pod := cliutils.GetPodByName(dbBackupPod, ns, kubeClientSet)
72+
pod := apiv1.Pod{}
73+
cliutils.GetMOrDie(&env, dbBackupPod, &pod)
9474

9575
kubectlPath := cliutils.GetKubectlPath()
9676
dropDBCMD := []string{
9777
"mysql",
9878
"-e DROP DATABASE zuul;",
9979
}
100-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.MariaDBIdent, dropDBCMD)
80+
cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.MariaDBIdent, dropDBCMD)
10181

10282
mariadbBackupPath := backupDir + "/" + DBBackupPath
10383

@@ -106,32 +86,22 @@ func restoreDB(ns string, backupDir string, kubeClientSet *kubernetes.Clientset,
10686
// but in that case, we need to do it via system kubernetes client.
10787
executeCommand := fmt.Sprintf(
10888
"cat %s | %s -n %s exec -it %s -c %s -- sh -c \"mysql -h0\"",
109-
mariadbBackupPath, kubectlPath, ns, pod.Name, controllers.MariaDBIdent,
89+
mariadbBackupPath, kubectlPath, env.Ns, pod.Name, controllers.MariaDBIdent,
11090
)
11191

112-
cliutils.ExecuteKubectlClient(ns, pod.Name, controllers.MariaDBIdent, executeCommand)
92+
cliutils.ExecuteKubectlClient(env.Ns, pod.Name, controllers.MariaDBIdent, executeCommand)
11393

11494
ctrl.Log.Info("Finished restoring DB from backup!")
11595
}
116-
func restoreZuul(ns string, backupDir string, kubeClientSet *kubernetes.Clientset, kubeContext string) {
96+
func restoreZuul(backupDir string, kubeContext string, env cliutils.ENV) {
11797
ctrl.Log.Info("Restoring Zuul...")
118-
pod := cliutils.GetPodByName(zuulBackupPod, ns, kubeClientSet)
98+
pod := apiv1.Pod{}
99+
cliutils.GetMOrDie(&env, zuulBackupPod, &pod)
119100

120101
// ensure that pod does not have any restore file
121-
restoreZuulRemoveCMD := []string{
122-
"rm",
123-
"-rf",
124-
"/tmp/zuul-import",
125-
}
126-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, restoreZuulRemoveCMD)
127-
128-
// create empty directory for future restore
129-
restoreZuulCreateDirCMD := []string{
130-
"mkdir",
131-
"-p",
132-
"/tmp/zuul-import",
133-
}
134-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, restoreZuulCreateDirCMD)
102+
cleanCMD := []string{
103+
"bash", "-c", "rm -rf /tmp/zuul-import && mkdir -p /tmp/zuul-import"}
104+
cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.ZuulSchedulerIdent, cleanCMD)
135105

136106
// copy the Zuul private keys backup to pod
137107
// tar cf - -C /tmp/backup/zuul zuul.keys | /usr/bin/kubectl exec -i -n sf zuul-scheduler-0 -c zuul-scheduler -- tar xf - -C /tmp
@@ -140,38 +110,26 @@ func restoreZuul(ns string, backupDir string, kubeClientSet *kubernetes.Clientse
140110
baseFile := filepath.Base(ZuulBackupPath)
141111
executeCommand := fmt.Sprintf(
142112
"tar cf - -C %s %s | %s exec -i -n %s %s -c %s -- tar xf - -C /tmp/zuul-import",
143-
basePath, baseFile, kubectlPath, ns, pod.Name, controllers.ZuulSchedulerIdent,
113+
basePath, baseFile, kubectlPath, env.Ns, pod.Name, controllers.ZuulSchedulerIdent,
144114
)
145115
ctrl.Log.Info("Executing " + executeCommand)
146116

147-
cliutils.ExecuteKubectlClient(ns, pod.Name, controllers.ZuulSchedulerIdent, executeCommand)
117+
cliutils.ExecuteKubectlClient(env.Ns, pod.Name, controllers.ZuulSchedulerIdent, executeCommand)
148118

149119
// https://zuul-ci.org/docs/zuul/latest/client.html
150-
restoreZuulCMD := []string{
151-
"zuul-admin",
152-
"import-keys",
153-
"--force",
154-
"/tmp/zuul-import/" + baseFile,
155-
}
120+
restoreCMD := []string{
121+
"bash", "-c", "zuul-admin import-keys --force /tmp/zuul-import/" + baseFile + " && " +
122+
"rm -rf /tmp/zuul-import"}
156123

157124
// Execute command for restore
158-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, restoreZuulCMD)
159-
160-
// remove after all
161-
cliutils.RunRemoteCmd(kubeContext, ns, pod.Name, controllers.ZuulSchedulerIdent, restoreZuulRemoveCMD)
125+
cliutils.RunRemoteCmd(kubeContext, env.Ns, pod.Name, controllers.ZuulSchedulerIdent, restoreCMD)
162126

163127
ctrl.Log.Info("Finished doing Zuul private keys restore!")
164128

165129
}
166130

167-
func clearComponents(ns string, kubeContext string) {
168-
ctrl.Log.Info("Removing components requiring a complete restart ...")
169-
170-
env := cliutils.ENV{
171-
Cli: cliutils.CreateKubernetesClientOrDie(kubeContext),
172-
Ctx: context.TODO(),
173-
Ns: ns,
174-
}
131+
func clearComponents(env cliutils.ENV) {
132+
ctrl.Log.Info("Removing components requirering a complete restart ...")
175133

176134
for _, stsName := range []string{"zuul-scheduler", "zuul-executor", "zuul-merger", "nodepool-builder", "zookeeper"} {
177135
cliutils.DeleteOrDie(&env, &appsv1.StatefulSet{
@@ -209,18 +167,17 @@ func restoreCmd(kmd *cobra.Command, args []string) {
209167

210168
}
211169

212-
// prepare to make restore
213-
ns, kubeClientSet, kubeContext := prepareRestore(kmd)
170+
kubeContext, env := cliutils.GetCLIENV(kmd)
214171

215-
if ns == "" {
172+
if env.Ns == "" {
216173
ctrl.Log.Info("You did not specify the namespace!")
217174
os.Exit(1)
218175
}
219176

220-
restoreZuul(ns, backupDir, kubeClientSet, kubeContext)
221-
restoreSecret(ns, backupDir, kubeContext)
222-
restoreDB(ns, backupDir, kubeClientSet, kubeContext)
223-
clearComponents(ns, kubeContext)
177+
restoreZuul(backupDir, kubeContext, env)
178+
restoreSecret(backupDir, env)
179+
restoreDB(backupDir, kubeContext, env)
180+
clearComponents(env)
224181

225182
}
226183

cli/cmd/utils/utils.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ import (
2222
"context"
2323
"errors"
2424
"fmt"
25-
"gopkg.in/yaml.v3"
2625
"io/fs"
2726
"os"
2827
"os/exec"
2928
"reflect"
3029
"strings"
3130

31+
"gopkg.in/yaml.v3"
32+
3233
apiv1 "k8s.io/api/core/v1"
3334
apierrors "k8s.io/apimachinery/pkg/api/errors"
3435

@@ -51,7 +52,6 @@ import (
5152
sfv1 "github.com/softwarefactory-project/sf-operator/api/v1"
5253
controllers "github.com/softwarefactory-project/sf-operator/controllers"
5354

54-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5555
"k8s.io/client-go/kubernetes"
5656
)
5757

@@ -196,6 +196,25 @@ func CreateKubernetesClientOrDie(contextName string) client.Client {
196196
return cli
197197
}
198198

199+
func GetCLIENV(kmd *cobra.Command) (string, ENV) {
200+
201+
cliCtx, err := GetCLIContext(kmd)
202+
if err != nil {
203+
ctrl.Log.Error(err, "Error initializing CLI:")
204+
os.Exit(1)
205+
}
206+
207+
kubeContext := cliCtx.KubeContext
208+
209+
env := ENV{
210+
Cli: CreateKubernetesClientOrDie(kubeContext),
211+
Ctx: context.TODO(),
212+
Ns: cliCtx.Namespace,
213+
}
214+
215+
return kubeContext, env
216+
}
217+
199218
func GetM(env *ENV, name string, obj client.Object) (bool, error) {
200219
err := env.Cli.Get(env.Ctx,
201220
client.ObjectKey{
@@ -420,24 +439,6 @@ func RunRemoteCmd(kubeContext string, namespace string, podName string, containe
420439
return buffer
421440
}
422441

423-
func GetPodByName(podName string, ns string, kubeClientSet *kubernetes.Clientset) *apiv1.Pod {
424-
pod, err := kubeClientSet.CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
425-
if err != nil {
426-
ctrl.Log.Error(err, "Can not get pod "+podName)
427-
os.Exit(1)
428-
}
429-
return pod
430-
}
431-
432-
func GetSecretByName(secretName string, ns string, kubeClientSet *kubernetes.Clientset) *apiv1.Secret {
433-
secret, err := kubeClientSet.CoreV1().Secrets(ns).Get(context.TODO(), secretName, metav1.GetOptions{})
434-
if err != nil {
435-
ctrl.Log.Error(err, "Can not get pod "+secretName)
436-
os.Exit(1)
437-
}
438-
return secret
439-
}
440-
441442
func ReadYAMLToMapOrDie(filePath string) map[string]interface{} {
442443
readFile, _ := GetFileContent(filePath)
443444
secretContent := make(map[string]interface{})

0 commit comments

Comments
 (0)