Skip to content

Commit

Permalink
Introduce Backup API
Browse files Browse the repository at this point in the history
* Backup API for disaster recovery
  (kubebuilder project, ctrl and tests
  stubs, main ctrl add)
* edit/reader roles for the Backup API

Closes #604
  • Loading branch information
zerospiel committed Dec 10, 2024
1 parent 4822e0f commit 5996e1f
Show file tree
Hide file tree
Showing 13 changed files with 721 additions and 2 deletions.
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,13 @@ resources:
kind: MultiClusterService
path: github.com/Mirantis/hmc/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: hmc.mirantis.com
group: hmc.mirantis.com
kind: Backup
path: github.com/Mirantis/hmc/api/v1alpha1
version: v1alpha1
version: "3"
79 changes: 79 additions & 0 deletions api/v1alpha1/backup_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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/vmware-tanzu/velero/pkg/apis/velero/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// BackupSpec defines the desired state of Backup
type BackupSpec struct {
// +kubebuilder:default="0 */6 * * *"

// Schedule is a Cron expression defining when to run the Backup.
// A shortcut instead of filling the .customSchedule field up.
// Default value is to backup every 6 hours.
// If both this field and the .customSchedule field
// are given, the schedule from the latter will be utilized.
Schedule string `json:"schedule"`

// Oneshot indicates whether the Backup should not be scheduled
// and rather created immediately and only once.
// If set to true, the .schedule field is ignored.
// If set to true and the .customSchedule field is given,
// the .spec.template from the latter will be utilized,
// the HMC-required options still might override or precede the options
// from the field.
Oneshot bool `json:"oneshot,omitempty"`
}

// BackupStatus defines the observed state of Backup
type BackupStatus struct {
// Reference to the underlying Velero object being managed.
// Might be either Velero Backup or Schedule.
Reference *corev1.ObjectReference `json:"reference,omitempty"`
// Status of the Velero Schedule if .spec.oneshot is set to false.
Schedule *velerov1.ScheduleStatus `json:"schedule,omitempty"`
// Last Velero Backup that has been created.
LastBackup *velerov1.BackupStatus `json:"lastBackup,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster

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

Spec BackupSpec `json:"spec,omitempty"`
Status BackupStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

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

func init() {
SchemeBuilder.Register(&Backup{}, &BackupList{})
}
17 changes: 17 additions & 0 deletions api/v1alpha1/management_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
type ManagementSpec struct {
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253

// Release references the Release object.
Release string `json:"release"`
// Core holds the core Management components that are mandatory.
Expand All @@ -42,6 +43,8 @@ type ManagementSpec struct {

// Providers is the list of supported CAPI providers.
Providers []Provider `json:"providers,omitempty"`

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

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

// ManagementBackup enables a feature to backup HMC objects into a cloud.
type ManagementBackup struct {
// +kubebuilder:default=false

// 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.
//
// [Velero]: https://velero.io
Enabled bool `json:"enabled"`
}

// Component represents HMC management component
type Component struct {
// Config allows to provide parameters for management component customization.
Expand Down Expand Up @@ -116,6 +131,8 @@ type ManagementStatus struct {
CAPIContracts map[string]CompatibilityContracts `json:"capiContracts,omitempty"`
// Components indicates the status of installed HMC components and CAPI providers.
Components map[string]ComponentStatus `json:"components,omitempty"`
// BackupName is a name of the management cluster scheduled backup.
BackupName string `json:"backupName,omitempty"`
// Release indicates the current Release object.
Release string `json:"release,omitempty"`
// AvailableProviders holds all available CAPI providers.
Expand Down
121 changes: 121 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,13 @@ func main() {
setupLog.Error(err, "unable to create controller", "controller", "MultiClusterService")
os.Exit(1)
}
if err = (&controller.BackupReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "Backup")
os.Exit(1)
}
// +kubebuilder:scaffold:builder

if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/Mirantis/hmc

go 1.22.7
go 1.22.10

require (
github.com/Masterminds/semver/v3 v3.3.1
Expand All @@ -19,6 +19,7 @@ require (
github.com/projectsveltos/libsveltos v0.44.0
github.com/segmentio/analytics-go v3.1.0+incompatible
github.com/stretchr/testify v1.10.0
github.com/vmware-tanzu/velero v1.15.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.16.3
k8s.io/api v0.31.3
Expand Down
4 changes: 3 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/vmware-tanzu/velero v1.15.0 h1:+S/lNSDwQqlROGWfmNuZnnabopGmco978COIt3AP09c=
github.com/vmware-tanzu/velero v1.15.0/go.mod h1:28VhzPJRBo91GBRkgs4Ird0fx2vCpepBWmhF+5Pn/WQ=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
Expand Down Expand Up @@ -618,7 +620,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3 h1:1hfbdAfFbkmpg41000wDVqr7jUpK/Yo+LPnIxxGzmkg=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA=
google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM=
Expand Down
60 changes: 60 additions & 0 deletions internal/controller/backup_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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 controller

import (
"context"

"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

hmcmirantiscomv1alpha1 "github.com/Mirantis/hmc/api/v1alpha1"
)

// BackupReconciler reconciles a Backup object
type BackupReconciler struct {
client.Client
Scheme *runtime.Scheme
}

// +kubebuilder:rbac:groups=hmc.mirantis.com.hmc.mirantis.com,resources=Backups,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=hmc.mirantis.com.hmc.mirantis.com,resources=Backups/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=hmc.mirantis.com.hmc.mirantis.com,resources=Backups/finalizers,verbs=update

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Backup object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (*BackupReconciler) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)

// TODO(user): your logic here

return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *BackupReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&hmcmirantiscomv1alpha1.Backup{}).
Complete(r)
}
Loading

0 comments on commit 5996e1f

Please sign in to comment.