Skip to content

Commit

Permalink
Adjust the Status of NonAdminBackup
Browse files Browse the repository at this point in the history
Moves Status outside of Spec and adjusts this to reflect
Velero Backup status as well additional Status when the
Spec within NonAdminBackup is not defined.

Signed-off-by: Michal Pryc <[email protected]>
  • Loading branch information
mpryc committed Apr 15, 2024
1 parent c6505f4 commit 574576e
Show file tree
Hide file tree
Showing 10 changed files with 474 additions and 121 deletions.
46 changes: 38 additions & 8 deletions api/v1alpha1/nonadminbackup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,55 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NonAdminBackupSpec defines the desired state of NonAdminBackup
type NonAdminBackupSpec struct {
// https://github.com/vmware-tanzu/velero/blob/main/pkg/apis/velero/v1/backup_types.go
// +kubebuilder:validation:Enum=New;BackingOff;Created

Check failure on line 24 in api/v1alpha1/nonadminbackup_types.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

exported: comment on exported type NonAdminBackupPhase should be of the form "NonAdminBackupPhase ..." (with optional leading article) (revive)
type NonAdminBackupPhase string

// The phase is a simple one high-level summary of the lifecycle of an NonAdminBackup.
// Conditions are used for more detailed information supporing such state.
const (
// NonAdminBackup resource was accepted by the OpenShift cluster, but it has not yet been processed by the NonAdminController
NonAdminBackupPhaseNew NonAdminBackupPhase = "New"
// Velero Backup object was not created due to NonAdminBackup error (configuration or similar)
NonAdminBackupPhaseBackingOff NonAdminBackupPhase = "BackingOff"
// Velero Backup was created. The Phase will not have additional informations about the Backup.
NonAdminBackupPhaseCreated NonAdminBackupPhase = "Created"
)

// BackupSpec defines the specification for a Velero backup.
BackupSpec *velerov1api.BackupSpec `json:"backupSpec,omitempty"`
// +kubebuilder:validation:Enum=BackupAccepted;BackupQueued

Check failure on line 38 in api/v1alpha1/nonadminbackup_types.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

exported: comment on exported type NonAdminCondition should be of the form "NonAdminCondition ..." (with optional leading article) (revive)
type NonAdminCondition string

// BackupStatus captures the current status of a Velero backup.
BackupStatus *velerov1api.BackupStatus `json:"backupStatus,omitempty"`
// Predefined conditions for NonAdminBackup.
// One NonAdminBackup object may have multiple conditions.
// It is more granular knowledge of the NonAdminBackup object and represents the
// array of the conditions through which the NonAdminBackup has or has not passed
const (
NonAdminBackupConditionAccepted NonAdminCondition = "BackupAccepted"
NonAdminBackupConditionQueued NonAdminCondition = "BackupQueued"
)

// NonAdminBackupSpec defines the desired state of NonAdminBackup
type NonAdminBackupSpec struct {

Check failure on line 51 in api/v1alpha1/nonadminbackup_types.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

fieldalignment: struct with 24 pointer bytes could be 16 (govet)
// NonAdminBackup log level (use debug for the most logging, leave unset for default)
// +optional
// +kubebuilder:validation:Enum=trace;debug;info;warning;error;fatal;panic
LogLevel string `json:"logLevel,omitempty"`

// BackupSpec defines the specification for a Velero backup.
BackupSpec *velerov1api.BackupSpec `json:"backupSpec,omitempty"`
}

// NonAdminBackupStatus defines the observed state of NonAdminBackup
type NonAdminBackupStatus struct {

Check failure on line 62 in api/v1alpha1/nonadminbackup_types.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

fieldalignment: struct with 56 pointer bytes could be 48 (govet)
Conditions []metav1.Condition `json:"conditions,omitempty"`
Phase NonAdminBackupPhase `json:"phase,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`

// BackupStatus captures the current status of a Velero backup.
// +optional
BackupStatus *velerov1api.BackupStatus `json:"backupStatus,omitempty"`

// OadpVeleroBackup references the VeleroBackup object. Format: <name>.<namespace>
// +optional
OadpVeleroBackup string `json:"oadpVeleroBackup,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
10 changes: 5 additions & 5 deletions api/v1alpha1/zz_generated.deepcopy.go

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

42 changes: 26 additions & 16 deletions config/crd/bases/nac.oadp.openshift.io_nonadminbackups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,22 @@ spec:
type: string
type: array
type: object
logLevel:
description: NonAdminBackup log level (use debug for the most logging,
leave unset for default)
enum:
- trace
- debug
- info
- warning
- error
- fatal
- panic
type: string
type: object
status:
description: NonAdminBackupStatus defines the observed state of NonAdminBackup
properties:
backupStatus:
description: BackupStatus captures the current status of a Velero
backup.
Expand Down Expand Up @@ -634,22 +650,6 @@ spec:
file in object storage.
type: integer
type: object
logLevel:
description: NonAdminBackup log level (use debug for the most logging,
leave unset for default)
enum:
- trace
- debug
- info
- warning
- error
- fatal
- panic
type: string
type: object
status:
description: NonAdminBackupStatus defines the observed state of NonAdminBackup
properties:
conditions:
items:
description: "Condition contains details for one aspect of the current
Expand Down Expand Up @@ -719,6 +719,16 @@ spec:
- type
type: object
type: array
oadpVeleroBackup:
description: 'OadpVeleroBackup references the VeleroBackup object.
Format: <name>.<namespace>'
type: string
phase:
enum:
- New
- BackingOff
- Created
type: string
type: object
type: object
served: true
Expand Down
2 changes: 1 addition & 1 deletion config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ kind: Kustomization
images:
- name: controller
newName: quay.io/migi/oadp-nac-operator
newTag: v0.0.37
newTag: v0.0.56
131 changes: 119 additions & 12 deletions internal/common/function/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import (
"context"
"crypto/sha1" //nolint:gosec // TODO remove
"encoding/hex"
"errors"
"fmt"
"reflect"

"github.com/go-logr/logr"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -117,28 +120,134 @@ func GenerateVeleroBackupName(namespace, nabName string) string {
return veleroBackupName
}

func UpdateNonAdminPhase(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, phase nacv1alpha1.NonAdminBackupPhase) (bool, error) {

Check failure on line 123 in internal/common/function/function.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

exported: exported function UpdateNonAdminPhase should have comment or be unexported (revive)
if nab == nil {
return false, errors.New("NonAdminBackup object is nil")
}

// Ensure phase is valid
if phase == "" {
return false, errors.New("NonAdminBackupPhase cannot be empty")
}

oldPhase := nab.Status.Phase
nab.Status.Phase = phase

logger.V(1).Info(fmt.Sprintf("Setting NonAdminBackup Phase to: %s", phase))

if oldPhase == nab.Status.Phase {
// No change, no need to update
logger.V(1).Info("NonAdminBackup Phase is already up to date")
return false, nil
}

// Update NAB status
if err := r.Status().Update(ctx, nab); err != nil {
logger.Error(err, "Failed to update NonAdminBackup Phase")
return false, err
}

logger.V(1).Info(fmt.Sprintf("NonAdminBackup Phase set to: %s", phase))

return true, nil
}

func UpdateNonAdminBackupCondition(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, condition nacv1alpha1.NonAdminCondition, conditionStatus metav1.ConditionStatus, reason string, message string) (bool, error) {

Check failure on line 155 in internal/common/function/function.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

exported: exported function UpdateNonAdminBackupCondition should have comment or be unexported (revive)
if nab == nil {
return false, errors.New("NonAdminBackup object is nil")
}

// Ensure phase and condition are valid
if condition == "" {
return false, errors.New("NonAdminBackup Condition cannot be empty")
}

if conditionStatus == "" {

Check failure on line 165 in internal/common/function/function.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

add-constant: string literal "" appears, at least, 3 times, create a named constant for it (revive)
return false, errors.New("NonAdminBackup Condition Status cannot be empty")
} else if conditionStatus != metav1.ConditionTrue && conditionStatus != metav1.ConditionFalse && conditionStatus != metav1.ConditionUnknown {
return false, errors.New("NonAdminBackup Condition Status must be valid metav1.ConditionStatus")
}

if reason == "" {
return false, errors.New("NonAdminBackup Condition Reason cannot be empty")
}

if message == "" {
return false, errors.New("NonAdminBackup Condition Message cannot be empty")
}

// Check if the condition is already set to the desired status
currentCondition := apimeta.FindStatusCondition(nab.Status.Conditions, string(condition))
if currentCondition != nil && currentCondition.Status == conditionStatus {
// Condition is already set to the desired status, no need to update
logger.V(1).Info(fmt.Sprintf("NonAdminBackup Condition is already set to: %s", condition))
return false, nil
}

// Update NAB status condition
apimeta.SetStatusCondition(&nab.Status.Conditions,
metav1.Condition{
Type: string(condition),
Status: conditionStatus,
Reason: reason,
Message: message,
},
)

logger.V(1).Info(fmt.Sprintf("NonAdminBackup Condition to: %s", condition))
logger.V(1).Info(fmt.Sprintf("NonAdminBackup Condition Reason to: %s", reason))
logger.V(1).Info(fmt.Sprintf("NonAdminBackup Condition Message to: %s", message))

// Update NAB status
if err := r.Status().Update(ctx, nab); err != nil {
logger.Error(err, "NonAdminBackup Condition - Failed to update")
return false, err
}

return true, nil
}

// UpdateNonAdminBackupFromVeleroBackup update, if necessary, NonAdminBackup object fields related to referenced Velero Backup object, if no error occurs
func UpdateNonAdminBackupFromVeleroBackup(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, veleroBackup *velerov1api.Backup) error {
func UpdateNonAdminBackupFromVeleroBackup(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, veleroBackup *velerov1api.Backup) (bool, error) {
// Make a copy of the current status for comparison
oldStatus := nab.Spec.BackupStatus.DeepCopy()
oldStatus := nab.Status.BackupStatus.DeepCopy()
oldSpec := nab.Spec.BackupSpec.DeepCopy()

// Update the status & spec
nab.Spec.BackupStatus = &veleroBackup.Status
nab.Status.BackupStatus = &veleroBackup.Status
nab.Spec.BackupSpec = &veleroBackup.Spec

if reflect.DeepEqual(oldStatus, nab.Spec.BackupStatus) && reflect.DeepEqual(oldSpec, nab.Spec.BackupSpec) {
logger.V(1).Info("NonAdminBackup BackupSpec and BackupStatus - request to update")

if reflect.DeepEqual(oldStatus, nab.Status.BackupStatus) && reflect.DeepEqual(oldSpec, nab.Spec.BackupSpec) {
// No change, no need to update
logger.V(1).Info("NonAdminBackup status and spec is already up to date")
return nil
logger.V(1).Info("NonAdminBackup BackupSpec and BackupStatus - nothing to update")
return false, nil
}

if err := r.Update(ctx, nab); err != nil {
logger.Error(err, "Failed to update NonAdminBackup")
return err
if reflect.DeepEqual(oldStatus, nab.Status.BackupStatus) {
logger.V(1).Info("NonAdminBackup BackupStatus - up to date")
} else {
if err := r.Status().Update(ctx, nab); err != nil {
logger.Error(err, "NonAdminBackup BackupStatus - Failed to update")
return false, err
} else {

Check failure on line 234 in internal/common/function/function.go

View workflow job for this annotation

GitHub Actions / golang-check (1.21)

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
logger.V(1).Info("NonAdminBackup BackupStatus - updated")
}
}

return nil
if reflect.DeepEqual(oldSpec, nab.Spec.BackupSpec) {
logger.V(1).Info("NonAdminBackup BackupSpec - up to date")
} else {
if err := r.Update(ctx, nab); err != nil {
logger.Error(err, "NonAdminBackup BackupSpec - Failed to update")
return false, err
} else {
logger.V(1).Info("NonAdminBackup BackupSpec - updated")
}
}

return true, nil
}

// CheckVeleroBackupLabels return true if Velero Backup object has required Non Admin labels, false otherwise
Expand All @@ -149,8 +258,6 @@ func CheckVeleroBackupLabels(backup *velerov1api.Backup) bool {
return exists && value == constant.ManagedByLabelValue
}

// TODO not used

// GetNonAdminBackupFromVeleroBackup return referenced NonAdminBackup object from Velero Backup object, if no error occurs
func GetNonAdminBackupFromVeleroBackup(ctx context.Context, clientInstance client.Client, backup *velerov1api.Backup) (*nacv1alpha1.NonAdminBackup, error) {
// Check if the backup has the required annotations to identify the associated NonAdminBackup object
Expand Down
Loading

0 comments on commit 574576e

Please sign in to comment.