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

Add VolumeInfo metadata structures. #7070

Merged
merged 1 commit into from
Nov 17, 2023
Merged
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
1 change: 1 addition & 0 deletions changelogs/unreleased/7070-blackpiglet
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add VolumeInfo metadata structures.
66 changes: 30 additions & 36 deletions design/pv_backup_info.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,44 +35,50 @@ The `restoreItem` function can decode the _backup-name_-volumes-info.json file t
## Detailed Design

### The VolumeInfo structure
_backup-name_-volumes-info.json file is a structure that contains an array of structure `VolumeInfo` and a VolumeInfo version parameter. The version is used to support multiple VolumeInfo version, and make the backward-compatible support possible. The current version is `1`.
_backup-name_-volumes-info.json file is a structure that contains an array of structure `VolumeInfo`.

The 1 version of `VolumeInfo` definition is:
``` golang
type VolumeInfoV1 struct {
PVCName string // The PVC's name. The format should be <namespace-name>/<PVC-name>
type VolumeInfo struct {
PVCName string // The PVC's name.
PVCNamespace string // The PVC's namespace.
PVName string // The PV name.
BackupMethod string // The way the volume data is backed up. The valid value includes `VeleroNativeSnapshot`, `PodVolumeBackup`, `CSISnapshot` and `Skipped`.
SnapshotDataMovement bool // Whether the volume's snapshot data is moved to specified storage.
BackupMethod string // The way the volume data is backed up. The valid value includes `VeleroNativeSnapshot`, `PodVolumeBackup` and `CSISnapshot`.
blackpiglet marked this conversation as resolved.
Show resolved Hide resolved
SnapshotDataMoved bool // Whether the volume's snapshot data is moved to specified storage.

Skipped boolean // Whether the Volume is skipped in this backup.
SkippedReason string // The reason for the volume is skipped in the backup.
blackpiglet marked this conversation as resolved.
Show resolved Hide resolved
StartTimestamp *metav1.Time // Snapshot starts timestamp.

OperationID string // The Async Operation's ID.

CSISnapshotInfo CSISnapshotInfo
SnapshotDataMoveInfo SnapshotDataMoveInfo
SnapshotDataMovementInfo SnapshotDataMovementInfo
NativeSnapshotInfo VeleroNativeSnapshotInfo
PVBInfo PodVolumeBackupInfo
PVInfo PVInfo
}

// CSISnapshotInfo is used for displaying the CSI snapshot status
type CSISnapshotInfo struct {
SnapshotHandle string // The actual snapshot ID. It can be the cloud provider's snapshot ID or the file-system uploader's snapshot.
SnapshotHandle string // It's the storage provider's snapshot ID for CSI.
Size int64 // The snapshot corresponding volume size. Some of the volume backup methods cannot retrieve the data by current design, for example, the Velero native snapshot.

Driver string // The name of the CSI driver.
VSCName string // The name of the VolumeSnapshotContent.
}

// SnapshotDataMoveInfo is used for displaying the snapshot data mover status.
type SnapshotDataMoveInfo struct {
// SnapshotDataMovementInfo is used for displaying the snapshot data mover status.
type SnapshotDataMovementInfo struct {
blackpiglet marked this conversation as resolved.
Show resolved Hide resolved
DataMover string // The data mover used by the backup. The valid values are `velero` and ``(equals to `velero`).
UploaderType string // The type of the uploader that uploads the snapshot data. The valid values are `kopia` and `restic`. It's useful for file-system backup and snapshot data mover.
RetainedSnapshot string // The name or ID of the snapshot associated object(SAO).
RetainedSnapshot string // The name or ID of the snapshot associated object(SAO). SAO is used to support local snapshots for the snapshot data mover, e.g. it could be a VolumeSnapshot for CSI snapshot data moign/pv_backup_info.
SnapshotHandle string // It's the filesystem repository's snapshot ID.

}

// VeleroNativeSnapshotInfo is used for displaying the Velero native snapshot status.
type VeleroNativeSnapshotInfo struct {
SnapshotHandle string // The actual snapshot ID. It can be the cloud provider's snapshot ID or the file-system uploader's snapshot.
SnapshotHandle string // It's the storage provider's snapshot ID for the Velero-native snapshot.
Size int64 // The snapshot corresponding volume size. Some of the volume backup methods cannot retrieve the data by current design, for example, the Velero native snapshot.

VolumeType string // The cloud provider snapshot volume type.
Expand All @@ -82,33 +88,20 @@ type VeleroNativeSnapshotInfo struct {

// PodVolumeBackupInfo is used for displaying the PodVolumeBackup snapshot status.
type PodVolumeBackupInfo struct {
SnapshotHandle string // The actual snapshot ID. It can be the cloud provider's snapshot ID or the file-system uploader's snapshot.
SnapshotHandle string // It's the file-system uploader's snapshot ID for PodVolumeBackup.
Size int64 // The snapshot corresponding volume size. Some of the volume backup methods cannot retrieve the data by current design, for example, the Velero native snapshot.

UploaderType string // The type of the uploader that uploads the data. The valid values are `kopia` and `restic`. It's useful for file-system backup and snapshot data mover.
VolumeName string // The PVC's corresponding volume name used by Pod
PodName string // The Pod name mounting this PVC. The format should be <namespace-name>/<pod-name>.
}
```

To make Velero support multiple versions of VolumeInfo, Velero needs to create a structure to include the version and the versioned volume information together. The information is persisted in the metadata file during backup creation. When reading the VolumeInfo metadata file, Velero reads the version information first by un-marshalling the metadata file by structure `VolumeInfoVersion`, then decide to use which version of the VolumeInfos according to the version value.

If there is need to introduce a non compatible change to the VolumeInfo, a new version of `VolumeInfos` and `VolumeInfo` are needed. For example, version 2 is created, then `VolumeInfosV2` and `VolumeInfoV2` structures are needed.

Only when there a non-backward-compatible change introduced in the `VolumeInfo` structure, the `version`'s version will be incremented.

``` golang
type VolumeInfoVersion struct {
Version string
}

type VolumeInfosV2 struct {
Infos []VolumeInfoV2
Version string // VolumeInfo structure's version information.
VolumeName string // The PVC's corresponding volume name used by Pod: https://github.com/kubernetes/kubernetes/blob/e4b74dd12fa8cb63c174091d5536a10b8ec19d34/pkg/apis/core/types.go#L48
PodName string // The Pod name mounting this PVC. The format should be <namespace-name>/<pod-name>.
NodeName string // The PVB-taken k8s node's name.
}

type VolumeInfoV2 struct {
...
// PVInfo is used to store some PV information modified after creation.
// Those information are lost after PV recreation.
type PVInfo struct {
ReclaimPolicy string // ReclaimPolicy of PV. It could be different from the referenced StorageClass.
Labels map[string]string // The PV's labels should be kept after recreation.
}
```

Expand Down Expand Up @@ -164,11 +157,12 @@ After introducing the VolumeInfo array, the following logic will be added.
...
case CSISnapshot:
...
case Skipped:
// Check whether the Velero server should restore the PV depending on the DeletionPolicy setting.
default:
// Need to check whether the volume is backed up by the SnapshotDataMover.
if volumeInfo.SnapshotDataMovement:

// Check whether the Velero server should restore the PV depending on the DeletionPolicy setting.
if volumeInfo.Skipped:
```

### How the VolumeInfo metadata file is deleted
Expand Down
8 changes: 8 additions & 0 deletions pkg/controller/backup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,7 @@
) []error {
persistErrs := []error{}
backupJSON := new(bytes.Buffer)
volumeInfos := make([]volume.VolumeInfo, 0)

Check warning on line 852 in pkg/controller/backup_controller.go

View check run for this annotation

Codecov / codecov/patch

pkg/controller/backup_controller.go#L852

Added line #L852 was not covered by tests

if err := encode.To(backup.Backup, "json", backupJSON); err != nil {
persistErrs = append(persistErrs, errors.Wrap(err, "error encoding backup"))
Expand Down Expand Up @@ -895,6 +896,11 @@
persistErrs = append(persistErrs, errs...)
}

volumeInfoJSON, errs := encode.ToJSONGzip(volumeInfos, "backup volumes information")
if errs != nil {
persistErrs = append(persistErrs, errs...)
}

if len(persistErrs) > 0 {
// Don't upload the JSON files or backup tarball if encoding to json fails.
backupJSON = nil
Expand All @@ -906,6 +912,7 @@
csiSnapshotContentsJSON = nil
csiSnapshotClassesJSON = nil
backupResult = nil
volumeInfoJSON = nil
}

backupInfo := persistence.BackupInfo{
Expand All @@ -921,6 +928,7 @@
CSIVolumeSnapshots: csiSnapshotJSON,
CSIVolumeSnapshotContents: csiSnapshotContentsJSON,
CSIVolumeSnapshotClasses: csiSnapshotClassesJSON,
BackupVolumeInfo: volumeInfoJSON,
}
if err := backupStore.PutBackup(backupInfo); err != nil {
persistErrs = append(persistErrs, err)
Expand Down
23 changes: 22 additions & 1 deletion pkg/persistence/object_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
BackupResourceList,
CSIVolumeSnapshots,
CSIVolumeSnapshotContents,
CSIVolumeSnapshotClasses io.Reader
CSIVolumeSnapshotClasses,
BackupVolumeInfo io.Reader
}

// BackupStore defines operations for creating, retrieving, and deleting
Expand Down Expand Up @@ -270,6 +271,7 @@
s.layout.getCSIVolumeSnapshotContentsKey(info.Name): info.CSIVolumeSnapshotContents,
s.layout.getCSIVolumeSnapshotClassesKey(info.Name): info.CSIVolumeSnapshotClasses,
s.layout.getBackupResultsKey(info.Name): info.BackupResults,
s.layout.getBackupVolumeInfoKey(info.Name): info.BackupVolumeInfo,
}

for key, reader := range backupObjs {
Expand Down Expand Up @@ -491,6 +493,25 @@
return podVolumeBackups, nil
}

func (s *objectBackupStore) GetBackupVolumeInfos(name string) (*volume.VolumeInfos, error) {
var volumeInfos *volume.VolumeInfos

res, err := tryGet(s.objectStore, s.bucket, s.layout.getBackupVolumeInfoKey(name))
if err != nil {
return volumeInfos, err
}

Check warning on line 502 in pkg/persistence/object_store.go

View check run for this annotation

Codecov / codecov/patch

pkg/persistence/object_store.go#L501-L502

Added lines #L501 - L502 were not covered by tests
if res == nil {
return volumeInfos, nil
}
defer res.Close()

if err := decode(res, &volumeInfos); err != nil {
return volumeInfos, err
}

Check warning on line 510 in pkg/persistence/object_store.go

View check run for this annotation

Codecov / codecov/patch

pkg/persistence/object_store.go#L509-L510

Added lines #L509 - L510 were not covered by tests

return volumeInfos, nil
}

func (s *objectBackupStore) GetBackupContents(name string) (io.ReadCloser, error) {
return s.objectStore.GetObject(s.bucket, s.layout.getBackupContentsKey(name))
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/persistence/object_store_layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,7 @@ func (l *ObjectStoreLayout) getCSIVolumeSnapshotClassesKey(backup string) string
func (l *ObjectStoreLayout) getBackupResultsKey(backup string) string {
return path.Join(l.subdirs["backups"], backup, fmt.Sprintf("%s-results.gz", backup))
}

func (l *ObjectStoreLayout) getBackupVolumeInfoKey(backup string) string {
return path.Join(l.subdirs["backups"], backup, fmt.Sprintf("%s-volumeinfos.json.gz", backup))
}
Loading
Loading