Skip to content

Commit

Permalink
fixup! feat: Add Non Admin Restore controller
Browse files Browse the repository at this point in the history
Signed-off-by: Mateus Oliveira <[email protected]>
  • Loading branch information
mateusoliveira43 committed Apr 30, 2024
1 parent 1933c6c commit 861c8d9
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 48 deletions.
20 changes: 10 additions & 10 deletions api/v1alpha1/nonadminbackup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// NonAdminBackupPhase is a simple one high-level summary of the lifecycle of an NonAdminBackup.
// NonAdminPhase is a simple one high-level summary of the lifecycle of a non admin object.
// +kubebuilder:validation:Enum=New;BackingOff;Created
type NonAdminBackupPhase string
type NonAdminPhase string

const (
// NonAdminBackupPhaseNew - NonAdminBackup resource was accepted by the OpenShift cluster, but it has not yet been processed by the NonAdminController
NonAdminBackupPhaseNew NonAdminBackupPhase = "New"
// NonAdminBackupPhaseBackingOff - Velero Backup object was not created due to NonAdminBackup error (configuration or similar)
NonAdminBackupPhaseBackingOff NonAdminBackupPhase = "BackingOff"
// NonAdminBackupPhaseCreated - Velero Backup was created. The Phase will not have additional informations about the Backup.
NonAdminBackupPhaseCreated NonAdminBackupPhase = "Created"
// NonAdminPhaseNew - non admin resource was accepted by the OpenShift cluster, but it has not yet been processed by the NonAdminController
NonAdminPhaseNew NonAdminPhase = "New"
// NonAdminPhaseBackingOff - Velero object was not created due to error in non admin object (configuration or similar)
NonAdminPhaseBackingOff NonAdminPhase = "BackingOff"
// NonAdminPhaseCreated - Velero object was created. The Phase will not have additional information about the Velero object.
NonAdminPhaseCreated NonAdminPhase = "Created"
)

// NonAdminBackupSpec defines the desired state of NonAdminBackup
Expand Down Expand Up @@ -60,8 +60,8 @@ type NonAdminBackupStatus struct {
// +optional
VeleroBackupStatus *velerov1api.BackupStatus `json:"veleroBackupStatus,omitempty"`

Phase NonAdminBackupPhase `json:"phase,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
Phase NonAdminPhase `json:"phase,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down
10 changes: 8 additions & 2 deletions api/v1alpha1/nonadminrestore_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,15 @@ type NonAdminRestoreSpec struct {

// NonAdminRestoreStatus defines the observed state of NonAdminRestore
type NonAdminRestoreStatus struct {
// TODO https://github.com/migtools/oadp-non-admin/pull/23
// TODO https://github.com/migtools/oadp-non-admin/pull/13
// Related Velero Restore name.
// +optional
VeleroRestoreName string `json:"veleroRestoreName,omitempty"`

// Related Velero Restore status.
// +optional
VeleroRestoreStatus *velerov1api.RestoreStatus `json:"veleroRestoreStatus,omitempty"`

Phase NonAdminPhase `json:"phase,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

Expand Down
5 changes: 5 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.

4 changes: 2 additions & 2 deletions config/crd/bases/nac.oadp.openshift.io_nonadminbackups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -589,8 +589,8 @@ spec:
type: object
type: array
phase:
description: NonAdminBackupPhase is a simple one high-level summary
of the lifecycle of an NonAdminBackup.
description: NonAdminPhase is a simple one high-level summary of the
lifecycle of a non admin object.
enum:
- New
- BackingOff
Expand Down
97 changes: 97 additions & 0 deletions config/crd/bases/nac.oadp.openshift.io_nonadminrestores.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,103 @@ spec:
- type
type: object
type: array
phase:
description: NonAdminPhase is a simple one high-level summary of the
lifecycle of a non admin object.
enum:
- New
- BackingOff
- Created
type: string
veleroRestoreName:
description: Related Velero Restore name.
type: string
veleroRestoreStatus:
description: Related Velero Restore status.
properties:
completionTimestamp:
description: |-
CompletionTimestamp records the time the restore operation was completed.
Completion time is recorded even on failed restore.
The server's time is used for StartTimestamps
format: date-time
nullable: true
type: string
errors:
description: |-
Errors is a count of all error messages that were generated during
execution of the restore. The actual errors are stored in object storage.
type: integer
failureReason:
description: FailureReason is an error that caused the entire
restore to fail.
type: string
phase:
description: Phase is the current state of the Restore
enum:
- New
- FailedValidation
- InProgress
- WaitingForPluginOperations
- WaitingForPluginOperationsPartiallyFailed
- Completed
- PartiallyFailed
- Failed
type: string
progress:
description: |-
Progress contains information about the restore's execution progress. Note
that this information is best-effort only -- if Velero fails to update it
during a restore for any reason, it may be inaccurate/stale.
nullable: true
properties:
itemsRestored:
description: ItemsRestored is the number of items that have
actually been restored so far
type: integer
totalItems:
description: |-
TotalItems is the total number of items to be restored. This number may change
throughout the execution of the restore due to plugins that return additional related
items to restore
type: integer
type: object
restoreItemOperationsAttempted:
description: |-
RestoreItemOperationsAttempted is the total number of attempted
async RestoreItemAction operations for this restore.
type: integer
restoreItemOperationsCompleted:
description: |-
RestoreItemOperationsCompleted is the total number of successfully completed
async RestoreItemAction operations for this restore.
type: integer
restoreItemOperationsFailed:
description: |-
RestoreItemOperationsFailed is the total number of async
RestoreItemAction operations for this restore which ended with an error.
type: integer
startTimestamp:
description: |-
StartTimestamp records the time the restore operation was started.
The server's time is used for StartTimestamps
format: date-time
nullable: true
type: string
validationErrors:
description: |-
ValidationErrors is a slice of all validation errors (if
applicable)
items:
type: string
nullable: true
type: array
warnings:
description: |-
Warnings is a count of all warning messages that were generated during
execution of the restore. The actual warnings are stored in object storage.
type: integer
type: object
type: object
type: object
served: true
Expand Down
15 changes: 14 additions & 1 deletion internal/common/constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ limitations under the License.
// Package constant contains all common constants used in the project
package constant

import "os"
import (
"os"

"github.com/migtools/oadp-non-admin/internal/common/types"
)

// Common labels for objects manipulated by the Non Admin Controller
// Labels should be used to identify the NAC object
Expand All @@ -37,6 +41,15 @@ const (
NamespaceEnvVar = "WATCH_NAMESPACE"
)

// 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 (
NonAdminConditionAccepted types.NonAdminCondition = "Accepted"
NonAdminConditionQueued types.NonAdminCondition = "Queued"
)

// OadpNamespace is the namespace OADP operator is installed
var OadpNamespace = os.Getenv(NamespaceEnvVar)

Expand Down
11 changes: 6 additions & 5 deletions internal/common/function/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ import (
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"
apitypes "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

nacv1alpha1 "github.com/migtools/oadp-non-admin/api/v1alpha1"
"github.com/migtools/oadp-non-admin/internal/common/constant"
"github.com/migtools/oadp-non-admin/internal/common/types"
)

const requiredAnnotationError = "backup does not have the required annotation '%s'"
Expand Down Expand Up @@ -127,7 +128,7 @@ func GenerateVeleroBackupName(namespace, nabName string) string {
}

// UpdateNonAdminPhase updates the phase of a NonAdminBackup object with the provided phase.
func UpdateNonAdminPhase(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, phase nacv1alpha1.NonAdminBackupPhase) (bool, error) {
func UpdateNonAdminPhase(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, phase nacv1alpha1.NonAdminPhase) (bool, error) {
if nab == nil {
return false, errors.New("NonAdminBackup object is nil")
}
Expand Down Expand Up @@ -159,7 +160,7 @@ func UpdateNonAdminPhase(ctx context.Context, r client.Client, logger logr.Logge
// based on the provided parameters. It validates the input parameters and ensures
// that the condition is set to the desired status only if it differs from the current status.
// If the condition is already set to the desired status, no update is performed.
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) {
func UpdateNonAdminBackupCondition(ctx context.Context, r client.Client, logger logr.Logger, nab *nacv1alpha1.NonAdminBackup, condition types.NonAdminCondition, conditionStatus metav1.ConditionStatus, reason string, message string) (bool, error) {
if nab == nil {
return false, errors.New("NonAdminBackup object is nil")
}
Expand Down Expand Up @@ -288,7 +289,7 @@ func GetNonAdminBackupFromVeleroBackup(ctx context.Context, clientInstance clien
return nil, fmt.Errorf(requiredAnnotationError, constant.NabOriginNameAnnotation)
}

nonAdminBackupKey := types.NamespacedName{
nonAdminBackupKey := apitypes.NamespacedName{
Namespace: nabOriginNamespace,
Name: nabOriginName,
}
Expand All @@ -304,7 +305,7 @@ func GetNonAdminBackupFromVeleroBackup(ctx context.Context, clientInstance clien
return nil, fmt.Errorf(requiredAnnotationError, constant.NabOriginUUIDAnnotation)
}
// Ensure UID matches
if nonAdminBackup.ObjectMeta.UID != types.UID(nabOriginUUID) {
if nonAdminBackup.ObjectMeta.UID != apitypes.UID(nabOriginUUID) {
return nil, fmt.Errorf("UID from annotation does not match UID of fetched NonAdminBackup object")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1
// Package types contains all common types used in the project
package types

// NonAdminCondition are used for more detailed information supporing NonAdminBackupPhase state.
// +kubebuilder:validation:Enum=Accepted;Queued
// NonAdminCondition are used for more detailed information supporting NonAdminBackupPhase state.
type NonAdminCondition string

// 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 (
NonAdminConditionAccepted NonAdminCondition = "Accepted"
NonAdminConditionQueued NonAdminCondition = "Queued"
)
14 changes: 7 additions & 7 deletions internal/controller/nonadminbackup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (r *NonAdminBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reque

if nab.Status.Phase == constant.EmptyString {
// Phase: New
updatedStatus, errUpdate := function.UpdateNonAdminPhase(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminBackupPhaseNew)
updatedStatus, errUpdate := function.UpdateNonAdminPhase(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminPhaseNew)
if updatedStatus {
logger.V(1).Info("NonAdminBackup CR - Rqueue after Phase Update")
return ctrl.Result{Requeue: true, RequeueAfter: requeueTimeSeconds * time.Second}, nil
Expand All @@ -117,7 +117,7 @@ func (r *NonAdminBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reque
// Phase: BackingOff
// BackupAccepted: False
// BackupQueued: False # already set
updatedStatus, errUpdate := function.UpdateNonAdminPhase(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminBackupPhaseBackingOff)
updatedStatus, errUpdate := function.UpdateNonAdminPhase(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminPhaseBackingOff)
if errUpdate != nil {
logger.Error(errUpdate, "Unable to set NonAdminBackup Phase: BackingOff", nameField, req.Name, constant.NameSpaceString, req.Namespace)
return ctrl.Result{}, errUpdate
Expand All @@ -126,7 +126,7 @@ func (r *NonAdminBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{}, nil
}

updatedStatus, errUpdate = function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminConditionAccepted, metav1.ConditionFalse, "InvalidBackupSpec", errMsg)
updatedStatus, errUpdate = function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, constant.NonAdminConditionAccepted, metav1.ConditionFalse, "InvalidBackupSpec", errMsg)
if updatedStatus {
return ctrl.Result{}, nil
}
Expand All @@ -141,7 +141,7 @@ func (r *NonAdminBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reque
// Phase: New # already set
// BackupAccepted: True
// BackupQueued: False # already set
updatedStatus, errUpdate := function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminConditionAccepted, metav1.ConditionTrue, "BackupAccepted", "backup accepted")
updatedStatus, errUpdate := function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, constant.NonAdminConditionAccepted, metav1.ConditionTrue, "BackupAccepted", "backup accepted")
if updatedStatus {
return ctrl.Result{Requeue: true, RequeueAfter: requeueTimeSeconds * time.Second}, nil
}
Expand Down Expand Up @@ -216,17 +216,17 @@ func (r *NonAdminBackupReconciler) Reconcile(ctx context.Context, req ctrl.Reque
// Phase: Created
// BackupAccepted: True # do not update
// BackupQueued: True
_, errUpdate = function.UpdateNonAdminPhase(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminBackupPhaseCreated)
_, errUpdate = function.UpdateNonAdminPhase(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminPhaseCreated)
if errUpdate != nil {
logger.Error(errUpdate, "Unable to set NonAdminBackup Phase: Created", nameField, req.Name, constant.NameSpaceString, req.Namespace)
return ctrl.Result{}, errUpdate
}
_, errUpdate = function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminConditionAccepted, metav1.ConditionTrue, "Validated", "Valid Backup config")
_, errUpdate = function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, constant.NonAdminConditionAccepted, metav1.ConditionTrue, "Validated", "Valid Backup config")
if errUpdate != nil {
logger.Error(errUpdate, "Unable to set BackupAccepted Condition: True", nameField, req.Name, constant.NameSpaceString, req.Namespace)
return ctrl.Result{}, errUpdate
}
_, errUpdate = function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, nacv1alpha1.NonAdminConditionQueued, metav1.ConditionTrue, "BackupScheduled", "Created Velero Backup object")
_, errUpdate = function.UpdateNonAdminBackupCondition(ctx, r.Client, logger, &nab, constant.NonAdminConditionQueued, metav1.ConditionTrue, "BackupScheduled", "Created Velero Backup object")
if errUpdate != nil {
logger.Error(errUpdate, "Unable to set BackupQueued Condition: True", nameField, req.Name, constant.NameSpaceString, req.Namespace)
return ctrl.Result{}, errUpdate
Expand Down
18 changes: 12 additions & 6 deletions internal/controller/nonadminrestore_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ func (r *NonAdminRestoreReconciler) Reconcile(ctx context.Context, req ctrl.Requ

// TODO try to create Velero Restore

// TODO update status of NonAdminRestore as Velero Restore progresses

return ctrl.Result{}, nil
}

Expand All @@ -77,7 +79,7 @@ func (r *NonAdminRestoreReconciler) validateSpec(ctx context.Context, req ctrl.R
return fmt.Errorf("spec.restoreSpec.scheduleName field is not allowed in NonAdminRestore")
}

// TODO nonAdminBackup respect restricted fields
// TODO nonAdminRestore respect restricted fields

nonAdminBackupName := objectSpec.RestoreSpec.BackupName
nonAdminBackup := &nacv1alpha1.NonAdminBackup{}
Expand All @@ -89,18 +91,22 @@ func (r *NonAdminRestoreReconciler) validateSpec(ctx context.Context, req ctrl.R
}
return err
}
// TODO nonAdminBackup has necessary labels (NAB controller job :question:)
// TODO nonAdminBackup is in complete state :question:!!!!

// TODO move this following to another function, it does not check spec
// TODO create get function in common :question:
oadpNamespace := os.Getenv(constant.NamespaceEnvVar)

veleroBackupName := nonAdminBackup.Labels["naoSei"]
veleroBackupName := nonAdminBackup.Status.VeleroBackupName
if len(veleroBackupName) == 0 {
return fmt.Errorf("NonAdminBackup '%s' does not reference Velero Backup name", nonAdminBackupName)
}
veleroBackup := &velerov1api.Backup{}
err = r.Get(ctx, types.NamespacedName{Namespace: oadpNamespace, Name: veleroBackupName}, veleroBackup)
if err != nil {
// TODO test error messages, THEY MUST BE INFORMATIVE
return err
if errors.IsNotFound(err) {
// TODO add this error message to NonAdminRestore status
return fmt.Errorf("related Velero backup '%s' for NonAdminBackup '%s' does not exist in OADP namespace %s", veleroBackupName, nonAdminBackupName, oadpNamespace)
}
}

return nil
Expand Down
1 change: 0 additions & 1 deletion internal/controller/nonadminrestore_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ var _ = ginkgo.Describe("Test NonAdminRestore Reconcile function", func() {
BackupName: "do-not-exist",
},
}),
// TODO Should NOT accept NonAdminBackup that is not in complete state :question:
// TODO Should NOT accept non existing related Velero Backup
)
})
Loading

0 comments on commit 861c8d9

Please sign in to comment.