Skip to content

Commit

Permalink
Remove rotation function from the sub command
Browse files Browse the repository at this point in the history
The expiration is done by MB reconciler, delete the function from the
sub command. Now the command name becomes backup.

Signed-off-by: Toshikuni Fukaya <toshikuni-fukaya@cybozu.co.jp>
  • Loading branch information
toshipp committed Sep 18, 2024
1 parent af5aa29 commit 3af1d9d
Show file tree
Hide file tree
Showing 6 changed files with 9 additions and 178 deletions.
3 changes: 0 additions & 3 deletions charts/mantle/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ spec:
{{- with .Values.controller.mantleServiceEndpoint }}
- --mantle-service-endpoint={{ . }}
{{- end }}
{{- with .Values.controller.expireOffset }}
- --expire-offset={{ . }}
{{- end }}
{{- with .Values.controller.overwriteMBCSchedule }}
- --overwrite-mbc-schedule={{ . }}
{{- end }}
Expand Down
80 changes: 2 additions & 78 deletions cmd/backupandrotate/main.go → cmd/backup/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import (
"fmt"
"io"
"os"
"time"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/kube-openapi/pkg/validation/strfmt"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
Expand All @@ -29,16 +26,14 @@ import (

var (
mbcName, mbcNamespace string
expireOffset string
zapOpts zap.Options

scheme = runtime.NewScheme()
MantleBackupConfigUID = "mantle.cybozu.io/mbc-uid"
MantleRetainIfExpired = "mantle.cybozu.io/retainIfExpired"
logger = ctrl.Log.WithName("backup-and-rotate")
logger = ctrl.Log.WithName("backup")

BackupAndRotateCmd = &cobra.Command{
Use: "backup-and-rotate",
Use: "backup",
RunE: func(cmd *cobra.Command, args []string) error {
return subMain(cmd.Context())
},
Expand All @@ -49,9 +44,6 @@ func init() {
flags := BackupAndRotateCmd.Flags()
flags.StringVar(&mbcName, "name", "", "MantleBackupConfig resource's name")
flags.StringVar(&mbcNamespace, "namespace", "", "MantleBackupConfig resource's namespace")
flags.StringVar(&expireOffset, "expire-offset", "0s",
"An offset for MantleBackupConfig's .spec.expire field. A MantleBackup will expire after "+
"it has been active for (.spec.expire - expire-offset) time. This option is intended for testing purposes only.")

goflags := flag.NewFlagSet("goflags", flag.ExitOnError)
zapOpts.Development = true
Expand Down Expand Up @@ -91,11 +83,6 @@ func fetchJobID() (string, error) {
func subMain(ctx context.Context) error {
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&zapOpts)))

parsedExpireOffset, err := strfmt.ParseDuration(expireOffset)
if err != nil {
return fmt.Errorf("couldn't parse the expire offset: %w", err)
}

cli, err := client.New(config.GetConfigOrDie(), client.Options{Scheme: scheme})
if err != nil {
return fmt.Errorf("couldn't create a new client: %w", err)
Expand All @@ -111,10 +98,6 @@ func subMain(ctx context.Context) error {
return fmt.Errorf("backup failed: %s: %s: %w", mbcName, mbcNamespace, err)
}

if err := rotateMantleBackup(ctx, cli, &mbc, parsedExpireOffset); err != nil {
return fmt.Errorf("rotation failed: %s: %s: %w", mbcName, mbcNamespace, err)
}

return nil
}

Expand Down Expand Up @@ -170,62 +153,3 @@ func createMantleBackup(ctx context.Context, cli client.Client, mbc *mantlev1.Ma
"mbcName", mbcName, "mbcNamespace", mbcNamespace)
return nil
}

func rotateMantleBackup(
ctx context.Context,
cli client.Client,
mbc *mantlev1.MantleBackupConfig,
expireOffset time.Duration,
) error {
// List all MantleBackup objects associated with the mbc.
var mbList mantlev1.MantleBackupList
if err := cli.List(ctx, &mbList, &client.ListOptions{
LabelSelector: labels.SelectorFromSet(map[string]string{MantleBackupConfigUID: string(mbc.GetUID())}),
}); err != nil {
return fmt.Errorf("couldn't list MantleBackups: %s: %w", string(mbc.UID), err)
}

// Delete the MantleBackup objects that are already expired and don't have the retainIfExpired label.
expire, err := strfmt.ParseDuration(mbc.Spec.Expire)
if err != nil {
return fmt.Errorf("couldn't parse spec.expire: %s: %w", mbc.Spec.Expire, err)
}
if expire >= expireOffset {
expire -= expireOffset
} else {
expire = 0
}
for _, mb := range mbList.Items {
if mb.Status.CreatedAt == (metav1.Time{}) {
// mb is not created yet (at least from the cache's perspective), so let's ignore it.
continue
}
elapsed := time.Since(mb.Status.CreatedAt.Time)
if elapsed <= expire {
continue
}
retain, ok := mb.GetAnnotations()[MantleRetainIfExpired]
if ok && retain == "true" {
continue
}

if err := cli.Delete(ctx, &mb, &client.DeleteOptions{
Preconditions: &metav1.Preconditions{
UID: &mb.UID,
ResourceVersion: &mb.ResourceVersion,
},
}); err == nil || errors.IsNotFound(err) {
logger.Info("MantleBackup deleted",
"mb.Name", mb.Name, "mb.Namespace", mb.Namespace,
"mb.UID", mb.UID, "mb.ResourceVersion", mb.ResourceVersion,
"mbcName", mbcName, "mbcNamespace", mbcNamespace,
"elapsed", elapsed, "expire", expire,
)
} else {
return fmt.Errorf("couldn't delete MantleBackup: %s: %s: %s: %s: %w",
mb.Name, mb.Namespace, mb.UID, mb.ResourceVersion, err)
}
}

return nil
}
5 changes: 0 additions & 5 deletions cmd/controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ var (
enableLeaderElection bool
probeAddr string
zapOpts zap.Options
expireOffset string
overwriteMBCSchedule string
role string
mantleServiceEndpoint string
Expand All @@ -62,9 +61,6 @@ func init() {
flags.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flags.StringVar(&expireOffset, "expire-offset", "",
"An offset for MantleBackupConfig's .spec.expire field. A MantleBackup will expire after "+
"it has been active for (.spec.expire - expire-offset) time. This option is intended for testing purposes only.")
flags.StringVar(&overwriteMBCSchedule, "overwrite-mbc-schedule", "",
"By setting this option, every CronJob created by this controller for every MantleBackupConfig "+
"will use its value as .spec.schedule. This option is intended for testing purposes only.")
Expand Down Expand Up @@ -141,7 +137,6 @@ func setupReconcilers(mgr manager.Manager, primarySettings *controller.PrimarySe
mgr.GetClient(),
mgr.GetScheme(),
managedCephClusterID,
expireOffset,
overwriteMBCSchedule,
role,
).SetupWithManager(mgr); err != nil {
Expand Down
9 changes: 3 additions & 6 deletions internal/controller/mantlebackupconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ type MantleBackupConfigReconciler struct {
Client client.Client
Scheme *runtime.Scheme
managedCephClusterID string
expireOffset string
overwriteMBCSchedule string
role string
}
Expand All @@ -42,11 +41,10 @@ func NewMantleBackupConfigReconciler(
cli client.Client,
scheme *runtime.Scheme,
managedCephClusterID string,
expireOffset string,
overwriteMBCSchedule string,
role string,
) *MantleBackupConfigReconciler {
return &MantleBackupConfigReconciler{cli, scheme, managedCephClusterID, expireOffset, overwriteMBCSchedule, role}
return &MantleBackupConfigReconciler{cli, scheme, managedCephClusterID, overwriteMBCSchedule, role}
}

//+kubebuilder:rbac:groups=mantle.cybozu.io,resources=mantlebackupconfigs,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -226,14 +224,13 @@ func (r *MantleBackupConfigReconciler) createOrUpdateCronJob(ctx context.Context
podSpec.Containers = append(podSpec.Containers, corev1.Container{})
}
container := &podSpec.Containers[0]
container.Name = "backup-and-rotate"
container.Name = "backup"
container.Image = image
container.Command = []string{
"/manager",
"backup-and-rotate",
"backup",
"--name", mbc.GetName(),
"--namespace", mbc.GetNamespace(),
"--expire-offset", r.expireOffset,
}
container.ImagePullPolicy = corev1.PullIfNotPresent
container.Env = []corev1.EnvVar{
Expand Down
89 changes: 4 additions & 85 deletions test/e2e/singlek8s/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func (test *backupTest) testCase1() {
}

func (test *backupTest) testCase2() {
It("should create and rotate MantleBackups from MantleBackupConfig", func() {
It("should create MantleBackups from MantleBackupConfig", func() {
By("Creating MantleBackupConfig")
err := applyMantleBackupConfigTemplate(test.tenantNamespace, test.pvcName1, test.mantleBackupConfigName[2])
Expect(err).NotTo(HaveOccurred())
Expand All @@ -251,34 +251,19 @@ func (test *backupTest) testCase2() {
}).Should(Succeed())

// Because of the e2e's values-mantle.yaml, the CronJob's .spec.schedule
// is overwritten with "* * * * *", so backup-and-rotate subcommand
// should be triggered every minute. And every MantleBackup created at minute N will be deleted at minute (N+1),
// because of `expire-offset` setting in the e2e's values-mantle.yaml.
// is overwritten with "* * * * *", so backup subcommand
// should be triggered every minute.
By("Waiting for a MantleBackup to be created")
var mb mantlev1.MantleBackup
Eventually(func() error {
mbs, err := listMantleBackupsByMBCUID(test.tenantNamespace, string(mbc.UID))
if err != nil {
return err
}
if len(mbs) == 1 {
mb = mbs[0]
if len(mbs) > 0 {
return nil
}
return errors.New("MantleBackup not found")
}).Should(Succeed())

By("Waiting for MantleBackups to be rotated")
Eventually(func() error {
mbs, err := listMantleBackupsByMBCUID(test.tenantNamespace, string(mbc.UID))
if err != nil {
return err
}
if len(mbs) == 1 && mbs[0].Name != mb.Name {
return nil
}
return errors.New("MantleBackup not rotated")
}).Should(Succeed())
})

It("should not delete the MantleBackups even when the MantleBackupConfig is deleted", func() {
Expand Down Expand Up @@ -314,72 +299,6 @@ func (test *backupTest) testCase2() {
}, "5s", "1s").Should(Succeed())
})

It("should not delete a MantleBackup if it has an annotation of retainIfExpired", func() {
By("Creating MantleBackupConfig")
err := applyMantleBackupConfigTemplate(test.tenantNamespace, test.pvcName1, test.mantleBackupConfigName[1])
Expect(err).NotTo(HaveOccurred())

By("Waiting for a CronJob to be created")
mbc, err := getMBC(test.tenantNamespace, test.mantleBackupConfigName[1])
Expect(err).NotTo(HaveOccurred())
cronJobName := "mbc-" + string(mbc.UID)
Eventually(func() error {
_, err := getCronJob(cephCluster1Namespace, cronJobName)
return err
}).Should(Succeed())

By("Attaching an annotation of retainIfExpired to a MantleBackup")
var mb mantlev1.MantleBackup
Eventually(func() error {
mbs, err := listMantleBackupsByMBCUID(test.tenantNamespace, string(mbc.UID))
if err != nil {
return err
}
if len(mbs) == 0 {
return errors.New("no MantleBackup available")
}
mb = mbs[0]

_, _, err = kubectl("patch", "mantlebackup", "-n", mb.Namespace, mb.Name, "--type=json",
"-p", "[{\"op\":\"add\",\"path\":\"/metadata/annotations\","+
"\"value\":{\"mantle.cybozu.io/retainIfExpired\":\"true\"}}]")
return err
}, "120s", "1s").Should(Succeed())

By("Checking mb is NOT deleted thanks to retainIfExpired annotation")
Consistently(func() error {
_, _, err := kubectl("get", "mantlebackup", "-n", mb.Namespace, mb.Name)
return err
}, "70s", "10s").Should(Succeed())

By("Checking mbs not annotated with retainIfExpired are rotated")
Eventually(func() error {
mbs, err := listMantleBackupsByMBCUID(test.tenantNamespace, string(mbc.UID))
if err != nil {
return err
}

for _, mb1 := range mbs {
value, ok := mb1.Annotations["mantle.cybozu.io/retainIfExpired"]
if !ok || value != "true" {
mb = mb1
return nil
}
}
return errors.New("no MantleBackup available")
}).Should(Succeed())
Eventually(func() error {
_, stderr, err := kubectl("get", "mantlebackup", "-n", mb.Namespace, mb.Name)
if err != nil {
if strings.Contains(string(stderr), "NotFound") {
return nil
}
return err
}
return errors.New("still exists")
}).Should(Succeed())
})

It("should re-create a CronJob associated with a MantleBackup when it's deleted by someone", func() {
By("Creating MantleBackupConfig")
err := applyMantleBackupConfigTemplate(test.tenantNamespace, test.pvcName1, test.mantleBackupConfigName[3])
Expand Down
1 change: 0 additions & 1 deletion test/e2e/testdata/values-mantle1.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
controller:
expireOffset: 1w6d23h59m50s # 2w - 10s
overwriteMBCSchedule: "* * * * *"

0 comments on commit 3af1d9d

Please sign in to comment.