Skip to content

Commit 171acda

Browse files
authored
Merge pull request #484 from acekingke/BackupStatus
*: Add backup Name into Backup status
2 parents 8538f05 + 2f98bfc commit 171acda

File tree

10 files changed

+173
-29
lines changed

10 files changed

+173
-29
lines changed

api/v1alpha1/backup_types.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ import (
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
)
2323

24-
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
25-
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
26-
24+
// This is the backup Job CRD.
2725
// BackupSpec defines the desired state of Backup
2826
type BackupSpec struct {
2927
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
@@ -59,14 +57,21 @@ type BackupStatus struct {
5957
// Completed indicates whether the backup is in a final state,
6058
// no matter whether its' corresponding job failed or succeeded
6159
Completed bool `json:"completed,omitempty"`
62-
60+
// Get the backup path.
61+
BackupName string `json:"backupName,omitempty"`
62+
// Get the backup Date
63+
BackupDate string `json:"backupDate,omitempty"`
64+
// Get the backup Type
65+
BackupType string `json:"backupType,omitempty"`
6366
// Conditions represents the backup resource conditions list.
6467
Conditions []BackupCondition `json:"conditions,omitempty"`
6568
}
6669

67-
//+kubebuilder:object:root=true
68-
//+kubebuilder:subresource:status
69-
70+
// +kubebuilder:object:root=true
71+
// +kubebuilder:subresource:status
72+
// +kubebuilder:printcolumn:name="BackupName",type="string",JSONPath=".status.backupName",description="The Backup name"
73+
// +kubebuilder:printcolumn:name="BackupDate",type="string",JSONPath=".status.backupDate",description="The Backup Date time"
74+
// +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".status.backupType",description="The Backup Type"
7075
// Backup is the Schema for the backups API
7176
type Backup struct {
7277
metav1.TypeMeta `json:",inline"`

backup/syncer/job.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ type jobSyncer struct {
3737
backup *backup.Backup
3838
}
3939

40+
// Owner returns the object owner or nil if object does not have one.
41+
func (s *jobSyncer) ObjectOwner() runtime.Object { return s.backup.Unwrap() }
42+
4043
// NewJobSyncer returns a syncer for backup jobs
4144
func NewJobSyncer(c client.Client, s *runtime.Scheme, backup *backup.Backup) syncer.Interface {
4245
obj := &batchv1.Job{
@@ -83,6 +86,15 @@ func (s *jobSyncer) updateStatus(job *batchv1.Job) {
8386
if cond.Status == corev1.ConditionTrue {
8487
s.backup.Status.Completed = true
8588
}
89+
if backupName := s.job.Annotations[utils.JobAnonationName]; backupName != "" {
90+
s.backup.Status.BackupName = backupName
91+
}
92+
if backDate := s.job.Annotations[utils.JobAnonationDate]; backDate != "" {
93+
s.backup.Status.BackupDate = backDate
94+
}
95+
if backType := s.job.Annotations[utils.JobAnonationType]; backType != "" {
96+
s.backup.Status.BackupType = backType
97+
}
8698
}
8799

88100
// check for failed condition
@@ -92,6 +104,7 @@ func (s *jobSyncer) updateStatus(job *batchv1.Job) {
92104
s.backup.Status.Completed = true
93105
}
94106
}
107+
95108
}
96109

97110
func jobCondition(condType batchv1.JobConditionType, job *batchv1.Job) *batchv1.JobCondition {
@@ -113,7 +126,7 @@ func (s *jobSyncer) ensurePodSpec(in corev1.PodSpec) corev1.PodSpec {
113126
sctName := fmt.Sprintf("%s-secret", s.backup.Spec.ClusterName)
114127
in.Containers[0].Name = utils.ContainerBackupName
115128
in.Containers[0].Image = fmt.Sprintf("%s%s", mysqlcluster.GetPrefixFromEnv(), s.backup.Spec.Image)
116-
129+
in.ServiceAccountName = s.backup.Spec.ClusterName
117130
if len(s.backup.Spec.NFSServerAddress) != 0 {
118131
// add volumn about pvc
119132
in.Volumes = []corev1.Volume{
@@ -131,10 +144,15 @@ func (s *jobSyncer) ensurePodSpec(in corev1.PodSpec) corev1.PodSpec {
131144
in.Containers[0].Command = []string{
132145
"/bin/bash", "-c", "--",
133146
}
134-
var backupToDir string = utils.BuildBackupName(s.backup.Spec.ClusterName)
147+
backupToDir, DateTime := utils.BuildBackupName(s.backup.Spec.ClusterName)
148+
strAnnonations := fmt.Sprintf(`curl -X PATCH -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" -H "Content-Type: application/json-patch+json" \
149+
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_PORT_443_TCP_PORT/apis/batch/v1/namespaces/%s/jobs/%s \
150+
-d '[{"op": "add", "path": "/metadata/annotations/backupName", "value": "%s"}, {"op": "add", "path": "/metadata/annotations/backupDate", "value": "%s"}, {"op": "add", "path": "/metadata/annotations/backupType", "value": "NFS"}]';`,
151+
s.backup.Namespace, s.backup.GetNameForJob(), backupToDir, DateTime)
135152
in.Containers[0].Args = []string{
136153
fmt.Sprintf("mkdir -p /backup/%s;"+
137-
"curl --user $BACKUP_USER:$BACKUP_PASSWORD %s/download|xbstream -x -C /backup/%s; exit ${PIPESTATUS[0]}",
154+
"curl --user $BACKUP_USER:$BACKUP_PASSWORD %s/download|xbstream -x -C /backup/%s;"+
155+
strAnnonations+"exit ${PIPESTATUS[0]}",
138156
backupToDir,
139157
s.backup.GetBackupURL(s.backup.Spec.ClusterName, s.backup.Spec.HostName), backupToDir),
140158
}
@@ -200,6 +218,11 @@ func (s *jobSyncer) ensurePodSpec(in corev1.PodSpec) corev1.PodSpec {
200218
},
201219
},
202220
},
221+
// Cluster Name for set Anotations.
222+
{
223+
Name: "JOB_NAME",
224+
Value: s.job.Name,
225+
},
203226
}
204227
return in
205228
}

charts/mysql-operator/crds/mysql.radondb.com_backups.yaml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,20 @@ spec:
1616
singular: backup
1717
scope: Namespaced
1818
versions:
19-
- name: v1alpha1
19+
- additionalPrinterColumns:
20+
- description: The Backup name
21+
jsonPath: .status.backupName
22+
name: BackupName
23+
type: string
24+
- description: The Backup Date time
25+
jsonPath: .status.backupDate
26+
name: BackupDate
27+
type: string
28+
- description: The Backup Type
29+
jsonPath: .status.backupType
30+
name: Type
31+
type: string
32+
name: v1alpha1
2033
schema:
2134
openAPIV3Schema:
2235
description: Backup is the Schema for the backups API
@@ -34,7 +47,8 @@ spec:
3447
metadata:
3548
type: object
3649
spec:
37-
description: BackupSpec defines the desired state of Backup
50+
description: This is the backup Job CRD. BackupSpec defines the desired
51+
state of Backup
3852
properties:
3953
clusterName:
4054
description: ClusterName represents the cluster name to backup
@@ -61,6 +75,15 @@ spec:
6175
status:
6276
description: BackupStatus defines the observed state of Backup
6377
properties:
78+
backupDate:
79+
description: Get the backup Date
80+
type: string
81+
backupName:
82+
description: Get the backup path.
83+
type: string
84+
backupType:
85+
description: Get the backup Type
86+
type: string
6487
completed:
6588
description: Completed indicates whether the backup is in a final
6689
state, no matter whether its' corresponding job failed or succeeded

config/crd/bases/mysql.radondb.com_backups.yaml

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,20 @@ spec:
1616
singular: backup
1717
scope: Namespaced
1818
versions:
19-
- name: v1alpha1
19+
- additionalPrinterColumns:
20+
- description: The Backup name
21+
jsonPath: .status.backupName
22+
name: BackupName
23+
type: string
24+
- description: The Backup Date time
25+
jsonPath: .status.backupDate
26+
name: BackupDate
27+
type: string
28+
- description: The Backup Type
29+
jsonPath: .status.backupType
30+
name: Type
31+
type: string
32+
name: v1alpha1
2033
schema:
2134
openAPIV3Schema:
2235
description: Backup is the Schema for the backups API
@@ -34,7 +47,8 @@ spec:
3447
metadata:
3548
type: object
3649
spec:
37-
description: BackupSpec defines the desired state of Backup
50+
description: This is the backup Job CRD. BackupSpec defines the desired
51+
state of Backup
3852
properties:
3953
clusterName:
4054
description: ClusterName represents the cluster name to backup
@@ -61,6 +75,15 @@ spec:
6175
status:
6276
description: BackupStatus defines the observed state of Backup
6377
properties:
78+
backupDate:
79+
description: Get the backup Date
80+
type: string
81+
backupName:
82+
description: Get the backup path.
83+
type: string
84+
backupType:
85+
description: Get the backup Type
86+
type: string
6487
completed:
6588
description: Completed indicates whether the backup is in a final
6689
state, no matter whether its' corresponding job failed or succeeded

mysqlcluster/syncer/role.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ func NewRoleSyncer(cli client.Client, c *mysqlcluster.MysqlCluster) syncer.Inter
4646
APIGroups: []string{""},
4747
Resources: []string{"pods"},
4848
},
49+
{
50+
Verbs: []string{"get", "update", "patch"},
51+
APIGroups: []string{"batch"},
52+
Resources: []string{"jobs"},
53+
},
4954
}
5055
return nil
5156
})

sidecar/config.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ type Config struct {
8585
// for mysql backup
8686
// backup user and password for http endpoint
8787
ClusterName string
88-
88+
// Job name if is backup Job
89+
JobName string
8990
// Backup user name to http Server
9091
BackupUser string
9192

@@ -232,6 +233,7 @@ func NewReqBackupConfig() *Config {
232233

233234
BackupUser: getEnvValue("BACKUP_USER"),
234235
BackupPassword: getEnvValue("BACKUP_PASSWORD"),
236+
JobName: getEnvValue("JOB_NAME"),
235237
}
236238
}
237239

@@ -261,7 +263,7 @@ func (cfg *Config) XtrabackupArgs() []string {
261263
}
262264

263265
// Build xbcloud arguments
264-
func (cfg *Config) XCloudArgs() []string {
266+
func (cfg *Config) XCloudArgs(backupName string) []string {
265267
xcloudArgs := []string{
266268
"put",
267269
"--storage=S3",
@@ -270,12 +272,17 @@ func (cfg *Config) XCloudArgs() []string {
270272
fmt.Sprintf("--s3-secret-key=%s", cfg.XCloudS3SecretKey),
271273
fmt.Sprintf("--s3-bucket=%s", cfg.XCloudS3Bucket),
272274
"--parallel=10",
273-
utils.BuildBackupName(cfg.ClusterName),
275+
// utils.BuildBackupName(cfg.ClusterName),
276+
backupName,
274277
"--insecure",
275278
}
276279
return xcloudArgs
277280
}
278281

282+
func (cfg *Config) XBackupName() (string, string) {
283+
return utils.BuildBackupName(cfg.ClusterName)
284+
}
285+
279286
// buildExtraConfig build a ini file for mysql.
280287
func (cfg *Config) buildExtraConfig(filePath string) (*ini.File, error) {
281288
conf := ini.Empty()

sidecar/server.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package sidecar
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"fmt"
2223
"io"
2324
"net"
@@ -27,6 +28,10 @@ import (
2728
"strings"
2829
"time"
2930

31+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32+
"k8s.io/client-go/kubernetes"
33+
"k8s.io/client-go/rest"
34+
3035
"github.com/radondb/radondb-mysql-kubernetes/utils"
3136
)
3237

@@ -93,15 +98,17 @@ func (s *server) healthHandler(w http.ResponseWriter, r *http.Request) {
9398

9499
func (s *server) backupHandler(w http.ResponseWriter, r *http.Request) {
95100
w.Header().Set("Connection", "keep-alive")
101+
w.Header().Set("content-type", "text/json")
96102
if !s.isAuthenticated(r) {
97103
http.Error(w, "Not authenticated!", http.StatusForbidden)
98104
return
99105
}
100-
err := RunTakeBackupCommand(s.cfg)
106+
backName, Datetime, err := RunTakeBackupCommand(s.cfg)
101107
if err != nil {
102108
http.Error(w, err.Error(), http.StatusInternalServerError)
103109
} else {
104-
w.Write([]byte("OK"))
110+
msg, _ := json.Marshal(utils.JsonResult{Status: backupSuccessful, BackupName: backName, Date: Datetime})
111+
w.Write(msg)
105112
}
106113
}
107114

@@ -204,6 +211,34 @@ func transportWithTimeout(connectTimeout time.Duration) http.RoundTripper {
204211
}
205212
}
206213

214+
func setAnnonations(cfg *Config, backname string, DateTime string, BackupType string) error {
215+
config, err := rest.InClusterConfig()
216+
if err != nil {
217+
return err
218+
}
219+
// creates the clientset
220+
clientset, err := kubernetes.NewForConfig(config)
221+
if err != nil {
222+
return err
223+
}
224+
225+
job, err := clientset.BatchV1().Jobs(cfg.NameSpace).Get(context.TODO(), cfg.JobName, metav1.GetOptions{})
226+
if err != nil {
227+
return err
228+
}
229+
if job.Annotations == nil {
230+
job.Annotations = make(map[string]string)
231+
}
232+
job.Annotations[utils.JobAnonationName] = backname
233+
job.Annotations[utils.JobAnonationDate] = DateTime
234+
job.Annotations[utils.JobAnonationType] = BackupType
235+
_, err = clientset.BatchV1().Jobs(cfg.NameSpace).Update(context.TODO(), job, metav1.UpdateOptions{})
236+
if err != nil {
237+
return err
238+
}
239+
return nil
240+
}
241+
207242
// requestABackup connects to specified host and endpoint and gets the backup.
208243
func requestABackup(cfg *Config, host string, endpoint string) (*http.Response, error) {
209244
log.Info("initialize a backup", "host", host, "endpoint", endpoint)
@@ -227,6 +262,13 @@ func requestABackup(cfg *Config, host string, endpoint string) (*http.Response,
227262
}
228263
return nil, fmt.Errorf("fail to get backup: %s, code: %s", err, status)
229264
}
265+
defer resp.Body.Close()
266+
var result utils.JsonResult
267+
json.NewDecoder(resp.Body).Decode(&result)
230268

269+
err = setAnnonations(cfg, result.BackupName, result.Date, "S3") // set annotation
270+
if err != nil {
271+
return nil, fmt.Errorf("fail to set annotation: %s", err)
272+
}
231273
return resp, nil
232274
}

sidecar/takebackup.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,28 @@ import (
2323
)
2424

2525
// RunTakeBackupCommand starts a backup command
26-
func RunTakeBackupCommand(cfg *Config) error {
26+
func RunTakeBackupCommand(cfg *Config) (string, string, error) {
2727
// cfg->XtrabackupArgs()
2828
xtrabackup := exec.Command(xtrabackupCommand, cfg.XtrabackupArgs()...)
2929

3030
var err error
31-
xcloud := exec.Command(xcloudCommand, cfg.XCloudArgs()...)
32-
log.Info("xargs ", "xargs", strings.Join(cfg.XCloudArgs(), " "))
31+
backupName, DateTime := cfg.XBackupName()
32+
xcloud := exec.Command(xcloudCommand, cfg.XCloudArgs(backupName)...)
33+
log.Info("xargs ", "xargs", strings.Join(cfg.XCloudArgs(backupName), " "))
3334
if xcloud.Stdin, err = xtrabackup.StdoutPipe(); err != nil {
3435
log.Error(err, "failed to pipline")
35-
return err
36+
return "", "", err
3637
}
3738
xtrabackup.Stderr = os.Stderr
3839
xcloud.Stderr = os.Stderr
3940

4041
if err := xtrabackup.Start(); err != nil {
4142
log.Error(err, "failed to start xtrabackup command")
42-
return err
43+
return "", "", err
4344
}
4445
if err := xcloud.Start(); err != nil {
4546
log.Error(err, "fail start xcloud ")
46-
return err
47+
return "", "", err
4748
}
4849

4950
// pipe command fail one, whole things fail
@@ -57,8 +58,8 @@ func RunTakeBackupCommand(cfg *Config) error {
5758

5859
for i := 0; i < 2; i++ {
5960
if err = <-errorChannel; err != nil {
60-
return err
61+
return "", "", err
6162
}
6263
}
63-
return nil
64+
return backupName, DateTime, nil
6465
}

0 commit comments

Comments
 (0)