Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/qiuming-best/velero into su…
Browse files Browse the repository at this point in the history
…pport-restore-sparse
  • Loading branch information
qiuming-best committed Nov 30, 2023
2 parents b57dde1 + 85482ae commit 7b95b3c
Show file tree
Hide file tree
Showing 95 changed files with 2,429 additions and 562 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/6958-blackpiglet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change controller-runtime List option from MatchingFields to ListOptions
1 change: 1 addition & 0 deletions changelogs/unreleased/7069-27149chen
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
improve discoveryHelper.Refresh() in restore
1 change: 1 addition & 0 deletions changelogs/unreleased/7117-allenxu404
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add hooks status to backup/restore CR
1 change: 1 addition & 0 deletions changelogs/unreleased/7130-qiuming-best
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Node agent restart enhancement
32 changes: 24 additions & 8 deletions config/crd/v1/bases/velero.io_backups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ spec:
spec:
description: BackupSpec defines the specification for a Velero backup.
properties:
backupConfig:
description: BackupConfig defines the configuration for the backup.
properties:
parallelFilesUpload:
description: ParallelFilesUpload is the number of files parallel
uploads to perform when using the uploader.
type: integer
type: object
csiSnapshotTimeout:
description: CSISnapshotTimeout specifies the time used to wait for
CSI VolumeSnapshot status turns to ReadyToUse during creation, before
Expand Down Expand Up @@ -485,6 +477,14 @@ spec:
description: TTL is a time.Duration-parseable string describing how
long the Backup should be retained for.
type: string
uploaderConfig:
description: UploaderConfig specifies the configuration for the uploader.
properties:
parallelFilesUpload:
description: ParallelFilesUpload is the number of files parallel
uploads to perform when using the uploader.
type: integer
type: object
volumeSnapshotLocations:
description: VolumeSnapshotLocations is a list containing names of
VolumeSnapshotLocations associated with this backup.
Expand Down Expand Up @@ -543,6 +543,22 @@ spec:
description: FormatVersion is the backup format version, including
major, minor, and patch version.
type: string
hookStatus:
description: HookStatus contains information about the status of the
hooks.
nullable: true
properties:
hooksAttempted:
description: HooksAttempted is the total number of attempted hooks
Specifically, HooksAttempted represents the number of hooks
that failed to execute and the number of hooks that executed
successfully.
type: integer
hooksFailed:
description: HooksFailed is the total number of hooks which ended
with an error
type: integer
type: object
phase:
description: Phase is the current state of the Backup.
enum:
Expand Down
32 changes: 24 additions & 8 deletions config/crd/v1/bases/velero.io_restores.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -387,14 +387,6 @@ spec:
- name
type: object
x-kubernetes-map-type: atomic
restoreConfig:
description: RestoreConfig specifies the configuration for the restore.
properties:
writeSparseFiles:
description: WriteSparseFiles is a flag to indicate whether write
files sparsely or not.
type: boolean
type: object
restorePVs:
description: RestorePVs specifies whether to restore all included
PVs from snapshot
Expand Down Expand Up @@ -426,6 +418,14 @@ spec:
restore from the most recent successful backup created from this
schedule.
type: string
uploaderConfig:
description: UploaderConfig specifies the configuration for the restore.
properties:
writeSparseFiles:
description: WriteSparseFiles is a flag to indicate whether write
files sparsely or not.
type: boolean
type: object
required:
- backupName
type: object
Expand All @@ -448,6 +448,22 @@ spec:
description: FailureReason is an error that caused the entire restore
to fail.
type: string
hookStatus:
description: HookStatus contains information about the status of the
hooks.
nullable: true
properties:
hooksAttempted:
description: HooksAttempted is the total number of attempted hooks
Specifically, HooksAttempted represents the number of hooks
that failed to execute and the number of hooks that executed
successfully.
type: integer
hooksFailed:
description: HooksFailed is the total number of hooks which ended
with an error
type: integer
type: object
phase:
description: Phase is the current state of the Restore
enum:
Expand Down
17 changes: 9 additions & 8 deletions config/crd/v1/bases/velero.io_schedules.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,6 @@ spec:
description: Template is the definition of the Backup to be run on
the provided schedule
properties:
backupConfig:
description: BackupConfig defines the configuration for the backup.
properties:
parallelFilesUpload:
description: ParallelFilesUpload is the number of files parallel
uploads to perform when using the uploader.
type: integer
type: object
csiSnapshotTimeout:
description: CSISnapshotTimeout specifies the time used to wait
for CSI VolumeSnapshot status turns to ReadyToUse during creation,
Expand Down Expand Up @@ -522,6 +514,15 @@ spec:
description: TTL is a time.Duration-parseable string describing
how long the Backup should be retained for.
type: string
uploaderConfig:
description: UploaderConfig specifies the configuration for the
uploader.
properties:
parallelFilesUpload:
description: ParallelFilesUpload is the number of files parallel
uploads to perform when using the uploader.
type: integer
type: object
volumeSnapshotLocations:
description: VolumeSnapshotLocations is a list containing names
of VolumeSnapshotLocations associated with this backup.
Expand Down
6 changes: 3 additions & 3 deletions config/crd/v1/crds/crds.go

Large diffs are not rendered by default.

41 changes: 1 addition & 40 deletions design/velero-uploader-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type UploaderConfig struct {
}
```

### Integration with Backup & Restore CRD
### Integration with Backup CRD
The Velero CLI will support an uploader configuration-related flag, allowing users to set the value when creating backups or restores. This value will be stored in the `UploaderConfig` field within the `Backup` CRD and `Restore` CRD:

```go
Expand Down Expand Up @@ -122,44 +122,5 @@ Roughly, the process is as follows:
3. Each respective controller within the CRs calls the uploader, and the ParallelFilesUpload from UploaderConfig in CRs is passed to the uploader.
4. When the uploader subsequently calls the Kopia API, it can use the ParallelFilesUpload to set the MaxParallelFileReads parameter, and if the uploader calls the Restic command it would output one warning log for Restic does not support this feature.

### Sparse Option For Kopia & Restic Restore
In many system files, there are numerous zero bytes or empty blocks that still occupy physical storage space. Sparse backup employs a more intelligent approach by only backing up the actual data-containing portions. For those empty blocks or zero bytes, it merely records their presence without actually storing them. This can significantly reduce the storage space required for backups, especially in situations where there is a substantial amount of empty data in large file systems.

Below are the key steps that should be added to support this new feature.
#### Velero CLI
The Velero CLI will support a `--write-sparse-files` flag, allowing users to set the `WriteSparseFiles` value when creating restores with Restic or Kopia uploader.

#### UploaderConfig
below the sub-option `WriteSparseFiles` is added into UploaderConfig:

```go
type UploaderConfig struct {
// +optional
WriteSparseFiles bool `json:"writeSparseFiles,omitempty"`
}
```

### Enable Sparse in Restic
For Restic, it could be enabled by pass the flag `--sparse` in creating restore:

```bash
restic restore create --sparse $snapshotID
```

### Enable Sparse in Kopia
For Kopia, it could be enabled this feature by the `WriteSparseFiles` field in the [FilesystemOutput](https://pkg.go.dev/github.com/kopia/kopia@v0.13.0/snapshot/restore#FilesystemOutput).

```golang
fsOutput := &restore.FilesystemOutput{
WriteSparseFiles: veleroCfg.WriteSparseFiles,
}
```

Roughly, the process is as follows:
1. Users pass the WriteSparseFiles parameter and its value through the Velero CLI. This parameter and its value are stored as a sub-option within UploaderConfig and then placed into the Restore CR.
2. When users perform file system restores, UploaderConfig is passed to the PodVolumeRestore CR. When users use the Data-mover for restores, it is passed to the DataDownload CR.
3. Each respective controller within the CRs calls the uploader, and the WriteSparseFiles from UploaderConfig in CRs is passed to the uploader.
4. When the uploader subsequently calls the Kopia API, it can use the WriteSparseFiles to set the WriteSparseFiles parameter, and if the uploader calls the Restic command it would append `--sparse` flag within the restore command.

## Alternatives Considered
To enhance extensibility further, the option of storing `UploaderConfig` in a Kubernetes ConfigMap can be explored, this approach would allow the addition and modification of configuration options without the need to modify the CRD.
137 changes: 137 additions & 0 deletions internal/hook/hook_tracker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
Copyright 2020 the Velero contributors.
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 hook

import "sync"

const (
HookSourceAnnotation = "annotation"
HookSourceSpec = "spec"
)

// hookTrackerKey identifies a backup/restore hook
type hookTrackerKey struct {
// PodNamespace indicates the namespace of pod where hooks are executed.
// For hooks specified in the backup/restore spec, this field is the namespace of an applicable pod.
// For hooks specified in pod annotation, this field is the namespace of pod where hooks are annotated.
podNamespace string
// PodName indicates the pod where hooks are executed.
// For hooks specified in the backup/restore spec, this field is an applicable pod name.
// For hooks specified in pod annotation, this field is the pod where hooks are annotated.
podName string
// HookPhase is only for backup hooks, for restore hooks, this field is empty.
hookPhase hookPhase
// HookName is only for hooks specified in the backup/restore spec.
// For hooks specified in pod annotation, this field is empty or "<from-annotation>".
hookName string
// HookSource indicates where hooks come from.
hookSource string
// Container indicates the container hooks use.
// For hooks specified in the backup/restore spec, the container might be the same under different hookName.
container string
}

// hookTrackerVal records the execution status of a specific hook.
// hookTrackerVal is extensible to accommodate additional fields as needs develop.
type hookTrackerVal struct {
// HookFailed indicates if hook failed to execute.
hookFailed bool
// hookExecuted indicates if hook already execute.
hookExecuted bool
}

// HookTracker tracks all hooks' execution status
type HookTracker struct {
lock *sync.RWMutex
tracker map[hookTrackerKey]hookTrackerVal
}

// NewHookTracker creates a hookTracker.
func NewHookTracker() *HookTracker {
return &HookTracker{
lock: &sync.RWMutex{},
tracker: make(map[hookTrackerKey]hookTrackerVal),
}
}

// Add adds a hook to the tracker
func (ht *HookTracker) Add(podNamespace, podName, container, source, hookName string, hookPhase hookPhase) {
ht.lock.Lock()
defer ht.lock.Unlock()

key := hookTrackerKey{
podNamespace: podNamespace,
podName: podName,
hookSource: source,
container: container,
hookPhase: hookPhase,
hookName: hookName,
}

if _, ok := ht.tracker[key]; !ok {
ht.tracker[key] = hookTrackerVal{
hookFailed: false,
hookExecuted: false,
}
}
}

// Record records the hook's execution status
func (ht *HookTracker) Record(podNamespace, podName, container, source, hookName string, hookPhase hookPhase, hookFailed bool) {
ht.lock.Lock()
defer ht.lock.Unlock()

key := hookTrackerKey{
podNamespace: podNamespace,
podName: podName,
hookSource: source,
container: container,
hookPhase: hookPhase,
hookName: hookName,
}

if _, ok := ht.tracker[key]; ok {
ht.tracker[key] = hookTrackerVal{
hookFailed: hookFailed,
hookExecuted: true,
}
}
}

// Stat calculates the number of attempted hooks and failed hooks
func (ht *HookTracker) Stat() (hookAttemptedCnt int, hookFailed int) {
ht.lock.RLock()
defer ht.lock.RUnlock()

for _, hookInfo := range ht.tracker {
if hookInfo.hookExecuted {
hookAttemptedCnt++
if hookInfo.hookFailed {
hookFailed++
}
}
}
return
}

// GetTracker gets the tracker inside HookTracker
func (ht *HookTracker) GetTracker() map[hookTrackerKey]hookTrackerVal {
ht.lock.RLock()
defer ht.lock.RUnlock()

return ht.tracker
}
Loading

0 comments on commit 7b95b3c

Please sign in to comment.