Skip to content

Commit

Permalink
Backup implementation part 2
Browse files Browse the repository at this point in the history
* rename Backup to ManagementBackup
* reconcile scheduled backups
  (collect statuses, create schedules, etc.)
* reconcile backups
  (collect statuses, create velero backups)
* collect the required velero backup
  spec for the whole backup
* TODO: label Credential references in order
  include them in backup
* backup validation webhook
* backup controller watches velero resources
* amend backup controller logic
  to better handle scheduled and
  non-scheduled backups
* set velero maintained plugins settings
* add custom plugins set via mgmt spec
* reconcile all the velero plugins either
  during the installation or depending
  on existing BSL objects exist in a cluster
  • Loading branch information
zerospiel committed Dec 30, 2024
1 parent e641b08 commit 1f36449
Show file tree
Hide file tree
Showing 30 changed files with 1,447 additions and 580 deletions.
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: hmc.mirantis.com
group: hmc.mirantis.com
kind: Backup
kind: ManagementBackup
path: github.com/Mirantis/hmc/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.

99 changes: 99 additions & 0 deletions api/v1alpha1/management_backup_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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 (
velerov1 "github.com/zerospiel/velero/pkg/apis/velero/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
// Name to label most of the HMC-related components.
// Mostly utilized by the backup feature.
GenericComponentLabelName = "hmc.mirantis.com/component"
// Component label value for the HMC-related components.
GenericComponentLabelValueHMC = "hmc"
)

// ManagementBackupSpec defines the desired state of ManagementBackup
type ManagementBackupSpec struct {
// Oneshot indicates whether the ManagementBackup should not be scheduled
// and rather created immediately and only once.
Oneshot bool `json:"oneshot,omitempty"`
}

// ManagementBackupStatus defines the observed state of ManagementBackup
type ManagementBackupStatus struct {
// Reference to the underlying Velero object being managed.
// Might be either Velero Backup or Schedule.
Reference *corev1.ObjectReference `json:"reference,omitempty"`
// NextAttempt indicates the time when the next scheduled backup will be performed.
// Always absent for the ManagementBackups with the .spec.oneshot set to true.
NextAttempt *metav1.Time `json:"nextAttempt,omitempty"`
// Last Velero Backup that has been created.
LastBackup *velerov1.BackupStatus `json:"lastBackup,omitempty"`
// Status of the Velero Schedule for the Management scheduled backups.
// Always absent for the ManagementBackups with the .spec.oneshot set to true.
Schedule *velerov1.ScheduleStatus `json:"schedule,omitempty"`
// SchedulePaused indicates if the Velero Schedule is paused.
SchedulePaused bool `json:"schedulePaused,omitempty"`
}

func (in *ManagementBackupStatus) GetLastBackupCopy() velerov1.BackupStatus {
if in.LastBackup == nil {
return velerov1.BackupStatus{}
}
return *in.LastBackup
}

func (in *ManagementBackupStatus) GetScheduleCopy() velerov1.ScheduleStatus {
if in.Schedule == nil {
return velerov1.ScheduleStatus{}
}
return *in.Schedule
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster,shortName=hmcbackup;mgmtbackup
// +kubebuilder:printcolumn:name="NextBackup",type=string,JSONPath=`.status.nextAttempt`,description="Next scheduled attempt to back up",priority=0
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.schedule.phase`,description="Schedule phase",priority=0
// +kubebuilder:printcolumn:name="SinceLastBackup",type=date,JSONPath=`.status.schedule.lastBackup`,description="Time elapsed since last backup run",priority=1
// +kubebuilder:printcolumn:name="LastBackupStatus",type=string,JSONPath=`.status.lastBackup.phase`,description="Status of last backup run",priority=0
// +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.schedulePaused`,description="Schedule is on pause",priority=1

// ManagementBackup is the Schema for the backups 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{})
}
33 changes: 28 additions & 5 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,29 @@ type Core struct {
CAPI Component `json:"capi,omitempty"`
}

// ManagementBackup enables a feature to backup HMC objects into a cloud.
type ManagementBackup struct {
// Schedule is a Cron expression defining when to run the scheduled Backup.
// Backup enables a feature to backup HMC objects into a cloud.
type Backup struct {
// +kubebuilder:example={customPlugins: {"alibabacloud": "registry.<region>.aliyuncs.com/acs/velero:1.4.2", "community.openstack.org/openstack": "lirt/velero-plugin-for-openstack:v0.6.0"}}

// CustomPlugins holds key value pairs with [Velero] [community] and [custom] plugins, where:
// - key represents the provider's name in the format [velero.io/]<plugin-name>;
// - value represents the provider's plugin name;
//
// Provider name must be exactly the same as in a [BackupStorageLocation] object.
//
// [Velero]: https://velero.io
// [community] and third-party plugins]: https://velero.io/docs/v1.15/supported-providers/#provider-plugins-maintained-by-the-velero-community
// [custom]: https://velero.io/docs/v1.15/custom-plugins/
// [BackupStorageLocation]: https://velero.io/docs/v1.15/api-types/backupstoragelocation/
CustomPlugins map[string]string `json:"customPlugins,omitempty"`

// Schedule is a Cron expression defining when to run the scheduled ManagementBackup.
// Default value is to backup every 6 hours.
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.
// If set to false, creation or modification of ManagementBackups will be blocked.
//
// [Velero]: https://velero.io
Enabled bool `json:"enabled,omitempty"`
Expand Down Expand Up @@ -123,6 +137,15 @@ func (in *Management) Templates() []string {
return templates
}

// GetBackupSchedule safely returns backup schedule.
func (in *Management) GetBackupSchedule() string {
if in == nil {
return ""
}

return in.Spec.Backup.Schedule
}

// ManagementStatus defines the observed state of Management
type ManagementStatus struct {
// For each CAPI provider name holds its compatibility [contract versions]
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 = "hmc-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

0 comments on commit 1f36449

Please sign in to comment.