Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backup implementation: controller, plugins, collection, webhooks #841

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ resources:
controller: true
domain: k0rdent.mirantis.com
group: k0rdent.mirantis.com
kind: Backup
kind: ManagementBackup
path: github.com/K0rdent/kcm/api/v1alpha1
version: v1alpha1
webhooks:
validation: true
webhookVersion: v1
version: "3"
77 changes: 0 additions & 77 deletions api/v1alpha1/backup_types.go

This file was deleted.

23 changes: 23 additions & 0 deletions api/v1alpha1/indexers.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func SetupIndexers(ctx context.Context, mgr ctrl.Manager) error {
setupClusterTemplateProvidersIndexer,
setupMultiClusterServiceServicesIndexer,
setupOwnerReferenceIndexers,
setupManagementBackupScheduledIndexer,
} {
merr = errors.Join(merr, f(ctx, mgr))
}
Expand Down Expand Up @@ -237,3 +238,25 @@ func extractOwnerReferences(rawObj client.Object) []string {
}
return owners
}

// management backup indexers

// ManagementBackupScheduledIndexKey indexer field name to extract only [ManagementBackup] objects
// that meant to be scheduled.
const ManagementBackupScheduledIndexKey = "k0rdent.scheduled-backup"

func setupManagementBackupScheduledIndexer(ctx context.Context, mgr ctrl.Manager) error {
return mgr.GetFieldIndexer().IndexField(ctx, &ManagementBackup{}, ManagementBackupScheduledIndexKey, func(o client.Object) []string {
mb, ok := o.(*ManagementBackup)
if !ok {
return nil
}

v, ok := mb.Annotations[ScheduleBackupAnnotation]
if !ok {
return nil
}

return []string{v}
})
}
102 changes: 102 additions & 0 deletions api/v1alpha1/management_backup_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2024
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1alpha1

import (
"strconv"
"time"

velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
// Name to label most of the KCM-related components.
// Mostly utilized by the backup feature.
GenericComponentNameLabel = "k0rdent.mirantis.com/component"
// Component label value for the KCM-related components.
GenericComponentLabelValueKCM = "kcm"

// ScheduleBackupAnnotation is an annotation for ease the listing
// of [ManagementBackup]. Indicates that the type of the object is schedule.
ScheduleBackupAnnotation = "k0rdent.mirantis.com/schedule"
)

// ManagementBackupSpec defines the desired state of ManagementBackup
type ManagementBackupSpec struct {
// StorageLocation is the name of a [github.com/vmware-tanzu/velero/pkg/apis/velero/v1.StorageLocation]
// where the backup should be stored.
StorageLocation string `json:"storageLocation,omitempty"`
}

// ManagementBackupStatus defines the observed state of ManagementBackup
type ManagementBackupStatus struct {
// NextAttempt indicates the time when the next backup will be created.
// Always absent for a single [ManagementBackup].
NextAttempt *metav1.Time `json:"nextAttempt,omitempty"`
// Time of the most recently created [github.com/vmware-tanzu/velero/pkg/apis/velero/v1.Backup].
LastBackupTime *metav1.Time `json:"lastBackupTime,omitempty"`
// Most recently [github.com/vmware-tanzu/velero/pkg/apis/velero/v1.Backup] that has been created.
LastBackup *velerov1.BackupStatus `json:"lastBackup,omitempty"`
// Name of most recently created [github.com/vmware-tanzu/velero/pkg/apis/velero/v1.Backup].
LastBackupName string `json:"lastBackupName,omitempty"`
// Paused indicates if the schedule is currently paused.
Paused bool `json:"paused,omitempty"`
}

// IsSchedule checks if an instance of [ManagementBackup] is schedulable.
func (s *ManagementBackup) IsSchedule() bool {
if _, err := strconv.ParseBool(s.Annotations[ScheduleBackupAnnotation]); err == nil {
return true
}

return false
}

// TimestampedBackupName returns the backup name related to scheduled [ManagementBackup] based on the given timestamp.
func (s *ManagementBackup) TimestampedBackupName(timestamp time.Time) string {
return s.Name + "-" + timestamp.Format("20060102150405")
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster,shortName=kcmbackup;mgmtbackup
// +kubebuilder:printcolumn:name="LastBackupStatus",type=string,JSONPath=`.status.lastBackup.phase`,description="Status of last backup run",priority=0
// +kubebuilder:printcolumn:name="NextBackup",type=string,JSONPath=`.status.nextAttempt`,description="Next scheduled attempt to back up",priority=0
// +kubebuilder:printcolumn:name="SinceLastBackup",type=date,JSONPath=`.status.lastBackupTime`,description="Time elapsed since last backup run",priority=1
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,description="Time elapsed since object creation",priority=0
// +kubebuilder:printcolumn:name="Paused",type=boolean,JSONPath=`.status.paused`,description="Schedule is on pause",priority=1

// ManagementBackup is the Schema for the managementbackups API
type ManagementBackup struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec ManagementBackupSpec `json:"spec,omitempty"`
Status ManagementBackupStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// ManagementBackupList contains a list of ManagementBackup
type ManagementBackupList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ManagementBackup `json:"items"`
}

func init() {
SchemeBuilder.Register(&ManagementBackup{}, &ManagementBackupList{})
}
20 changes: 12 additions & 8 deletions api/v1alpha1/management_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type ManagementSpec struct {
// Providers is the list of supported CAPI providers.
Providers []Provider `json:"providers,omitempty"`

Backup ManagementBackup `json:"backup,omitempty"`
Backup Backup `json:"backup,omitempty"`
}

// Core represents a structure describing core Management components.
Expand All @@ -55,15 +55,19 @@ type Core struct {
CAPI Component `json:"capi,omitempty"`
}

// ManagementBackup enables a feature to backup KCM objects into a cloud.
type ManagementBackup struct {
// Schedule is a Cron expression defining when to run the scheduled Backup.
// Default value is to backup every 6 hours.
// Backup enables a feature to backup KCM objects into a cloud.
type Backup struct {
// Schedule is a Cron expression defining when to run the scheduled [ManagementBackup].
// Default value is to backup at minute 0 past every 6th hour (0 */6 * * *).
Schedule string `json:"schedule,omitempty"`

// Flag to indicate whether the backup feature is enabled.
// If set to true, [Velero] platform will be installed.
// If set to false, creation or modification of Backups/Restores will be blocked.
// StorageLocation is the name of a [github.com/vmware-tanzu/velero/pkg/apis/velero/v1.StorageLocation]
// where the backup should be stored. It is propagated to the corresponding scheduled [ManagementBackup]
// unless set in the object.
StorageLocation string `json:"storageLocation,omitempty"`

// Flag to indicate whether the management cluster backup feature is enabled.
// The backup is done using [Velero].
//
// [Velero]: https://velero.io
Enabled bool `json:"enabled,omitempty"`
Expand Down
7 changes: 2 additions & 5 deletions api/v1alpha1/templates_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ import (
helmcontrollerv2 "github.com/fluxcd/helm-controller/api/v2"
sourcev1 "github.com/fluxcd/source-controller/api/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
clusterapiv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
)

const (
// ChartAnnotationProviderName is the annotation set on components in a Template.
// This annotations allows to identify all the components belonging to a provider.
ChartAnnotationProviderName = "cluster.x-k8s.io/provider"

chartAnnoCAPIPrefix = "cluster.x-k8s.io/"

DefaultRepoName = "kcm-templates"
Expand Down Expand Up @@ -103,7 +100,7 @@ func getProvidersList(providers Providers, annotations map[string]string) Provid
return slices.Compact(res)
}

providersFromAnno := annotations[ChartAnnotationProviderName]
providersFromAnno := annotations[clusterapiv1beta1.ProviderNameLabel]
if len(providersFromAnno) == 0 {
return Providers{}
}
Expand Down
Loading
Loading