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

Fix for #89 - Use custom UUID for NAB Object #101

Open
wants to merge 6 commits into
base: master
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
4 changes: 2 additions & 2 deletions api/v1alpha1/nonadminbackup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ type VeleroBackup struct {
// +optional
Status *velerov1.BackupStatus `json:"status,omitempty"`

// name references the Velero backup by it's name.
// nameuuid references the Velero Backup object by it's label containing same NameUUID.
// +optional
Name string `json:"name,omitempty"`
NameUUID string `json:"nameuuid,omitempty"`
mateusoliveira43 marked this conversation as resolved.
Show resolved Hide resolved

// namespace references the Namespace in which Velero backup exists.
// +optional
Expand Down
7 changes: 4 additions & 3 deletions config/crd/bases/nac.oadp.openshift.io_nonadminbackups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -612,13 +612,14 @@ spec:
description: VeleroBackup contains information of the related Velero
backup object.
properties:
name:
description: name references the Velero backup by it's name.
type: string
namespace:
description: namespace references the Namespace in which Velero
backup exists.
type: string
nameuuid:
description: nameuuid references the Velero Backup object by it's
label containing same NameUUID.
type: string
status:
description: status captures the current status of the Velero
backup.
Expand Down
8 changes: 4 additions & 4 deletions docs/design/Non_Admin_Controller_design.md
mateusoliveira43 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,17 @@ This design intends to enable non-admin users the ability to perform Backup and
backupSpec: {}
```
- **NAB controller reconciles on this NAB CR:** The NonAdminBackup controller continuously reconciles the NonAdminBackup object's desired state with the actual state in the cluster.
- **NAB controller validates the NAB CR and then creates a corresponding Velero Backup CR:** When the NonAdminBackup controller detects a new or modified NonAdminBackup object, it creates or updates a corresponding Velero Backup object within the OADP Namespace using the information provided in the `backupSpec` field of the NonAdminBackup object. The resulting Backup object is named as `nab-<namespace>-<hash>`, where the `<namespace>` is the NonAdminBackup namespace and the `<hash>` is computed from the original NonAdminBackup name. The resulting Backup object is labeled and annotated with the following additional metadata:
- **NAB controller validates the NAB CR and then creates a corresponding Velero Backup CR:** When the NonAdminBackup controller detects a new or modified NonAdminBackup object, it creates or updates a corresponding Velero Backup object within the OADP Namespace using the information provided in the `backupSpec` field of the NonAdminBackup object. The resulting Backup object is named as `<namespace>-<name>-<hash>`, where the `<namespace>` is the NonAdminBackup namespace, `<name>` is the NonAdminBackup name and the `<hash>` is the generated UUID (version 4). If the resulting Backup object name is too long the name is adapted to 63 characters limit stripping first characters from name and then from namespace. The resulting Backup object is labeled and annotated with the following additional metadata:

```yaml
metadata:
annotations:
openshift.io/oadp-nab-origin-name: <NonAdminBackup name>
openshift.io/oadp-nab-origin-namespace: <NonAdminBackup Namespace>
openshift.io/oadp-nab-origin-uuid: <NonAdminBackup UUID>
labels:
app.kubernetes.io/managed-by: <OADP NonAdminController id>
openshift.io/oadp: 'True'
openshift.io/oadp-nab-origin-nameuuid: <NonAdminBackup's NameUUID from Status>
```
- **Velero runs Backup**: Velero executes the backup operation based on the configuration specified in the Velero Backup object. Velero updates the status of the Velero Backup object to reflect the outcome of the backup process.
- **Reconcile loop updates NonAdminBackup object Status**: Upon detecting changes in the status of the Velero Backup object, the NonAdminBackup controller's reconciliation loop updates the Status field of the corresponding NonAdminBackup object with the updated status from the Velero Backup object.
Expand All @@ -162,17 +162,17 @@ This design intends to enable non-admin users the ability to perform Backup and
- **Backup Sync controller syncs the Non-admin Backup CRs:** The Backup-Sync controller ensures that the NS relevant backups are synced and Non-admin backup CRs exists for non-admin users to refer them for restore operations.
- **Non-Admin user creates the Non-Admin restore CR:** The user creates NonAdminRestore custom resource object in the Namespace on which the restore will run within the Kubernetes cluster. The `NonAdminRestore` schema has the `restoreSpec`, which is the same as `Restore` CR from the `velero.io/v1` apiVersion. Note that the non-admin user will use non-admin backup name (and not Velero backup name) in non-admin restore spec.
- **NAR controller reconciles on this NAR CR:** The NonAdminRestore controller continuously reconciles the NonAdminRestore object's desired state with the actual state in the cluster.
- **NAR controller validates the NAR CR and then creates a corresponding Velero Restore CR:** When the NonAdminRestore controller detects a new or modified NonAdminRestore object, it creates the corresponding Velero Restore object within the OADP Namespace using the information provided in the `restoreSpec` field of the NonAdminRestore object. The resulting Restore object is named as `nar-<namespace>-<hash>`, where the `<namespace>` is the NonAdminRestore namespace and the `<hash>` is computed from the original NonAdminRestore name. The resulting Restore object is labeled and annotated with the following additional metadata:
- **NAR controller validates the NAR CR and then creates a corresponding Velero Restore CR:** When the NonAdminRestore controller detects a new or modified NonAdminRestore object, it creates the corresponding Velero Restore object within the OADP Namespace using the information provided in the `restoreSpec` field of the NonAdminRestore object. The resulting Restore object is named as `<namespace>-<name>-<hash>`, where the `<namespace>` is the NonAdminRestore namespace, `<name>` is the NonAdminRestore name and the `<hash>` is the generated UUID (version 4). If the resulting Restore object name is too long the name is adapted to 63 characters limit stripping first characters from name and then from namespace. The resulting Restore object is labeled and annotated with the following additional metadata:

```yaml
metadata:
annotations:
openshift.io/oadp-nar-origin-name: <NonAdminRestore name>
openshift.io/oadp-nar-origin-namespace: <NonAdminRestore Namespace>
openshift.io/oadp-nar-origin-uuid: <NonAdminRestore UUID>
labels:
app.kubernetes.io/managed-by: <OADP NonAdminController id>
openshift.io/oadp: 'True'
openshift.io/oadp-nar-origin-nameuuid: <NonAdminRestore's NameUUID from Status>
```
- **Velero runs Restore**: Velero executes the restore operation based on the configuration specified in the Velero Restore object. Velero updates the status of the Velero Restore object to reflect the outcome of the restore process.
- **Reconcile loop updates NonAdminRestore object Status**: Upon detecting changes in the status of the Velero Restore object, the NonAdminRestore controller's reconciliation loop updates the Status field of the corresponding NonAdminRestore object with the updated status from the Velero Restore object.
Expand Down
134 changes: 86 additions & 48 deletions docs/design/nab_and_nar_status_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ Those are are the possible values for `NonAdminCondition`:

NonAdminBackup/NonAdminRestore `status` contains reference to the related Velero Backup/Restore.

NonAdminBackup `status.veleroBackup` contains `name`, `namespace` and `status`.
- `status.veleroBackup.name` represents the name of the `VeleroBackup` object.
NonAdminBackup `status.veleroBackup` contains `nameuuid`, `namespace` and `status`.
- `status.veleroBackup.nameuuid` field stores generated unique UUID of the `VeleroBackup` object. The same UUID is also stored as the label value `openshift.io/oadp-nab-origin-nameuuid` within the created `VeleroBackup` object.
- `status.veleroBackup.namespace` represents the namespace in which the `VeleroBackup` object was created.
- `status.veleroBackup.status` field is a copy of the `VeleroBackup` object status.

Expand All @@ -76,10 +76,10 @@ status:
velero backup describe -n openshift-adp nab-nacproject-c3499c2729730a
```

Similarly, NonAdminRestore `status.veleroRestore` contains `name`, `namespace` and `status`.
- `status.veleroRestore.name` represents the name of the `veleroRestore` object.
Similarly, NonAdminRestore `status.veleroRestore` contains `nameuuid`, `namespace` and `status`.
- `status.veleroRestore.nameuuid` field stores generated unique UUID of the `VeleroRestore` object. The same UUID is also stored as the label value `openshift.io/oadp-nar-origin-nameuuid` within the created `VeleroRestore` object.
- `status.veleroRestore.namespace` represents the namespace in which the `veleroRestore` object was created.
- `status.veleroRestore.status` field is a copy of the `VeleroBackup` object status.
- `status.veleroRestore.status` field is a copy of the `VeleroRestore` object status.

## Example

Expand All @@ -91,7 +91,7 @@ Object passed validation and Velero `Backup` object was created, but there was a
```yaml
status:
veleroBackup:
name: nab-nacproject-83fc04a2fd253d
nameuuid: nonadmin-test-86b8d92b-66b2-11e4-8a2d-42010af06f3f
namespace: openshift-adp
status:
expiration: '2024-05-16T08:12:11Z'
Expand Down Expand Up @@ -124,69 +124,107 @@ It is similar for a NonAdminRestore.
```mermaid
%%{init: {'theme':'neutral'}}%%
graph
event1{{predicate: Create event NAB}} == If event is accepted ==>

reconcileStart1[/Reconcile start\] ==>

phaseNew["`status.phase to **New**`"] -. Requeue: false, err .-> reconcileStart1
phaseNew ==>
predicateUpdateNabEvent{{predicate: Accepted **update** event NAB}};
predicateCreateNabEvent{{predicate: Accepted **create** event NAB}};
predicateUpdateVBEvent{{predicate: Accepted **update** event Velero Backup}};

reconcileExit1[\Requeue: true, nil/]
reconcileExit1 ==> question(is NonAdminBackup Spec valid?) == yes ==> reconcileStart2
question == no ==> reconcileStartInvalid1
requeueTrueNil[\"Requeue: true"/];
requeueFalseNil[\"Requeue: false"/];
requeueFalseErr[\"Requeue: false, error"/];
requeueFalseTerminalErr[\"Requeue: false, Terminal error"/];

reconcileStart2[/Reconcile start\] ==>
reconcileStartAcceptedPredicate[/Reconcile start\];

conditionsAcceptedTrue["`status.conditions[Accepted] to **True**`"] -. Requeue: false, err .- reconcileStart2
conditionsAcceptedTrue ==>
questionPhaseStatusSetToNew{"Is status.phase: **New** ?"};
mateusoliveira43 marked this conversation as resolved.
Show resolved Hide resolved
questionConditionAcceptedTrue{"Is status.conditions[Accepted]: **True** ?"};
questionIsNabValid{"Is NonAdminBackup Spec valid ?"};
questionPhaseStatusSetToBackingOff{"Is status.phase: **BackingOff**
and status.conditions[Accepted]: **False** ?"};
questionPhaseStatusSetToCreated{"Is status.phase: **Created**
and status.conditions[BackupScheduled]: **True** ?"};
questionStatusVeleroBackupUUID{"Does status.VeleroBackup.NameUUID exist ?"};
questionSuccess{"Success ?"};
questionSuccessCreateVB{"Success ?"}
questionSuccessWithTerminalError{"Success ?"};
questionSuccessWithNoRequeue{"Success ?"};
questionSuccessGetVB{"Error ?"};
mateusoliveira43 marked this conversation as resolved.
Show resolved Hide resolved
questionGetSingleVB{"Is Single Velero Backup found ?"};
questionNabStatusUpdateFromVB{"Does NAB Object status requires update ?"};

reconcileExit2[\Requeue: true, nil/] ==>
createVBObject{{"Create New Velero Backup Object"}};

reconcileStart3[/Reconcile start\] ==>

createVeleroBackup([Create Velero Backup]) -. Requeue: false, err .- reconcileStart3
createVeleroBackup ==>
getUUIDMatchingVeleroBackup("Get Velero Backup with label openshift.io/oadp-nab-origin-nameuuid matching status.VeleroBackup.NameUUID");

phaseCreated["`
status.phase: **Created**
status.conditions[Queued] to **True**
status.conditions.veleroBackup.name
status.conditions.veleroBackup.namespace
`"] -. Requeue: false, err .- reconcileStart3
phaseCreated ==>
statusPhaseSetToNew["Set status.phase to: **New**"];
statusPhaseStatusSetToBackingOff["Set status.phase: **BackingOff**
and status.conditions[Accepted]: **False** ?"];
statusConditionSetAcceptedToTrue["Set status.conditions[Accepted] to **True**"];
statusPhaseStatusSetToCreated["Set status.phase: **Created**
and status.conditions[BackupScheduled]: **True** ?"];
statusSetVeleroBackupUUID["Generate a NameUUID and set it as status.VeleroBackup.NameUUID"];
statusNabStatusUpdateFromVB["Update NonAdminBackup status from Velero Backup"];

reconcileExit4[\Requeue: false, nil/]
predicateCreateNabEvent --> reconcileStartAcceptedPredicate;
predicateUpdateNabEvent --> reconcileStartAcceptedPredicate;
predicateUpdateVBEvent --> reconcileStartAcceptedPredicate;

reconcileStartInvalid1[/Reconcile start\] ==>
reconcileStartAcceptedPredicate --> questionPhaseStatusSetToNew;
questionPhaseStatusSetToNew -- No --> statusPhaseSetToNew;
questionPhaseStatusSetToNew -- Yes --> questionIsNabValid;

phaseBackingOff["`
status.phase to **BackingOff**
status.conditions[Accepted] to **False**
`"] -. Requeue: false, err .- reconcileStartInvalid1
phaseBackingOff ==>
statusPhaseSetToNew --> questionSuccess;
questionSuccess -- No --> requeueFalseErr;
questionSuccess -- Yes --> requeueTrueNil;

reconcileExitInvalid1[\Requeue: false, TerminalError/]
requeueTrueNil --> reconcileStartAcceptedPredicate;

reconcileExit4 ~~~ event2
reconcileExitInvalid1 ~~~ event2
questionIsNabValid -- No --> questionPhaseStatusSetToBackingOff;
questionIsNabValid -- Yes --> questionConditionAcceptedTrue;

event2{{predicate: Update event VeleroBackup}} == If event is accepted ==>
handler1{{handler: Handle VeleroBackup update event}} ==> reconcileStart5
questionConditionAcceptedTrue -- No --> statusConditionSetAcceptedToTrue;
questionConditionAcceptedTrue -- Yes --> questionStatusVeleroBackupUUID;

reconcileStart5[/Reconcile start\] ==> conditionsVeleroBackupStatus
questionStatusVeleroBackupUUID -- No --> statusSetVeleroBackupUUID;
questionStatusVeleroBackupUUID -- Yes --> getUUIDMatchingVeleroBackup;

conditionsVeleroBackupStatus["`status.conditions.veleroBackup.status`"] -. Requeue: false, err .- reconcileStart5
conditionsVeleroBackupStatus ==>
statusSetVeleroBackupUUID --> questionSuccess;

reconcileExit5[\Requeue: false, nil/]
statusConditionSetAcceptedToTrue --> questionSuccess;

reconcileExit5 ~~~ event3

event3{{predicate: Delete event NAB}} == If event is accepted ==>
questionPhaseStatusSetToBackingOff -- No --> statusPhaseStatusSetToBackingOff;
questionPhaseStatusSetToBackingOff -- Yes --> requeueFalseTerminalErr;
statusPhaseStatusSetToBackingOff --> questionSuccessWithTerminalError;

reconcileDelete1[/Reconcile start\] ==>
questionSuccessWithTerminalError -- No --> requeueFalseErr;
questionSuccessWithTerminalError -- Yes --> requeueFalseTerminalErr;

reconcileExitDelete1[\Requeue: false, nil/] -. Requeue: false, err .-> reconcileDelete1
getUUIDMatchingVeleroBackup --> questionSuccessGetVB;

questionSuccessGetVB -- No --> questionGetSingleVB;
questionSuccessGetVB -- Yes --> requeueFalseErr;

questionGetSingleVB -- No --> createVBObject;
questionGetSingleVB -- Yes --> questionPhaseStatusSetToCreated;
createVBObject --> questionSuccessCreateVB;

questionSuccessCreateVB -- No --> requeueFalseErr;
questionSuccessCreateVB -- Yes --> questionPhaseStatusSetToCreated;

questionPhaseStatusSetToCreated -- No --> statusPhaseStatusSetToCreated;
questionPhaseStatusSetToCreated -- Yes --> questionNabStatusUpdateFromVB;
statusPhaseStatusSetToCreated --> questionSuccessWithNoRequeue;

questionSuccessWithNoRequeue -- No --> requeueFalseErr;
questionSuccessWithNoRequeue -- Yes --> requeueFalseNil;

questionNabStatusUpdateFromVB -- No --> requeueFalseNil;

questionNabStatusUpdateFromVB -- Yes --> statusNabStatusUpdateFromVB;

statusNabStatusUpdateFromVB --> questionSuccessWithNoRequeue;

event4{{predicate: Update event NAB}} == If event is accepted ==> question
```
14 changes: 10 additions & 4 deletions internal/common/constant/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
// Package constant contains all common constants used in the project
package constant

import "k8s.io/apimachinery/pkg/util/validation"

// Common labels for objects manipulated by the Non Admin Controller
// Labels should be used to identify the NAC object
// Annotations on the other hand should be used to define ownership
Expand All @@ -28,7 +30,8 @@ const (
ManagedByLabelValue = "oadp-nac-controller" // TODO why not use same project name as in PROJECT file?
NabOriginNameAnnotation = "openshift.io/oadp-nab-origin-name"
NabOriginNamespaceAnnotation = "openshift.io/oadp-nab-origin-namespace"
NabOriginUUIDAnnotation = "openshift.io/oadp-nab-origin-uuid"
NabOriginNameUUIDLabel = "openshift.io/oadp-nab-origin-nameuuid"
NarOriginNameUUIDLabel = "openshift.io/oadp-nar-origin-nameuuid"
)

// Common environment variables for the Non Admin Controller
Expand All @@ -39,9 +42,12 @@ const (
// EmptyString defines a constant for the empty string
const EmptyString = ""

// NameDelimiter defines character that is used to separate name parts
const NameDelimiter = "-"

// TrueString defines a constant for the True string
const TrueString = "True"

// VeleroBackupNamePrefix represents the prefix for the object name generated
// by the NonAdminController
const VeleroBackupNamePrefix = "nab"
// MaximumNacObjectNameLength represents Generated Non Admin Object Name and
// must be below 63 characters, because it's used within object Label Value
const MaximumNacObjectNameLength = validation.DNS1123LabelMaxLength
mateusoliveira43 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading