Compare commits

..

197 Commits

Author SHA1 Message Date
Xun Jiang/Bruce Jiang
7d8417b2c5 Merge pull request #7466 from allenxu404/release-1.12
Add changelogs for v1.12.4
2024-02-26 16:51:01 +08:00
Qi Xu
26ca08b1f5 Merge branch 'vmware-tanzu:release-1.12' into release-1.12 2024-02-26 16:28:22 +08:00
Daniel Jiang
dd5f74d53e Merge pull request #7469 from blackpiglet/7464_fix_release_1.12
[release-1.12]Modify the label used by the restore CLI to filter the PVR.
2024-02-26 14:07:16 +08:00
Xun Jiang/Bruce Jiang
dcdc32f16f Merge branch 'release-1.12' into 7464_fix_release_1.12 2024-02-26 11:11:18 +08:00
Xun Jiang
5b07cbb97f Modify the label used by the restore CLI to filter the PVR.
Signed-off-by: Xun Jiang <blackpigletbruce@gmail.com>
2024-02-26 10:49:00 +08:00
allenxu404
a3bb4d2947 Add changelogs for v1.12.4
Signed-off-by: allenxu404 <qix2@vmware.com>
2024-02-26 10:43:37 +08:00
Wenkai Yin(尹文开)
d71b298ceb Merge pull request #7454 from blackpiglet/bump_grpc_for_restic_in_release-1.12
Bump the Restic's gRPC version in go.mod to fix CVEs.
2024-02-21 16:57:56 +08:00
Xun Jiang
9e35ecd47a Bump the Restic's gRPC version in go.mod to fix CVEs.
Bump crypto version to fix CVE-2023-48795.

Signed-off-by: Xun Jiang <blackpigletbruce@gmail.com>
2024-02-21 16:20:05 +08:00
lyndon-li
341d8006af Merge pull request #7397 from kaovilai/restic-recreate-repo-vel1.12
release-1.12: BackupRepositories associated with a BSL are invalidated when BSL is (re-)created. (#7380)
2024-02-20 10:50:34 +08:00
Tiger Kaovilai
e0b437e2e1 BackupRepositories associated with a BSL are invalidated when BSL is (re-)created. (#7380)
* Add BackupRepositories invalidation on BSL Create
Simplify comments

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>

* Simplify

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>

---------

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2024-02-06 11:00:45 -05:00
Wenkai Yin(尹文开)
5f32403968 Merge pull request #7350 from ywk253100/240124_informer_1.12
[cherry-pick]Check whether the API resource exists before creating the informer cache
2024-01-25 09:50:31 +08:00
Wenkai Yin(尹文开)
4d1c20bbab Check whether the API resource exists before creating the informer cache
Check whether the API resource exists before creating the informer cache

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2024-01-24 12:39:05 +08:00
Wenkai Yin(尹文开)
3c379edcd0 Merge pull request #7341 from ywk253100/240122_log_error_1.12
[cherry-pick]Log the error got from the discovery helper
2024-01-23 09:59:53 +08:00
Wenkai Yin(尹文开)
7295609bd6 Log the error got from the discovery helper
Log the error got from the discovery helper

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2024-01-22 15:25:26 +08:00
Wenkai Yin(尹文开)
21667a14b4 Merge pull request #7337 from ywk253100/240122_cherrypick_1.12
[cherry-pick]Do not attempt restore resource with no available GVK in cluster
2024-01-22 10:51:53 +08:00
Tiger Kaovilai
bd0ea3a648 Do not attempt restore resource with no available GVK in cluster (#7322)
Check for GVK before attempting restore.

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2024-01-22 10:05:33 +08:00
Wenkai Yin(尹文开)
509ceaafbf Specify the Kind explicitly in the API resource
Specify the Kind explicitly in the API resource to avoid wrong Kind conversion

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2024-01-22 10:04:54 +08:00
Daniel Jiang
cd9b5ed37b Merge pull request #7298 from ywk253100/240110_informer_cache
[cherry-pick]Make "disable-informer-cache" option false(enabled) by default to keep it consistent with the help message
2024-01-18 15:24:56 +08:00
Wenkai Yin(尹文开)
1cc6f74341 Make "disable-informer-cache" option false(enabled) by default to keep it consistent with the help message
Make "disable-informer-cache" option false(enabled) by default to keep it consi
stent with the help message

Fixes #7264

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2024-01-18 13:20:33 +08:00
Daniel Jiang
50a12217e4 Merge pull request #7327 from ywk253100/240118_informer_1.12
[cherry-pick]Create informer per resources to avoid huge memory consumption
2024-01-18 13:16:28 +08:00
Wenkai Yin(尹文开)
85189a0dc6 Create informer per resources to avoid huge memory consumption
Create informer per resources to avoid huge memory consumption

Fixes #7323

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2024-01-18 10:48:55 +08:00
Xun Jiang/Bruce Jiang
c3aecbb761 Merge pull request #7042 from shubham-pampattiwar/add-desc-markers-1.12-rel
Add description markers for dataupload and datadownload CRDs (#7028)
2024-01-17 15:34:02 +08:00
Xun Jiang/Bruce Jiang
6886ff6643 Merge branch 'release-1.12' into add-desc-markers-1.12-rel 2024-01-17 14:50:23 +08:00
Wenkai Yin(尹文开)
165cd5e908 Merge pull request #7280 from danfengliu/fix-backup-deletion-snapshot-throttle-issue
Add sleep to avoid snapshot throttle issue
2024-01-16 15:39:11 +08:00
danfengl
ce00387ccf Add sleep to avoid AWS snapshot throttle issue
1. Add sleep in backup deletion E2E test to avoid AWS snapshot throttle issue: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html#:~:text=SnapshotCreationPerVolumeRateExceeded;
2. Support CSI snapshot checkpoint for EKS pipeline.

Signed-off-by: danfengl <danfengl@vmware.com>
2024-01-16 06:00:35 +00:00
Wenkai Yin(尹文开)
684f71306e Merge pull request #7299 from allenxu404/release-1.12
Modify changelog for v1.12.3
2024-01-10 13:05:00 +08:00
allenxu404
805ec1d3a6 Modify changelog for v1.12.3
Signed-off-by: allenxu404 <qix2@vmware.com>
2024-01-10 12:52:01 +08:00
Xun Jiang/Bruce Jiang
4d544ac3bb Merge pull request #7289 from allenxu404/release-1.12
Add v1.12.3 changelog
2024-01-09 10:44:00 +08:00
Xun Jiang/Bruce Jiang
5a178b88d1 Merge branch 'release-1.12' into release-1.12 2024-01-09 10:31:41 +08:00
allenxu404
03bad256b0 Add v1.12.3 changelog
Signed-off-by: allenxu404 <qix2@vmware.com>
2024-01-09 10:12:22 +08:00
Wenkai Yin(尹文开)
cf7074f943 Merge pull request #7283 from Lyndon-Li/release-1.12
[1.12] Issue 6928: remove snapshot deletion timeout for PVB
2024-01-08 13:49:43 +08:00
Lyndon-Li
0722927df2 isue 6928: remove snapshot deletion timeout for PVB
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2024-01-08 13:01:47 +08:00
qiuming
106e802f1e Merge pull request #7273 from qiuming-best/cp-intermediate-pv-delete
[Cherry-Pick 1.12] Fix intermediate pv delete for data mover
2024-01-04 16:33:52 +08:00
Ming Qiu
9a093a7b75 Fix intermediate pv delete for data mover
Signed-off-by: Ming Qiu <mqiu@vmware.com>
2024-01-04 07:47:51 +00:00
qiuming
09ff5af208 Merge pull request #7267 from qiuming-best/node-agent-recoverability
[Cherry-Pick 1.12] Node agent restart enhancement
2024-01-04 10:04:22 +08:00
qiuming
1da7f30fba Merge branch 'release-1.12' into node-agent-recoverability 2024-01-04 09:42:54 +08:00
Wenkai Yin(尹文开)
dd2553916e Merge pull request #7266 from qiuming-best/data-mover-recoverability
[Cherry-Pick 1.12] Don't fail backup/restore on velero server restart in PhaseWaitingFor…
2024-01-03 20:13:39 +08:00
Ming Qiu
6ff9dfab33 Node agent restart enhancement
Signed-off-by: Ming Qiu <mqiu@vmware.com>
2024-01-03 09:48:27 +00:00
Anshul Ahuja
c3b5b1fadd Don't fail backup/restore on velero server restart in PhaseWaitingForPluginOperation
Signed-off-by: Anshul Ahuja <anshulahuja@microsoft.com>
2024-01-03 09:28:36 +00:00
Shubham Pampattiwar
568e5bf04a Merge pull request #7247 from Lyndon-Li/release-1.12
[1.12] Issue 7244: delete incomplete snapshot automatically for kopia uploader
2023-12-22 10:47:32 -08:00
Lyndon-Li
5ff8a4f2a3 Issue 7244: delete incomplete snapshot automatically for kopia uploader
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-12-22 17:02:02 +08:00
Lyndon-Li
33e3c9589b issue 7244: delete incomplete snapshot automatically for kopia uploader
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-12-22 16:48:32 +08:00
Xun Jiang/Bruce Jiang
ee7b60f723 Merge pull request #7202 from blackpiglet/7163_fix_release_1.12
Fix csiVolumeSnapshotsAttempted/Completed metrics issue on release-1.12
2023-12-18 20:43:46 +08:00
Xun Jiang
ecb8e80f30 Fix issue #7163.
Update CSIVolumeSnapshotsCompleted in backup's status and the metric
during backup finalize stage according to async operations content.

Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-12-18 15:59:40 +08:00
lyndon-li
a80981524b Merge pull request #7203 from Lyndon-Li/release-1.12
[1.12] Issue 7189: generic restore - don't assume the first volume as the restore volume
2023-12-13 09:58:55 +08:00
Lyndon-Li
5e71b38993 issue 7189: generic restore - don't assume the first volume as the restore volume
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-12-12 19:19:06 +08:00
Anshul Ahuja
06d12dec40 RM support for Escaped bool, float, null (#7118) (#7131)
* RM support for Escaped bool, float, null



* fix ci



---------

Signed-off-by: Anshul Ahuja <anshul.ahu@gmail.com>
2023-11-23 10:59:49 +05:30
Xun Jiang/Bruce Jiang
b68486221d Merge pull request #7126 from allenxu404/release-1.12
Add v1.12.2 changelog
2023-11-20 16:49:22 +08:00
allenxu404
5abd318b2c Add v1.12.2 changelog
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-11-20 16:35:06 +08:00
danfengliu
7c051514fd Merge pull request #7111 from kaovilai/backup-patch-status-unittest-release-1.12
release-1.12: Update Backup.Status.CSIVolumeSnapshotsCompleted during finalize
2023-11-17 14:19:13 +08:00
Tiger Kaovilai
c8fd9d4d62 revert test changes
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
ccfbcc5455 make update
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
ea25b8a793 update changelog to reflect removed waits
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
2d6578635d CSIFeatureFlag enable check
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
fc44f3b8f0 remove waiting during finalize
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
df72745909 skip this if SnapshotMoveData
https://github.com/vmware-tanzu/velero/pull/7046/files#r1380708644
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
453bd93c90 refactor backup snapshot status updates into UpdateBackupSnapshotsStatus() and run in backup_finalizer_controller
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
Tiger Kaovilai
65939c920e Add PatchResource unit test for backup status
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-17 10:45:35 +08:00
lyndon-li
c042d477ab Merge pull request #7049 from 27149chen/cherry-pick-6917
Cherry-pick #6917 to release 1.12
2023-11-17 09:33:37 +08:00
Guang Jiong Lou
5c44ed49a5 Merge branch 'release-1.12' into cherry-pick-6917 2023-11-17 09:21:40 +08:00
lyndon-li
3325a0cd1b Merge pull request #7114 from Lyndon-Li/release-1.12
Issue 7068: add a finalizer to protect retained VSC
2023-11-17 09:20:33 +08:00
Guang Jiong Lou
b2d3fa0bec Merge branch 'release-1.12' into cherry-pick-6917 2023-11-17 09:17:19 +08:00
Lyndon-Li
25fc2f4d6e Issue 7068: add a finalizer to protect retained VSC
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-11-16 18:53:34 +08:00
Wenkai Yin(尹文开)
a036e8d463 Merge pull request #7110 from allenxu404/release-1.12
Bump up Velero base image to latest patch release
2023-11-16 16:00:29 +08:00
allenxu404
f92cdb1f76 Bump up Velero base image to latest patch release
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-11-16 15:03:52 +08:00
Guang Jiong Lou
0531dbb1a2 Merge branch 'release-1.12' into cherry-pick-6917 2023-11-16 10:38:11 +08:00
lou
de55794381 update changelog
Signed-off-by: lou <alex1988@outlook.com>
2023-11-15 17:24:02 +08:00
Wenkai Yin(尹文开)
d7b4b0a770 Merge pull request #6917 from 27149chen/rm-improvement
support JSON Merge Patch and Strategic Merge Patch in Resource Modifiers

Signed-off-by: lou <alex1988@outlook.com>
2023-11-15 17:20:15 +08:00
qiuming
f1c93bd6c4 Merge pull request #7098 from allenxu404/release-1.12
[Cherry-pick][release-1.12]Fix node-agent metrics missing
2023-11-14 17:50:45 +08:00
yanggang
06e3773b22 Fix node-agent missing metrics-addr parms to define the server start.
Signed-off-by: yanggang <gang.yang@daocloud.io>
2023-11-14 16:27:43 +08:00
Wenkai Yin(尹文开)
32a8bbb9ac Merge pull request #7097 from Lyndon-Li/release-1.12
[1.12] Issue 7094: fallback to full backup if previous snapshot is not found
2023-11-14 13:20:11 +08:00
Lyndon-Li
84d8bbda24 issue 7094: fallback to full backup if previous snapshot is not found
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-11-14 11:48:44 +08:00
qiuming
86e34eec28 Merge pull request #7087 from blackpiglet/cherry_pick_7061_to_1.12
[Cherry-pick][release-1.12]Add DataUpload Result and CSI VolumeSnapshot check for restore PV.
2023-11-13 10:51:05 +08:00
Xun Jiang
5923046471 Add DataUpload Result and CSI VolumeSnapshot check for restore PV.
Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-11-11 11:44:01 +08:00
qiuming
d1399225da Merge pull request #7058 from ywk253100/231106_file
Truncate the credential file to avoid the change of secret content messing it up
2023-11-08 09:21:01 +08:00
lyndon-li
88732e9b51 Merge branch 'release-1.12' into add-desc-markers-1.12-rel 2023-11-08 07:59:02 +08:00
Shubham Pampattiwar
dd9de76381 add description markers for dataupload and datadownload CRDs (#7028)
add changelog file

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>
(cherry picked from commit 23921e5d29)

rename changelog file

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

fix PR CI validation errors

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>
2023-11-07 06:52:05 -08:00
Wenkai Yin(尹文开)
6438fc9a69 Truncate the credential file to avoid the change of secret content messing it up
Truncate the credential file to avoid the change of secret content messing it up

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2023-11-06 17:18:00 +08:00
qiuming
a674a1eaff Merge pull request #7060 from Lyndon-Li/release-1.12
[1.12] Issue 7027: backup exposer -- don't assume first volume as the backup volume
2023-11-06 17:16:18 +08:00
Lyndon-Li
bb4f9094fd issue 7027: backup exposer -- don't assume first volume as the backup volume
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-11-06 16:59:34 +08:00
lyndon
1264c438c1 Merge pull request #7054 from kaovilai/warnOnCreateAlreadyExistsGetError-release-1.12
release-1.12: restore: Use warning when Create IsAlreadyExist and Get error (#7004)
2023-11-06 14:23:13 +08:00
Tiger Kaovilai
7e35fd3261 restore: Use warning when Create IsAlreadyExist and Get error (#7004)
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-11-02 16:05:50 -04:00
lyndon
482ec13d38 Merge pull request #7033 from ywk253100/231030_azure
Read information from the credential specified by BSL
2023-10-31 11:59:31 +08:00
Wenkai Yin(尹文开)
dd825ef8bb Read information from the credential specified by BSL
Read information from the credential specified by BSL

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2023-10-30 17:29:43 +08:00
lyndon
dc525aa045 Merge pull request #7025 from shubham-pampattiwar/cp-fix-ducr-cancel
[cherry-pick release-1.12] Fix issue 6913
2023-10-27 11:07:25 +08:00
lyndon
36ad5dafa9 Merge branch 'release-1.12' into cp-fix-ducr-cancel
Signed-off-by: lyndon <98304688+Lyndon-Li@users.noreply.github.com>
2023-10-27 10:47:38 +08:00
Anshul Ahuja
7b76047596 Make configmapref check case insensitive (#6804) (#7023)
* Make configmapref check case insensitive



* update resourcemodfier test case to validate case



---------

Signed-off-by: Anshul Ahuja <anshul.ahu@gmail.com>
Signed-off-by: Anshul Ahuja <anshulahuja@microsoft.com>
Co-authored-by: Anshul Ahuja <anshulahuja@microsoft.com>
2023-10-26 16:40:43 -04:00
Shubham Pampattiwar
f1fcec3514 Fix issue 6913
Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

add changelog file

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

keep canceling phase const

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

fix data download as well

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

address PR feedback

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

minor fixes

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>
(cherry picked from commit ee271b7b69)

update changelog filename

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>
2023-10-26 07:50:58 -07:00
Xun Jiang/Bruce Jiang
17ad487803 Merge pull request #7020 from kaovilai/CVE-2023-44487-gRPC-Go-release-1.12
release-1.12: CVE-2023-44487 gRPC-Go HTTP/2 Rapid Reset vulnerability
2023-10-26 17:19:31 +08:00
Tiger Kaovilai
bb6c1f60ea CVE-2023-44487 gRPC-Go HTTP/2 Rapid Reset vulnerability
`go get google.golang.org/grpc@v1.56.3 && go mod tidy`

https://github.com/grpc/grpc-go/security/advisories/GHSA-m425-mq94-257g
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-10-26 02:23:15 -04:00
qiuming
0be6ad3a06 Merge pull request #7019 from danfengliu/update-testbed-matrix-1.12.1
Update testbed matrix for v1.12.1
2023-10-26 14:21:18 +08:00
danfengl
1c462d5f6d Update testbed matrix for v1.12.1
Signed-off-by: danfengl <danfengl@vmware.com>
2023-10-26 02:51:26 +00:00
Shubham Pampattiwar
32deef7ae3 Merge pull request #6997 from kaovilai/kopias3profilecred-1.12
release-1.12: kopia/repository/config/aws.go: Set session.Options profile from config
2023-10-25 04:44:35 -07:00
Tiger Kaovilai
72b5e7aad6 kopia/repository/config/aws.go: Set session.Options profile from config
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-10-24 21:51:07 -04:00
Xun Jiang/Bruce Jiang
5c4fdfe147 Merge pull request #6993 from allenxu404/release-1.12
Change v1.12.1 changelog
2023-10-20 21:04:47 +08:00
allenxu404
226237bab4 Change v1.12.1 changelog
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-10-20 20:50:12 +08:00
Xun Jiang/Bruce Jiang
bbc9790316 Merge pull request #6991 from Lyndon-Li/release-1.12
[1.12] Issue 6988: udmrepo use region specified in BSL when s3URL is empty
2023-10-20 20:32:29 +08:00
Lyndon-Li
10744ec516 udmrepo use region specified in BSL when s3URL is empty
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-10-20 20:14:01 +08:00
lyndon
905cd43140 Merge pull request #6986 from blackpiglet/support_windows_build
Add both non-Windows version and Windows version code for PVC block mode logic
2023-10-20 19:37:05 +08:00
Xun Jiang
3034cdb448 Make Windows build skip BlockMode code.
PVC block mode backup and restore introduced some OS specific
system calls. Those calls are not available for Windows, so
add both non Windows version and Windows version code, and
return error for block mode on the Windows platform.

Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-10-20 17:44:38 +08:00
Xun Jiang/Bruce Jiang
353ff55e42 Merge pull request #6984 from allenxu404/release-1.12
Add v1.12.1 changelog
2023-10-20 12:00:11 +08:00
allenxu404
468017d7db Add v1.12.1 changelog
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-10-20 11:18:27 +08:00
lyndon
6bf705fd25 Merge pull request #6970 from ywk253100/231018_auth
[cherry-pick]Import auth provider plugins
2023-10-18 16:48:58 +08:00
Sebastian Glab
7a909d8ff5 Import auth provider plugins
Signed-off-by: Sebastian Glab <sglab@catalogicsoftware.com>
2023-10-18 16:06:18 +08:00
lyndon
ef1b9816b2 Merge pull request #6943 from sseago/retry-generateName1.12
[release-1.12]: CP issue #6807: Retry failed create when using generateName
2023-10-16 11:09:21 +08:00
Scott Seago
457fcc6893 issue #6807: Retry failed create when using generateName
When creating resources with generateName, apimachinery
does not guarantee uniqueness when it appends the random
suffix to the generateName stub, so if it fails with
already exists error, we need to retry.

Signed-off-by: Scott Seago <sseago@redhat.com>
2023-10-13 10:29:46 -04:00
Wenkai Yin(尹文开)
b498847b5b Merge pull request #6951 from blackpiglet/fix_CVE-2023-39325
Fix CVE-2023-39325.
2023-10-13 18:22:45 +08:00
Xun Jiang
af9697814e Fix CVE-2023-39325.
Bump Velero and Restic golang.org/x/net to v0.17.0.
Bump golang version to v1.20.10.

Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-10-13 14:22:18 +08:00
lyndon
d92a051795 Merge pull request #6948 from sseago/restore-get-perf1.12
[release-1.120: CP Perf improvements for existing resource restore
2023-10-13 08:13:50 +08:00
Scott Seago
a3cb39d62e Perf improvements for existing resource restore
Use informer cache with dynamic client for Get calls on restore
When enabled, also make the Get call before create.

Add server and install parameter to allow disabling this feature,
but enable by default

Signed-off-by: Scott Seago <sseago@redhat.com>
2023-10-12 15:07:55 -04:00
Shubham Pampattiwar
c1ace31466 Merge pull request #6940 from Lyndon-Li/release-1.12
[1.12] Issue 6647: add default-snapshot-move-data parameter to Velero install
2023-10-11 08:54:35 -07:00
Lyndon-Li
8bf98e8895 fix issue 6647
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-10-11 17:43:38 +08:00
Xun Jiang/Bruce Jiang
e53cfdf85e Merge pull request #6887 from allenxu404/release-1.12
Add docs link for new features to release note
2023-10-10 16:55:30 +08:00
allenxu404
d93cc9094a Add doc links for new features to release note
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-10-10 16:05:11 +08:00
lyndon
15dd67e203 Merge pull request #6935 from Lyndon-Li/release-1.12
[1.12] Issue 6734: spread backup pod evenly
2023-10-10 11:41:37 +08:00
Lyndon-Li
877592194b issue 6734: spread backup pod evenly
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-10-10 11:04:04 +08:00
Wenkai Yin(尹文开)
17b495fcfd Merge pull request #6934 from ywk253100/231010_image
[cherry-pick]Replace the base image with paketobuildpacks image
2023-10-10 10:32:14 +08:00
Wenkai Yin(尹文开)
b99a59480d Replace the base image with paketobuildpacks image
Replace the base image with paketobuildpacks image

Fixes #6851

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2023-10-10 09:38:54 +08:00
qiuming
a789976a03 Merge pull request #6925 from qiuming-best/target-v1.12.1
[Cherry-pick v1.12]Keep the logs info ns/name same with other modules
2023-10-08 11:23:52 +08:00
qiuming
52878de077 Merge branch 'release-1.12' into target-v1.12.1 2023-10-08 11:08:07 +08:00
yanggang
432a5fe566 [Cherry-pick v1.12]Keep the logs info ns/name is the same with other modules.
Signed-off-by: yanggang <gang.yang@daocloud.io>
2023-10-08 03:07:43 +00:00
Xun Jiang/Bruce Jiang
175047baa9 Merge pull request #6912 from blackpiglet/6750_cherry_pick
[cherry-pick][release-1.12]Code clean for backup cmd client. (#6750)
2023-10-08 11:05:06 +08:00
Yang Gang
0eaf14ed19 Code clean for backup cmd client. (#6750)
Address some code spell check errors.

Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-10-03 23:55:25 +08:00
David Zaninovic
c415fd4bcc Add support for block volumes (#6680) (#6897)
(cherry picked from commit 8e01d1b9be)

Signed-off-by: David Zaninovic <dzaninovic@catalogicsoftware.com>
2023-09-29 15:28:35 -04:00
Shubham Pampattiwar
554403df5c Merge pull request #6713 from kaovilai/jobs-label-k8s1.27-velero1.12
release-1.12: On restore, delete Kubernetes 1.27 job controller uid label
2023-09-29 11:49:32 -07:00
Tiger Kaovilai
aba64ba151 Remove legacy label version check, to be added back when version is known
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-09-29 12:27:29 -04:00
Tiger Kaovilai
3a410c9f04 changelog
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-09-29 12:27:29 -04:00
Tiger Kaovilai
2f92f78be5 Handle 1.27 k8s job label changes
per  0e86fa5115/CHANGELOG/CHANGELOG-1.27.md (L1768)

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-09-29 12:27:29 -04:00
Shubham Pampattiwar
9d5dd8e09d Merge pull request #6899 from sseago/pvb-start-logs
[release-1.12] cherry-pick Fix some wrong logs and code clean.
2023-09-29 09:27:01 -07:00
yanggang
6103073551 Fix some wrong logs and code clean.
Signed-off-by: yanggang <gang.yang@daocloud.io>
2023-09-28 13:27:51 -04:00
Xun Jiang/Bruce Jiang
83f892d81f Add go clean in Dockerfile and action. (#6896)
Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-09-28 10:20:48 -04:00
Wenkai Yin(尹文开)
2cd15f1e4b Merge pull request #6892 from reasonerjt/cp-6768-1.12
[Cherry-pick v1.12] code clean for repository (#6768)
2023-09-28 17:56:59 +08:00
Yang Gang (成都)
27a89df34d code clean for repository (#6768)
Signed-off-by: Yang Gang (成都) <gang.yang@daocloud.io>
2023-09-28 16:51:22 +08:00
lyndon
e4c2b2b157 Merge pull request #6886 from Lyndon-Li/release-1.12
[1.12] Issue 6880: set ParallelUploadAboveSize as MaxInt64
2023-09-28 15:15:53 +08:00
Lyndon-Li
edefe7a63b issue 6880: set ParallelUploadAboveSize as MaxInt64
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-28 14:26:46 +08:00
Wenkai Yin(尹文开)
a097094bcf Merge pull request #6881 from ywk253100/230927_cherry_pick
Add 'orLabelSelector' for backup, restore command
2023-09-28 07:21:13 +08:00
Wenkai Yin(尹文开)
bc4dc6c0c8 Rename the changelog
Rename the changelog

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2023-09-27 20:16:48 +08:00
Nilesh Akhade
343e54f1b8 Add 'orLabelSelector' for backup, restore command
Signed-off-by: Nilesh Akhade <nakhade@catalogicsoftware.com>
2023-09-27 20:13:48 +08:00
lyndon
08d44b02a8 Merge pull request #6877 from Lyndon-Li/release-1.12
[1.12] Issue: 6859 move plugin depdending podvolume functions to util pkg
2023-09-27 17:46:48 +08:00
Lyndon-Li
a8c76a4a00 issue: move plugin depdending podvolume functions to util pkg
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-27 11:29:02 +08:00
lyndon
0623ac363a Merge pull request #6873 from Lyndon-Li/release-1.12
[1.12] Issue 6786:always delete VSC regardless of the deletion policy
2023-09-26 20:56:50 +08:00
Lyndon-Li
1aea12a80c issue 6786:always delete VSC regardless of the deletion policy
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-26 15:53:05 +08:00
Xun Jiang/Bruce Jiang
7112c62e49 Merge pull request #6842 from allenxu404/release-1.12
Modify changelogs for v1.12
2023-09-19 17:53:28 +08:00
allenxu404
dcb891a307 Modify changelogs for v1.12
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-09-19 17:36:36 +08:00
lyndon
21353f00a8 Merge pull request #6841 from Lyndon-Li/release-1.12
[1.12] Doc for multiple snapshot class
2023-09-19 16:45:26 +08:00
Lyndon-Li
5e7114899b doc for multiple snapshot class
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-19 16:28:28 +08:00
Wenkai Yin(尹文开)
b035680ce6 Set data mover related properties for schedule (#6823)
Set data mover related properties for schedule

Fixes #6820

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2023-09-14 18:04:48 +08:00
lyndon
9eb133e635 Merge pull request #6821 from reasonerjt/update-kopia-repo-1.12
[cherrypick-1.12]Switch the kopia repo to new org
2023-09-14 11:53:12 +08:00
Daniel Jiang
6f1262d4c6 Switch the kopia repo to new org
Signed-off-by: Daniel Jiang <jiangd@vmware.com>
2023-09-14 11:19:43 +08:00
lyndon
48e3278c6c Merge pull request #6814 from allenxu404/release-1.12
[Cherry-pick]Add doc changes after rc1 to v1.12 docs
2023-09-14 10:25:23 +08:00
Qi Xu
acfc6e474f Add doc changes after rc1 to v1.12 docs (#6812)
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-09-13 18:43:00 +08:00
qiuming
993d2c775f Merge pull request #6803 from qiuming-best/finalizer-optimize
Optimize of removing dataupload datadownload finalizer
2023-09-12 15:44:21 +08:00
qiuming
b70b01cde9 Merge branch 'release-1.12' into finalizer-optimize 2023-09-12 15:00:58 +08:00
Anshul Ahuja
8b8a5a2bcc use old namespace in resource modifier (#6724) (#6794)
* use old namespace in resource modifier



* add changelog



* update docs



* updated after review



---------

Signed-off-by: lou <alex1988@outlook.com>
Signed-off-by: Anshul Ahuja <anshulahuja@microsoft.com>
Co-authored-by: Guang Jiong Lou <7991675+27149chen@users.noreply.github.com>
Co-authored-by: Daniel Jiang <jiangd@vmware.com>
2023-09-12 14:54:03 +08:00
qiuming
5b36cd7e83 Merge branch 'release-1.12' into finalizer-optimize 2023-09-12 11:57:07 +08:00
Ming Qiu
3240fb196c Optimize of removing finalizer no matter the dataupload datadownload cr is been deleted or not
Signed-off-by: Ming Qiu <mqiu@vmware.com>
2023-09-12 11:55:44 +08:00
Daniel Jiang
d9859d99ba Merge pull request #6793 from Lyndon-Li/release-1.12
[1.12] Add csi snapshot data mover doc
2023-09-08 18:09:31 +08:00
Lyndon-Li
18d4fe45e8 add csi snapshot data movement doc
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-08 17:51:49 +08:00
qiuming
60d5bb22f7 Merge pull request #6791 from Lyndon-Li/release-1.12
[1.12] Fix issue 6785
2023-09-08 16:32:39 +08:00
Lyndon-Li
9468b8cfa9 fix issue 6785
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-08 15:18:02 +08:00
lyndon
420562111b Merge pull request #6789 from Lyndon-Li/release-1.12
[1.12] Fix issue 6748 [2]
2023-09-08 15:15:19 +08:00
lyndon
cf0b2e9139 Merge branch 'release-1.12' into release-1.12 2023-09-08 14:57:03 +08:00
lyndon
506415e60c Merge pull request #6787 from kaovilai/fsb-yaml-example-r1.12
cherry-pick: r1.12: Show yaml example of repository password: file-system-backup.md #6783
2023-09-08 12:53:42 +08:00
Lyndon-Li
3733a40637 fix issue 6748
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-08 09:53:00 +08:00
Tiger Kaovilai
fe1ade0226 Show yaml example of repository password: file-system-backup.md
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
2023-09-07 11:54:10 -04:00
Xun Jiang/Bruce Jiang
86e1a74937 Merge pull request #6778 from allenxu404/release-1.12
[cherry-pick] add note for backup repository password configuration
2023-09-07 10:25:05 +08:00
Shubham Pampattiwar
6260a44e62 add note for backup repository password configuration
Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

address PR feedback

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

reword the note

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>

change FS backups to normal backups in the note

Signed-off-by: Shubham Pampattiwar <spampatt@redhat.com>
2023-09-06 17:58:57 +08:00
Xun Jiang/Bruce Jiang
06d9bfae8d Merge pull request #6762 from blackpiglet/6750_fix_1.12
[cherry-pick][release-1.12]Fix #6752: add namespace exclude check.
2023-09-06 15:44:09 +08:00
Xun Jiang
4d1617470f Fix #6752: add namespace exclude check.
Add PSA audit and warn labels.

Signed-off-by: Xun Jiang <jxun@vmware.com>
2023-09-06 15:28:17 +08:00
lyndon
1b2c82c9eb Merge pull request #6772 from Lyndon-Li/release-1.12
[1.12] Fix issue 6748
2023-09-06 11:21:19 +08:00
Lyndon-Li
040060082a fix issue 6748
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-06 10:37:47 +08:00
Wenkai Yin(尹文开)
fc653bdfbe Update restore controller logic for restore deletion (#6761)
1. Skip deleting the restore files from storage if the backup/BSL is not found
2. Allow deleting the restore files from storage even though the BSL is readonly

Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
2023-09-06 08:38:45 +08:00
lyndon
6790a18814 Merge pull request #6758 from Lyndon-Li/release-1.12
[1.12] Fix issue 6753
2023-09-05 11:06:55 +08:00
Lyndon-Li
93995bfd00 fix issue 6753
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-05 10:44:58 +08:00
lyndon
80572934dc Merge pull request #6743 from Lyndon-Li/release-1.12-1
[1.12] Fix issue 6733
2023-09-01 18:40:11 +08:00
lyndon
41d9b67945 Merge branch 'release-1.12' into release-1.12-1 2023-09-01 18:22:05 +08:00
lyndon
a06107ac70 Merge pull request #6742 from Lyndon-Li/release-1.12
[1.12] Fix issue 6709
2023-09-01 18:18:27 +08:00
lyndon
40a94e39ad Merge branch 'release-1.12' into release-1.12-1 2023-09-01 18:07:13 +08:00
lyndon
7ea0d434d6 Merge branch 'release-1.12' into release-1.12 2023-09-01 17:53:16 +08:00
qiuming
6b884ecc39 Merge pull request #6740 from qiuming-best/release-1.12
Fix kopia snapshot policy not work
2023-09-01 17:43:36 +08:00
Lyndon-Li
183f7ac154 fix issue 6733
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-01 17:30:52 +08:00
lyndon
75bda412a1 fix issue 6709 (#6741)
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-09-01 17:12:31 +08:00
Ming Qiu
a2eb10df8f Fix kopia snapshot policy not work
Signed-off-by: Ming Qiu <mqiu@vmware.com>
2023-09-01 16:34:02 +08:00
Daniel Jiang
90bc1abd21 Merge pull request #6725 from anshulahuja98/cherrypick-6704
[1.12] Cherry Pick - add label selector in Resource Modifiers  (#6704)
2023-08-31 15:59:34 +08:00
Guang Jiong Lou
45165503ba add label selector in Resource Modifiers (#6704)
* add label selector in resource modifier

Signed-off-by: lou <alex1988@outlook.com>

* add ut

Signed-off-by: lou <alex1988@outlook.com>

* update after review

Signed-off-by: lou <alex1988@outlook.com>

* update after review

Signed-off-by: lou <alex1988@outlook.com>

---------

Signed-off-by: lou <alex1988@outlook.com>
Signed-off-by: Anshul Ahuja <anshulahuja@microsoft.com>
2023-08-31 10:52:03 +05:30
qiuming
53530130a5 Fix velero uninstall bug (#6720)
Signed-off-by: Ming <mqiu@vmware.com>
2023-08-30 17:54:30 +08:00
danfengliu
ed256d74dd Merge pull request #6708 from danfengliu/cherry-pick-fix-nightly-issues
[cherry-pick to v1.12] monitor velero logs and fix E2E issues
2023-08-29 15:40:18 +08:00
Xun Jiang/Bruce Jiang
ab28a09a07 Merge branch 'release-1.12' into cherry-pick-fix-nightly-issues 2023-08-29 10:17:53 +08:00
qiuming
90f4cc5497 Merge pull request #6707 from qiuming-best/mqiu-release-1.12
make Velero uninstall backward compatible
2023-08-29 09:03:37 +08:00
qiuming
f505ed709b Merge branch 'release-1.12' into mqiu-release-1.12 2023-08-28 17:31:48 +08:00
Ming
28074e3f37 make velero uninstall backward compatible
Signed-off-by: Ming <mqiu@vmware.com>
2023-08-28 09:31:29 +00:00
danfengl
240f33c09d monitor velero logs and fix E2E issues
1. Capture Velero pod log and K8S cluster event;
2. Fix wrong path of storageclass yaml file issue caused by pert test;
3. Fix change storageclass test issue that no sc named 'default' in EKS cluster;
4. Support AWS credential as config format;
5. Support more E2E script input parameters like standy cluster plugins and provider.

Signed-off-by: danfengl <danfengl@vmware.com>
2023-08-28 06:04:09 +00:00
lyndon
fd08848471 fix issue 6391 (#6703)
Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
2023-08-25 16:36:45 +08:00
qiuming
5f585be24b Merge pull request #6701 from qiuming-best/mqiu-release-1.12
[CherryPick v1.12] Fix delete dataupload datadownload CR failure
2023-08-25 11:45:33 +08:00
Ming
5480acf0a0 [CherryPick v1.12] Fix delete dataupload datadownload failure when Velero uninstall
Signed-off-by: Ming <mqiu@vmware.com>
2023-08-25 03:24:40 +00:00
Daniel Jiang
e2d3e84bab skip subresource in resource discovery (#6688)
Signed-off-by: lou <alex1988@outlook.com>
Co-authored-by: lou <alex1988@outlook.com>
2023-08-23 15:13:34 +08:00
Qi Xu
0c0ccf949b Ping golang/distroless image to latest version (#6679)
Signed-off-by: allenxu404 <qix2@vmware.com>
2023-08-18 19:17:50 +08:00
844 changed files with 7625 additions and 54674 deletions

View File

@@ -16,7 +16,6 @@ reviewers:
- qiuming-best
- shubham-pampattiwar
- Lyndon-Li
- anshulahuja98
tech-writer:
- sseago

View File

@@ -1,14 +1,5 @@
version: 2
updates:
# Dependencies listed in .github/workflows
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "Dependencies"
- "github_actions"
- "kind/changelog-not-required"
# Dependencies listed in go.mod
- package-ecosystem: "gomod"
directory: "/" # Location of package manifests

33
.github/labeler.yml vendored
View File

@@ -1,33 +0,0 @@
# This file is used by Auto Label PRs action.
# Works with https://github.com/actions/labeler/
# Below this line, the keys are labels to be applied, and the values are the file globs to match against.
# Anything in the `design` directory gets the `Design` label.
Area/Design:
- changed-files:
- any-glob-to-any-file: design/*
# Anything that has plugin infra will be labeled.
# Individual plugins don't necessarily live here, though
Area/Plugins:
- changed-files:
- any-glob-to-any-file: pkg/plugins/**/*
Dependencies:
- changed-files:
- any-glob-to-any-file: go.mod
Documentation:
- changed-files:
- any-glob-to-any-file: site/content/docs/**/*
# Anything in the site directory gets the website label *EXCEPT* docs
Website:
- all:
- changed-files:
- any-glob-to-any-file: site/**/*
- all-globs-to-all-files: '!site/content/docs/**/*'
has-changelog:
- changed-files:
- any-glob-to-any-file: changelogs/**
has-e2e-2tests:
- changed-files:
- any-glob-to-any-file: test/e2e/**/*
has-unit-tests:
- changed-files:
- any-glob-to-any-file: pkg/**/*_test.go

43
.github/labels.yaml vendored
View File

@@ -1,43 +0,0 @@
# This file is used by [prow github action](https://github.com/jpmcb/prow-github-actions/) in .github/workflows/prow-action.yml.
# This file only has values for kind and area commands.
area:
- CLI
- CSI
- Cloud/AWS
- Cloud/Azure
- Cloud/DigitalOcean
- Cloud/GCP
- Cloud/vSphere
- Design
- Documentation
- Filters
- Plugins
- Process
- Storage/Minio
- Storage/Cinder
- WindowsSupport
- datamover
- fs-backup
- fs-backup/deletion
- fs-backup/file-selectable
- fs-uploader
- kopia-integration
- migration
- multi-tenancy
- progress-monitoring
- resilience
- schedule
- storage/IBM-ObjectStorage
- upgrade
- volume-snapshot-dm
kind:
- changelog-not-required
- question
- refactor
- requirement
- release-note
- release-blocker
- spike
- tech-debt
- usage-error
- voting

41
.github/labels.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
area:
- "Cloud/AWS"
- "Cloud/GCP"
- "Cloud/Azure"
- "Design"
- "Plugins"
# Labels that can be applied to PRs with the /kind command
kind:
- "changelog-not-required"
- "tech-debt"
# Works with https://github.com/actions/labeler/
# Below this line, the keys are labels to be applied, and the values are the file globs to match against.
# Anything in the `design` directory gets the `Design` label.
Area/Design:
- design/*
# Anything in the site directory gets the website label *EXCEPT* docs
Website:
- any: ["site/**/*", "!site/content/docs/**/*"]
Documentation:
- site/content/docs/**/*
Dependencies:
- go.mod
# Anything that has plugin infra will be labeled.
# Individual plugins don't necessarily live here, though
Area/Plugins:
- "pkg/plugins/**/*"
has-unit-tests:
- "pkg/**/*_test.go"
has-e2e-2tests:
- "test/e2e/**/*"
has-changelog:
- "changelogs/**"

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set the author of a PR as the assignee
uses: kentaro-m/auto-assign-action@v2.0.0
uses: kentaro-m/auto-assign-action@v1.1.1
with:
configuration-path: ".github/auto-assignees.yml"
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -13,7 +13,7 @@ jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v3
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/labeler.yml
configuration-path: .github/labels.yml

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Request a PR review based on files types/paths, and/or groups the author belongs to
uses: necojackarc/auto-request-review@v0.13.0
uses: necojackarc/auto-request-review@v0.7.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: .github/auto-assignees.yml

View File

@@ -12,14 +12,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22.6'
go-version: '1.20.10'
id: go
# Look for a CLI that's made for this PR
- name: Fetch built CLI
id: cache
uses: actions/cache@v4
uses: actions/cache@v2
env:
cache-name: cache-velero-cli
with:
@@ -31,7 +31,7 @@ jobs:
velero-${{ github.event.pull_request.number }}-
- name: Fetch cached go modules
uses: actions/cache@v4
uses: actions/cache@v2
if: steps.cache.outputs.cache-hit != 'true'
with:
path: ~/go/pkg/mod
@@ -40,7 +40,7 @@ jobs:
${{ runner.os }}-go-
- name: Check out the code
uses: actions/checkout@v4
uses: actions/checkout@v2
if: steps.cache.outputs.cache-hit != 'true'
# If no binaries were built for this PR, build it now.
@@ -57,19 +57,19 @@ jobs:
matrix:
# Latest k8s versions. There's no series-based tag, nor is there a latest tag.
k8s:
- 1.23.17
- 1.24.17
- 1.25.16
- 1.26.13
- 1.27.10
- 1.28.6
- 1.29.1
- 1.19.7
- 1.20.2
- 1.21.1
- 1.22.0
- 1.23.6
- 1.24.2
- 1.25.3
# All steps run in parallel unless otherwise specified.
# See https://docs.github.com/en/actions/learn-github-actions/managing-complex-workflows#creating-dependent-jobs
steps:
- name: Fetch built CLI
id: cache
uses: actions/cache@v4
uses: actions/cache@v2
env:
cache-name: cache-velero-cli
with:
@@ -81,7 +81,7 @@ jobs:
velero-${{ github.event.pull_request.number }}-
- uses: engineerd/setup-kind@v0.5.0
with:
version: "v0.21.0"
version: "v0.17.0"
image: "kindest/node:v${{ matrix.k8s }}"
- name: Install CRDs
run: |

View File

@@ -12,27 +12,27 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22.6'
go-version: '1.20.10'
id: go
# Look for a CLI that's made for this PR
- name: Fetch built CLI
id: cli-cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ./_output/bin/linux/amd64/velero
# The cache key a combination of the current PR number and the commit SHA
key: velero-cli-${{ github.event.pull_request.number }}-${{ github.sha }}
- name: Fetch built image
id: image-cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ./velero.tar
# The cache key a combination of the current PR number and the commit SHA
key: velero-image-${{ github.event.pull_request.number }}-${{ github.sha }}
- name: Fetch cached go modules
uses: actions/cache@v4
uses: actions/cache@v2
if: steps.cli-cache.outputs.cache-hit != 'true'
with:
path: ~/go/pkg/mod
@@ -40,7 +40,7 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Check out the code
uses: actions/checkout@v4
uses: actions/checkout@v2
if: steps.cli-cache.outputs.cache-hit != 'true' || steps.image-cache.outputs.cache-hit != 'true'
# If no binaries were built for this PR, build it now.
- name: Build Velero CLI
@@ -60,48 +60,38 @@ jobs:
strategy:
matrix:
k8s:
- 1.23.17
- 1.24.17
- 1.25.16
- 1.26.13
- 1.27.10
- 1.28.6
- 1.29.1
focus:
# tests to focus on, use `|` to concatenate multiple regexes to run on the same job
# ordered according to e2e_suite_test.go order
- Basic\]\[ClusterResource
- ResourceFiltering
- ResourceModifier|Backups|PrivilegesMgmt\]\[SSR
- Schedule\]\[OrderedResources
- NamespaceMapping\]\[Single\]\[Restic|NamespaceMapping\]\[Multiple\]\[Restic
- Basic\]\[Nodeport
- Basic\]\[StorageClass
- 1.19.16
- 1.20.15
- 1.21.12
- 1.22.9
- 1.23.6
- 1.24.0
- 1.25.3
fail-fast: false
steps:
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22.6'
go-version: '1.20.10'
id: go
- name: Check out the code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install MinIO
run:
docker run -d --rm -p 9000:9000 -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -e "MINIO_DEFAULT_BUCKETS=bucket,additional-bucket" bitnami/minio:2021.6.17-debian-10-r7
- uses: engineerd/setup-kind@v0.5.0
with:
version: "v0.21.0"
version: "v0.17.0"
image: "kindest/node:v${{ matrix.k8s }}"
- name: Fetch built CLI
id: cli-cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ./_output/bin/linux/amd64/velero
key: velero-cli-${{ github.event.pull_request.number }}-${{ github.sha }}
- name: Fetch built Image
id: image-cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ./velero.tar
key: velero-image-${{ github.event.pull_request.number }}-${{ github.sha }}
@@ -110,7 +100,7 @@ jobs:
kind load image-archive velero.tar
# always try to fetch the cached go modules as the e2e test needs it either
- name: Fetch cached go modules
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@@ -133,13 +123,12 @@ jobs:
CREDS_FILE=/tmp/credential BSL_BUCKET=bucket \
ADDITIONAL_OBJECT_STORE_PROVIDER=aws ADDITIONAL_BSL_CONFIG=region=minio,s3ForcePathStyle="true",s3Url=http://$(hostname -i):9000 \
ADDITIONAL_CREDS_FILE=/tmp/credential ADDITIONAL_BSL_BUCKET=additional-bucket \
GINKGO_FOCUS='${{ matrix.focus }}' VELERO_IMAGE=velero:pr-test \
GINKGO_SKIP='SKIP_KIND|pv-backup|Restic|Snapshot|LongTime' \
make -C test/ run-e2e
GINKGO_FOCUS='Basic\]\[ClusterResource' VELERO_IMAGE=velero:pr-test \
make -C test/e2e run
timeout-minutes: 30
- name: Upload debug bundle
if: ${{ failure() }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: DebugBundle
path: /home/runner/work/velero/velero/test/e2e/debug-bundle*

View File

@@ -19,7 +19,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
@@ -31,6 +31,6 @@ jobs:
output: 'trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'

View File

@@ -12,7 +12,7 @@ jobs:
steps:
- name: Check out the code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Changelog check
if: ${{ !(contains(github.event.pull_request.labels.*.name, 'kind/changelog-not-required') || contains(github.event.pull_request.labels.*.name, 'Design') || contains(github.event.pull_request.labels.*.name, 'Website') || contains(github.event.pull_request.labels.*.name, 'Documentation'))}}

View File

@@ -8,14 +8,14 @@ jobs:
fail-fast: false
steps:
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22.6'
go-version: '1.20.10'
id: go
- name: Check out the code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Fetch cached go modules
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@@ -24,7 +24,7 @@ jobs:
- name: Make ci
run: make ci
- name: Upload test coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.out

View File

@@ -8,14 +8,14 @@ jobs:
steps:
- name: Check out the code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Codespell
uses: codespell-project/actions-codespell@master
with:
# ignore the config/.../crd.go file as it's generated binary data that is edited elswhere.
skip: .git,*.png,*.jpg,*.woff,*.ttf,*.gif,*.ico,./config/crd/v1beta1/crds/crds.go,./config/crd/v1/crds/crds.go,./config/crd/v2alpha1/crds/crds.go,./go.sum,./LICENSE
ignore_words_list: iam,aks,ist,bridget,ue,shouldnot,atleast,notin,sme
ignore_words_list: iam,aks,ist,bridget,ue,shouldnot,atleast
check_filenames: true
check_hidden: true

View File

@@ -13,18 +13,18 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
name: Checkout
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v1
with:
version: latest

View File

@@ -14,7 +14,7 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
name: Checkout
- name: Verify .goreleaser.yml and try a dryrun release.

View File

@@ -6,15 +6,9 @@ jobs:
name: Run Linter Check
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
id: go
- name: Linter check
uses: golangci/golangci-lint-action@v6
with:
version: v1.57.2
args: --verbose
- name: Check out the code
uses: actions/checkout@v2
- name: Linter check
run: make lint

View File

@@ -9,21 +9,12 @@ jobs:
execute:
runs-on: ubuntu-latest
steps:
- uses: jpmcb/prow-github-actions@v1.1.3
- uses: jpmcb/prow-github-actions@v1.1.2
with:
# Only support /kind command for now.
# TODO: before allowing the /lgtm command, see if we can block merging if changelog labels are missing.
prow-commands: |
/approve
/area
/assign
/cc
/close
/hold
prow-commands: "/area
/kind
/milestone
/retitle
/remove
/reopen
/uncc
/unassign
/cc
/uncc"
github-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
# The default value is "1" which fetches only a single commit. If we merge PR without squash or rebase,
# there are at least two commits: the first one is the merge commit and the second one is the real commit

View File

@@ -16,39 +16,34 @@ jobs:
steps:
- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v4
with:
go-version: '1.22.6'
go-version: '1.20.10'
id: go
- uses: actions/checkout@v4
- uses: actions/checkout@v3
# Fix issue of setup-gcloud
- run: |
sudo apt-get install python2.7
export CLOUDSDK_PYTHON="/usr/bin/python2"
- id: 'auth'
uses: google-github-actions/auth@v2
- uses: google-github-actions/setup-gcloud@v0
with:
credentials_json: '${{ secrets.GCS_SA_KEY }}'
- name: 'set up GCloud SDK'
uses: google-github-actions/setup-gcloud@v2
- name: 'use gcloud CLI'
run: |
gcloud info
version: '285.0.0'
service_account_key: ${{ secrets.GCS_SA_KEY }}
export_default_credentials: true
- run: gcloud info
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v1
with:
version: latest
@@ -62,14 +57,14 @@ jobs:
run: make test
- name: Upload test coverage
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.out
verbose: true
# Use the JSON key in secret to login gcr.io
- uses: 'docker/login-action@v3'
- uses: 'docker/login-action@v2'
with:
registry: 'gcr.io' # or REGION.docker.pkg.dev
username: '_json_key'
@@ -81,7 +76,7 @@ jobs:
run: |
sudo swapoff -a
sudo rm -f /mnt/swapfile
docker system prune -a --force
docker image prune -a --force
# Build and push Velero image to docker registry
docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -9,10 +9,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@v4
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.8
uses: cirrus-actions/rebase@1.3.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -7,7 +7,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9.0.0
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 14 days. If a Velero team member has requested log or more information, please provide the output of the shared commands."

View File

@@ -16,7 +16,6 @@ If you're using Velero and want to add your organization to this list,
<a href="https://mayadata.io/" border="0" target="_blank"><img alt="mayadata.io" src="site/static/img/adopters/mayadata.svg" height="50"></a>&nbsp; &nbsp; &nbsp;
<a href="https://www.replicated.com/" border="0" target="_blank"><img alt="replicated.com" src="site/static/img/adopters/replicated-logo-red.svg" height="50"></a>
<a href="https://cloudcasa.io/" border="0" target="_blank"><img alt="cloudcasa.io" src="site/static/img/adopters/cloudcasa.svg" height="50"></a>
<a href="https://azure.microsoft.com/" border="0" target="_blank"><img alt="azure.com" src="site/static/img/adopters/azure.svg" height="50"></a>
## Success Stories
Below is a list of adopters of Velero in **production environments** that have
@@ -63,10 +62,7 @@ Okteto integrates Velero in [Okteto Cloud][94] and [Okteto Enterprise][95] to pe
Replicated uses the Velero open source project to enable snapshots in [KOTS][101] to backup Kubernetes manifests & persistent volumes. In addition to the default functionality that Velero provides, [KOTS][101] provides a detailed interface in the [Admin Console][102] that can be used to manage the storage destination and schedule, and to perform and monitor the backup and restore process.<br>
**[CloudCasa][103]**<br>
[Catalogic Software][104] integrates Velero with [CloudCasa][103] - A Smart Home in the Cloud for Backups. CloudCasa is a full-featured, scalable, cloud-native solution providing Kubernetes data protection, disaster recovery, and migration as a service. An option to manage existing Velero instances and an enterprise self-hosted option are also available.<br>
**[Microsoft Azure][105]**<br>
[Azure Backup for AKS][106] is an Azure native, Kubernetes aware, Enterprise ready backup for containerized applications deployed on Azure Kubernetes Service (AKS). AKS Backup utilizes Velero to perform backup and restore operations to protect stateful applications in AKS clusters.<br>
[Catalogic Software][104] integrates Velero with [CloudCasa][103] - A Smart Home in the Cloud for Backups. CloudCasa is a simple, scalable, cloud-native solution providing data protection and disaster recovery as a service. This solution is built using Kubernetes for protecting Kubernetes clusters.<br>
## Adding your organization to the list of Velero Adopters
@@ -122,6 +118,3 @@ If you would like to add your logo to a future `Adopters of Velero` section on [
[103]: https://cloudcasa.io/
[104]: https://www.catalogicsoftware.com/
[105]: https://azure.microsoft.com/
[106]: https://learn.microsoft.com/azure/backup/backup-overview

View File

@@ -1,10 +1,7 @@
## Current release:
* [CHANGELOG-1.14.md][24]
* [CHANGELOG-1.11.md][21]
## Older releases:
* [CHANGELOG-1.13.md][23]
* [CHANGELOG-1.12.md][22]
* [CHANGELOG-1.11.md][21]
* [CHANGELOG-1.10.md][20]
* [CHANGELOG-1.9.md][19]
* [CHANGELOG-1.8.md][18]
@@ -27,9 +24,6 @@
* [CHANGELOG-0.3.md][1]
[24]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.14.md
[23]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.13.md
[22]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.12.md
[21]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.11.md
[20]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.10.md
[19]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.9.md

View File

@@ -5,7 +5,7 @@
We as members, contributors, and leaders pledge to make participation in the Velero project and our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socioeconomic status,
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

View File

@@ -13,7 +13,7 @@
# limitations under the License.
# Velero binary build section
FROM --platform=$BUILDPLATFORM golang:1.22.6-bookworm as velero-builder
FROM --platform=$BUILDPLATFORM golang:1.20.10-bullseye as velero-builder
ARG GOPROXY
ARG BIN
@@ -47,7 +47,7 @@ RUN mkdir -p /output/usr/bin && \
go clean -modcache -cache
# Restic binary build section
FROM --platform=$BUILDPLATFORM golang:1.22.6-bookworm as restic-builder
FROM --platform=$BUILDPLATFORM golang:1.20.10-bullseye as restic-builder
ARG BIN
ARG TARGETOS
@@ -70,7 +70,7 @@ RUN mkdir -p /output/usr/bin && \
go clean -modcache -cache
# Velero image packing section
FROM paketobuildpacks/run-jammy-tiny:0.2.46
FROM paketobuildpacks/run-jammy-tiny:0.2.11
LABEL maintainer="Xun Jiang <jxun@vmware.com>"

View File

@@ -4,16 +4,16 @@
## Maintainers
| Maintainer | GitHub ID | Affiliation |
|---------------------|---------------------------------------------------------------|--------------------------------------------------|
| Scott Seago | [sseago](https://github.com/sseago) | [OpenShift](https://github.com/openshift) |
| Daniel Jiang | [reasonerjt](https://github.com/reasonerjt) | [VMware](https://www.github.com/vmware/) |
| Wenkai Yin | [ywk253100](https://github.com/ywk253100) | [VMware](https://www.github.com/vmware/) |
| Xun Jiang | [blackpiglet](https://github.com/blackpiglet) | [VMware](https://www.github.com/vmware/) |
| Ming Qiu | [qiuming-best](https://github.com/qiuming-best) | [VMware](https://www.github.com/vmware/) |
| Shubham Pampattiwar | [shubham-pampattiwar](https://github.com/shubham-pampattiwar) | [OpenShift](https://github.com/openshift) |
| Yonghui Li | [Lyndon-Li](https://github.com/Lyndon-Li) | [VMware](https://www.github.com/vmware/) |
| Anshul Ahuja | [anshulahuja98](https://github.com/anshulahuja98) | [Microsoft Azure](https://www.github.com/azure/) |
| Maintainer | GitHub ID | Affiliation |
|---------------------|---------------------------------------------------------------|-------------------------------------------|
| Dave Smith-Uchida | [dsu-igeek](https://github.com/dsu-igeek) | [Kasten](https://github.com/kastenhq/) |
| Scott Seago | [sseago](https://github.com/sseago) | [OpenShift](https://github.com/openshift) |
| Daniel Jiang | [reasonerjt](https://github.com/reasonerjt) | [VMware](https://www.github.com/vmware/) |
| Wenkai Yin | [ywk253100](https://github.com/ywk253100) | [VMware](https://www.github.com/vmware/) |
| Xun Jiang | [blackpiglet](https://github.com/blackpiglet) | [VMware](https://www.github.com/vmware/) |
| Ming Qiu | [qiuming-best](https://github.com/qiuming-best) | [VMware](https://www.github.com/vmware/) |
| Shubham Pampattiwar | [shubham-pampattiwar](https://github.com/shubham-pampattiwar) | [OpenShift](https://github.com/openshift) |
| Yonghui Li | [Lyndon-Li](https://github.com/Lyndon-Li) | [VMware](https://www.github.com/vmware/) |
## Emeritus Maintainers
* Adnan Abdulhussein ([prydonius](https://github.com/prydonius))
@@ -25,12 +25,12 @@
* Carlisia Thompson ([carlisia](https://github.com/carlisia))
* Bridget McErlean ([zubron](https://github.com/zubron))
* JenTing Hsiao ([jenting](https://github.com/jenting))
* Dave Smith-Uchida ([dsu-igeek](https://github.com/dsu-igeek))
## Velero Contributors & Stakeholders
| Feature Area | Lead |
|------------------------|:------------------------------------------------------------------------------------:|
| Architect | Dave Smith-Uchida [dsu-igeek](https://github.com/dsu-igeek) |
| Technical Lead | Daniel Jiang [reasonerjt](https://github.com/reasonerjt) |
| Kubernetes CSI Liaison | |
| Deployment | |

View File

@@ -74,18 +74,8 @@ else
GCR_IMAGE_TAGS ?= $(GCR_IMAGE):$(VERSION)
endif
# check buildx is enabled
# macOS/Windows docker cli without Docker Desktop license: https://github.com/abiosoft/colima
# To add buildx to docker cli: https://github.com/abiosoft/colima/discussions/273#discussioncomment-2684502
ifeq ($(shell docker buildx inspect 2>/dev/null | awk '/Status/ { print $$2 }'), running)
BUILDX_ENABLED ?= true
# if emulated docker cli from podman, assume enabled
# emulated docker cli from podman: https://podman-desktop.io/docs/migrating-from-docker/emulating-docker-cli-with-podman
# podman known issues:
# - on remote podman, such as on macOS,
# --output issue: https://github.com/containers/podman/issues/15922
else ifeq ($(shell cat $(shell which docker) | grep -c "exec podman"), 1)
BUILDX_ENABLED ?= true
else
BUILDX_ENABLED ?= false
endif
@@ -118,7 +108,6 @@ platform_temp = $(subst -, ,$(ARCH))
GOOS = $(word 1, $(platform_temp))
GOARCH = $(word 2, $(platform_temp))
GOPROXY ?= https://proxy.golang.org
GOBIN=$$(pwd)/.go/bin
# If you want to build all binaries, see the 'all-build' rule.
# If you want to build all containers, see the 'all-containers' rule.
@@ -140,7 +129,6 @@ local: build-dirs
# Add DEBUG=1 to enable debug locally
GOOS=$(GOOS) \
GOARCH=$(GOARCH) \
GOBIN=$(GOBIN) \
VERSION=$(VERSION) \
REGISTRY=$(REGISTRY) \
PKG=$(PKG) \
@@ -157,7 +145,6 @@ _output/bin/$(GOOS)/$(GOARCH)/$(BIN): build-dirs
$(MAKE) shell CMD="-c '\
GOOS=$(GOOS) \
GOARCH=$(GOARCH) \
GOBIN=$(GOBIN) \
VERSION=$(VERSION) \
REGISTRY=$(REGISTRY) \
PKG=$(PKG) \
@@ -370,11 +357,11 @@ gen-docs:
.PHONY: test-e2e
test-e2e: local
$(MAKE) -e VERSION=$(VERSION) -C test/ run-e2e
$(MAKE) -e VERSION=$(VERSION) -C test/e2e run
.PHONY: test-perf
test-perf: local
$(MAKE) -e VERSION=$(VERSION) -C test/ run-perf
$(MAKE) -e VERSION=$(VERSION) -C test/perf run
go-generate:
go generate ./pkg/...

24
OWNERS
View File

@@ -1,24 +0,0 @@
# This file is used by the [PROW action](https://github.com/jpmcb/prow-github-actions) to approve and merge PRs.
# The file's format follows the [OWNERS SPEC](https://www.kubernetes.dev/docs/guide/owners/#owners-spec).
# List of usernames who may use /lgtm
reviewers:
- @Lyndon-Li
- @anshulahuja98
- @blackpiglet
- @qiuming-best
- @reasonerjt
- @shubham-pampattiwar
- @sseago
- @ywk253100
# List of usernames who may use /approve
approvers:
- @Lyndon-Li
- @anshulahuja98
- @blackpiglet
- @qiuming-best
- @reasonerjt
- @shubham-pampattiwar
- @sseago
- @ywk253100

View File

@@ -40,17 +40,17 @@ See [the list of releases][6] to find out about feature changes.
The following is a list of the supported Kubernetes versions for each Velero version.
| Velero version | Expected Kubernetes version compatibility | Tested on Kubernetes version |
|----------------|-------------------------------------------|-------------------------------------|
| 1.14 | 1.18-latest | 1.27.9, 1.28.9, and 1.29.4 |
| 1.13 | 1.18-latest | 1.26.5, 1.27.3, 1.27.8, and 1.28.3 |
| 1.12 | 1.18-latest | 1.25.7, 1.26.5, 1.26.7, and 1.27.3 |
| 1.11 | 1.18-latest | 1.23.10, 1.24.9, 1.25.5, and 1.26.1 |
| 1.10 | 1.18-latest | 1.22.5, 1.23.8, 1.24.6 and 1.25.1 |
| Velero version | Expected Kubernetes version compatibility | Tested on Kubernetes version |
|----------------|-------------------------------------------|----------------------------------------|
| 1.12 | 1.18-latest | 1.25.7, 1.26.5, 1.27.6 and 1.28.0 |
| 1.11 | 1.18-latest | 1.23.10, 1.24.9, 1.25.5, and 1.26.1 |
| 1.10 | 1.18-latest | 1.22.5, 1.23.8, 1.24.6 and 1.25.1 |
| 1.9 | 1.18-latest | 1.20.5, 1.21.2, 1.22.5, 1.23, and 1.24 |
| 1.8 | 1.18-latest | |
Velero supports IPv4, IPv6, and dual stack environments. Support for this was tested against Velero v1.8.
The Velero maintainers are continuously working to expand testing coverage, but are not able to test every combination of Velero and supported Kubernetes versions for each Velero release. The table above is meant to track the current testing coverage and the expected supported Kubernetes versions for each Velero version.
The Velero maintainers are continuously working to expand testing coverage, but are not able to test every combination of Velero and supported Kubernetes versions for each Velero release. The table above is meant to track the current testing coverage and the expected supported Kubernetes versions for each Velero version. If you have a question about test coverage before v1.9, please reach out in the [#velero-users](https://kubernetes.slack.com/archives/C6VCGP4MT) Slack channel.
If you are interested in using a different version of Kubernetes with a given Velero version, we'd recommend that you perform testing before installing or upgrading your environment. For full information around capabilities within a release, also see the Velero [release notes](https://github.com/vmware-tanzu/velero/releases) or Kubernetes [release notes](https://github.com/kubernetes/kubernetes/tree/master/CHANGELOG). See the Velero [support page](https://velero.io/docs/latest/support-process/) for information about supported versions of Velero.

View File

@@ -52,7 +52,7 @@ git_sha = str(local("git rev-parse HEAD", quiet = True, echo_off = True)).strip(
tilt_helper_dockerfile_header = """
# Tilt image
FROM golang:1.22.6 as tilt-helper
FROM golang:1.20.10 as tilt-helper
# Support live reloading with Tilt
RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \

View File

@@ -1,3 +1,122 @@
## v1.12.4
### 2024-02-26
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.12.4
### Container Image
`velero/velero:v1.12.4`
### Documentation
https://velero.io/docs/v1.12/
### Upgrading
https://velero.io/docs/v1.12/upgrade-to-1.12/
### All changes
* BackupRepositories associated with a BSL are invalidated when BSL is (re-)created. (#7397, @kaovilai)
* Check resource Group Version and Kind is available in cluster before attempting restore to prevent being stuck. (#7337, @kaovilai)
* Make "disable-informer-cache" option false(enabled) by default to keep it consistent with the help message (#7298, @ywk253100)
* Add description markers for dataupload and datadownload CRDs (#7042, @shubham-pampattiwar)
## v1.12.3
### 2024-01-09
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.12.3
### Container Image
`velero/velero:v1.12.3`
### Documentation
https://velero.io/docs/v1.12/
### Upgrading
https://velero.io/docs/v1.12/upgrade-to-1.12/
### All changes
* Fix issue #7244. By the end of the upload, check the outstanding incomplete snapshots and delete them by calling ApplyRetentionPolicy (#7247, @Lyndon-Li)
* Fix issue #7189, data mover generic restore - don't assume the first volume as the restore volume (#7203, @Lyndon-Li)
* Update CSIVolumeSnapshotsCompleted in backup's status and the metric
during backup finalize stage according to async operations content. (#7202, @blackpiglet)
* Node agent restart enhancement (#7130, @qiuming-best)
* Fix issue #6928, remove snapshot deletion timeout for PVB (#7283, @Lyndon-Li)
## v1.12.2
### 2023-11-20
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.12.2
### Container Image
`velero/velero:v1.12.2`
### Documentation
https://velero.io/docs/v1.12/
### Upgrading
https://velero.io/docs/v1.12/upgrade-to-1.12/
### All changes
* Fix issue #7068, due to a behavior of CSI external snapshotter, manipulations of VS and VSC may not be handled in the same order inside external snapshotter as the API is called. So add a protection finalizer to ensure the order (#7114, @Lyndon-Li)
* Update Backup.Status.CSIVolumeSnapshotsCompleted during finalize (#7111, @kaovilai)
* Cherry-pick #6917 - Support JSON Merge Patch and Strategic Merge Patch in Resource Modifiers (#7049, @27149chen)
* Bump up Velero base image to latest patch release (#7110, @allenxu404)
* Fix the node-agent missing metrics-address defines. (#7098, @yanggangtony)
* Fix issue #7094, fallback to full backup if previous snapshot is not found (#7097, @Lyndon-Li)
* Add DataUpload Result and CSI VolumeSnapshot check for restore PV. (#7087, @blackpiglet)
* Fix issue #7027, data mover backup exposer should not assume the first volume as the backup volume in backup pod (#7060, @Lyndon-Li)
* Truncate the credential file to avoid the change of secret content messing it up (#7058, @ywk253100)
* restore: Use warning when Create IsAlreadyExist and Get error (#7054, @kaovilai)
* Read information from the credential specified by BSL (#7033, @ywk253100)
* Fix issue 6913: Velero Built-in Datamover: Backup stucks in phase WaitingForPluginOperations when Node Agent pod gets restarted (#7025, @shubham-pampattiwar)
* Fix unified repository (kopia) s3 credentials profile selection (#6997, @kaovilai)
## v1.12.1
### 2023-10-20
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.12.1
### Container Image
`velero/velero:v1.12.1`
### Documentation
https://velero.io/docs/v1.12/
### Upgrading
https://velero.io/docs/v1.12/upgrade-to-1.12/
### Highlights
#### Data Mover Adds Support for Block Mode Volumes
For PersistentVolumes with volumeMode set as Block, the volumes are mounted as raw block devices in pods, in 1.12.1, Velero CSI snapshot data movement supports to backup and restore this kind of volumes under linux based Kubernetes clusters.
#### New Parameter in Installation to Enable Data Mover
The `velero install` sub-command now includes a new parameter,`--default-snapshot-move-data`, which configures Velero server to move data by default for all snapshots supporting data movement. This feature is useful for users who will always want to use VBDM for backups instead of plain CSI , as they no longer need to specify the `--snapshot-move-data` flag for each individual backup.
#### Velero Base Image change
The base image previously used by Velero was `distroless`, which contains several CVEs cannot be addressed quickly. As a result, Velero will now use `paketobuildpacks` image starting from this new version.
### Limitations/Known issues
* The data mover's support for block mode volumes is currently only applicable to Linux environments.
### All changes
* Import auth provider plugins (#6970, @0x113)
* Perf improvements for existing resource restore (#6948, @sseago)
* Retry failed create when using generateName (#6943, @sseago)
* Fix issue #6647, add the --default-snapshot-move-data parameter to Velero install, so that users don't need to specify --snapshot-move-data per backup when they want to move snapshot data for all backups (#6940, @Lyndon-Li)
* Partially fix #6734, guide Kubernetes' scheduler to spread backup pods evenly across nodes as much as possible, so that data mover backup could achieve better parallelism (#6935, @Lyndon-Li)
* Replace the base image with paketobuildpacks image (#6934, @ywk253100)
* Add support for block volumes with Kopia (#6897, @dzaninovic)
* Set ParallelUploadAboveSize as MaxInt64 and flush repo after setting up policy so that policy is retrieved correctly by TreeForSource (#6886, @Lyndon-Li)
* Kubernetes 1.27 new job label batch.kubernetes.io/controller-uid are deleted during restore per https://github.com/kubernetes/kubernetes/pull/114930 (#6713, @kaovilai)
* Add `orLabelSelectors` for backup, restore commands (#6881, @nilesh-akhade)
* Fix issue #6859, move plugin depending podvolume functions to util pkg, so as to remove the dependencies to unnecessary repository packages like kopia, azure, etc. (#6877, @Lyndon-Li)
* Fix issue #6786, always delete VSC regardless of the deletion policy (#6873, @Lyndon-Li)
* Fix #6988, always get region from BSL if it is not empty (#6991, @Lyndon-Li)
* Add both non-Windows version and Windows version code for PVC block mode logic. (#6986, @blackpiglet)
## v1.12
### 2023-08-18
@@ -23,17 +142,17 @@ CSI Snapshot Data Movement is useful in below scenarios:
* For on-premises users, the storage usually doesn't support durable snapshots, so it is impossible/less efficient/cost ineffective to keep volume snapshots by the storage This feature helps to move the snapshot data to a storage with lower cost and larger scale for long time preservation.
* For public cloud users, this feature helps users to fulfill the multiple cloud strategy. It allows users to back up volume snapshots from one cloud provider and preserve or restore the data to another cloud provider. Then users will be free to flow their business data across cloud providers based on Velero backup and restore
CSI Snapshot Data Movement is built according to the Volume Snapshot Data Movement design ([Volume Snapshot Data Movement](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md)). More details can be found in the design.
CSI Snapshot Data Movement is built according to the Volume Snapshot Data Movement design ([Volume Snapshot Data Movement design](https://github.com/vmware-tanzu/velero/blob/main/design/volume-snapshot-data-movement/volume-snapshot-data-movement.md)). Additionally, guidance on how to use the feature can be found in the Volume Snapshot Data Movement doc([Volume Snapshot Data Movement doc](https://velero.io/docs/v1.12/csi-snapshot-data-movement)).
#### Resource Modifiers
In many use cases, customers often need to substitute specific values in Kubernetes resources during the restoration process like changing the namespace, changing the storage class, etc.
To address this need, Resource Modifiers (also known as JSON Substitutions) offer a generic solution in the restore workflow. It allows the user to define filters for specific resources and then specify a JSON patch (operator, path, value) to apply to the resource. This feature simplifies the process of making substitutions without requiring the implementation of a new RestoreItemAction plugin. More details can be found in Volume Snapshot Resource Modifiers design ([Resource Modifiers](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/json-substitution-action-design.md)).
To address this need, Resource Modifiers (also known as JSON Substitutions) offer a generic solution in the restore workflow. It allows the user to define filters for specific resources and then specify a JSON patch (operator, path, value) to apply to the resource. This feature simplifies the process of making substitutions without requiring the implementation of a new RestoreItemAction plugin. More design details can be found in Resource Modifiers design ([Resource Modifiers design](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/json-substitution-action-design.md)). For instructions on how to use the feature, please refer to Resource Modifiers doc([Resource Modifiers doc](https://velero.io/docs/v1.12/restore-resource-modifiers)).
#### Multiple VolumeSnapshotClasses
Prior to version 1.12, the Velero CSI plugin would choose the VolumeSnapshotClass in the cluster based on matching driver names and the presence of the "velero.io/csi-volumesnapshot-class" label. However, this approach proved inadequate for many user scenarios.
With the introduction of version 1.12, Velero now offers support for multiple VolumeSnapshotClasses in the CSI Plugin, enabling users to select a specific class for a particular backup. More details can be found in Multiple VolumeSnapshotClasses design ([Multiple VolumeSnapshotClasses](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/multiple-csi-volumesnapshotclass-support.md)).
With the introduction of version 1.12, Velero now offers support for multiple VolumeSnapshotClasses in the CSI Plugin, enabling users to select a specific class for a particular backup. More design details can be found in Multiple VolumeSnapshotClasses design ([Multiple VolumeSnapshotClasses design](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/multiple-csi-volumesnapshotclass-support.md)). For instructions on how to use the feature, please refer to Multiple VolumeSnapshotClasses doc ([Multiple VolumeSnapshotClasses doc](https://velero.io/docs/v1.12/csi/#implementation-choices)).
#### Restore Finalizer
Before v1.12, the restore controller would only delete restore resources but wouldnt delete restore data from the backup storage location when the command `velero restore delete` was executed. The only chance Velero deletes restores data from the backup storage location is when the associated backup is deleted.
@@ -51,10 +170,12 @@ To fix CVEs and keep pace with Golang, Velero made changes as follows:
* Prior to v1.12, the parameter `uploader-type` for Velero installation had a default value of "restic". However, starting from this version, the default value has been changed to "kopia". This means that Velero will now use Kopia as the default path for file system backup.
* The ways of setting CSI snapshot time have changed in v1.12. First, the sync waiting time for creating a snapshot handle in the CSI plugin is changed from the fixed 10 minutes into backup.Spec.CSISnapshotTimeout. The second, the async waiting time for VolumeSnapshot and VolumeSnapshotContent's status turning into `ReadyToUse` in operation uses the operation's timeout. The default value is 4 hours.
* As from [Velero helm chart v4.0.0](https://github.com/vmware-tanzu/helm-charts/releases/tag/velero-4.0.0), it supports multiple BSL and VSL, and the BSL and VSL have changed from the map into a slice, and[ this breaking change](https://github.com/vmware-tanzu/helm-charts/pull/413) is not backward compatible. So it would be best to change the BSL and VSL configuration into slices before the Upgrade.
* Prior to v1.12, deleting the Velero namespace would easily remove all the resources within it. However, with the introduction of finalizers attached to the Velero CR including `restore`, `dataupload`, and `datadownload` in this version, directly deleting Velero namespace may get stuck indefinitely because the pods responsible for handling the finalizers might be deleted before the resources attached to the finalizers. To avoid this issue, please use the command `velero uninstall` to delete all the Velero resources or ensure that you handle the finalizer appropriately before deleting the Velero namespace.
### Limitations/Known issues
* The Azure plugin supports Azure AD Workload identity way, but it only works for Velero native snapshots. It cannot support filesystem backup and snapshot data mover scenarios.
* File System backup under Kopia path and CSI Snapshot Data Movement backup fail to back up files that are large the 2GiB due to issue https://github.com/vmware-tanzu/velero/issues/6668.
### All Changes
@@ -132,3 +253,10 @@ prior PVC restores with CSI (#6111, @eemcmullan)
* Make GetPluginConfig accessible from other packages. (#6151, @tkaovila)
* Ignore not found error during patching managedFields (#6136, @ywk253100)
* Fix the goreleaser issues and add a new goreleaser action (#6109, @blackpiglet)
* Add CSI snapshot data movement doc (#6793, @Lyndon-Li)
* Use old(origin) namespace in resource modifier conditions in case namespace may change during restore (#6724, @27149chen)
* Fix #6752: add namespace exclude check. (#6762, @blackpiglet)
* Update restore controller logic for restore deletion (#6761, @ywk253100)
* Fix issue #6753, remove the check for read-only BSL in restore async operation controller since Velero cannot fully support read-only mode BSL in restore at present (#6758, @Lyndon-Li)
* Fixes #6636, skip subresource in resource discovery (#6688, @27149chen)
* This pr made some improvements in Resource Modifiers:1. add label selector 2. change the field name from groupKind to groupResource (#6704, @27149chen)

View File

@@ -1,166 +0,0 @@
## v1.13
### 2024-01-10
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.13.0
### Container Image
`velero/velero:v1.13.0`
### Documentation
https://velero.io/docs/v1.13/
### Upgrading
https://velero.io/docs/v1.13/upgrade-to-1.13/
### Highlights
#### Resource Modifier Enhancement
Velero introduced the Resource Modifiers in v1.12.0. This feature allows users to specify a ConfigMap with a set of rules to modify the resources during restoration. However, only the JSON Patch is supported when creating the rules, and JSON Patch has some limitations, which cannot cover all use cases. In v1.13.0, Velero adds new support for JSON Merge Patch and Strategic Merge Patch, which provide more power and flexibility and allow users to use the same ConfigMap to apply patches on the resources. More design details can be found in [Support JSON Merge Patch and Strategic Merge Patch in Resource Modifiers](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/merge-patch-and-strategic-in-resource-modifier.md) design. For instructions on how to use the feature, please refer to the [Resource Modifiers](https://velero.io/docs/v1.13/restore-resource-modifiers/) doc.
#### Node-Agent Concurrency
Velero data movement activities from fs-backups and CSI snapshot data movements run in Velero node-agent, so may be hosted by every node in the cluster and consume resources (i.e. CPU, memory, network bandwidth) from there. With v1.13, users are allowed to configure how many data movement activities (a.k.a, loads) run in each node globally or by node, so that users can better leverage the performance of Velero data movement activities and the resource consumption in the cluster. For more information, check the [Node-Agent Concurrency](https://velero.io/docs/v1.13/node-agent-concurrency/) document.
#### Parallel Files Upload Options
Velero now supports configurable options for parallel files upload when using Kopia uploader to do fs-backups or CSI snapshot data movements which makes speed up backup possible.
For more information, please check [Here](https://velero.io/docs/v1.13/backup-reference/#parallel-files-upload).
#### Write Sparse Files Options
If using fs-restore or CSI snapshot data movements, its supported to write sparse files during restore. For more information, please check [Here](https://velero.io/docs/v1.13/restore-reference/#write-sparse-files).
#### Backup Describe
In v1.13, the Backup Volume section is added to the velero backup describe command output. The backup Volumes section describes information for all the volumes included in the backup of various backup types, i.e. native snapshot, fs-backup, CSI snapshot, and CSI snapshot data movement. Particularly, the velero backup description now supports showing the information of CSI snapshot data movements, which is not supported in v1.12.
Additionally, backup describe command will not check EnableCSI feature gate from client side, so if a backup has volumes with CSI snapshot or CSI snapshot data movement, backup describe command always shows the corresponding information in its output.
#### Backup's new VolumeInfo metadata
Create a new metadata file in the backup repository's backup name sub-directory to store the backup-including PVC and PV information. The information includes the backing-up method of the PVC and PV data, snapshot information, and status. The VolumeInfo metadata file determines how the PV resource should be restored. The Velero downstream software can also use this metadata file to get a summary of the backup's volume data information.
#### Enhancement for CSI Snapshot Data Movements when Velero Pod Restart
When performing backup and restore operations, enhancements have been implemented for Velero server pods or node agents to ensure that the current backup or restore process is not stuck or interrupted after restart due to certain exceptional circumstances.
#### New status fields added to show hook execution details
Hook execution status is now included in the backup/restore CR status and displayed in the backup/restore describe command output. Specifically, it will show the number of hooks which attempted to execute under the HooksAttempted field and the number of hooks which failed to execute under the HooksFailed field.
#### AWS SDK Bump Up
Bump up AWS SDK for Go to version 2, which offers significant performance improvements in CPU and memory utilization over version 1.
#### Azure AD/Workload Identity Support
Azure AD/Workload Identity is the recommended approach to do the authentication with Azure services/AKS, Velero has introduced support for Azure AD/Workload Identity on the Velero Azure plugin side in previous releases, and in v1.13.0 Velero adds new support for Kopia operations(file system backup/data mover/etc.) with Azure AD/Workload Identity.
#### Runtime and dependencies
To fix CVEs and keep pace with Golang, Velero made changes as follows:
* Bump Golang runtime to v1.21.6.
* Bump several dependent libraries to new versions.
* Bump Kopia to v0.15.0.
### Breaking changes
* Backup describe command: due to the backup describe output enhancement, some existing information (i.e. the output for native snapshot, CSI snapshot, and fs-backup) has been moved to the Backup Volumes section with some format changes.
* API type changes: changes the field [DataMoverConfig](https://github.com/vmware-tanzu/velero/blob/v1.13.0/pkg/apis/velero/v2alpha1/data_upload_types.go#L54) in DataUploadSpec from `*map[string][string]`` to `map[string]string`
* Velero install command: due to the issue [#7264](https://github.com/vmware-tanzu/velero/issues/7264), v1.13.0 introduces a break change that make the informer cache enabled by default to keep the actual behavior consistent with the helper message(the informer cache is disabled by default before the change).
### Limitations/Known issues
* The backup's VolumeInfo metadata doesn't have the information updated in the async operations. This function could be supported in v1.14 release.
### Note
* Velero introduces the informer cache which is enabled by default. The informer cache improves the restore performance but may cause higher memory consumption. Increase the memory limit of the Velero pod or disable the informer cache by specifying the `--disable-informer-cache` option when installing Velero if you get the OOM error.
### Deprecation announcement
* The generated k8s clients, informers, and listers are deprecated in the Velero v1.13 release. They are put in the Velero repository's pkg/generated directory. According to the n+2 supporting policy, the deprecated are kept for two more releases. The pkg/generated directory should be deleted in the v1.15 release.
* After the backup VolumeInfo metadata file is added to the backup, Velero decides how to restore the PV resource according to the VolumeInfo content. To support the backup generated by the older version of Velero, the old logic is also kept. The support for the backup without the VolumeInfo metadata file will be kept for two releases. The support logic will be deleted in the v1.15 release.
### All Changes
* Make "disable-informer-cache" option false(enabled) by default to keep it consistent with the help message (#7294, @ywk253100)
* Fix issue #6928, remove snapshot deletion timeout for PVB (#7282, @Lyndon-Li)
* Do not set "targetNamespace" to namespace items (#7274, @reasonerjt)
* Fix issue #7244. By the end of the upload, check the outstanding incomplete snapshots and delete them by calling ApplyRetentionPolicy (#7245, @Lyndon-Li)
* Adjust the newline output of resource list in restore describer (#7238, @allenxu404)
* Remove the redundant newline in backup describe output (#7229, @allenxu404)
* Fix issue #7189, data mover generic restore - don't assume the first volume as the restore volume (#7201, @Lyndon-Li)
* Update CSIVolumeSnapshotsCompleted in backup's status and the metric
during backup finalize stage according to async operations content. (#7184, @blackpiglet)
* Refactor DownloadRequest Stream function (#7175, @blackpiglet)
* Add `--skip-immediately` flag to schedule commands; `--schedule-skip-immediately` server and install (#7169, @kaovilai)
* Add node-agent concurrency doc and change the config name from dataPathConcurrency to loadCocurrency (#7161, @Lyndon-Li)
* Enhance hooks tracker by adding a returned error to record function (#7153, @allenxu404)
* Track the skipped PV when SnapshotVolumes set as false (#7152, @reasonerjt)
* Add more linters part 2. (#7151, @blackpiglet)
* Fix issue #7135, check pod status before checking node-agent pod status (#7150, @Lyndon-Li)
* Treat namespace as a regular restorable item (#7143, @reasonerjt)
* Allow sparse option for Kopia & Restic restore (#7141, @qiuming-best)
* Use VolumeInfo to help restore the PV. (#7138, @blackpiglet)
* Node agent restart enhancement (#7130, @qiuming-best)
* Fix issue #6695, add describe for data mover backups (#7125, @Lyndon-Li)
* Add hooks status to backup/restore CR (#7117, @allenxu404)
* Include plugin name in the error message by operations (#7115, @reasonerjt)
* Fix issue #7068, due to a behavior of CSI external snapshotter, manipulations of VS and VSC may not be handled in the same order inside external snapshotter as the API is called. So add a protection finalizer to ensure the order (#7102, @Lyndon-Li)
* Generate VolumeInfo for backup. (#7100, @blackpiglet)
* Fix issue #7094, fallback to full backup if previous snapshot is not found (#7096, @Lyndon-Li)
* Fix issue #7068, due to an behavior of CSI external snapshotter, manipulations of VS and VSC may not be handled in the same order inside external snapshotter as the API is called. So add a protection finalizer to ensure the order (#7095, @Lyndon-Li)
* Skip syncing the backup which doesn't contain backup metadata (#7081, @ywk253100)
* Fix issue #6693, partially fail restore if CSI snapshot is involved but CSI feature is not ready, i.e., CSI feature gate is not enabled or CSI plugin is not installed. (#7077, @Lyndon-Li)
* Truncate the credential file to avoid the change of secret content messing it up (#7072, @ywk253100)
* Add VolumeInfo metadata structures. (#7070, @blackpiglet)
* improve discoveryHelper.Refresh() in restore (#7069, @27149chen)
* Add DataUpload Result and CSI VolumeSnapshot check for restore PV. (#7061, @blackpiglet)
* Add the implementation for design #6950, configurable data path concurrency (#7059, @Lyndon-Li)
* Make data mover fail early (#7052, @qiuming-best)
* Remove dependency of generated client part 3. (#7051, @blackpiglet)
* Update Backup.Status.CSIVolumeSnapshotsCompleted during finalize (#7046, @kaovilai)
* Remove the Velero generated client. (#7041, @blackpiglet)
* Fix issue #7027, data mover backup exposer should not assume the first volume as the backup volume in backup pod (#7038, @Lyndon-Li)
* Read information from the credential specified by BSL (#7034, @ywk253100)
* Fix #6857. Added check for matching Owner References when synchronizing backups, removing references that are not found/have mismatched uid. (#7032, @deefdragon)
* Add description markers for dataupload and datadownload CRDs (#7028, @shubham-pampattiwar)
* Add HealthCheckNodePort deletion logic for Service restore. (#7026, @blackpiglet)
* Fix inconsistent behavior of Backup and Restore hook execution (#7022, @allenxu404)
* Fix #6964. Don't use csiSnapshotTimeout (10 min) for waiting snapshot to readyToUse for data mover, so as to make the behavior complied with CSI snapshot backup (#7011, @Lyndon-Li)
* restore: Use warning when Create IsAlreadyExist and Get error (#7004, @kaovilai)
* Bump kopia to 0.15.0 (#7001, @Lyndon-Li)
* Make Kopia file parallelism configurable (#7000, @qiuming-best)
* Fix unified repository (kopia) s3 credentials profile selection (#6995, @kaovilai)
* Fix #6988, always get region from BSL if it is not empty (#6990, @Lyndon-Li)
* Limit PVC block mode logic to non-Windows platform. (#6989, @blackpiglet)
* It is a valid case that the Status.RestoreSize field in VolumeSnapshot is not set, if so, get the volume size from the source PVC to create the backup PVC (#6976, @Lyndon-Li)
* Check whether the action is a CSI action and whether CSI feature is enabled, before executing the action. (#6968, @blackpiglet)
* Add the PV backup information design document. (#6962, @blackpiglet)
* Change controller-runtime List option from MatchingFields to ListOptions (#6958, @blackpiglet)
* Add the design for node-agent concurrency (#6950, @Lyndon-Li)
* Import auth provider plugins (#6947, @0x113)
* Fix #6668, add a limitation for file system restore parallelism with other types of restores (CSI snapshot restore, CSI snapshot movement restore) (#6946, @Lyndon-Li)
* Add MSI Support for Azure plugin. (#6938, @yanggangtony)
* Partially fix #6734, guide Kubernetes' scheduler to spread backup pods evenly across nodes as much as possible, so that data mover backup could achieve better parallelism (#6926, @Lyndon-Li)
* Bump up aws sdk to aws-sdk-go-v2 (#6923, @reasonerjt)
* Optional check if targeted container is ready before executing a hook (#6918, @Ripolin)
* Support JSON Merge Patch and Strategic Merge Patch in Resource Modifiers (#6917, @27149chen)
* Fix issue 6913: Velero Built-in Datamover: Backup stucks in phase WaitingForPluginOperations when Node Agent pod gets restarted (#6914, @shubham-pampattiwar)
* Set ParallelUploadAboveSize as MaxInt64 and flush repo after setting up policy so that policy is retrieved correctly by TreeForSource (#6885, @Lyndon-Li)
* Replace the base image with paketobuildpacks image (#6883, @ywk253100)
* Fix issue #6859, move plugin depending podvolume functions to util pkg, so as to remove the dependencies to unnecessary repository packages like kopia, azure, etc. (#6875, @Lyndon-Li)
* Fix #6861. Only Restic path requires repoIdentifier, so for non-restic path, set the repoIdentifier fields as empty in PVB and PVR and also remove the RepoIdentifier column in the get output of PVBs and PVRs (#6872, @Lyndon-Li)
* Add volume types filter in resource policies (#6863, @qiuming-best)
* change the metrics backup_attempt_total default value to 1. (#6838, @yanggangtony)
* Bump kopia to v0.14 (#6833, @Lyndon-Li)
* Retry failed create when using generateName (#6830, @sseago)
* Fix issue #6786, always delete VSC regardless of the deletion policy (#6827, @Lyndon-Li)
* Proposal to support JSON Merge Patch and Strategic Merge Patch in Resource Modifiers (#6797, @27149chen)
* Fix the node-agent missing metrics-address defines. (#6784, @yanggangtony)
* Fix default BSL setting not work (#6771, @qiuming-best)
* Update restore controller logic for restore deletion (#6770, @ywk253100)
* Fix #6752: add namespace exclude check. (#6760, @blackpiglet)
* Fix issue #6753, remove the check for read-only BSL in restore async operation controller since Velero cannot fully support read-only mode BSL in restore at present (#6757, @Lyndon-Li)
* Fix issue #6647, add the --default-snapshot-move-data parameter to Velero install, so that users don't need to specify --snapshot-move-data per backup when they want to move snapshot data for all backups (#6751, @Lyndon-Li)
* Use old(origin) namespace in resource modifier conditions in case namespace may change during restore (#6724, @27149chen)
* Perf improvements for existing resource restore (#6723, @sseago)
* Remove schedule-related metrics on schedule delete (#6715, @nilesh-akhade)
* Kubernetes 1.27 new job label batch.kubernetes.io/controller-uid are deleted during restore per https://github.com/kubernetes/kubernetes/pull/114930 (#6712, @kaovilai)
* This pr made some improvements in Resource Modifiers: 1. add label selector 2. change the field name from groupKind to groupResource (#6704, @27149chen)
* Make Kopia support Azure AD (#6686, @ywk253100)
* Add support for block volumes with Kopia (#6680, @dzaninovic)
* Delete PartiallyFailed orphaned backups as well as Completed ones (#6649, @sseago)
* Add CSI snapshot data movement doc (#6637, @Lyndon-Li)
* Fixes #6636, skip subresource in resource discovery (#6635, @27149chen)
* Add `orLabelSelectors` for backup, restore commands (#6475, @nilesh-akhade)
* fix run preHook and postHook on completed pods (#5211, @cleverhu)

View File

@@ -1,131 +0,0 @@
## v1.14.1
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.14.1
### Container Image
`velero/velero:v1.14.1`
### Documentation
https://velero.io/docs/v1.14/
### Upgrading
https://velero.io/docs/v1.14/upgrade-to-1.14/
### All Changes
* Avoid wrapping failed PVB status with empty message. (#8037, @mrnold)
* Make PVPatchMaximumDuration timeout configurable (#8035, @shubham-pampattiwar)
* Reuse existing plugin manager for get/put volume info (#8016, @sseago)
* Skip PV patch step in Restoe workflow for WaitForFirstConsumer VolumeBindingMode Pending state PVCs (#8006, @shubham-pampattiwar)
* Check whether the namespaces specified in namespace filter exist. (#7998, @blackpiglet)
* Check whether the volume's source is PVC before fetching its PV. (#7976, @blackpiglet)
* Fix issue #7904, add the limitation clarification for change PVC selected-node feature (#7949, @Lyndon-Li)
* Expose the VolumeHelper to third-party plugins. (#7944, @blackpiglet)
* Don't consider unschedulable pods unrecoverable (#7926, @sseago)
## v1.14
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.14.0
### Container Image
`velero/velero:v1.14.0`
### Documentation
https://velero.io/docs/v1.14/
### Upgrading
https://velero.io/docs/v1.14/upgrade-to-1.14/
### Highlights
#### The maintenance work for kopia/restic backup repositories is run in jobs
Since velero started using kopia as the approach for filesystem-level backup/restore, we've noticed an issue when velero connects to the kopia backup repositories and performs maintenance, it sometimes consumes excessive memory that can cause the velero pod to get OOM Killed. To mitigate this issue, the maintenance work will be moved out of velero pod to a separate kubernetes job, and the user will be able to specify the resource request in "velero install".
#### Volume Policies are extended to support more actions to handle volumes
In an earlier release, a flexible volume policy was introduced to skip certain volumes from a backup. In v1.14 we've made enhancement to this policy to allow the user to set how the volumes should be backed up. The user will be able to set "fs-backup" or "snapshot" as value of “action" in the policy and velero will backup the volumes accordingly. This enhancement allows the user to achieve a fine-grained control like "opt-in/out" without having to update the target workload. For more details please refer to https://velero.io/docs/v1.14/resource-filtering/#supported-volumepolicy-actions
#### Node Selection for Data Movement Backup
In velero the data movement flow relies on datamover pods, and these pods may take substantial resources and keep running for a long time. In v1.14, the user will be able to create a configmap to define the eligible nodes on which the datamover pods are launched. For more details refer to https://velero.io/docs/v1.14/data-movement-backup-node-selection/
#### VolumeInfo metadata for restored volumes
In v1.13, we introduced volumeinfo metadata for backup to help velero CLI and downstream adopter understand how velero handles each volume during backup. In v1.14, similar metadata will be persisted for each restore. velero CLI is also updated to bring more info in the output of "velero restore describe".
#### "Finalizing" phase is introduced to restores
The "Finalizing" phase is added to the state transition flow to restore, which helps us fix several issues: The labels added to PVs will be restored after the data in the PV is restored via volumesnapshotter. The post restore hook will be executed after datamovement is finished.
#### Certificate-based authentication support for Azure
Besides the service principal with secret(password)-based authentication, Velero introduces the new support for service principal with certificate-based authentication in v1.14.0. This approach enables you to adopt a phishing resistant authentication by using conditional access policies, which better protects Azure resources and is the recommended way by Azure.
### Runtime and dependencies
* Golang runtime: v1.22.2
* kopia: v0.17.0
### Limitations/Known issues
* For the external BackupItemAction plugins that take snapshots for PVs, such as vsphere plugin. If the plugin checks the value of the field "snapshotVolumes" in the backup spec as a criteria for snapshot, the settings in the volume policy will not take effect. For example, if the "snapshotVolumes" is set to False in the backup spec, but a volume meets the condition in the volume policy for "snapshot" action, because the plugin will not check the settings in the volume policy, the plugin will not take snapshot for the volume. For more details please refer to #7818
### Breaking changes
* CSI plugin has been merged into velero repo in v1.14 release. It will be installed by default as an internal plugin, and should not be installed via "plugins " parameter in "velero install" command.
* The default resource requests and limitations for node agent are removed in v1.14, to make the node agent pods have the QoS class of "BestEffort", more details please refer to #7391
* There's a change in namespace filtering behavior during backup: In v1.14, when the includedNamespaces/excludedNamespaces fields are not set and the labelSelector/OrLabelSelectors are set in the backup spec, the backup will only include the namespaces which contain the resources that match the label selectors, while in previous releases all namespaces will be included in the backup with such settings. More details refer to #7105
* Patching the PV in the "Finalizing" state may cause the restore to be in "PartiallyFailed" state when the PV is blocked in "Pending" state, while in the previous release the restore may end up being in "Complete" state. For more details refer to #7866
### All Changes
* Fix backup log to show error string, not index (#7805, @piny940)
* Modify the volume helper logic. (#7794, @blackpiglet)
* Add documentation for extension of volume policy feature (#7779, @shubham-pampattiwar)
* Surface errors when waiting for backupRepository and timeout occurs (#7762, @kaovilai)
* Add existingResourcePolicy restore CR validation to controller (#7757, @kaovilai)
* Fix condition matching in resource modifier when there are multiple rules (#7715, @27149chen)
* Bump up the version of KinD and k8s in github actions (#7702, @reasonerjt)
* Implementation for Extending VolumePolicies to support more actions (#7664, @shubham-pampattiwar)
* Migrate from `github.com/Azure/azure-storage-blob-go` to `github.com/Azure/azure-sdk-for-go/sdk/storage/azblob` (#7598, @mmorel-35)
* When Included/ExcludedNamespaces are omitted, and LabelSelector or OrLabelSelector is used, namespaces without selected items are excluded from backup. (#7697, @blackpiglet)
* Display CSI snapshot restores in restore describe (#7687, @reasonerjt)
* Use specific credential rather than the credential chain for Azure (#7680, @ywk253100)
* Modify hook docs for clarity on displaying hook execution results (#7679, @allenxu404)
* Wait for results of restore exec hook executions in Finalizing phase instead of InProgress phase (#7619, @allenxu404)
* migrating to `sdk/resourcemanager/**/arm**` from `services/**/mgmt/**` (#7596, @mmorel-35)
* Bump up to go1.22 (#7666, @reasonerjt)
* Fix issue #7648. Adjust the exposing logic to avoid exposing failure and snapshot leak when expose fails (#7662, @Lyndon-Li)
* Track and persist restore volume info (#7630, @reasonerjt)
* Check the existence of the namespaces provided in the "--include-namespaces" option (#7569, @ywk253100)
* Add the finalization phase to the restore workflow (#7377, @allenxu404)
* Upgrade the version of go plugin related libs/tools (#7373, @ywk253100)
* Check resource Group Version and Kind is available in cluster before attempting restore to prevent being stuck. (#7322, @kaovilai)
* Merge CSI plugin code into Velero. (#7609, @blackpiglet)
* Fix issue #7391, remove the default constraint for node-agent pods (#7488, @Lyndon-Li)
* Fix DataDownload fails during restore for empty PVC workload (#7521, @qiuming-best)
* Add repository maintenance job (#7451, @qiuming-best)
* Check whether the VolumeSnapshot's source PVC is nil before using it.
Skip populate VolumeInfo for data-moved PV when CSI is not enabled. (#7515, @blackpiglet)
* Fix issue #7308, change the data path requeue time to 5 second for data mover backup/restore, PVB and PVR. (#7458, @Lyndon-Li)
* Patch newly dynamically provisioned PV with volume info to restore custom setting of PV (#7504, @allenxu404)
* Adjust the logic for the backup_last_status metrics to stop incorrectly incrementing over time (#7445, @allenxu404)
* dependabot: support github-actions updates (#7594, @mmorel-35)
* Include the design for adding the finalization phase to the restore workflow (#7317, @allenxu404)
* Fix issue #7211. Enable advanced feature capability and add support to concatenate objects for unified repo. (#7452, @Lyndon-Li)
* Add design to introduce restore volume info (#7610, @reasonerjt)
* Increase the k8s client QPS/burst to avoid throttling request errors (#7311, @ywk253100)
* Support update the backup VolumeInfos by the Async ops result. (#7554, @blackpiglet)
* FS backup create PodVolumeBackup when the backup excluded PVC,
so I added logic to skip PVC volume type when PVC is not included in the backup resources to be backed up. (#7472, @sbahar619)
* Respect and use `credentialsFile` specified in BSL.spec.config when IRSA is configured over Velero Pod Environment credentials (#7374, @reasonerjt)
* Move the native snapshot definition code into internal directory (#7544, @blackpiglet)
* Fix issue #7036. Add the implementation of node selection for data mover backups (#7437, @Lyndon-Li)
* Fix issue #7535, add the MustHave resource check during item collection and item filter for restore (#7585, @Lyndon-Li)
* build(deps): bump json-patch to v5.8.0 (#7584, @mmorel-35)
* Add confirm flag to velero plugin add (#7566, @kaovilai)
* do not skip unknown gvr at the beginning and get new gr when kind is changed (#7523, @27149chen)
* Fix snapshot leak for backup (#7558, @qiuming-best)
* For issue #7036, add the document for data mover node selection (#7640, @Lyndon-Li)
* Add design for Extending VolumePolicies to support more actions (#6956, @shubham-pampattiwar)
* BackupRepositories associated with a BSL are invalidated when BSL is (re-)created. (#7380, @kaovilai)
* Improve the concurrency for PVBs in different pods (#7571, @ywk253100)
* Bump up Kopia to v0.16.0 and open kopia repo with no index change (#7559, @Lyndon-Li)
* Bump up the versions of several Kubernetes-related libs (#7489, @ywk253100)
* Make parallel restore configurable (#7512, @qiuming-best)
* Support certificate-based authentication for Azure (#7549, @ywk253100)
* Fix issue #7281, batch delete snapshots in the same repo (#7438, @Lyndon-Li)
* Add CRD name to error message when it is not ready to use (#7295, @josemarevalo)
* Add the design for node selection for data mover backup (#7383, @Lyndon-Li)
* Bump up aws-sdk to latest version to leverage Pod Identity credentials. (#7307, @guikcd)
* Fix issue #7246. Document the behavior for repo snapshot deletion (#7622, @Lyndon-Li)
* Fix issue #7583, set backupName optional for Restore CRD (#7617, @Lyndon-Li)

View File

@@ -1,19 +1,3 @@
/*
Copyright 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 main
import (

View File

@@ -66,14 +66,14 @@ func done() bool {
doneFile := filepath.Join("/restores", child.Name(), ".velero", os.Args[1])
if _, err := os.Stat(doneFile); os.IsNotExist(err) {
fmt.Printf("The filesystem restore done file %s is not found yet. Retry later.\n", doneFile)
fmt.Printf("Not found: %s\n", doneFile)
return false
} else if err != nil {
fmt.Fprintf(os.Stderr, "ERROR looking filesystem restore done file %s: %s\n", doneFile, err)
fmt.Fprintf(os.Stderr, "ERROR looking for %s: %s\n", doneFile, err)
return false
}
fmt.Printf("Found the done file %s\n", doneFile)
fmt.Printf("Found %s", doneFile)
}
return true

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: backuprepositories.velero.io
spec:
group: velero.io
@@ -26,19 +26,14 @@ spec:
openAPIV3Schema:
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -46,8 +41,7 @@ spec:
description: BackupRepositorySpec is the specification for a BackupRepository.
properties:
backupStorageLocation:
description: |-
BackupStorageLocation is the name of the BackupStorageLocation
description: BackupStorageLocation is the name of the BackupStorageLocation
that should contain this repository.
type: string
maintenanceFrequency:
@@ -62,14 +56,12 @@ spec:
- ""
type: string
resticIdentifier:
description: |-
ResticIdentifier is the full restic-compatible string for identifying
this repository.
description: ResticIdentifier is the full restic-compatible string
for identifying this repository.
type: string
volumeNamespace:
description: |-
VolumeNamespace is the namespace this backup repository contains
pod volume backups for.
description: VolumeNamespace is the namespace this backup repository
contains pod volume backups for.
type: string
required:
- backupStorageLocation

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: backups.velero.io
spec:
group: velero.io
@@ -17,24 +17,18 @@ spec:
- name: v1
schema:
openAPIV3Schema:
description: |-
Backup is a Velero resource that represents the capture of Kubernetes
description: Backup is a Velero resource that represents the capture of Kubernetes
cluster state at a point in time (API objects and associated volume state).
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -42,63 +36,55 @@ spec:
description: BackupSpec defines the specification for a Velero backup.
properties:
csiSnapshotTimeout:
description: |-
CSISnapshotTimeout specifies the time used to wait for CSI VolumeSnapshot status turns to
ReadyToUse during creation, before returning error as timeout.
The default value is 10 minute.
description: CSISnapshotTimeout specifies the time used to wait for
CSI VolumeSnapshot status turns to ReadyToUse during creation, before
returning error as timeout. The default value is 10 minute.
type: string
datamover:
description: |-
DataMover specifies the data mover to be used by the backup.
If DataMover is "" or "velero", the built-in data mover will be used.
description: DataMover specifies the data mover to be used by the
backup. If DataMover is "" or "velero", the built-in data mover
will be used.
type: string
defaultVolumesToFsBackup:
description: |-
DefaultVolumesToFsBackup specifies whether pod volume file system backup should be used
for all volumes by default.
description: DefaultVolumesToFsBackup specifies whether pod volume
file system backup should be used for all volumes by default.
nullable: true
type: boolean
defaultVolumesToRestic:
description: |-
DefaultVolumesToRestic specifies whether restic should be used to take a
backup of all pod volumes by default.
Deprecated: this field is no longer used and will be removed entirely in future. Use DefaultVolumesToFsBackup instead.
description: "DefaultVolumesToRestic specifies whether restic should
be used to take a backup of all pod volumes by default. \n Deprecated:
this field is no longer used and will be removed entirely in future.
Use DefaultVolumesToFsBackup instead."
nullable: true
type: boolean
excludedClusterScopedResources:
description: |-
ExcludedClusterScopedResources is a slice of cluster-scoped
resource type names to exclude from the backup.
If set to "*", all cluster-scoped resource types are excluded.
The default value is empty.
description: ExcludedClusterScopedResources is a slice of cluster-scoped
resource type names to exclude from the backup. If set to "*", all
cluster-scoped resource types are excluded. The default value is
empty.
items:
type: string
nullable: true
type: array
excludedNamespaceScopedResources:
description: |-
ExcludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to exclude from the backup.
If set to "*", all namespace-scoped resource types are excluded.
The default value is empty.
description: ExcludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to exclude from the backup. If set to "*", all
namespace-scoped resource types are excluded. The default value
is empty.
items:
type: string
nullable: true
type: array
excludedNamespaces:
description: |-
ExcludedNamespaces contains a list of namespaces that are not
included in the backup.
description: ExcludedNamespaces contains a list of namespaces that
are not included in the backup.
items:
type: string
nullable: true
type: array
excludedResources:
description: |-
ExcludedResources is a slice of resource names that are not
included in the backup.
description: ExcludedResources is a slice of resource names that are
not included in the backup.
items:
type: string
nullable: true
@@ -111,9 +97,9 @@ spec:
description: Resources are hooks that should be executed when
backing up individual instances of a resource.
items:
description: |-
BackupResourceHookSpec defines one or more BackupResourceHooks that should be executed based on
the rules defined for namespaces, resources, and label selector.
description: BackupResourceHookSpec defines one or more BackupResourceHooks
that should be executed based on the rules defined for namespaces,
resources, and label selector.
properties:
excludedNamespaces:
description: ExcludedNamespaces specifies the namespaces
@@ -130,17 +116,17 @@ spec:
nullable: true
type: array
includedNamespaces:
description: |-
IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies
description: IncludedNamespaces specifies the namespaces
to which this hook spec applies. If empty, it applies
to all namespaces.
items:
type: string
nullable: true
type: array
includedResources:
description: |-
IncludedResources specifies the resources to which this hook spec applies. If empty, it applies
to all resources.
description: IncludedResources specifies the resources to
which this hook spec applies. If empty, it applies to
all resources.
items:
type: string
nullable: true
@@ -154,8 +140,8 @@ spec:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
description: A label selector requirement is a selector
that contains values, a key, and an operator that
relates the key and values.
properties:
key:
@@ -163,16 +149,17 @@ spec:
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In,
NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string values.
If the operator is In or NotIn, the values array
must be non-empty. If the operator is Exists
or DoesNotExist, the values array must be empty.
This array is replaced during a strategic merge
patch.
items:
type: string
type: array
@@ -184,10 +171,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs.
A single {key,value} in the matchLabels map is equivalent
to an element of matchExpressions, whose key field
is "key", the operator is "In", and the values array
contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -195,9 +183,10 @@ spec:
description: Name is the name of this hook.
type: string
post:
description: |-
PostHooks is a list of BackupResourceHooks to execute after storing the item in the backup.
These are executed after all "additional items" from item actions are processed.
description: PostHooks is a list of BackupResourceHooks
to execute after storing the item in the backup. These
are executed after all "additional items" from item actions
are processed.
items:
description: BackupResourceHook defines a hook for a resource.
properties:
@@ -212,9 +201,10 @@ spec:
minItems: 1
type: array
container:
description: |-
Container is the container in the pod where the command should be executed. If not specified,
the pod's first container is used.
description: Container is the container in the
pod where the command should be executed. If
not specified, the pod's first container is
used.
type: string
onError:
description: OnError specifies how Velero should
@@ -225,9 +215,9 @@ spec:
- Fail
type: string
timeout:
description: |-
Timeout defines the maximum amount of time Velero should wait for the hook to complete before
considering the execution a failure.
description: Timeout defines the maximum amount
of time Velero should wait for the hook to complete
before considering the execution a failure.
type: string
required:
- command
@@ -237,9 +227,10 @@ spec:
type: object
type: array
pre:
description: |-
PreHooks is a list of BackupResourceHooks to execute prior to storing the item in the backup.
These are executed before any "additional items" from item actions are processed.
description: PreHooks is a list of BackupResourceHooks to
execute prior to storing the item in the backup. These
are executed before any "additional items" from item actions
are processed.
items:
description: BackupResourceHook defines a hook for a resource.
properties:
@@ -254,9 +245,10 @@ spec:
minItems: 1
type: array
container:
description: |-
Container is the container in the pod where the command should be executed. If not specified,
the pod's first container is used.
description: Container is the container in the
pod where the command should be executed. If
not specified, the pod's first container is
used.
type: string
onError:
description: OnError specifies how Velero should
@@ -267,9 +259,9 @@ spec:
- Fail
type: string
timeout:
description: |-
Timeout defines the maximum amount of time Velero should wait for the hook to complete before
considering the execution a failure.
description: Timeout defines the maximum amount
of time Velero should wait for the hook to complete
before considering the execution a failure.
type: string
required:
- command
@@ -285,81 +277,74 @@ spec:
type: array
type: object
includeClusterResources:
description: |-
IncludeClusterResources specifies whether cluster-scoped resources
should be included for consideration in the backup.
description: IncludeClusterResources specifies whether cluster-scoped
resources should be included for consideration in the backup.
nullable: true
type: boolean
includedClusterScopedResources:
description: |-
IncludedClusterScopedResources is a slice of cluster-scoped
resource type names to include in the backup.
If set to "*", all cluster-scoped resource types are included.
The default value is empty, which means only related
cluster-scoped resources are included.
description: IncludedClusterScopedResources is a slice of cluster-scoped
resource type names to include in the backup. If set to "*", all
cluster-scoped resource types are included. The default value is
empty, which means only related cluster-scoped resources are included.
items:
type: string
nullable: true
type: array
includedNamespaceScopedResources:
description: |-
IncludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to include in the backup.
The default value is "*".
description: IncludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to include in the backup. The default value
is "*".
items:
type: string
nullable: true
type: array
includedNamespaces:
description: |-
IncludedNamespaces is a slice of namespace names to include objects
from. If empty, all namespaces are included.
description: IncludedNamespaces is a slice of namespace names to include
objects from. If empty, all namespaces are included.
items:
type: string
nullable: true
type: array
includedResources:
description: |-
IncludedResources is a slice of resource names to include
description: IncludedResources is a slice of resource names to include
in the backup. If empty, all resources are included.
items:
type: string
nullable: true
type: array
itemOperationTimeout:
description: |-
ItemOperationTimeout specifies the time used to wait for asynchronous BackupItemAction operations
The default value is 4 hour.
description: ItemOperationTimeout specifies the time used to wait
for asynchronous BackupItemAction operations The default value is
1 hour.
type: string
labelSelector:
description: |-
LabelSelector is a metav1.LabelSelector to filter with
when adding individual objects to the backup. If empty
or nil, all objects are included. Optional.
description: LabelSelector is a metav1.LabelSelector to filter with
when adding individual objects to the backup. If empty or nil, all
objects are included. Optional.
nullable: true
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements.
The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a selector that
contains values, a key, and an operator that relates the key
and values.
properties:
key:
description: key is the label key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship to
a set of values. Valid operators are In, NotIn, Exists
and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
description: values is an array of string values. If the
operator is In or NotIn, the values array must be non-empty.
If the operator is Exists or DoesNotExist, the values
array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
@@ -372,10 +357,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs. A single
{key,value} in the matchLabels map is equivalent to an element
of matchExpressions, whose key field is "key", the operator
is "In", and the values array contains only "value". The requirements
are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -387,41 +373,40 @@ spec:
type: object
type: object
orLabelSelectors:
description: |-
OrLabelSelectors is list of metav1.LabelSelector to filter with
when adding individual objects to the backup. If multiple provided
description: OrLabelSelectors is list of metav1.LabelSelector to filter
with when adding individual objects to the backup. If multiple provided
they will be joined by the OR operator. LabelSelector as well as
OrLabelSelectors cannot co-exist in backup request, only one of them
can be used.
OrLabelSelectors cannot co-exist in backup request, only one of
them can be used.
items:
description: |-
A label selector is a label query over a set of resources. The result of matchLabels and
matchExpressions are ANDed. An empty label selector matches all objects. A null
label selector matches no objects.
description: A label selector is a label query over a set of resources.
The result of matchLabels and matchExpressions are ANDed. An empty
label selector matches all objects. A null label selector matches
no objects.
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements.
The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a selector that
contains values, a key, and an operator that relates the
key and values.
properties:
key:
description: key is the label key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn, Exists
and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string values. If the
operator is In or NotIn, the values array must be non-empty.
If the operator is Exists or DoesNotExist, the values
array must be empty. This array is replaced during a
strategic merge patch.
items:
type: string
type: array
@@ -433,10 +418,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs. A single
{key,value} in the matchLabels map is equivalent to an element
of matchExpressions, whose key field is "key", the operator
is "In", and the values array contains only "value". The requirements
are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -445,10 +431,11 @@ spec:
orderedResources:
additionalProperties:
type: string
description: |-
OrderedResources specifies the backup order of resources of specific Kind.
The map key is the resource name and value is a list of object names separated by commas.
Each resource name has format "namespace/objectname". For cluster resources, simply use "objectname".
description: OrderedResources specifies the backup order of resources
of specific Kind. The map key is the resource name and value is
a list of object names separated by commas. Each resource name has
format "namespace/objectname". For cluster resources, simply use
"objectname".
nullable: true
type: object
resourcePolicy:
@@ -456,10 +443,10 @@ spec:
that backup should follow
properties:
apiGroup:
description: |-
APIGroup is the group for the resource being referenced.
If APIGroup is not specified, the specified Kind must be in the core API group.
For any other third-party types, APIGroup is required.
description: APIGroup is the group for the resource being referenced.
If APIGroup is not specified, the specified Kind must be in
the core API group. For any other third-party types, APIGroup
is required.
type: string
kind:
description: Kind is the type of resource being referenced
@@ -478,10 +465,8 @@ spec:
nullable: true
type: boolean
snapshotVolumes:
description: |-
SnapshotVolumes specifies whether to take snapshots
of any PV's referenced in the set of objects included
in the Backup.
description: SnapshotVolumes specifies whether to take snapshots of
any PV's referenced in the set of objects included in the Backup.
nullable: true
type: boolean
storageLocation:
@@ -489,19 +474,9 @@ spec:
BackupStorageLocation where the backup should be stored.
type: string
ttl:
description: |-
TTL is a time.Duration-parseable string describing how long
the Backup should be retained for.
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.
nullable: true
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.
@@ -513,44 +488,39 @@ spec:
description: BackupStatus captures the current status of a Velero backup.
properties:
backupItemOperationsAttempted:
description: |-
BackupItemOperationsAttempted is the total number of attempted
async BackupItemAction operations for this backup.
description: BackupItemOperationsAttempted is the total number of
attempted async BackupItemAction operations for this backup.
type: integer
backupItemOperationsCompleted:
description: |-
BackupItemOperationsCompleted is the total number of successfully completed
async BackupItemAction operations for this backup.
description: BackupItemOperationsCompleted is the total number of
successfully completed async BackupItemAction operations for this
backup.
type: integer
backupItemOperationsFailed:
description: |-
BackupItemOperationsFailed is the total number of async
BackupItemAction operations for this backup which ended with an error.
description: BackupItemOperationsFailed is the total number of async
BackupItemAction operations for this backup which ended with an
error.
type: integer
completionTimestamp:
description: |-
CompletionTimestamp records the time a backup was completed.
Completion time is recorded even on failed backups.
Completion time is recorded before uploading the backup object.
The server's time is used for CompletionTimestamps
description: CompletionTimestamp records the time a backup was completed.
Completion time is recorded even on failed backups. Completion time
is recorded before uploading the backup object. The server's time
is used for CompletionTimestamps
format: date-time
nullable: true
type: string
csiVolumeSnapshotsAttempted:
description: |-
CSIVolumeSnapshotsAttempted is the total number of attempted
description: CSIVolumeSnapshotsAttempted is the total number of attempted
CSI VolumeSnapshots for this backup.
type: integer
csiVolumeSnapshotsCompleted:
description: |-
CSIVolumeSnapshotsCompleted is the total number of successfully
description: CSIVolumeSnapshotsCompleted is the total number of successfully
completed CSI VolumeSnapshots for this backup.
type: integer
errors:
description: |-
Errors is a count of all error messages that were generated during
execution of the backup. The actual errors are in the backup's log
file in object storage.
description: Errors is a count of all error messages that were generated
during execution of the backup. The actual errors are in the backup's
log file in object storage.
type: integer
expiration:
description: Expiration is when this Backup is eligible for garbage-collection.
@@ -565,22 +535,6 @@ 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:
@@ -597,62 +551,53 @@ spec:
- Deleting
type: string
progress:
description: |-
Progress contains information about the backup's execution progress. Note
that this information is best-effort only -- if Velero fails to update it
during a backup for any reason, it may be inaccurate/stale.
description: Progress contains information about the backup's execution
progress. Note that this information is best-effort only -- if Velero
fails to update it during a backup for any reason, it may be inaccurate/stale.
nullable: true
properties:
itemsBackedUp:
description: |-
ItemsBackedUp is the number of items that have actually been written to the
backup tarball so far.
description: ItemsBackedUp is the number of items that have actually
been written to the backup tarball so far.
type: integer
totalItems:
description: |-
TotalItems is the total number of items to be backed up. This number may change
throughout the execution of the backup due to plugins that return additional related
items to back up, the velero.io/exclude-from-backup label, and various other
description: TotalItems is the total number of items to be backed
up. This number may change throughout the execution of the backup
due to plugins that return additional related items to back
up, the velero.io/exclude-from-backup label, and various other
filters that happen as items are processed.
type: integer
type: object
startTimestamp:
description: |-
StartTimestamp records the time a backup was started.
Separate from CreationTimestamp, since that value changes
on restores.
description: StartTimestamp records the time a backup was started.
Separate from CreationTimestamp, since that value changes on restores.
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).
description: ValidationErrors is a slice of all validation errors
(if applicable).
items:
type: string
nullable: true
type: array
version:
description: |-
Version is the backup format major version.
Deprecated: Please see FormatVersion
description: 'Version is the backup format major version. Deprecated:
Please see FormatVersion'
type: integer
volumeSnapshotsAttempted:
description: |-
VolumeSnapshotsAttempted is the total number of attempted
description: VolumeSnapshotsAttempted is the total number of attempted
volume snapshots for this backup.
type: integer
volumeSnapshotsCompleted:
description: |-
VolumeSnapshotsCompleted is the total number of successfully
description: VolumeSnapshotsCompleted is the total number of successfully
completed volume snapshots for this backup.
type: integer
warnings:
description: |-
Warnings is a count of all warning messages that were generated during
execution of the backup. The actual warnings are in the backup's log
file in object storage.
description: Warnings is a count of all warning messages that were
generated during execution of the backup. The actual warnings are
in the backup's log file in object storage.
type: integer
type: object
type: object

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: backupstoragelocations.velero.io
spec:
group: velero.io
@@ -40,19 +40,14 @@ spec:
objects
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -86,10 +81,8 @@ spec:
valid secret key.
type: string
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
optional:
description: Specify whether the Secret or its key must be defined
@@ -138,36 +131,29 @@ spec:
BackupStorageLocation
properties:
accessMode:
description: |-
AccessMode is an unused field.
Deprecated: there is now an AccessMode field on the Spec and this field
will be removed entirely as of v2.0.
description: "AccessMode is an unused field. \n Deprecated: there
is now an AccessMode field on the Spec and this field will be removed
entirely as of v2.0."
enum:
- ReadOnly
- ReadWrite
type: string
lastSyncedRevision:
description: |-
LastSyncedRevision is the value of the `metadata/revision` file in the backup
storage location the last time the BSL's contents were synced into the cluster.
Deprecated: this field is no longer updated or used for detecting changes to
the location's contents and will be removed entirely in v2.0.
description: "LastSyncedRevision is the value of the `metadata/revision`
file in the backup storage location the last time the BSL's contents
were synced into the cluster. \n Deprecated: this field is no longer
updated or used for detecting changes to the location's contents
and will be removed entirely in v2.0."
type: string
lastSyncedTime:
description: |-
LastSyncedTime is the last time the contents of the location were synced into
the cluster.
description: LastSyncedTime is the last time the contents of the location
were synced into the cluster.
format: date-time
nullable: true
type: string
lastValidationTime:
description: |-
LastValidationTime is the last time the backup store location was validated
the cluster.
description: LastValidationTime is the last time the backup store
location was validated the cluster.
format: date-time
nullable: true
type: string

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: deletebackuprequests.velero.io
spec:
group: velero.io
@@ -29,19 +29,14 @@ spec:
description: DeleteBackupRequest is a request to delete one or more backups.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: downloadrequests.velero.io
spec:
group: velero.io
@@ -17,24 +17,18 @@ spec:
- name: v1
schema:
openAPIV3Schema:
description: |-
DownloadRequest is a request to download an artifact from backup object storage, such as a backup
log file.
description: DownloadRequest is a request to download an artifact from backup
object storage, such as a backup log file.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -59,8 +53,6 @@ spec:
- RestoreItemOperations
- CSIBackupVolumeSnapshots
- CSIBackupVolumeSnapshotContents
- BackupVolumeInfos
- RestoreVolumeInfo
type: string
name:
description: Name is the name of the Kubernetes resource with

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: podvolumebackups.velero.io
spec:
group: velero.io
@@ -35,6 +35,10 @@ spec:
jsonPath: .spec.volume
name: Volume
type: string
- description: Backup repository identifier for this backup
jsonPath: .spec.repoIdentifier
name: Repository ID
type: string
- description: The type of the uploader to handle data transfer
jsonPath: .spec.uploaderType
name: Uploader Type
@@ -52,19 +56,14 @@ spec:
openAPIV3Schema:
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -72,9 +71,8 @@ spec:
description: PodVolumeBackupSpec is the specification for a PodVolumeBackup.
properties:
backupStorageLocation:
description: |-
BackupStorageLocation is the name of the backup storage location
where the backup repository is stored.
description: BackupStorageLocation is the name of the backup storage
location where the backup repository is stored.
type: string
node:
description: Node is the name of the node that the Pod is running
@@ -88,40 +86,33 @@ spec:
description: API version of the referent.
type: string
fieldPath:
description: |-
If referring to a piece of an object instead of an entire object, this string
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within a pod, this would take on a value like:
"spec.containers{name}" (where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]" (container with
index 2 in this pod). This syntax is chosen only to have some well-defined way of
referencing a part of an object.
TODO: this design is not final and this field is subject to change in the future.
description: 'If referring to a piece of an object instead of
an entire object, this string should contain a valid JSON/Go
field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within
a pod, this would take on a value like: "spec.containers{name}"
(where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]"
(container with index 2 in this pod). This syntax is chosen
only to have some well-defined way of referencing a part of
an object. TODO: this design is not final and this field is
subject to change in the future.'
type: string
kind:
description: |-
Kind of the referent.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: |-
Namespace of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
resourceVersion:
description: |-
Specific resourceVersion to which this reference is made, if any.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
description: 'Specific resourceVersion to which this reference
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
uid:
description: |-
UID of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
x-kubernetes-map-type: atomic
@@ -131,17 +122,8 @@ spec:
tags:
additionalProperties:
type: string
description: |-
Tags are a map of key-value pairs that should be applied to the
volume backup as tags.
type: object
uploaderSettings:
additionalProperties:
type: string
description: |-
UploaderSettings are a map of key-value pairs that should be applied to the
uploader configuration.
nullable: true
description: Tags are a map of key-value pairs that should be applied
to the volume backup as tags.
type: object
uploaderType:
description: UploaderType is the type of the uploader to handle the
@@ -152,9 +134,8 @@ spec:
- ""
type: string
volume:
description: |-
Volume is the name of the volume within the Pod to be backed
up.
description: Volume is the name of the volume within the Pod to be
backed up.
type: string
required:
- backupStorageLocation
@@ -167,11 +148,10 @@ spec:
description: PodVolumeBackupStatus is the current status of a PodVolumeBackup.
properties:
completionTimestamp:
description: |-
CompletionTimestamp records the time a backup was completed.
Completion time is recorded even on failed backups.
Completion time is recorded before uploading the backup object.
The server's time is used for CompletionTimestamps
description: CompletionTimestamp records the time a backup was completed.
Completion time is recorded even on failed backups. Completion time
is recorded before uploading the backup object. The server's time
is used for CompletionTimestamps
format: date-time
nullable: true
type: string
@@ -191,10 +171,9 @@ spec:
- Failed
type: string
progress:
description: |-
Progress holds the total number of bytes of the volume and the current
number of backed up bytes. This can be used to display progress information
about the backup operation.
description: Progress holds the total number of bytes of the volume
and the current number of backed up bytes. This can be used to display
progress information about the backup operation.
properties:
bytesDone:
format: int64
@@ -208,10 +187,8 @@ spec:
pod volume.
type: string
startTimestamp:
description: |-
StartTimestamp records the time a backup was started.
Separate from CreationTimestamp, since that value changes
on restores.
description: StartTimestamp records the time a backup was started.
Separate from CreationTimestamp, since that value changes on restores.
The server's time is used for StartTimestamps
format: date-time
nullable: true

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: podvolumerestores.velero.io
spec:
group: velero.io
@@ -53,19 +53,14 @@ spec:
openAPIV3Schema:
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -73,9 +68,8 @@ spec:
description: PodVolumeRestoreSpec is the specification for a PodVolumeRestore.
properties:
backupStorageLocation:
description: |-
BackupStorageLocation is the name of the backup storage location
where the backup repository is stored.
description: BackupStorageLocation is the name of the backup storage
location where the backup repository is stored.
type: string
pod:
description: Pod is a reference to the pod containing the volume to
@@ -85,40 +79,33 @@ spec:
description: API version of the referent.
type: string
fieldPath:
description: |-
If referring to a piece of an object instead of an entire object, this string
should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within a pod, this would take on a value like:
"spec.containers{name}" (where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]" (container with
index 2 in this pod). This syntax is chosen only to have some well-defined way of
referencing a part of an object.
TODO: this design is not final and this field is subject to change in the future.
description: 'If referring to a piece of an object instead of
an entire object, this string should contain a valid JSON/Go
field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within
a pod, this would take on a value like: "spec.containers{name}"
(where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]"
(container with index 2 in this pod). This syntax is chosen
only to have some well-defined way of referencing a part of
an object. TODO: this design is not final and this field is
subject to change in the future.'
type: string
kind:
description: |-
Kind of the referent.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: |-
Namespace of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
resourceVersion:
description: |-
Specific resourceVersion to which this reference is made, if any.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
description: 'Specific resourceVersion to which this reference
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
uid:
description: |-
UID of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
x-kubernetes-map-type: atomic
@@ -132,14 +119,6 @@ spec:
description: SourceNamespace is the original namespace for namaspace
mapping.
type: string
uploaderSettings:
additionalProperties:
type: string
description: |-
UploaderSettings are a map of key-value pairs that should be applied to the
uploader configuration.
nullable: true
type: object
uploaderType:
description: UploaderType is the type of the uploader to handle the
data transfer.
@@ -164,10 +143,9 @@ spec:
description: PodVolumeRestoreStatus is the current status of a PodVolumeRestore.
properties:
completionTimestamp:
description: |-
CompletionTimestamp records the time a restore was completed.
Completion time is recorded even on failed restores.
The server's time is used for CompletionTimestamps
description: CompletionTimestamp records the time a restore was completed.
Completion time is recorded even on failed restores. The server's
time is used for CompletionTimestamps
format: date-time
nullable: true
type: string
@@ -183,10 +161,9 @@ spec:
- Failed
type: string
progress:
description: |-
Progress holds the total number of bytes of the snapshot and the current
number of restored bytes. This can be used to display progress information
about the restore operation.
description: Progress holds the total number of bytes of the snapshot
and the current number of restored bytes. This can be used to display
progress information about the restore operation.
properties:
bytesDone:
format: int64
@@ -196,8 +173,7 @@ spec:
type: integer
type: object
startTimestamp:
description: |-
StartTimestamp records the time a restore was started.
description: StartTimestamp records the time a restore was started.
The server's time is used for StartTimestamps
format: date-time
nullable: true

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: restores.velero.io
spec:
group: velero.io
@@ -17,24 +17,18 @@ spec:
- name: v1
schema:
openAPIV3Schema:
description: |-
Restore is a Velero resource that represents the application of
resources from a Velero backup to a target Kubernetes cluster.
description: Restore is a Velero resource that represents the application
of resources from a Velero backup to a target Kubernetes cluster.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -42,22 +36,19 @@ spec:
description: RestoreSpec defines the specification for a Velero restore.
properties:
backupName:
description: |-
BackupName is the unique name of the Velero backup to restore
from.
description: BackupName is the unique name of the Velero backup to
restore from.
type: string
excludedNamespaces:
description: |-
ExcludedNamespaces contains a list of namespaces that are not
included in the restore.
description: ExcludedNamespaces contains a list of namespaces that
are not included in the restore.
items:
type: string
nullable: true
type: array
excludedResources:
description: |-
ExcludedResources is a slice of resource names that are not
included in the restore.
description: ExcludedResources is a slice of resource names that are
not included in the restore.
items:
type: string
nullable: true
@@ -73,9 +64,9 @@ spec:
properties:
resources:
items:
description: |-
RestoreResourceHookSpec defines one or more RestoreResrouceHooks that should be executed based on
the rules defined for namespaces, resources, and label selector.
description: RestoreResourceHookSpec defines one or more RestoreResrouceHooks
that should be executed based on the rules defined for namespaces,
resources, and label selector.
properties:
excludedNamespaces:
description: ExcludedNamespaces specifies the namespaces
@@ -92,17 +83,17 @@ spec:
nullable: true
type: array
includedNamespaces:
description: |-
IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies
description: IncludedNamespaces specifies the namespaces
to which this hook spec applies. If empty, it applies
to all namespaces.
items:
type: string
nullable: true
type: array
includedResources:
description: |-
IncludedResources specifies the resources to which this hook spec applies. If empty, it applies
to all resources.
description: IncludedResources specifies the resources to
which this hook spec applies. If empty, it applies to
all resources.
items:
type: string
nullable: true
@@ -116,8 +107,8 @@ spec:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
description: A label selector requirement is a selector
that contains values, a key, and an operator that
relates the key and values.
properties:
key:
@@ -125,16 +116,17 @@ spec:
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In,
NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string values.
If the operator is In or NotIn, the values array
must be non-empty. If the operator is Exists
or DoesNotExist, the values array must be empty.
This array is replaced during a strategic merge
patch.
items:
type: string
type: array
@@ -146,10 +138,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs.
A single {key,value} in the matchLabels map is equivalent
to an element of matchExpressions, whose key field
is "key", the operator is "In", and the values array
contains only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -175,14 +168,15 @@ spec:
minItems: 1
type: array
container:
description: |-
Container is the container in the pod where the command should be executed. If not specified,
the pod's first container is used.
description: Container is the container in the
pod where the command should be executed. If
not specified, the pod's first container is
used.
type: string
execTimeout:
description: |-
ExecTimeout defines the maximum amount of time Velero should wait for the hook to complete before
considering the execution a failure.
description: ExecTimeout defines the maximum amount
of time Velero should wait for the hook to complete
before considering the execution a failure.
type: string
onError:
description: OnError specifies how Velero should
@@ -192,16 +186,10 @@ spec:
- Continue
- Fail
type: string
waitForReady:
description: WaitForReady ensures command will
be launched when container is Ready instead
of Running.
nullable: true
type: boolean
waitTimeout:
description: |-
WaitTimeout defines the maximum amount of time Velero should wait for the container to be Ready
before attempting to run the command.
description: WaitTimeout defines the maximum amount
of time Velero should wait for the container
to be Ready before attempting to run the command.
type: string
required:
- command
@@ -231,62 +219,57 @@ spec:
type: array
type: object
includeClusterResources:
description: |-
IncludeClusterResources specifies whether cluster-scoped resources
should be included for consideration in the restore. If null, defaults
to true.
description: IncludeClusterResources specifies whether cluster-scoped
resources should be included for consideration in the restore. If
null, defaults to true.
nullable: true
type: boolean
includedNamespaces:
description: |-
IncludedNamespaces is a slice of namespace names to include objects
from. If empty, all namespaces are included.
description: IncludedNamespaces is a slice of namespace names to include
objects from. If empty, all namespaces are included.
items:
type: string
nullable: true
type: array
includedResources:
description: |-
IncludedResources is a slice of resource names to include
description: IncludedResources is a slice of resource names to include
in the restore. If empty, all resources in the backup are included.
items:
type: string
nullable: true
type: array
itemOperationTimeout:
description: |-
ItemOperationTimeout specifies the time used to wait for RestoreItemAction operations
The default value is 4 hour.
description: ItemOperationTimeout specifies the time used to wait
for RestoreItemAction operations The default value is 1 hour.
type: string
labelSelector:
description: |-
LabelSelector is a metav1.LabelSelector to filter with
when restoring individual objects from the backup. If empty
or nil, all objects are included. Optional.
description: LabelSelector is a metav1.LabelSelector to filter with
when restoring individual objects from the backup. If empty or nil,
all objects are included. Optional.
nullable: true
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements.
The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a selector that
contains values, a key, and an operator that relates the key
and values.
properties:
key:
description: key is the label key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship to
a set of values. Valid operators are In, NotIn, Exists
and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
description: values is an array of string values. If the
operator is In or NotIn, the values array must be non-empty.
If the operator is Exists or DoesNotExist, the values
array must be empty. This array is replaced during a strategic
merge patch.
items:
type: string
@@ -299,58 +282,57 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs. A single
{key,value} in the matchLabels map is equivalent to an element
of matchExpressions, whose key field is "key", the operator
is "In", and the values array contains only "value". The requirements
are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
namespaceMapping:
additionalProperties:
type: string
description: |-
NamespaceMapping is a map of source namespace names
to target namespace names to restore into. Any source
namespaces not included in the map will be restored into
namespaces of the same name.
description: NamespaceMapping is a map of source namespace names to
target namespace names to restore into. Any source namespaces not
included in the map will be restored into namespaces of the same
name.
type: object
orLabelSelectors:
description: |-
OrLabelSelectors is list of metav1.LabelSelector to filter with
when restoring individual objects from the backup. If multiple provided
they will be joined by the OR operator. LabelSelector as well as
OrLabelSelectors cannot co-exist in restore request, only one of them
can be used
description: OrLabelSelectors is list of metav1.LabelSelector to filter
with when restoring individual objects from the backup. If multiple
provided they will be joined by the OR operator. LabelSelector as
well as OrLabelSelectors cannot co-exist in restore request, only
one of them can be used
items:
description: |-
A label selector is a label query over a set of resources. The result of matchLabels and
matchExpressions are ANDed. An empty label selector matches all objects. A null
label selector matches no objects.
description: A label selector is a label query over a set of resources.
The result of matchLabels and matchExpressions are ANDed. An empty
label selector matches all objects. A null label selector matches
no objects.
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements.
The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a selector that
contains values, a key, and an operator that relates the
key and values.
properties:
key:
description: key is the label key that the selector applies
to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn, Exists
and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string values. If the
operator is In or NotIn, the values array must be non-empty.
If the operator is Exists or DoesNotExist, the values
array must be empty. This array is replaced during a
strategic merge patch.
items:
type: string
type: array
@@ -362,10 +344,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs. A single
{key,value} in the matchLabels map is equivalent to an element
of matchExpressions, whose key field is "key", the operator
is "In", and the values array contains only "value". The requirements
are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -382,10 +365,10 @@ spec:
nullable: true
properties:
apiGroup:
description: |-
APIGroup is the group for the resource being referenced.
If APIGroup is not specified, the specified Kind must be in the core API group.
For any other third-party types, APIGroup is required.
description: APIGroup is the group for the resource being referenced.
If APIGroup is not specified, the specified Kind must be in
the core API group. For any other third-party types, APIGroup
is required.
type: string
kind:
description: Kind is the type of resource being referenced
@@ -399,15 +382,13 @@ spec:
type: object
x-kubernetes-map-type: atomic
restorePVs:
description: |-
RestorePVs specifies whether to restore all included
description: RestorePVs specifies whether to restore all included
PVs from snapshot
nullable: true
type: boolean
restoreStatus:
description: |-
RestoreStatus specifies which resources we should restore the status
field. If nil, no objects are included. Optional.
description: RestoreStatus specifies which resources we should restore
the status field. If nil, no objects are included. Optional.
nullable: true
properties:
excludedResources:
@@ -418,71 +399,41 @@ spec:
nullable: true
type: array
includedResources:
description: |-
IncludedResources specifies the resources to which will restore the status.
If empty, it applies to all resources.
description: IncludedResources specifies the resources to which
will restore the status. If empty, it applies to all resources.
items:
type: string
nullable: true
type: array
type: object
scheduleName:
description: |-
ScheduleName is the unique name of the Velero schedule to restore
from. If specified, and BackupName is empty, Velero will restore
from the most recent successful backup created from this schedule.
description: ScheduleName is the unique name of the Velero schedule
to restore from. If specified, and BackupName is empty, Velero will
restore from the most recent successful backup created from this
schedule.
type: string
uploaderConfig:
description: UploaderConfig specifies the configuration for the restore.
nullable: true
properties:
parallelFilesDownload:
description: ParallelFilesDownload is the concurrency number setting
for restore.
type: integer
writeSparseFiles:
description: WriteSparseFiles is a flag to indicate whether write
files sparsely or not.
nullable: true
type: boolean
type: object
required:
- backupName
type: object
status:
description: RestoreStatus captures the current status of a Velero restore
properties:
completionTimestamp:
description: |-
CompletionTimestamp records the time the restore operation was completed.
Completion time is recorded even on failed restore.
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.
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
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:
@@ -494,14 +445,11 @@ spec:
- Completed
- PartiallyFailed
- Failed
- Finalizing
- FinalizingPartiallyFailed
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.
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:
@@ -509,46 +457,42 @@ spec:
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
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.
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.
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.
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
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)
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.
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

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: schedules.velero.io
spec:
group: velero.io
@@ -36,24 +36,18 @@ spec:
name: v1
schema:
openAPIV3Schema:
description: |-
Schedule is a Velero resource that represents a pre-scheduled or
periodic Backup that should be run.
description: Schedule is a Velero resource that represents a pre-scheduled
or periodic Backup that should be run.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -64,80 +58,63 @@ spec:
description: Paused specifies whether the schedule is paused or not
type: boolean
schedule:
description: |-
Schedule is a Cron expression defining when to run
the Backup.
description: Schedule is a Cron expression defining when to run the
Backup.
type: string
skipImmediately:
description: |-
SkipImmediately specifies whether to skip backup if schedule is due immediately from `schedule.status.lastBackup` timestamp when schedule is unpaused or if schedule is new.
If true, backup will be skipped immediately when schedule is unpaused if it is due based on .Status.LastBackupTimestamp or schedule is new, and will run at next schedule time.
If false, backup will not be skipped immediately when schedule is unpaused, but will run at next schedule time.
If empty, will follow server configuration (default: false).
type: boolean
template:
description: |-
Template is the definition of the Backup to be run
on the provided schedule
description: Template is the definition of the Backup to be run on
the provided schedule
properties:
csiSnapshotTimeout:
description: |-
CSISnapshotTimeout specifies the time used to wait for CSI VolumeSnapshot status turns to
ReadyToUse during creation, before returning error as timeout.
The default value is 10 minute.
description: CSISnapshotTimeout specifies the time used to wait
for CSI VolumeSnapshot status turns to ReadyToUse during creation,
before returning error as timeout. The default value is 10 minute.
type: string
datamover:
description: |-
DataMover specifies the data mover to be used by the backup.
If DataMover is "" or "velero", the built-in data mover will be used.
description: DataMover specifies the data mover to be used by
the backup. If DataMover is "" or "velero", the built-in data
mover will be used.
type: string
defaultVolumesToFsBackup:
description: |-
DefaultVolumesToFsBackup specifies whether pod volume file system backup should be used
for all volumes by default.
description: DefaultVolumesToFsBackup specifies whether pod volume
file system backup should be used for all volumes by default.
nullable: true
type: boolean
defaultVolumesToRestic:
description: |-
DefaultVolumesToRestic specifies whether restic should be used to take a
backup of all pod volumes by default.
Deprecated: this field is no longer used and will be removed entirely in future. Use DefaultVolumesToFsBackup instead.
description: "DefaultVolumesToRestic specifies whether restic
should be used to take a backup of all pod volumes by default.
\n Deprecated: this field is no longer used and will be removed
entirely in future. Use DefaultVolumesToFsBackup instead."
nullable: true
type: boolean
excludedClusterScopedResources:
description: |-
ExcludedClusterScopedResources is a slice of cluster-scoped
resource type names to exclude from the backup.
If set to "*", all cluster-scoped resource types are excluded.
The default value is empty.
description: ExcludedClusterScopedResources is a slice of cluster-scoped
resource type names to exclude from the backup. If set to "*",
all cluster-scoped resource types are excluded. The default
value is empty.
items:
type: string
nullable: true
type: array
excludedNamespaceScopedResources:
description: |-
ExcludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to exclude from the backup.
If set to "*", all namespace-scoped resource types are excluded.
The default value is empty.
description: ExcludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to exclude from the backup. If set to "*",
all namespace-scoped resource types are excluded. The default
value is empty.
items:
type: string
nullable: true
type: array
excludedNamespaces:
description: |-
ExcludedNamespaces contains a list of namespaces that are not
included in the backup.
description: ExcludedNamespaces contains a list of namespaces
that are not included in the backup.
items:
type: string
nullable: true
type: array
excludedResources:
description: |-
ExcludedResources is a slice of resource names that are not
included in the backup.
description: ExcludedResources is a slice of resource names that
are not included in the backup.
items:
type: string
nullable: true
@@ -150,9 +127,9 @@ spec:
description: Resources are hooks that should be executed when
backing up individual instances of a resource.
items:
description: |-
BackupResourceHookSpec defines one or more BackupResourceHooks that should be executed based on
the rules defined for namespaces, resources, and label selector.
description: BackupResourceHookSpec defines one or more
BackupResourceHooks that should be executed based on the
rules defined for namespaces, resources, and label selector.
properties:
excludedNamespaces:
description: ExcludedNamespaces specifies the namespaces
@@ -169,16 +146,16 @@ spec:
nullable: true
type: array
includedNamespaces:
description: |-
IncludedNamespaces specifies the namespaces to which this hook spec applies. If empty, it applies
description: IncludedNamespaces specifies the namespaces
to which this hook spec applies. If empty, it applies
to all namespaces.
items:
type: string
nullable: true
type: array
includedResources:
description: |-
IncludedResources specifies the resources to which this hook spec applies. If empty, it applies
description: IncludedResources specifies the resources
to which this hook spec applies. If empty, it applies
to all resources.
items:
type: string
@@ -193,25 +170,26 @@ spec:
description: matchExpressions is a list of label
selector requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a
selector that contains values, a key, and an
operator that relates the key and values.
properties:
key:
description: key is the label key that the
selector applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are
In, NotIn, Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If the
operator is Exists or DoesNotExist, the
values array must be empty. This array is
replaced during a strategic merge patch.
items:
type: string
type: array
@@ -223,10 +201,12 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is "In",
and the values array contains only "value". The
requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -234,9 +214,10 @@ spec:
description: Name is the name of this hook.
type: string
post:
description: |-
PostHooks is a list of BackupResourceHooks to execute after storing the item in the backup.
These are executed after all "additional items" from item actions are processed.
description: PostHooks is a list of BackupResourceHooks
to execute after storing the item in the backup. These
are executed after all "additional items" from item
actions are processed.
items:
description: BackupResourceHook defines a hook for
a resource.
@@ -252,9 +233,10 @@ spec:
minItems: 1
type: array
container:
description: |-
Container is the container in the pod where the command should be executed. If not specified,
the pod's first container is used.
description: Container is the container in
the pod where the command should be executed.
If not specified, the pod's first container
is used.
type: string
onError:
description: OnError specifies how Velero
@@ -265,9 +247,10 @@ spec:
- Fail
type: string
timeout:
description: |-
Timeout defines the maximum amount of time Velero should wait for the hook to complete before
considering the execution a failure.
description: Timeout defines the maximum amount
of time Velero should wait for the hook
to complete before considering the execution
a failure.
type: string
required:
- command
@@ -277,9 +260,10 @@ spec:
type: object
type: array
pre:
description: |-
PreHooks is a list of BackupResourceHooks to execute prior to storing the item in the backup.
These are executed before any "additional items" from item actions are processed.
description: PreHooks is a list of BackupResourceHooks
to execute prior to storing the item in the backup.
These are executed before any "additional items" from
item actions are processed.
items:
description: BackupResourceHook defines a hook for
a resource.
@@ -295,9 +279,10 @@ spec:
minItems: 1
type: array
container:
description: |-
Container is the container in the pod where the command should be executed. If not specified,
the pod's first container is used.
description: Container is the container in
the pod where the command should be executed.
If not specified, the pod's first container
is used.
type: string
onError:
description: OnError specifies how Velero
@@ -308,9 +293,10 @@ spec:
- Fail
type: string
timeout:
description: |-
Timeout defines the maximum amount of time Velero should wait for the hook to complete before
considering the execution a failure.
description: Timeout defines the maximum amount
of time Velero should wait for the hook
to complete before considering the execution
a failure.
type: string
required:
- command
@@ -326,56 +312,50 @@ spec:
type: array
type: object
includeClusterResources:
description: |-
IncludeClusterResources specifies whether cluster-scoped resources
should be included for consideration in the backup.
description: IncludeClusterResources specifies whether cluster-scoped
resources should be included for consideration in the backup.
nullable: true
type: boolean
includedClusterScopedResources:
description: |-
IncludedClusterScopedResources is a slice of cluster-scoped
resource type names to include in the backup.
If set to "*", all cluster-scoped resource types are included.
The default value is empty, which means only related
cluster-scoped resources are included.
description: IncludedClusterScopedResources is a slice of cluster-scoped
resource type names to include in the backup. If set to "*",
all cluster-scoped resource types are included. The default
value is empty, which means only related cluster-scoped resources
are included.
items:
type: string
nullable: true
type: array
includedNamespaceScopedResources:
description: |-
IncludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to include in the backup.
The default value is "*".
description: IncludedNamespaceScopedResources is a slice of namespace-scoped
resource type names to include in the backup. The default value
is "*".
items:
type: string
nullable: true
type: array
includedNamespaces:
description: |-
IncludedNamespaces is a slice of namespace names to include objects
from. If empty, all namespaces are included.
description: IncludedNamespaces is a slice of namespace names
to include objects from. If empty, all namespaces are included.
items:
type: string
nullable: true
type: array
includedResources:
description: |-
IncludedResources is a slice of resource names to include
in the backup. If empty, all resources are included.
description: IncludedResources is a slice of resource names to
include in the backup. If empty, all resources are included.
items:
type: string
nullable: true
type: array
itemOperationTimeout:
description: |-
ItemOperationTimeout specifies the time used to wait for asynchronous BackupItemAction operations
The default value is 4 hour.
description: ItemOperationTimeout specifies the time used to wait
for asynchronous BackupItemAction operations The default value
is 1 hour.
type: string
labelSelector:
description: |-
LabelSelector is a metav1.LabelSelector to filter with
when adding individual objects to the backup. If empty
description: LabelSelector is a metav1.LabelSelector to filter
with when adding individual objects to the backup. If empty
or nil, all objects are included. Optional.
nullable: true
properties:
@@ -383,25 +363,25 @@ spec:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a selector
that contains values, a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn,
Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string values. If
the operator is In or NotIn, the values array must
be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced
during a strategic merge patch.
items:
type: string
type: array
@@ -413,10 +393,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs. A
single {key,value} in the matchLabels map is equivalent
to an element of matchExpressions, whose key field is "key",
the operator is "In", and the values array contains only
"value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -428,41 +409,40 @@ spec:
type: object
type: object
orLabelSelectors:
description: |-
OrLabelSelectors is list of metav1.LabelSelector to filter with
when adding individual objects to the backup. If multiple provided
they will be joined by the OR operator. LabelSelector as well as
OrLabelSelectors cannot co-exist in backup request, only one of them
can be used.
description: OrLabelSelectors is list of metav1.LabelSelector
to filter with when adding individual objects to the backup.
If multiple provided they will be joined by the OR operator.
LabelSelector as well as OrLabelSelectors cannot co-exist in
backup request, only one of them can be used.
items:
description: |-
A label selector is a label query over a set of resources. The result of matchLabels and
matchExpressions are ANDed. An empty label selector matches all objects. A null
label selector matches no objects.
description: A label selector is a label query over a set of
resources. The result of matchLabels and matchExpressions
are ANDed. An empty label selector matches all objects. A
null label selector matches no objects.
properties:
matchExpressions:
description: matchExpressions is a list of label selector
requirements. The requirements are ANDed.
items:
description: |-
A label selector requirement is a selector that contains values, a key, and an operator that
relates the key and values.
description: A label selector requirement is a selector
that contains values, a key, and an operator that relates
the key and values.
properties:
key:
description: key is the label key that the selector
applies to.
type: string
operator:
description: |-
operator represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists and DoesNotExist.
description: operator represents a key's relationship
to a set of values. Valid operators are In, NotIn,
Exists and DoesNotExist.
type: string
values:
description: |-
values is an array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. This array is replaced during a strategic
merge patch.
description: values is an array of string values.
If the operator is In or NotIn, the values array
must be non-empty. If the operator is Exists or
DoesNotExist, the values array must be empty. This
array is replaced during a strategic merge patch.
items:
type: string
type: array
@@ -474,10 +454,11 @@ spec:
matchLabels:
additionalProperties:
type: string
description: |-
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions, whose key field is "key", the
operator is "In", and the values array contains only "value". The requirements are ANDed.
description: matchLabels is a map of {key,value} pairs.
A single {key,value} in the matchLabels map is equivalent
to an element of matchExpressions, whose key field is
"key", the operator is "In", and the values array contains
only "value". The requirements are ANDed.
type: object
type: object
x-kubernetes-map-type: atomic
@@ -486,10 +467,11 @@ spec:
orderedResources:
additionalProperties:
type: string
description: |-
OrderedResources specifies the backup order of resources of specific Kind.
The map key is the resource name and value is a list of object names separated by commas.
Each resource name has format "namespace/objectname". For cluster resources, simply use "objectname".
description: OrderedResources specifies the backup order of resources
of specific Kind. The map key is the resource name and value
is a list of object names separated by commas. Each resource
name has format "namespace/objectname". For cluster resources,
simply use "objectname".
nullable: true
type: object
resourcePolicy:
@@ -497,10 +479,10 @@ spec:
policies that backup should follow
properties:
apiGroup:
description: |-
APIGroup is the group for the resource being referenced.
If APIGroup is not specified, the specified Kind must be in the core API group.
For any other third-party types, APIGroup is required.
description: APIGroup is the group for the resource being
referenced. If APIGroup is not specified, the specified
Kind must be in the core API group. For any other third-party
types, APIGroup is required.
type: string
kind:
description: Kind is the type of resource being referenced
@@ -519,10 +501,9 @@ spec:
nullable: true
type: boolean
snapshotVolumes:
description: |-
SnapshotVolumes specifies whether to take snapshots
of any PV's referenced in the set of objects included
in the Backup.
description: SnapshotVolumes specifies whether to take snapshots
of any PV's referenced in the set of objects included in the
Backup.
nullable: true
type: boolean
storageLocation:
@@ -530,20 +511,9 @@ spec:
a BackupStorageLocation where the backup should be stored.
type: string
ttl:
description: |-
TTL is a time.Duration-parseable string describing how long
the Backup should be retained for.
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.
nullable: true
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.
@@ -552,9 +522,8 @@ spec:
type: array
type: object
useOwnerReferencesInBackup:
description: |-
UseOwnerReferencesBackup specifies whether to use
OwnerReferences on backups created by this Schedule.
description: UseOwnerReferencesBackup specifies whether to use OwnerReferences
on backups created by this Schedule.
nullable: true
type: boolean
required:
@@ -565,17 +534,11 @@ spec:
description: ScheduleStatus captures the current state of a Velero schedule
properties:
lastBackup:
description: |-
LastBackup is the last time a Backup was run for this
description: LastBackup is the last time a Backup was run for this
Schedule schedule
format: date-time
nullable: true
type: string
lastSkipped:
description: LastSkipped is the last time a Schedule was skipped
format: date-time
nullable: true
type: string
phase:
description: Phase is the current phase of the Schedule
enum:
@@ -584,9 +547,8 @@ spec:
- FailedValidation
type: string
validationErrors:
description: |-
ValidationErrors is a slice of all validation errors (if
applicable)
description: ValidationErrors is a slice of all validation errors
(if applicable)
items:
type: string
type: array

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: serverstatusrequests.velero.io
spec:
group: velero.io
@@ -19,24 +19,18 @@ spec:
- name: v1
schema:
openAPIV3Schema:
description: |-
ServerStatusRequest is a request to access current status information about
the Velero server.
description: ServerStatusRequest is a request to access current status information
about the Velero server.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -69,9 +63,8 @@ spec:
nullable: true
type: array
processedTimestamp:
description: |-
ProcessedTimestamp is when the ServerStatusRequest was processed
by the ServerStatusRequestController.
description: ProcessedTimestamp is when the ServerStatusRequest was
processed by the ServerStatusRequestController.
format: date-time
nullable: true
type: string

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: volumesnapshotlocations.velero.io
spec:
group: velero.io
@@ -23,19 +23,14 @@ spec:
snapshots.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -57,10 +52,8 @@ spec:
valid secret key.
type: string
name:
description: |-
Name of the referent.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
TODO: Add other useful fields. apiVersion, kind, uid?'
type: string
optional:
description: Specify whether the Secret or its key must be defined

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: datadownloads.velero.io
spec:
group: velero.io
@@ -52,19 +52,14 @@ spec:
and data mover controller for the datamover restore operation
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -72,14 +67,12 @@ spec:
description: DataDownloadSpec is the specification for a DataDownload.
properties:
backupStorageLocation:
description: |-
BackupStorageLocation is the name of the backup storage location
where the backup repository is stored.
description: BackupStorageLocation is the name of the backup storage
location where the backup repository is stored.
type: string
cancel:
description: |-
Cancel indicates request to cancel the ongoing DataDownload. It can be set
when the DataDownload is in InProgress phase
description: Cancel indicates request to cancel the ongoing DataDownload.
It can be set when the DataDownload is in InProgress phase
type: boolean
dataMoverConfig:
additionalProperties:
@@ -88,23 +81,22 @@ spec:
fields.
type: object
datamover:
description: |-
DataMover specifies the data mover to be used by the backup.
If DataMover is "" or "velero", the built-in data mover will be used.
description: DataMover specifies the data mover to be used by the
backup. If DataMover is "" or "velero", the built-in data mover
will be used.
type: string
operationTimeout:
description: |-
OperationTimeout specifies the time used to wait internal operations,
before returning error as timeout.
description: OperationTimeout specifies the time used to wait internal
operations, before returning error as timeout.
type: string
snapshotID:
description: SnapshotID is the ID of the Velero backup snapshot to
be restored from.
type: string
sourceNamespace:
description: |-
SourceNamespace is the original namespace where the volume is backed up from.
It may be different from SourcePVC's namespace if namespace is remapped during restore.
description: SourceNamespace is the original namespace where the volume
is backed up from. It may be different from SourcePVC's namespace
if namespace is remapped during restore.
type: string
targetVolume:
description: TargetVolume is the information of the target PVC and
@@ -137,10 +129,9 @@ spec:
description: DataDownloadStatus is the current status of a DataDownload.
properties:
completionTimestamp:
description: |-
CompletionTimestamp records the time a restore was completed.
Completion time is recorded even on failed restores.
The server's time is used for CompletionTimestamps
description: CompletionTimestamp records the time a restore was completed.
Completion time is recorded even on failed restores. The server's
time is used for CompletionTimestamps
format: date-time
nullable: true
type: string
@@ -163,10 +154,9 @@ spec:
- Failed
type: string
progress:
description: |-
Progress holds the total number of bytes of the snapshot and the current
number of restored bytes. This can be used to display progress information
about the restore operation.
description: Progress holds the total number of bytes of the snapshot
and the current number of restored bytes. This can be used to display
progress information about the restore operation.
properties:
bytesDone:
format: int64
@@ -176,8 +166,7 @@ spec:
type: integer
type: object
startTimestamp:
description: |-
StartTimestamp records the time a restore was started.
description: StartTimestamp records the time a restore was started.
The server's time is used for StartTimestamps
format: date-time
nullable: true

View File

@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
controller-gen.kubebuilder.io/version: v0.12.0
name: datauploads.velero.io
spec:
group: velero.io
@@ -53,19 +53,14 @@ spec:
data mover controller for the datamover backup operation
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -73,14 +68,12 @@ spec:
description: DataUploadSpec is the specification for a DataUpload.
properties:
backupStorageLocation:
description: |-
BackupStorageLocation is the name of the backup storage location
where the backup repository is stored.
description: BackupStorageLocation is the name of the backup storage
location where the backup repository is stored.
type: string
cancel:
description: |-
Cancel indicates request to cancel the ongoing DataUpload. It can be set
when the DataUpload is in InProgress phase
description: Cancel indicates request to cancel the ongoing DataUpload.
It can be set when the DataUpload is in InProgress phase
type: boolean
csiSnapshot:
description: If SnapshotType is CSI, CSISnapshot provides the information
@@ -111,23 +104,22 @@ spec:
nullable: true
type: object
datamover:
description: |-
DataMover specifies the data mover to be used by the backup.
If DataMover is "" or "velero", the built-in data mover will be used.
description: DataMover specifies the data mover to be used by the
backup. If DataMover is "" or "velero", the built-in data mover
will be used.
type: string
operationTimeout:
description: |-
OperationTimeout specifies the time used to wait internal operations,
before returning error as timeout.
description: OperationTimeout specifies the time used to wait internal
operations, before returning error as timeout.
type: string
snapshotType:
description: SnapshotType is the type of the snapshot to be backed
up.
type: string
sourceNamespace:
description: |-
SourceNamespace is the original namespace where the volume is backed up from.
It is the same namespace for SourcePVC and CSI namespaced objects.
description: SourceNamespace is the original namespace where the volume
is backed up from. It is the same namespace for SourcePVC and CSI
namespaced objects.
type: string
sourcePVC:
description: SourcePVC is the name of the PVC which the snapshot is
@@ -144,11 +136,10 @@ spec:
description: DataUploadStatus is the current status of a DataUpload.
properties:
completionTimestamp:
description: |-
CompletionTimestamp records the time a backup was completed.
Completion time is recorded even on failed backups.
Completion time is recorded before uploading the backup object.
The server's time is used for CompletionTimestamps
description: CompletionTimestamp records the time a backup was completed.
Completion time is recorded even on failed backups. Completion time
is recorded before uploading the backup object. The server's time
is used for CompletionTimestamps
format: date-time
nullable: true
type: string
@@ -182,10 +173,9 @@ spec:
- Failed
type: string
progress:
description: |-
Progress holds the total number of bytes of the volume and the current
number of backed up bytes. This can be used to display progress information
about the backup operation.
description: Progress holds the total number of bytes of the volume
and the current number of backed up bytes. This can be used to display
progress information about the backup operation.
properties:
bytesDone:
format: int64
@@ -199,10 +189,8 @@ spec:
backup repository.
type: string
startTimestamp:
description: |-
StartTimestamp records the time a backup was started.
Separate from CreationTimestamp, since that value changes
on restores.
description: StartTimestamp records the time a backup was started.
Separate from CreationTimestamp, since that value changes on restores.
The server's time is used for StartTimestamps
format: date-time
nullable: true

File diff suppressed because one or more lines are too long

View File

@@ -1,344 +0,0 @@
# Extend VolumePolicies to support more actions
## Abstract
Currently, the [VolumePolicies feature](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/handle-backup-of-volumes-by-resources-filters.md) which can be used to filter/handle volumes during backup only supports the skip action on matching conditions. Users need more actions to be supported.
## Background
The `VolumePolicies` feature was introduced in Velero 1.11 as a flexible way to handle volumes. The main agenda of
introducing the VolumePolicies feature was to improve the overall user experience when performing backup operations
for volume resources, the feature enables users to group volumes according the `conditions` (criteria) specified and
also lets you specify the `action` that velero needs to take for these grouped volumes during the backup operation.
The limitation being that currently `VolumePolicies` only supports `skip` as an action, We want to extend the `action`
functionality to support more usable options like `fs-backup` (File system backup) and `snapshot` (VolumeSnapshots).
## Goals
- Extending the VolumePolicies to support more actions like `fs-backup` (File system backup) and `snapshot` (VolumeSnapshots).
- Improve user experience when backing up Volumes via Velero
## Non-Goals
- No changes to existing approaches to opt-in/opt-out annotations for volumes
- No changes to existing `VolumePolicies` functionalities
- No additions or implementations to support more granular actions like `snapshot-csi` and `snapshot-datamover`. These actions can be implemented as a future enhancement
## Use-cases/Scenarios
**Use-case 1:**
- A user wants to use `snapshot` (volumesnapshots) backup option for all the csi supported volumes and `fs-backup` for the rest of the volumes.
- Currently, velero supports this use-case but the user experience is not that great.
- The user will have to individually annotate the volume mounting pod with the annotation "backup.velero.io/backup-volumes" for `fs-backup`
- This becomes cumbersome at scale.
- Using `VolumePolicies`, the user can just specify 2 simple `VolumePolicies` like for csi supported volumes as `snapshot` action and rest can be backed up`fs-backup` action:
```yaml
version: v1
volumePolicies:
- conditions:
storageClass:
- gp2
action:
type: snapshot
- conditions: {}
action:
type: fs-backup
```
**Use-case 2:**
- A user wants to use `fs-backup` for nfs volumes pertaining to a particular server
- In such a scenario the user can just specify a `VolumePolicy` like:
```yaml
version: v1
volumePolicies:
- conditions:
nfs:
server: 192.168.200.90
action:
type: fs-backup
```
## High-Level Design
- When the VolumePolicy action is set as `fs-backup` the backup workflow modifications would be:
- We call [backupItem() -> backupItemInternal()](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_backupper.go#L95) on all the items that are to be backed up
- Here when we encounter [Pod as an item ](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_backupper.go#L195)
- We will have to modify the backup workflow to account for the `fs-backup` VolumePolicy action
- When the VolumePolicy action is set as `snapshot` the backup workflow modifications would be:
- Once again, We call [backupItem() -> backupItemInternal()](https://github.com/vmware-tanzu/velero/blob/main/pkg/backup/item_backupper.go#L95) on all the items that are to be backed up
- Here when we encounter [Persistent Volume as an item](https://github.com/vmware-tanzu/velero/blob/d4128542590470b204a642ee43311921c11db880/pkg/backup/item_backupper.go#L253)
- And we call the [takePVSnapshot func](https://github.com/vmware-tanzu/velero/blob/d4128542590470b204a642ee43311921c11db880/pkg/backup/item_backupper.go#L508)
- We need to modify the takePVSnapshot function to account for the `snapshot` VolumePolicy action.
- In case of csi snapshots for PVC objects, these snapshot actions are taken by the velero-plugin-for-csi, we need to modify the [executeActions()](https://github.com/vmware-tanzu/velero/blob/512fe0dabdcb3bbf1ca68a9089056ae549663bcf/pkg/backup/item_backupper.go#L232) function to account for the `snapshot` VolumePolicy action.
**Note:** `Snapshot` action can either be a native snapshot or a csi snapshot, as is the case with the current flow where velero itself makes the decision based on the backup CR.
## Detailed Design
- Update VolumePolicy action type validation to account for `fs-backup` and `snapshot` as valid VolumePolicy actions.
- Modifications needed for `fs-backup` action:
- Now based on the specification of volume policy on backup request we will decide whether to go via legacy pod annotations approach or the newer volume policy based fs-backup action approach.
- If there is a presence of volume policy(fs-backup/snapshot) on the backup request that matches as an action for a volume we use the newer volume policy approach to get the list of the volumes for `fs-backup` action
- Else continue with the annotation based legacy approach workflow.
- Modifications needed for `snapshot` action:
- In the [takePVSnapshot function](https://github.com/vmware-tanzu/velero/blob/d4128542590470b204a642ee43311921c11db880/pkg/backup/item_backupper.go#L508) we will check the PV fits the volume policy criteria and see if the associated action is `snapshot`
- If it is not snapshot then we skip the further workflow and avoid taking the snapshot of the PV
- Similarly, For csi snapshot of PVC object, we need to do similar changes in [executeAction() function](https://github.com/vmware-tanzu/velero/blob/512fe0dabdcb3bbf1ca68a9089056ae549663bcf/pkg/backup/item_backupper.go#L348). we will check the PVC fits the volume policy criteria and see if the associated action is `snapshot` via csi plugin
- If it is not snapshot then we skip the csi BIA execute action and avoid taking the snapshot of the PVC by not invoking the csi plugin action for the PVC
**Note:**
- When we are using the `VolumePolicy` approach for backing up the volumes then the volume policy criteria and action need to be specific and explicit, there is no default behavior, if a volume matches `fs-backup` action then `fs-backup` method will be used for that volume and similarly if the volume matches the criteria for `snapshot` action then the snapshot workflow will be used for the volume backup.
- Another thing to note is the workflow proposed in this design uses the legacy `opt-in/opt-out` approach as a fallback option. For instance, the user specifies a VolumePolicy but for a particular volume included in the backup there are no actions(fs-backup/snapshot) matching in the volume policy for that volume, in such a scenario the legacy approach will be used for backing up the particular volume.
- The relation between the `VolumePolicy` and the backup's legacy parameter `SnapshotVolumes`:
- The `VolumePolicy`'s `snapshot` action matching for volume has higher priority. When there is a `snapshot` action matching for the selected volume, it will be backed by the snapshot way, no matter of the `backup.Spec.SnapshotVolumes` setting.
- If there is no `snapshot` action matching the selected volume in the `VolumePolicy`, then the volume will be backed up by `snapshot` way, if the `backup.Spec.SnapshotVolumes` is not set to false.
- The relation between the `VolumePolicy` and the backup's legacy filesystem `opt-in/opt-out` approach:
- The `VolumePolicy`'s `fs-backup` action matching for volume has higher priority. When there is a `fs-backup` action matching for the selected volume, it will be backed by the fs-backup way, no matter of the `backup.Spec.DefaultVolumesToFsBackup` setting and the pod's `opt-in/opt-out` annotation setting.
- If there is no `fs-backup` action matching the selected volume in the `VolumePolicy`, then the volume will be backed up by the legacy `opt-in/opt-out` way.
## Implementation
- The implementation should be included in velero 1.14
- We will introduce a `VolumeHelper` interface. It will consist of two methods:
```go
type VolumeHelper interface {
ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error)
ShouldPerformFSBackup(volume corev1api.Volume, pod corev1api.Pod) (bool, error)
}
```
- The `VolumeHelperImpl` struct will implement the `VolumeHelper` interface and will consist of the functions that we will use through the backup workflow to accommodate volume policies for PVs and PVCs.
```go
type volumeHelperImpl struct {
volumePolicy *resourcepolicies.Policies
snapshotVolumes *bool
logger logrus.FieldLogger
client crclient.Client
defaultVolumesToFSBackup bool
backupExcludePVC bool
}
```
- We will create an instance of the structure `volumeHelperImpl` in `item_backupper.go`
```go
itemBackupper := &itemBackupper{
...
volumeHelperImpl: volumehelper.NewVolumeHelperImpl(
resourcePolicy,
backupRequest.Spec.SnapshotVolumes,
log,
kb.kbClient,
boolptr.IsSetToTrue(backupRequest.Spec.DefaultVolumesToFsBackup),
!backupRequest.ResourceIncludesExcludes.ShouldInclude(kuberesource.PersistentVolumeClaims.String()),
),
}
```
#### FS-Backup
- Regarding `fs-backup` action to decide whether to use legacy annotation based approach or volume policy based approach:
- We will use the `vh.ShouldPerformFSBackup()` function from the `volumehelper` package
- Functions involved in processing `fs-backup` volume policy action will somewhat look like:
```go
func (v volumeHelperImpl) ShouldPerformFSBackup(volume corev1api.Volume, pod corev1api.Pod) (bool, error) {
if !v.shouldIncludeVolumeInBackup(volume) {
v.logger.Debugf("skip fs-backup action for pod %s's volume %s, due to not pass volume check.", pod.Namespace+"/"+pod.Name, volume.Name)
return false, nil
}
if v.volumePolicy != nil {
pvc, err := kubeutil.GetPVCForPodVolume(&volume, &pod, v.client)
if err != nil {
v.logger.WithError(err).Errorf("fail to get PVC for pod %s", pod.Namespace+"/"+pod.Name)
return false, err
}
pv, err := kubeutil.GetPVForPVC(pvc, v.client)
if err != nil {
v.logger.WithError(err).Errorf("fail to get PV for PVC %s", pvc.Namespace+"/"+pvc.Name)
return false, err
}
action, err := v.volumePolicy.GetMatchAction(pv)
if err != nil {
v.logger.WithError(err).Errorf("fail to get VolumePolicy match action for PV %s", pv.Name)
return false, err
}
if action != nil {
if action.Type == resourcepolicies.FSBackup {
v.logger.Infof("Perform fs-backup action for volume %s of pod %s due to volume policy match",
volume.Name, pod.Namespace+"/"+pod.Name)
return true, nil
} else {
v.logger.Infof("Skip fs-backup action for volume %s for pod %s because the action type is %s",
volume.Name, pod.Namespace+"/"+pod.Name, action.Type)
return false, nil
}
}
}
if v.shouldPerformFSBackupLegacy(volume, pod) {
v.logger.Infof("Perform fs-backup action for volume %s of pod %s due to opt-in/out way",
volume.Name, pod.Namespace+"/"+pod.Name)
return true, nil
} else {
v.logger.Infof("Skip fs-backup action for volume %s of pod %s due to opt-in/out way",
volume.Name, pod.Namespace+"/"+pod.Name)
return false, nil
}
}
```
- The main function from the above will be called when we encounter Pods during the backup workflow:
```go
for _, volume := range pod.Spec.Volumes {
shouldDoFSBackup, err := ib.volumeHelperImpl.ShouldPerformFSBackup(volume, *pod)
if err != nil {
backupErrs = append(backupErrs, errors.WithStack(err))
}
...
}
```
#### Snapshot (PV)
- Making sure that `snapshot` action is skipped for PVs that do not fit the volume policy criteria, for this we will use the `vh.ShouldPerformSnapshot` from the `VolumeHelperImpl(vh)` receiver.
```go
func (v *volumeHelperImpl) ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error) {
// check if volume policy exists and also check if the object(pv/pvc) fits a volume policy criteria and see if the associated action is snapshot
// if it is not snapshot then skip the code path for snapshotting the PV/PVC
pvc := new(corev1api.PersistentVolumeClaim)
pv := new(corev1api.PersistentVolume)
var err error
if groupResource == kuberesource.PersistentVolumeClaims {
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pvc); err != nil {
return false, err
}
pv, err = kubeutil.GetPVForPVC(pvc, v.client)
if err != nil {
return false, err
}
}
if groupResource == kuberesource.PersistentVolumes {
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), &pv); err != nil {
return false, err
}
}
if v.volumePolicy != nil {
action, err := v.volumePolicy.GetMatchAction(pv)
if err != nil {
return false, err
}
// If there is a match action, and the action type is snapshot, return true,
// or the action type is not snapshot, then return false.
// If there is no match action, go on to the next check.
if action != nil {
if action.Type == resourcepolicies.Snapshot {
v.logger.Infof(fmt.Sprintf("performing snapshot action for pv %s", pv.Name))
return true, nil
} else {
v.logger.Infof("Skip snapshot action for pv %s as the action type is %s", pv.Name, action.Type)
return false, nil
}
}
}
// If this PV is claimed, see if we've already taken a (pod volume backup)
// snapshot of the contents of this PV. If so, don't take a snapshot.
if pv.Spec.ClaimRef != nil {
pods, err := podvolumeutil.GetPodsUsingPVC(
pv.Spec.ClaimRef.Namespace,
pv.Spec.ClaimRef.Name,
v.client,
)
if err != nil {
v.logger.WithError(err).Errorf("fail to get pod for PV %s", pv.Name)
return false, err
}
for _, pod := range pods {
for _, vol := range pod.Spec.Volumes {
if vol.PersistentVolumeClaim != nil &&
vol.PersistentVolumeClaim.ClaimName == pv.Spec.ClaimRef.Name &&
v.shouldPerformFSBackupLegacy(vol, pod) {
v.logger.Infof("Skipping snapshot of pv %s because it is backed up with PodVolumeBackup.", pv.Name)
return false, nil
}
}
}
}
if !boolptr.IsSetToFalse(v.snapshotVolumes) {
// If the backup.Spec.SnapshotVolumes is not set, or set to true, then should take the snapshot.
v.logger.Infof("performing snapshot action for pv %s as the snapshotVolumes is not set to false")
return true, nil
}
v.logger.Infof(fmt.Sprintf("skipping snapshot action for pv %s possibly due to no volume policy setting or snapshotVolumes is false", pv.Name))
return false, nil
}
```
- The function `ShouldPerformSnapshot` will be used as follows in `takePVSnapshot` function of the backup workflow:
```go
snapshotVolume, err := ib.volumeHelperImpl.ShouldPerformSnapshot(obj, kuberesource.PersistentVolumes)
if err != nil {
return err
}
if !snapshotVolume {
log.Info(fmt.Sprintf("skipping volume snapshot for PV %s as it does not fit the volume policy criteria specified by the user for snapshot action", pv.Name))
ib.trackSkippedPV(obj, kuberesource.PersistentVolumes, volumeSnapshotApproach, "does not satisfy the criteria for volume policy based snapshot action", log)
return nil
}
```
#### Snapshot (PVC)
- Making sure that `snapshot` action is skipped for PVCs that do not fit the volume policy criteria, for this we will again use the `vh.ShouldPerformSnapshot` from the `VolumeHelperImpl(vh)` receiver.
- We will pass the `VolumeHelperImpl(vh)` instance in `executeActions` method so that it is available to use.
```go
```
- The above function will be used as follows in the `executeActions` function of backup workflow.
- Considering the vSphere plugin doesn't support the VolumePolicy yet, don't use the VolumePolicy for vSphere plugin by now.
```go
if groupResource == kuberesource.PersistentVolumeClaims {
if actionName == csiBIAPluginName {
snapshotVolume, err := ib.volumeHelperImpl.ShouldPerformSnapshot(obj, kuberesource.PersistentVolumeClaims)
if err != nil {
return nil, itemFiles, errors.WithStack(err)
}
if !snapshotVolume {
log.Info(fmt.Sprintf("skipping csi volume snapshot for PVC %s as it does not fit the volume policy criteria specified by the user for snapshot action", namespace+"/"+name))
ib.trackSkippedPV(obj, kuberesource.PersistentVolumeClaims, volumeSnapshotApproach, "does not satisfy the criteria for volume policy based snapshot action", log)
continue
}
}
}
```
## Future Implementation
It makes sense to add more specific actions in the future, once we deprecate the legacy opt-in/opt-out approach to keep things simple. Another point of note is, csi related action can be
easier to implement once we decide to merge the csi plugin into main velero code flow.
In the future, we envision the following actions that can be implemented:
- `snapshot-native`: only use volume snapshotter (native cloud provider snapshots), do nothing if not present/not compatible
- `snapshot-csi`: only use csi-plugin, don't use volume snapshotter(native cloud provider snapshots), don't use datamover even if snapshotMoveData is true
- `snapshot-datamover`: only use csi with datamover, don't use volume snapshotter (native cloud provider snapshots), use datamover even if snapshotMoveData is false
**Note:** The above actions are just suggestions for future scope, we may not use/implement them as is. We could definitely merge these suggested actions as `Snapshot` actions and use volume policy parameters and criteria to segregate them instead of making the user explicitly supply the action names to such granular levels.
## Related to Design
[Handle backup of volumes by resources filters](https://github.com/vmware-tanzu/velero/blob/main/design/Implemented/handle-backup-of-volumes-by-resources-filters.md)
## Alternatives Considered
Same as the earlier design as this is an extension of the original VolumePolicies design

View File

@@ -65,7 +65,7 @@ This page contains a pre-migration checklist for ensuring a repo migration goes
#### Updating Netlify
The settings for Netlify should remain the same, except that it now needs to be installed in the new repo. The instructions on how to install Netlify on the new repo are here: https://www.netlify.com/docs/github-permissions/.
The settings for Netflify should remain the same, except that it now needs to be installed in the new repo. The instructions on how to install Netlify on the new repo are here: https://www.netlify.com/docs/github-permissions/.
#### Communication strategy

View File

@@ -1,137 +0,0 @@
# Node-agent Load Affinity Design
## Glossary & Abbreviation
**Velero Generic Data Path (VGDP)**: VGDP is the collective modules that is introduced in [Unified Repository design][1]. Velero uses these modules to finish data transfer for various purposes (i.e., PodVolume backup/restore, Volume Snapshot Data Movement). VGDP modules include uploaders and the backup repository.
**Exposer**: Exposer is a module that is introduced in [Volume Snapshot Data Movement Design][2]. Velero uses this module to expose the volume snapshots to Velero node-agent pods or node-agent associated pods so as to complete the data movement from the snapshots.
## Background
Velero node-agent is a daemonset hosting controllers and VGDP modules to complete the concrete work of backups/restores, i.e., PodVolume backup/restore, Volume Snapshot Data Movement backup/restore.
Specifically, node-agent runs DataUpload controllers to watch DataUpload CRs for Volume Snapshot Data Movement backups, so there is one controller instance in each node. One controller instance takes a DataUpload CR and then launches a VGDP instance, which initializes a uploader instance and the backup repository connection, to finish the data transfer. The VGDP instance runs inside a node-agent pod or in a pod associated to the node-agent pod in the same node.
Varying from the data size, data complexity, resource availability, VGDP may take a long time and remarkable resources (CPU, memory, network bandwidth, etc.).
Technically, VGDP instances are able to run in any node that allows pod schedule. On the other hand, users may want to constrain the nodes where VGDP instances run for various reasons, below are some examples:
- Prevent VGDP instances from running in specific nodes because users have more critical workloads in the nodes
- Constrain VGDP instances to run in specific nodes because these nodes have more resources than others
- Constrain VGDP instances to run in specific nodes because the storage allows volume/snapshot provisions in these nodes only
Therefore, in order to improve the compatibility, it is worthy to configure the affinity of VGDP to nodes, especially for backups for which VGDP instances run frequently and centrally.
## Goals
- Define the behaviors of node affinity of VGDP instances in node-agent for volume snapshot data movement backups
- Create a mechanism for users to specify the node affinity of VGDP instances for volume snapshot data movement backups
## Non-Goals
- It is also beneficial to support VGDP instances affinity for PodVolume backup/restore, however, it is not possible since VGDP instances for PodVolume backup/restore should always run in the node where the source/target pods are created.
- It is also beneficial to support VGDP instances affinity for data movement restores, however, it is not possible in some cases. For example, when the `volumeBindingMode` in the storageclass is `WaitForFirstConsumer`, the restore volume must be mounted in the node where the target pod is scheduled, so the VGDP instance must run in the same node. On the other hand, considering the fact that restores may not frequently and centrally run, we will not support data movement restores.
- As elaberated in the [Volume Snapshot Data Movement Design][2], the Exposer may take different ways to expose snapshots, i.e., through backup pods (this is the only way supported at present). The implementation section below only considers this approach currently, if a new expose method is introduced in future, the definition of the affinity configurations and behaviors should still work, but we may need a new implementation.
## Solution
We will use the ```node-agent-config``` configMap to host the node affinity configurations.
This configMap is not created by Velero, users should create it manually on demand. The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to node-agent in that namespace only.
Node-agent server checks these configurations at startup time and use it to initiate the related VGDP modules. Therefore, users could edit this configMap any time, but in order to make the changes effective, node-agent server needs to be restarted.
Inside ```node-agent-config``` configMap we will add one new kind of configuration as the data in the configMap, the name is ```loadAffinity```.
Users may want to set different LoadAffinity configurations according to different conditions (i.e., for different storages represented by StorageClass, CSI driver, etc.), so we define ```loadAffinity``` as an array. This is for extensibility consideration, at present, we don't implement multiple configurations support, so if there are multiple configurations, we always take the first one in the array.
The data structure for ```node-agent-config``` is as below:
```go
type Configs struct {
// LoadConcurrency is the config for load concurrency per node.
LoadConcurrency *LoadConcurrency `json:"loadConcurrency,omitempty"`
// LoadAffinity is the config for data path load affinity.
LoadAffinity []*LoadAffinity `json:"loadAffinity,omitempty"`
}
type LoadAffinity struct {
// NodeSelector specifies the label selector to match nodes
NodeSelector metav1.LabelSelector `json:"nodeSelector"`
}
```
### Affinity
Affinity configuration means allowing VGDP instances running in the nodes specified. There are two ways to define it:
- It could be defined by `MatchLabels` of `metav1.LabelSelector`. The labels defined in `MatchLabels` means a `LabelSelectorOpIn` operation by default, so in the current context, they will be treated as affinity rules.
- It could be defined by `MatchExpressions` of `metav1.LabelSelector`. The labels are defined in `Key` and `Values` of `MatchExpressions` and the `Operator` should be defined as `LabelSelectorOpIn` or `LabelSelectorOpExists`.
### Anti-affinity
Anti-affinity configuration means preventing VGDP instances running in the nodes specified. Below is the way to define it:
- It could be defined by `MatchExpressions` of `metav1.LabelSelector`. The labels are defined in `Key` and `Values` of `MatchExpressions` and the `Operator` should be defined as `LabelSelectorOpNotIn` or `LabelSelectorOpDoesNotExist`.
### Sample
A sample of the ```node-agent-config``` configMap is as below:
```json
{
"loadAffinity": [
{
"nodeSelector": {
"matchLabels": {
"beta.kubernetes.io/instance-type": "Standard_B4ms"
},
"matchExpressions": [
{
"key": "kubernetes.io/hostname",
"values": [
"node-1",
"node-2",
"node-3"
],
"operator": "In"
},
{
"key": "xxx/critial-workload",
"operator": "DoesNotExist"
}
]
}
}
]
}
```
This sample showcases two affinity configurations:
- matchLabels: VGDP instances will run only in nodes with label key `beta.kubernetes.io/instance-type` and value `Standard_B4ms`
- matchExpressions: VGDP instances will run in node `node1`, `node2` and `node3` (selected by `kubernetes.io/hostname` label)
This sample showcases one anti-affinity configuration:
- matchExpressions: VGDP instances will not run in nodes with label key `xxx/critial-workload`
To create the configMap, users need to save something like the above sample to a json file and then run below command:
```
kubectl create cm node-agent-config -n velero --from-file=<json file name>
```
### Implementation
As mentioned in the [Volume Snapshot Data Movement Design][2], the exposer decides where to launch the VGDP instances. At present, for volume snapshot data movement backups, the exposer creates backupPods and the VGDP instances will be initiated in the nodes where backupPods are scheduled. So the loadAffinity will be translated (from `metav1.LabelSelector` to `corev1.Affinity`) and set to the backupPods.
It is possible that node-agent pods, as a daemonset, don't run in every worker nodes, users could fulfil this by specify `nodeSelector` or `nodeAffinity` to the node-agent daemonset spec. On the other hand, at present, VGDP instances must be assigned to nodes where node-agent pods are running. Therefore, if there is any node selection for node-agent pods, users must consider this into this load affinity configuration, so as to guarantee that VGDP instances are always assigned to nodes where node-agent pods are available. This is done by users, we don't inherit any node selection configuration from node-agent daemonset as we think daemonset scheduler works differently from plain pod scheduler, simply inheriting all the configurations may cause unexpected result of backupPod schedule.
Otherwise, if a backupPod are scheduled to a node where node-agent pod is absent, the corresponding DataUpload CR will stay in `Accepted` phase until the prepare timeout (by default 30min).
At present, as part of the expose operations, the exposer creates a volume, represented by backupPVC, from the snapshot. The backupPVC uses the same storageClass with the source volume. If the `volumeBindingMode` in the storageClass is `Immediate`, the volume is immediately allocated from the underlying storage without waiting for the backupPod. On the other hand, the loadAffinity is set to the backupPod's affinity. If the backupPod is scheduled to a node where the snapshot volume is not accessible, e.g., because of storage topologies, the backupPod won't get into Running state, concequently, the data movement won't complete.
Once this problem happens, the backupPod stays in `Pending` phase, and the corresponding DataUpload CR stays in `Accepted` phase until the prepare timeout (by default 30min).
There is a common solution for the both problems:
- We have an existing logic to periodically enqueue the dataupload CRs which are in the `Accepted` phase for timeout and cancel checks
- We add a new logic to this existing logic to check if the corresponding backupPods are in unrecoverable status
- The above problems could be covered by this check, because in both cases the backupPods are in abnormal and unrecoverable status
- If a backupPod is unrecoverable, the dataupload controller cancels the dataupload and deletes the backupPod
Specifically, when the above problems happen, the status of a backupPod is like below:
```
status:
conditions:
- lastProbeTime: null
message: '0/2 nodes are available: 1 node(s) didn''t match Pod''s node affinity/selector,
1 node(s) had volume node affinity conflict. preemption: 0/2 nodes are available:
2 Preemption is not helpful for scheduling..'
reason: Unschedulable
status: "False"
type: PodScheduled
phase: Pending
```
[1]: Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md
[2]: volume-snapshot-data-movement/volume-snapshot-data-movement.md

View File

@@ -1,131 +0,0 @@
# Node-agent Concurrency Design
## Glossary & Abbreviation
**Velero Generic Data Path (VGDP)**: VGDP is the collective of modules that is introduced in [Unified Repository design][1]. Velero uses these modules to finish data transfer for various purposes (i.e., PodVolume backup/restore, Volume Snapshot Data Movement). VGDP modules include uploaders and the backup repository.
## Background
Velero node-agent is a daemonset hosting controllers and VGDP modules to complete the concrete work of backups/restores, i.e., PodVolume backup/restore, Volume Snapshot Data Movement backup/restore.
For example, node-agent runs DataUpload controllers to watch DataUpload CRs for Volume Snapshot Data Movement backups, so there is one controller instance in each node. One controller instance takes a DataUpload CR and then launches a VGDP instance, which initializes a uploader instance and the backup repository connection, to finish the data transfer. The VGDP instance runs inside the node-agent pod or in a pod associated to the node-agent pod in the same node.
Varying from the data size, data complexity, resource availability, VGDP may take a long time and remarkable resources (CPU, memory, network bandwidth, etc.).
Technically, VGDP instances are able to run in concurrent regardless of the requesters. For example, a VGDP instance for a PodVolume backup could run in parallel with another VGDP instance for a DataUpload. Then the two VGDP instances share the same resources if they are running in the same node.
Therefore, in order to gain the optimized performance with the limited resources, it is worthy to configure the concurrent number of VGDP per node. When the resources are sufficient in nodes, users can set a large concurrent number, so as to reduce the backup/restore time; otherwise, the concurrency should be reduced, otherwise, the backup/restore may encounter problems, i.e., time lagging, hang or OOM kill.
## Goals
- Define the behaviors of concurrent VGDP instances in node-agent
- Create a mechanism for users to specify the concurrent number of VGDP per node
## Non-Goals
- VGDP instances from different nodes always run in concurrent since in most common cases the resources are isolated. For special cases that some resources are shared across nodes, there is no support at present
- In practice, restores run in prioritized scenarios, e.g., disaster recovery. However, the current design doesn't consider this difference, a VGDP instance for a restore is blocked if it reaches to the limit of the concurrency, even though the ones block it are for backups. If users do meet some problems here, they should consider to stop the backups first
- Sometimes, users wants to totally block backups/restores from running in a specific node, this is out of the scope the current design. To archive this, more modules need to be considered (i.e., expoers of data movers), simply blocking the VGDP (e.g., by setting its concurrent number to 0) doesn't work. E.g., for a fs backup, VGDP instance must run in the node the source pod is running in, if we simply block from VGDP instance, the PodVolumeBackup CR is still submitted but never processed.
## Solution
We introduce a configMap named ```node-agent-config``` for users to specify the node-agent related configurations. This configMap is not created by Velero, users should create it manually on demand. The configMap should be in the same namespace where Velero is installed. If multiple Velero instances are installed in different namespaces, there should be one configMap in each namespace which applies to node-agent in that namespace only.
Node-agent server checks these configurations at startup time and use it to initiate the related VGDP modules. Therefore, users could edit this configMap any time, but in order to make the changes effective, node-agent server needs to be restarted.
The ```node-agent-config``` configMap may be used for other purpose of configuring node-agent in future, at present, there is only one kind of configuration as the data in the configMap, the name is ```loadConcurrency```.
The data structure for ```node-agent-config``` is as below:
```go
type Configs struct {
// LoadConcurrency is the config for load concurrency per node.
LoadConcurrency *LoadConcurrency `json:"loadConcurrency,omitempty"`
}
type LoadConcurrency struct {
// GlobalConfig specifies the concurrency number to all nodes for which per-node config is not specified
GlobalConfig int `json:"globalConfig,omitempty"`
// PerNodeConfig specifies the concurrency number to nodes matched by rules
PerNodeConfig []RuledConfigs `json:"perNodeConfig,omitempty"`
}
type RuledConfigs struct {
// NodeSelector specifies the label selector to match nodes
NodeSelector metav1.LabelSelector `json:"nodeSelector"`
// Number specifies the number value associated to the matched nodes
Number int `json:"number"`
}
```
### Global concurrent number
We allow users to specify a concurrent number that will be applied to all nodes if the per-node number is not specified. This number is set through ```globalConfig```.
The number starts from 1 which means there is no concurrency, only one instance of VGDP is allowed. There is no roof limit.
If this number is not specified or not valid, a hard-coded default value will be used, the value is set to 1.
### Per-node concurrent number
We allow users to specify different concurrent number per node, for example, users can set 3 concurrent instances in Node-1, 2 instances in Node-2 and 1 instance in Node-3. This is for below considerations:
- The resources may be different among nodes. Then users could specify smaller concurrent number for nodes with less resources while larger number for the ones with more resources
- Help users to isolate critical environments. Users may run some critical workloads in some specified nodes, since VGDP instances may take large resource consumption, users may want to run less number of instances in the nodes with critical workloads
The range of Per-node concurrent number is the same with Global concurrent number.
Per-node concurrent number is preferable to Global concurrent number, so it will overwrite the Global concurrent number for that node.
Per-node concurrent number is implemented through ```perNodeConfig``` field.
```perNodeConfig``` is a list of ```RuledConfigs``` each item of which matches one or more nodes by label selectors and specify the concurrent number for the matched nodes. This means, the nodes are identified by labels.
For example, the ```perNodeConfig`` could have below elements:
```
"nodeSelector: kubernetes.io/hostname=node1; number: 3"
"nodeSelector: beta.kubernetes.io/instance-type=Standard_B4ms; number: 5"
```
The first element means the node with host name ```node1``` gets the Per-node concurrent number of 3.
The second element means all the nodes with label ```beta.kubernetes.io/instance-type``` of value ```Standard_B4ms``` get the Per-node concurrent number of 5.
At least one node is expected to have a label with the specified ```RuledConfigs``` element (rule). If no node is with this label, the Per-node rule makes no effect.
If one node falls into more than one rules, e.g., if node1 also has the label ```beta.kubernetes.io/instance-type=Standard_B4ms```, the smallest number (3) will be used.
### Sample
A sample of the ```node-agent-config``` configMap is as below:
```json
{
"loadConcurrency": {
"globalConfig": 2,
"perNodeConfig": [
{
"nodeSelector": {
"matchLabels": {
"kubernetes.io/hostname": "node1"
}
},
"number": 3
},
{
"nodeSelector": {
"matchLabels": {
"beta.kubernetes.io/instance-type": "Standard_B4ms"
}
},
"number": 5
}
]
}
}
```
To create the configMap, users need to save something like the above sample to a json file and then run below command:
```
kubectl create cm node-agent-config -n velero --from-file=<json file name>
```
### Global data path manager
As for the code implementation, data path manager is to maintain the total number of the running VGDP instances and ensure the limit is not excceeded. At present, there is one data path manager instance per controller, as a result, the concurrent numbers are calculated separately for each controller. This doesn't help to limit the concurrency among different requesters.
Therefore, we need to create one global data path manager instance server-wide, and pass it to different controllers. The instance will be created at node-agent server startup.
The concurrent number is required to initiate a data path manager, the number comes from either Per-node concurrent number or Global concurrent number.
Below are some prototypes related to data path manager:
```go
func NewManager(cocurrentNum int) *Manager
func (m *Manager) CreateFileSystemBR(jobName string, requestorType string, ctx context.Context, client client.Client, namespace string, callbacks Callbacks, log logrus.FieldLogger) (AsyncBR, error)
```
[1]: Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md

View File

@@ -1,186 +0,0 @@
# PersistentVolume backup information design
## Abstract
Create a new metadata file in the backup repository's backup name sub-directory to store the backup-including PVC and PV information. The information includes the way of backing up the PVC and PV data, snapshot information, and status. The needed snapshot status can also be recorded there, but the Velero-Native snapshot plugin doesn't provide a way to get the snapshot size from the API, so it's possible that not all snapshot size information is available.
This new additional metadata file is needed when:
* Get a summary of the backup's PVC and PV information, including how the data in them is backed up, or whether the data in them is skipped from backup.
* Find out how the PVC and PV should be restored in the restore process.
* Retrieve the PV's snapshot information for backup.
## Background
There is already a [PR](https://github.com/vmware-tanzu/velero/pull/6496) to track the skipped PVC in the backup. This design will depend on it and go further to get a summary of PVC and PV information, then persist into a metadata file in the backup repository.
In the restore process, the Velero server needs to decide how the PV resource should be restored according to how the PV is backed up. The current logic is to check whether it's backed up by Velero-native snapshot, by file-system backup, or having `DeletionPolicy` set as `Delete`.
The checks are made by the backup-generated PVBs or Snapshots. There is no generic way to find this information, and the CSI backup and Snapshot data movement backup are not covered.
Another thing that needs noticing is when describing the backup, there is no generic way to find the PV's snapshot information.
## Goals
- Create a new metadata file to store backup's PVCs and PVs information and volume data backing up method. The file can be used to let downstream consumers generate a summary.
- Create a generic way to let the Velero server know how the PV resources are backed up.
- Create a generic way to let the Velero server find the PV corresponding snapshot information.
## Non Goals
- Unify how to get snapshot size information for all PV backing-up methods, and all other currently not ready PVs' information.
## High-Level Design
Create _backup-name_-volumes-info.json metadata file in the backup's repository. This file will be encoded to contain all the PVC and PV information included in the backup. The information covers whether the PV or PVC's data is skipped during backup, how its data is backed up, and the backed-up detail information.
Please notice that the new metadata file includes all skipped volume information. This is used to address [the second phase needs of skipped volumes information](https://github.com/vmware-tanzu/velero/issues/5834#issuecomment-1526624211).
The `restoreItem` function can decode the _backup-name_-volumes-info.json file to determine how to handle the PV resource.
## Detailed Design
### The VolumeInfo structure
_backup-name_-volumes-info.json file is a structure that contains an array of structure `VolumeInfo`.
``` golang
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` and `CSISnapshot`.
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.
StartTimestamp *metav1.Time // Snapshot starts timestamp.
OperationID string // The Async Operation's ID.
CSISnapshotInfo CSISnapshotInfo
SnapshotDataMovementInfo SnapshotDataMovementInfo
NativeSnapshotInfo VeleroNativeSnapshotInfo
PVBInfo PodVolumeBackupInfo
PVInfo PVInfo
}
// CSISnapshotInfo is used for displaying the CSI snapshot status
type CSISnapshotInfo struct {
SnapshotHandle string // It's the storage provider's snapshot ID for CSI.
Size int64 // The snapshot corresponding volume size.
Driver string // The name of the CSI driver.
VSCName string // The name of the VolumeSnapshotContent.
}
// SnapshotDataMovementInfo is used for displaying the snapshot data mover status.
type SnapshotDataMovementInfo struct {
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`.
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 // It's the storage provider's snapshot ID for the Velero-native snapshot.
VolumeType string // The cloud provider snapshot volume type.
VolumeAZ string // The cloud provider snapshot volume's availability zones.
IOPS string // The cloud provider snapshot volume's IOPS.
}
// PodVolumeBackupInfo is used for displaying the PodVolumeBackup snapshot status.
type PodVolumeBackupInfo struct {
SnapshotHandle string // It's the file-system uploader's snapshot ID for PodVolumeBackup.
Size int64 // The snapshot corresponding volume size.
UploaderType string // The type of the uploader that uploads the data. The valid values are `kopia` and `restic`.
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.
PodNamespace string // The Pod namespace.
NodeName string // The PVB-taken k8s node's name.
}
// 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.
}
```
### How the VolumeInfo array is generated.
The function `persistBackup` has `backup *pkgbackup.Request` in parameters.
From it, the `VolumeSnapshots`, `PodVolumeBackups`, `CSISnapshots`, `itemOperationsList`, and `SkippedPVTracker` can be read. All of them will be iterated and merged into the `VolumeInfo` array, and then persisted into backup repository in function `persistBackup`.
Please notice that the change happened in async operations are not reflected in the new metadata file. The file only covers the volume changes happen in the Velero server process scope.
A new methods are added to BackupStore to download the VolumeInfo metadata file.
Uploading the metadata file is covered in the exiting `PutBackup` method.
``` golang
type BackupStore interface {
...
GetVolumeInfos(name string) ([]*VolumeInfo, error)
...
}
```
### How the VolumeInfo array is used.
#### Generate the PVC backed-up information summary
The downstream tools can use this VolumeInfo array to format and display their volume information. This is not in the scope of this feature.
#### Retrieve volume backed-up information for `velero backup describe` command
The `velero backup describe` can also use this VolumeInfo array structure to display the volume information. The snapshot data mover volume should use this structure at first, then the Velero native snapshot, CSI snapshot, and PodVolumeBackup can also use this structure. The detailed implementation is also not in this feature's scope.
#### Let restore know how to restore the PV
In the function `restoreItem`, it will determine whether to restore the PV resource by checking it in the Velero native snapshots list, PodVolumeBackup list, and its DeletionPolicy. This logic is still kept. The logic will be used when the new `VolumeInfo` metadata cannot be found to support backward compatibility.
``` golang
if groupResource == kuberesource.PersistentVolumes {
switch {
case hasSnapshot(name, ctx.volumeSnapshots):
...
case hasPodVolumeBackup(obj, ctx):
...
case hasDeleteReclaimPolicy(obj.Object):
...
default:
...
```
After introducing the VolumeInfo array, the following logic will be added.
``` golang
if groupResource == kuberesource.PersistentVolumes {
volumeInfo := GetVolumeInfo(pvName)
switch volumeInfo.BackupMethod {
case VeleroNativeSnapshot:
...
case PodVolumeBackup:
...
case CSISnapshot:
...
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
_backup-name_-volumes-info.json file is deleted during backup deletion.
## Alternatives Considered
The restore process needs more information about how the PVs are backed up to determine whether this PV should be restored. The released branches also need a similar function, but backporting a new feature into previous releases may not be a good idea, so according to [Anshul Ahuja's suggestion](https://github.com/vmware-tanzu/velero/issues/6595#issuecomment-1731081580), adding more cases here to support checking PV backed-up by CSI plugin and CSI snapshot data mover: https://github.com/vmware-tanzu/velero/blob/5ff5073cc3f364bafcfbd26755e2a92af68ba180/pkg/restore/restore.go#L1206-L1324.
## Security Considerations
There should be no security impact introduced by this design.
## Compatibility
After this design is implemented, there should be no impact on the existing [skipped PVC summary feature](https://github.com/vmware-tanzu/velero/pull/6496).
To support older version backup, which doesn't have the VolumeInfo metadata file, the old logic, which is checking the Velero native snapshots list, PodVolumeBackup list, and PVC DeletionPolicy, is still kept, and supporting CSI snapshots and snapshot data mover logic will be added too.
## Implementation
This will be implemented in the Velero v1.13 development cycle.
## Open Issues
There are no open issues identified by now.

View File

@@ -1,143 +0,0 @@
# Volume information for restore design
## Background
Velero has different ways to handle data in the volumes during restore. The users want to have more clarity in terms of how
the volumes are handled in restore process via either Velero CLI or other downstream product which consumes Velero.
## Goals
- Create new metadata to store the information of the restored volume, which will have the same life-cycle as the restore CR.
- Consume the metadata in velero CLI to enable it display more details for volumes in the output of `velero restore describe --details`
## Non Goals
- Provide finer grained control of the volume restore process. The focus of the design is to enable displaying more details.
- Persist additional metadata like podvolume, datadownloads etc to the restore folder in backup-location.
## Design
### Structure of the restore volume info
The restore volume info will be stored in a file named like `${restore_name}-vol-info.json`. The content of the file will
be a list of volume info objects, each of which will map to a volume that is restored, and will contain the information
like name of the restored PV/PVC, restore method and related objects to provide details depending on the way it's restored,
it will look like this:
```
[
{
"pvcName": "nginx-logs-2",
"pvcNamespace": "nginx-app-restore",
"pvName": "pvc-e320d75b-a788-41a3-b6ba-267a553efa5e",
"restoreMethod": "PodVolumeRestore",
"snapshotDataMoved": false,
"pvrInfo": {
"snapshotHandle": "81973157c3a945a5229285c931b02c68",
"uploaderType": "kopia",
"volumeName": "nginx-logs",
"podName": "nginx-deployment-79b56c644b-mjdhp",
"podNamespace": "nginx-app-restore"
}
},
{
"pvcName": "nginx-logs-1",
"pvcNamespace": "nginx-app-restore",
"pvName": "pvc-98c151f4-df47-4980-ba6d-470842f652cc",
"restoreMethod": "CSISnapshot",
"snapshotDataMoved": false,
"csiSnapshotInfo": {
"snapshotHandle": "snap-01a3b21a5e9f85528",
"size": 2147483648,
"driver": "ebs.csi.aws.com",
"vscName": "velero-velero-nginx-logs-1-jxmbg-hx9x5"
}
}
......
]
```
Each field will have the same meaning as the corresponding field in the backup volume info. It will not have the fields
that were introduced to help with the backup process, like `pvInfo`, `dataupload` etc.
### How the restore volume info is generated
Two steps are involved in generating the restore volume info, the first is "collection", which is to gather the information
for restoration of the volumes, the second is "generation", which is to iterate through the data collected in the first step
and generate the volume info list as is described above.
Unlike backup, the CR objects created during the restore process will not be persisted to the backup storage location.
Therefore, to gather the information needed to generate volume information, we either need to collect the CRs in the middle
of the restore process, or retrieve the objects based on the `resouce-list.json` of the restore via API server.
The information to be collected are:
- **PV/PVC mapping relationship:** It will be collected via the `restore-resource-list.json`, b/c at the time the json is ready, all
PVCs and PVs are already created.
- **Native snapshot information:** It will be collected in the restore workflow when each snapshot is restored.
- **podvolumerestore CRs:** It will be collected in the restore workflow after each pvr is created.
- **volumesnapshot CRs for CSI snapshot:** It will be collected in the step of collecting PVC info, by reading the `dataSource`
field in the spec of the PVC.
- **datadownload CRs** It will be collected in the phase of collecting PVC info, by querying the API-server to list the datadownload
CRs labeled with the restore name.
After the collection step, the generation step is relatively straight-forward, as we have all the information needed in
the data structures.
The whole collection and generation steps will be done with the "best-effort" manner, i.e. if there are any failures we
will only log the error in restore log, rather than failing the whole restore process, we will not put these errors or warnings
into the `result.json`, b/c it won't impact the restored resources.
Depending on the number of the restored PVCs the "collection" step may involve many API calls, but it's considered acceptable
b/c at that time the resources are already created, so the actual RTO is not impacted. By using the client of controller runtime
we can make the collection step more efficient by using the cache of the API server. We may consider to make improvements if
we observe performance issues, like using multiple go-routines in the collection.
### Implementation
Because the restore volume info shares the same data structures with the backup volume info, we will refactor the code in
package `internal/volume` to make the sub-components in backup volume info shared by both backup and restore volume info.
We'll introduce a struct called `RestoreVolumeInfoTracker` which encapsulates the logic of collecting and generating the restore volume info:
```
// RestoreVolumeInfoTracker is used to track the volume information during restore.
// It is used to generate the RestoreVolumeInfo array.
type RestoreVolumeInfoTracker struct {
*sync.Mutex
restore *velerov1api.Restore
log logrus.FieldLogger
client kbclient.Client
pvPvc *pvcPvMap
// map of PV name to the NativeSnapshotInfo from which the PV is restored
pvNativeSnapshotMap map[string]NativeSnapshotInfo
// map of PV name to the CSISnapshot object from which the PV is restored
pvCSISnapshotMap map[string]snapshotv1api.VolumeSnapshot
datadownloadList *velerov2alpha1.DataDownloadList
pvrs []*velerov1api.PodVolumeRestore
}
```
The `RestoreVolumeInfoTracker` will be created when the restore request is initialized, and it will be passed to the `restoreContext`
and carried over the whole restore process.
The `client` in this struct is to be used to query the resources in the restored namespace, and the current client in restore
reconciler only watches the resources in the namespace where velero is installed. Therefore, we need to introduce the
`CrClient` which has the same life-cycle of velero server to the restore reconciler, because this is the client that watches all the
resources on the cluster.
In addition to that, we will make small changes in the restore workflow to collect the information needed. We'll make the
changes un-intrusive and make sure not to change the logic of the restore to avoid break change or regression.
We'll also introduce routine changes in the package `pkg/persistence` to persist the restore volume info to the backup storage location.
Last but not least, the `velero restore describe --details` will be updated to display the volume info in the output.
## Alternatives Considered
There used to be suggestion that to provide more details about volume, we can query the `backup-vol-info.json` with the resource
identifier in `restore-resource-list.json`. This will not work when there're resource modifiers involved in the restore process,
which may change the metadata of PVC/PV. In addition, we may add more detailed restore-specific information about the volumes that is not available
in the `backup-vol-info.json`. Therefore, the `restore-vol-info.json` is a better approach.
## Security Considerations
There should be no security impact introduced by this design.
## Compatibility
The restore volume info will be consumed by Velero CLI and downstream products for displaying details. So the functionality
of backup and restore will not be impacted for restores created by older versions of Velero which do not have the restore volume info
metadata. The client should properly handle the case when the restore volume info does not exist.
The data structures referenced by volume info is shared between both restore and backup and it's not versioned, so in the future
we must make sure there will only be incremental changes to the metadata, such that no break change will be introduced to the client.
## Open Issues
https://github.com/vmware-tanzu/velero/issues/7546
https://github.com/vmware-tanzu/velero/issues/6478

View File

@@ -1,318 +0,0 @@
# Design for repository maintenance job
## Abstract
This design proposal aims to decouple repository maintenance from the Velero server by launching a maintenance job when needed, to mitigate the impact on the Velero server during backups.
## Background
During backups, Velero performs periodic maintenance on the repository. This operation may consume significant CPU and memory resources in some cases, leading to potential issues such as the Velero server being killed by OOM. This proposal addresses these challenges by separating repository maintenance from the Velero server.
## Goals
1. **Independent Repository Maintenance**: Decouple maintenance from Velero's main logic to reduce the impact on the Velero server pod.
2. **Configurable Resources Usage**: Make the resources used by the maintenance job configurable.
3. **No API Changes**: Retain existing APIs and workflow in the backup repository controller.
## Non Goals
We have lots of concerns over parallel maintenance, which will increase the complexity of our design currently.
- Non-blocking maintenance job: it may conflict with updating the same `backuprepositories` CR when parallel maintenance.
- Maintenance job concurrency control: there is no one suitable mechanism in Kubernetes to control the concurrency of different jobs.
- Parallel maintenance: Maintaining the same repo by multiple jobs at the same time would have some compatible cases that some providers may not support.
Unfortunately, parallel maintenance is currently not a priority because of the concerns above, improving maintenance efficiency is not the primary focus at this stage.
## High-Level Design
1. **Add Maintenance Subcommand**: Introduce a new Velero server subcommand for repository maintenance.
2. **Create Jobs by Repository Manager**: Modify the backup repository controller to create a maintenance job instead of directly calling the multiple chain calls for Kopia or Restic maintenance.
3. **Update Maintenance Job Result in BackupRepository CR**: Retrieve the result of the maintenance job and update the status of the `BackupRepository` CR accordingly.
4. **Add Setting for Maintenance Job**: Introduce a configuration option to set maintenance jobs, including resource limits (CPU and memory), keeping the latest N maintenance jobs for each repository.
## Detailed Design
### 1. Add Maintenance sub-command
The CLI command will be added to the Velero CLI, the command is designed for use in a pod of maintenance jobs.
Our CLI command is designed as follows:
```shell
$ velero repo-maintenance --repo-name $repo-name --repo-type $repo-type --backup-storage-location $bsl
```
Compared with other CLI commands, the maintenance command is used in a pod of maintenance jobs not for user use, and the job should show the result of maintenance after finish.
Here we will write the error message into one specific file which could be read by the maintenance job.
on the whole, we record two kinds of logs:
- one is the log output of the intermediate maintenance process: this log could be retrieved via the Kubernetes API server, including the error log.
- one is the result of the command which could indicate whether the execution is an error or not: the result could be redirected to a file that the maintenance job itself could read, and the file only contains the error message.
we will write the error message into the `/dev/termination-log` file if execution is failed.
The main maintenance logic would be using the repository provider to do the maintenance.
```golang
func checkError(err error, file *os.File) {
if err != nil {
if err != context.Canceled {
if _, errWrite := file.WriteString(fmt.Sprintf("An error occurred: %v", err)); errWrite != nil {
fmt.Fprintf(os.Stderr, "Failed to write error to termination log file: %v\n", errWrite)
}
file.Close()
os.Exit(1) // indicate the command executed failed
}
}
}
func (o *Options) Run(f veleroCli.Factory) {
logger := logging.DefaultLogger(o.LogLevelFlag.Parse(), o.FormatFlag.Parse())
logger.SetOutput(os.Stdout)
errorFile, err := os.Create("/dev/termination-log")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create termination log file: %v\n", err)
return
}
defer errorFile.Close()
...
err = o.runRepoPrune(cli, f.Namespace(), logger)
checkError(err, errorFile)
...
}
func (o *Options) runRepoPrune(cli client.Client, namespace string, logger logrus.FieldLogger) error {
...
var repoProvider provider.Provider
if o.RepoType == velerov1api.BackupRepositoryTypeRestic {
repoProvider = provider.NewResticRepositoryProvider(credentialFileStore, filesystem.NewFileSystem(), logger)
} else {
repoProvider = provider.NewUnifiedRepoProvider(
credentials.CredentialGetter{
FromFile: credentialFileStore,
FromSecret: credentialSecretStore,
}, o.RepoType, cli, logger)
}
...
err = repoProvider.BoostRepoConnect(context.Background(), para)
if err != nil {
return errors.Wrap(err, "failed to boost repo connect")
}
err = repoProvider.PruneRepo(context.Background(), para)
if err != nil {
return errors.Wrap(err, "failed to prune repo")
}
return nil
}
```
### 2. Create Jobs by Repository Manager
Currently, the backup repository controller will call the repository manager to do the `PruneRepo`, and Kopia or Restic maintenance is then finally called through multiple chain calls.
We will keep using the `PruneRepo` function in the repository manager, but we cut off the multiple chain calls by creating a maintenance job.
The job definition would be like below:
```yaml
apiVersion: v1
items:
- apiVersion: batch/v1
kind: Job
metadata:
# labels or affinity or topology settings would inherit from the velero deployment
labels:
# label the job name for later list jobs by name
job-name: nginx-example-default-kopia-pqz6c
name: nginx-example-default-kopia-pqz6c
namespace: velero
spec:
# Not retry it again
backoffLimit: 1
# Only have one job one time
completions: 1
# Not parallel running job
parallelism: 1
template:
metadata:
labels:
job-name: nginx-example-default-kopia-pqz6c
name: kopia-maintenance-job
spec:
containers:
# arguments for repo maintenance job
- args:
- repo-maintenance
- --repo-name=nginx-example
- --repo-type=kopia
- --backup-storage-location=default
# inherit from Velero server
- --log-level=debug
command:
- /velero
# inherit environment variables from the velero deployment
env:
- name: AZURE_CREDENTIALS_FILE
value: /credentials/cloud
# inherit image from the velero deployment
image: velero/velero:main
imagePullPolicy: IfNotPresent
name: kopia-maintenance-container
# resource limitation set by Velero server configuration
# if not specified, it would apply best effort resources allocation strategy
resources: {}
# error message would be written to /dev/termination-log
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
# inherit volume mounts from the velero deployment
volumeMounts:
- mountPath: /credentials
name: cloud-credentials
dnsPolicy: ClusterFirst
restartPolicy: Never
schedulerName: default-scheduler
securityContext: {}
# inherit service account from the velero deployment
serviceAccount: velero
serviceAccountName: velero
volumes:
# inherit cloud credentials from the velero deployment
- name: cloud-credentials
secret:
defaultMode: 420
secretName: cloud-credentials
# ttlSecondsAfterFinished set the job expired seconds
ttlSecondsAfterFinished: 86400
status:
# which contains the result after maintenance
message: ""
lastMaintenanceTime: ""
```
Now, the backup repository controller will call the repository manager to create one maintenance job and wait for the job to complete. The Kopia or Restic maintenance multiple chains are called by the job.
### 3. Update the Result of the Maintenance Job into BackupRepository CR
The backup repository controller will update the result of the maintenance job into the backup repository CR.
For how to get the result of the maintenance job we could refer to [here](https://kubernetes.io/docs/tasks/debug/debug-application/determine-reason-pod-failure/#writing-and-reading-a-termination-message).
After the maintenance job is finished, we could get the result of maintenance by getting the terminated message from the related pod:
```golang
func GetContainerTerminatedMessage(pod *v1.Pod) string {
...
for _, containerStatus := range pod.Status.ContainerStatuses {
if containerStatus.LastTerminationState.Terminated != nil {
return containerStatus.LastTerminationState.Terminated.Message
}
}
...
return ""
}
```
Then we could update the status of backupRepository CR with the message.
### 4. Add Setting for Resource Usage of Maintenance
Add one configuration for setting the resource limit of maintenance jobs as below:
```shell
velero server --maintenance-job-cpu-request $cpu-request --maintenance-job-mem-request $mem-request --maintenance-job-cpu-limit $cpu-limit --maintenance-job-mem-limit $mem-limit
```
Our default value is 0, which means we don't limit the resources, and the resource allocation strategy would be [best effort](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#besteffort).
### 5. Automatic Cleanup for Finished Maintenance Jobs
Add configuration for clean up maintenance jobs:
- keep-latest-maintenance-jobs: the number of keeping latest maintenance jobs for each repository.
```shell
velero server --keep-latest-maintenance-jobs $num
```
We would check and keep the latest N jobs after a new job is finished.
```golang
func deleteOldMaintenanceJobs(cli client.Client, repo string, keep int) error {
// Get the maintenance job list by label
jobList := &batchv1.JobList{}
err := cli.List(context.TODO(), jobList, client.MatchingLabels(map[string]string{RepositoryNameLabel: repo}))
if err != nil {
return err
}
// Delete old maintenance jobs
if len(jobList.Items) > keep {
sort.Slice(jobList.Items, func(i, j int) bool {
return jobList.Items[i].CreationTimestamp.Before(&jobList.Items[j].CreationTimestamp)
})
for i := 0; i < len(jobList.Items)-keep; i++ {
err = cli.Delete(context.TODO(), &jobList.Items[i], client.PropagationPolicy(metav1.DeletePropagationBackground))
if err != nil {
return err
}
}
}
return nil
}
```
### 6 Velero Install with Maintenance Options
All the above maintenance options should be supported by Velero install command.
### 7. Observability and Debuggability
Some monitoring metrics are added for backup repository maintenance:
- repo_maintenance_total
- repo_maintenance_success_total
- repo_maintenance_failed_total
- repo_maintenance_duration_seconds
We will keep the latest N maintenance jobs for each repo, and users can get the log from the job. the job log level inherent from the Velero server setting.
Also, we would integrate maintenance job logs and `backuprepositories` CRs into `velero debug`.
Roughly, the process is as follows:
1. The backup repository controller will check the BackupRepository request in the queue periodically.
2. If the maintenance period of the repository checked by `runMaintenanceIfDue` in `Reconcile` is due, then the backup repository controller will call the Repository manager to execute `PruneRepo`
3. The `PruneRepo` of the Repository manager will create one maintenance job, the resource limitation, environment variables, service account, images, etc. would inherit from the Velero server pod. Also, one clean up TTL would be set to maintenance job.
4. The maintenance job will execute the Velero maintenance command, wait for maintaining to finish and write the maintenance result into the terminationMessagePath file of the related pod.
5. Kubernetes could show the result in the status of the pod by reading the termination message in the pod.
6. The backup repository controller will wait for the maintenance job to finish and read the status of the maintenance job, then update the message field and phase in the status of `backuprepositories` CR accordingly.
6. Clean up old maintenance jobs and keep only N latest for each repository.
### 8. Codes Refinement
Once `backuprepositories` CR status is modified, the CR would re-queue to be reconciled, and re-execute logics in reconcile shortly not respecting the re-queue frequency configured by `repoSyncPeriod`.
For one abnormal scenario if the maintenance job fails, the status of `backuprepositories` CR would be updated and the CR will re-queue immediately, if the new maintenance job still fails, then it will re-queue again, making the logic of `backuprepositories` CR re-queue like a dead loop.
So we change the Predicates logic in Controller manager making it only re-queue if the Spec of `backuprepositories` CR is changed.
```golang
ctrl.NewControllerManagedBy(mgr).For(&velerov1api.BackupRepository{}, builder.WithPredicates(kube.SpecChangePredicate{}))
```
This change would bring the behavior different from the previous, errors that occurred in the maintenance job would retry in the next reconciliation period instead of retrying immediately.
## Prospects for Future Work
Future work may focus on improving the efficiency of Velero maintenance through non-blocking parallel modes. Potential areas for enhancement include:
**Non-blocking Mode**: Explore the implementation of a non-blocking mode for parallel maintenance to enhance overall efficiency.
**Concurrency Control**: Investigate mechanisms for better concurrency control of different maintenance jobs.
**Provider Support for Parallel Maintenance**: Evaluate the feasibility of parallel maintenance for different providers and address any compatibility issues.
**Efficiency Improvements**: Investigate strategies to optimize maintenance efficiency without compromising reliability.
By considering these areas, future iterations of Velero may benefit from enhanced parallelization and improved resource utilization during repository maintenance.

View File

@@ -1,120 +0,0 @@
# Design for Adding Finalization Phase in Restore Workflow
## Abstract
This design proposes adding the finalization phase to the restore workflow. The finalization phase would be entered after all item restoration and plugin operations have been completed, similar to the way the backup process proceeds. Its purpose is to perform any wrap-up work necessary before transitioning the restore process to a terminal phase.
## Background
Currently, the restore process enters a terminal phase once all item restoration and plugin operations have been completed. However, there are some wrap-up works that need to be performed after item restoration and plugin operations have been fully executed. There is no suitable opportunity to perform them at present.
To address this, a new finalization phase should be added to the existing restore workflow. in this phase, all plugin operations and item restoration has been fully completed, which provides a clean opportunity to perform any wrap-up work before termination, improving the overall restore process.
Wrap-up tasks in Velero can serve several purposes:
- Post-restore modification - Velero can modify the restored data that was temporarily changed for some purpose but required to be changed back finally or data that was newly created but missing some information. For example, [issue6435](https://github.com/vmware-tanzu/velero/issues/6435) indicates that some custom settings(like labels, reclaim policy) on restored PVs was lost because those restored PVs was newly dynamically provisioned. Velero can address it by patching the PVs' custom settings back in the finalization phase.
- Clean up unused data - Velero can identify and delete any data that are no longer needed after a successful restore in the finalization phase.
- Post-restore validation - Velero can validate the state of restored data and report any errors to help users locate the issue in the finalization phase.
The uses of wrap-up tasks are not limited to these examples. Additional needs may be addressed as they develop over time.
## Goals
- Add the finalization phase and the corresponding controller to restore workflow.
## Non Goals
- Implement the specific wrap-up work.
## High-Level Design
- The finalization phase will be added to current restore workflow.
- The logic for handling current phase transition in restore and restore operations controller will be modified with the introduction of the finalization phase.
- A new restore finalizer controller will be implemented to handle the finalization phase.
## Detailed Design
### phase transition
Two new phases related to finalization will be added to restore workflow, which are `FinalizingPartiallyFailed` and `Finalizing`. The new phase transition will be similar to backup workflow, proceeding as follow:
![image](restore-phases-transition.png)
### restore finalizer controller
The new restore finalizer controller will be implemented to watch for restores in `FinalizingPartiallyFailed` and `Finalizing` phases. Any wrap-up work that needs to wait for the completion of item restoration and plugin operations will be executed by this controller, and the phase will be set to either `Completed` or `PartiallyFailed` based on the results of these works.
Points worth noting about the new restore finalizer controller:
A new structure `finalizerContext` will be created to facilitate the implementation of any wrap-up tasks. It includes all the dependencies the tasks require as well as a function `execute()` to orderly implement task logic.
```
// finalizerContext includes all the dependencies required by wrap-up tasks
type finalizerContext struct {
.......
restore *velerov1api.Restore
log logrus.FieldLogger
.......
}
// execute executes all the wrap-up tasks and return the result
func (ctx *finalizerContext) execute() (results.Result, results.Result) {
// execute task1
.......
// execute task2
.......
// the task execution logic will be expanded as new tasks are included
.......
}
// newFinalizerContext returns a finalizerContext object, the parameters will be added as new tasks are included.
func newFinalizerContext(restore *velerov1api.Restore, log logrus.FieldLogger, ...) *finalizerContext{
return &finalizerContext{
.......
restore: restore,
log: log,
.......
}
}
```
The finalizer controller is responsible for collecting all dependencies and creating a `finalizerContext` object using those dependencies. It then invokes the `execute` function.
```
func (r *restoreFinalizerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
.......
// collect all dependencies required by wrap-up tasks
.......
// create a finalizerContext object and invoke execute()
finalizerCtx := newFinalizerContext(restore, log, ...)
warnings, errs := finalizerCtx.execute()
.......
}
```
After completing all necessary tasks, the result metadata in object storage will be updated if any errors or warnings occur during the execution. This behavior breaks the feature of keeping metadata files in object storage immutable, However, we believe the tradeoff is justified because it provides users with the access to examine the error/warning details when the wrap-up tasks go wrong.
```
// UpdateResults updates the result metadata in object storage if necessary
func (r *restoreFinalizerReconciler) UpdateResults(restore *api.Restore, newWarnings *results.Result, newErrs *results.Result, backupStore persistence.BackupStore) error {
originResults, err := backupStore.GetRestoreResults(restore.Name)
if err != nil {
return errors.Wrap(err, "error getting restore results")
}
warnings := originResults["warnings"]
errs := originResults["errors"]
warnings.Merge(newWarnings)
errs.Merge(newErrs)
m := map[string]results.Result{
"warnings": warnings,
"errors": errs,
}
if err := putResults(restore, m, backupStore); err != nil {
return errors.Wrap(err, "error putting restore results")
}
return nil
}
```
## Compatibility
The new finalization phases are added without modifying the existing phases in the restore workflow. Both new and ongoing restore processes will continue to eventually transition to a terminal phase from any prior phase, ensuring backward compatibility.
## Implementation
This will be implemented during the Velero 1.14 development cycle.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

View File

@@ -29,7 +29,7 @@ During restore, the proposal is that Velero will determine if the `APIGroupVersi
The proposed code starts with creating three lists for each backed up resource. The three lists will be created by
(1) reading the directory names in the backup tarball file and seeing which API group versions were backed up from the source cluster,
(2) looking at the target cluster and determining which API group versions are supported, and
(3) getting ConfigMaps from the target cluster in order to get user-defined prioritization of versions.
(3) getting config maps from the target cluster in order to get user-defined prioritization of versions.
The three lists will be used to create a map of chosen versions for each resource to restore. If there is a user-defined list of priority versions, the versions will be checked against the supported versions lists. The highest user-defined priority version that is/was supported by both target and source clusters will be the chosen version for that resource. If no user specified versions are supported by neither target nor source, the versions will be logged and the restore will continue with other prioritizations.

View File

@@ -1,145 +0,0 @@
# Schedule Skip Immediately Config Design
## Abstract
When unpausing schedule, a backup could be due immediately.
New Schedules also create new backup immediately.
This design allows user to *skip **immediately due** backup run upon unpausing or schedule creation*.
## Background
Currently, the default behavior of schedule when `.Status.LastBackup` is nil or is due immediately after unpausing, a backup will be created. This may not be a desired by all users (https://github.com/vmware-tanzu/velero/issues/6517)
User want ability to skip the first immediately due backup when schedule is unpaused and or created.
If you create a schedule with cron "45 * * * *" and pause it at say the 43rd minute and then unpause it at say 50th minute, a backup gets triggered (since .Status.LastBackup is nil or >60min ago).
With this design, user can skip the first immediately due backup when schedule is unpaused and or created.
## Goals
- Add an option so user can when unpausing (when immediately due) or creating new schedule, to not create a backup immediately.
## Non Goals
- Changing the default behavior
## High-Level Design
Add a new field with to the schedule spec and as a new cli flags for install, server, schedule commands; allowing user to skip immediately due backup when unpausing or schedule creation.
If CLI flag is specified during schedule unpause, velero will update the schedule spec accordingly and override prior spec for `skipImmediately``.
## Detailed Design
### CLI Changes
`velero schedule unpause` will now take an optional bool flag `--skip-immediately` to allow user to override the behavior configured for velero server (see `velero server` below).
`velero schedule unpause schedule-1 --skip-immediately=false` will unpause the schedule but not skip the backup if due immediately from `Schedule.Status.LastBackup` timestamp. Backup will be run at the next cron schedule.
`velero schedule unpause schedule-1 --skip-immediately=true` will unpause the schedule and skip the backup if due immediately from `Schedule.Status.LastBackup` timestamp. Backup will also be run at the next cron schedule.
`velero schedule unpause schedule-1` will check `.spec.SkipImmediately` in the schedule to determine behavior. This field will default to false to maintain prior behavior.
`velero server` will add a new flag `--schedule-skip-immediately` to configure default value to patch new schedules created without the field. This flag will default to false to maintain prior behavior if not set.
`velero install` will add a new flag `--schedule-skip-immediately` to configure default value to patch new schedules created without the field. This flag will default to false to maintain prior behavior if not set.
### API Changes
`pkg/apis/velero/v1/schedule_types.go`
```diff
// ScheduleSpec defines the specification for a Velero schedule
type ScheduleSpec struct {
// Template is the definition of the Backup to be run
// on the provided schedule
Template BackupSpec `json:"template"`
// Schedule is a Cron expression defining when to run
// the Backup.
Schedule string `json:"schedule"`
// UseOwnerReferencesBackup specifies whether to use
// OwnerReferences on backups created by this Schedule.
// +optional
// +nullable
UseOwnerReferencesInBackup *bool `json:"useOwnerReferencesInBackup,omitempty"`
// Paused specifies whether the schedule is paused or not
// +optional
Paused bool `json:"paused,omitempty"`
+ // SkipImmediately specifies whether to skip backup if schedule is due immediately from `Schedule.Status.LastBackup` timestamp when schedule is unpaused or if schedule is new.
+ // If true, backup will be skipped immediately when schedule is unpaused if it is due based on .Status.LastBackupTimestamp or schedule is new, and will run at next schedule time.
+ // If false, backup will not be skipped immediately when schedule is unpaused, but will run at next schedule time.
+ // If empty, will follow server configuration (default: false).
+ // +optional
+ SkipImmediately bool `json:"skipImmediately,omitempty"`
}
```
`LastSkipped` will be added to `ScheduleStatus` struct to track the last time a schedule was skipped.
```diff
// ScheduleStatus captures the current state of a Velero schedule
type ScheduleStatus struct {
// Phase is the current phase of the Schedule
// +optional
Phase SchedulePhase `json:"phase,omitempty"`
// LastBackup is the last time a Backup was run for this
// Schedule schedule
// +optional
// +nullable
LastBackup *metav1.Time `json:"lastBackup,omitempty"`
+ // LastSkipped is the last time a Schedule was skipped
+ // +optional
+ // +nullable
+ LastSkipped *metav1.Time `json:"lastSkipped,omitempty"`
// ValidationErrors is a slice of all validation errors (if
// applicable)
// +optional
ValidationErrors []string `json:"validationErrors,omitempty"`
}
```
When `schedule.spec.SkipImmediately` is `true`, `LastSkipped` will be set to the current time, and `schedule.spec.SkipImmediately` set to nil so it can be used again.
The `getNextRunTime()` function below is updated so `LastSkipped` which is after `LastBackup` will be used to determine next run time.
```go
func getNextRunTime(schedule *velerov1.Schedule, cronSchedule cron.Schedule, asOf time.Time) (bool, time.Time) {
var lastBackupTime time.Time
if schedule.Status.LastBackup != nil {
lastBackupTime = schedule.Status.LastBackup.Time
} else {
lastBackupTime = schedule.CreationTimestamp.Time
}
if schedule.Status.LastSkipped != nil && schedule.Status.LastSkipped.After(lastBackupTime) {
lastBackupTime = schedule.Status.LastSkipped.Time
}
nextRunTime := cronSchedule.Next(lastBackupTime)
return asOf.After(nextRunTime), nextRunTime
}
```
When schedule is unpaused, and `Schedule.Status.LastBackup` is not nil, if `Schedule.Status.LastSkipped` is recent, a backup will not be created.
When schedule is unpaused or created with `Schedule.Status.LastBackup` set to nil or schedule is newly created, normally a backup will be created immediately. If `Schedule.Status.LastSkipped` is recent, a backup will not be created.
Backup will be run at the next cron schedule based on LastBackup or LastSkipped whichever is more recent.
## Alternatives Considered
N/A
## Security Considerations
None
## Compatibility
Upon upgrade, the new field will be added to the schedule spec automatically and will default to the prior behavior of running a backup when schedule is unpaused if it is due based on .Status.LastBackup or schedule is new.
Since this is a new field, it will be ignored by older versions of velero.
## Implementation
TBD
## Open Issues
N/A

View File

@@ -433,24 +433,23 @@ spec:
volume: nginx-log
```
We will add the flag for both CLI installation and Helm Chart Installation. Specifically:
- Helm Chart Installation: add the "--uploaderType" and "--default-volumes-to-fs-backup" flag into its value.yaml and then generate the deployments according to the value. Value.yaml is the user-provided configuration file, therefore, users could set this value at the time of installation. The changes in Value.yaml are as below:
- Helm Chart Installation: add the "--pod-volume-backup-uploader" flag into its value.yaml and then generate the deployments according to the value. Value.yaml is the user-provided configuration file, therefore, users could set this value at the time of installation. The changes in Value.yaml are as below:
```
command:
- /velero
args:
- server
{{- with .Values.configuration }}
- --uploader-type={{ default "restic" .uploaderType }}
{{- if .defaultVolumesToFsBackup }}
- --default-volumes-to-fs-backup
{{- end }}
{{- if .pod-volume-backup-uploader "restic" }}
- --legacy
{{- end }}
```
- CLI Installation: add the "--uploaderType" and "--default-volumes-to-fs-backup" flag into the installation command line, and then create the two deployments accordingly. Users could change the option at the time of installation. The CLI is as below:
```velero install --uploader-type=restic --default-volumes-to-fs-backup --use-node-agent```
```velero install --uploader-type=kopia --default-volumes-to-fs-backup --use-node-agent```
- CLI Installation: add the "--pod-volume-backup-uploader" flag into the installation command line, and then create the two deployments accordingly. Users could change the option at the time of installation. The CLI is as below:
```velero install --pod-volume-backup-uploader=restic```
```velero install --pod-volume-backup-uploader=kopia```
## Upgrade
For upgrade, we allow users to change the path by specifying "--uploader-type" flag in the same way as the fresh installation. Therefore, the flag change should be applied to the Velero server after upgrade. Additionally, We need to add a label to Velero server to indicate the current path, so as to provide an easy for querying it.
For upgrade, we allow users to change the path by specifying "--pod-volume-backup-uploader" flag in the same way as the fresh installation. Therefore, the flag change should be applied to the Velero server after upgrade. Additionally, We need to add a label to Velero server to indicate the current path, so as to provide an easy for querying it.
Moreover, if users upgrade from the old release, we need to change the existing Restic Daemonset name to VeleroNodeAgent daemonSet. The name change should be applied after upgrade.
The recommended way for upgrade is to modify the related Velero resource directly through kubectl, the above changes will be applied in the same way. We need to modify the Velero doc for all these changes.
@@ -460,7 +459,7 @@ Below Velero CLI or its output needs some changes:
- ```Velero restore describe```: the output should indicate the path
- ```Velero restic repo get```: the name of this CLI should be changed to a generic one, for example, "Velero repo get"; the output of this CLI should print all the backup repository if Restic repository and Unified Repository exist at the same time
At present, we don't have a requirement for selecting the path during backup, so we don't change the ```Velero backup create``` CLI for now. If there is a requirement in future, we could simply add a flag similar to "--uploader-type" to select the path.
At present, we don't have a requirement for selecting the path during backup, so we don't change the ```Velero backup create``` CLI for now. If there is a requirement in future, we could simply add a flag similar to "--pod-volume-backup-uploader" to select the path.
## CR Example
Below sample files demonstrate complete CRs with all the changes mentioned above:

View File

@@ -1,230 +0,0 @@
# Velero Uploader Configuration Integration and Extensibility
## Abstract
This design proposal aims to make Velero Uploader configurable by introducing a structured approach for managing Uploader settings. we will define and standardize a data structure to facilitate future additions to Uploader configurations. This enhancement provides a template for extending Uploader-related options. And also includes examples of adding sub-options to the Uploader Configuration.
## Background
Velero is widely used for backing up and restoring Kubernetes clusters. In various scenarios, optimizing the backup process is essential, future needs may arise for adding more configuration options related to the Uploader component especially when dealing with large datasets. Therefore, a standardized configuration template is required.
## Goals
1. **Extensible Uploader Configuration**: Provide an extensible approach to manage Uploader configurations, making it easy to add and modify configuration options related to the Velero uploader.
2. **User-friendliness**: Ensure that the new Uploader configuration options are easy to understand and use for Velero users without introducing excessive complexity.
## Non Goals
1. Expanding to other Velero components: The primary focus of this design is Uploader configuration and does not include extending to other components or modules within Velero. Configuration changes for other components may require separate design and implementation.
## High-Level Design
To achieve extensibility in Velero Uploader configurations, the following key components and changes are proposed:
### UploaderConfig Structure
Two new data structures, `UploaderConfigForBackup` and `UploaderConfigForRestore`, will be defined to store Uploader configurations. These structures will include the configuration options related to backup and restore for Uploader:
```go
type UploaderConfigForBackup struct {
}
type UploaderConfigForRestore struct {
}
```
### Integration with Backup & Restore 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
type BackupSpec struct {
// UploaderConfig specifies the configuration for the uploader.
// +optional
// +nullable
UploaderConfig *UploaderConfigForBackup `json:"uploaderConfig,omitempty"`
}
type RestoreSpec struct {
// UploaderConfig specifies the configuration for the restore.
// +optional
// +nullable
UploaderConfig *UploaderConfigForRestore `json:"uploaderConfig,omitempty"`
}
```
### Configuration Propagated to Different CRDs
The configuration specified in `UploaderConfig` needs to be effective for backup and restore both by file system way and data-mover way.
Therefore, the `UploaderConfig` field value from the `Backup` CRD should be propagated to `PodVolumeBackup` and `DataUpload` CRDs.
We aim for the configurations in PodVolumeBackup to originate not only from UploaderConfig in Backup but also potentially from other sources such as the server or configmap. Simultaneously, to align with the configurations in DataUpload's `DataMoverConfig map[string]string`, we have defined an `UploaderSettings map[string]string` here to record the configurations in PodVolumeBackup.
```go
type PodVolumeBackupSpec struct {
// UploaderSettings are a map of key-value pairs that should be applied to the
// uploader configuration.
// +optional
// +nullable
UploaderSettings map[string]string `json:"uploaderSettings,omitempty"`
}
```
`UploaderConfig` will be stored in DataUpload's `DataMoverConfig map[string]string` field.
Also the `UploaderConfig` field value from the `Restore` CRD should be propagated to `PodVolumeRestore` and `DataDownload` CRDs:
```go
type PodVolumeRestoreSpec struct {
// UploaderSettings are a map of key-value pairs that should be applied to the
// uploader configuration.
// +optional
// +nullable
UploaderSettings map[string]string `json:"uploaderSettings,omitempty"`
}
```
Also `UploaderConfig` will be stored in DataUpload's `DataMoverConfig map[string]string` field.
### Store and Get Configuration
We need to store and retrieve configurations in the PodVolumeBackup and DataUpload structs. This involves type conversion based on the configuration type, storing it in a map[string]string, or performing type conversion from this map for retrieval.
PodVolumeRestore and DataDownload are also similar.
## Sub-options in UploaderConfig
Adding fields above in CRDs can accommodate any future additions to Uploader configurations by adding new fields to the `UploaderConfigForBackup` or `UploaderConfigForRestore` structures.
### Parallel Files Upload
This section focuses on enabling the configuration for the number of parallel file uploads during backups.
below are the key steps that should be added to support this new feature.
#### Velero CLI
The Velero CLI will support a `--parallel-files-upload` flag, allowing users to set the `ParallelFilesUpload` value when creating backups.
#### UploaderConfig
below the sub-option `ParallelFilesUpload` is added into UploaderConfig:
```go
// UploaderConfigForBackup defines the configuration for the uploader when doing backup.
type UploaderConfigForBackup struct {
// ParallelFilesUpload is the number of files parallel uploads to perform when using the uploader.
// +optional
ParallelFilesUpload int `json:"parallelFilesUpload,omitempty"`
}
```
#### Kopia Parallel Upload Policy
Velero Uploader can set upload policies when calling Kopia APIs. In the Kopia codebase, the structure for upload policies is defined as follows:
```go
// UploadPolicy describes the policy to apply when uploading snapshots.
type UploadPolicy struct {
...
MaxParallelFileReads *OptionalInt `json:"maxParallelFileReads,omitempty"`
}
```
Velero can set the `MaxParallelFileReads` parameter for Kopia's upload policy as follows:
```go
curPolicy := getDefaultPolicy()
if parallelUpload > 0 {
curPolicy.UploadPolicy.MaxParallelFileReads = newOptionalInt(parallelUpload)
}
```
#### Restic Parallel Upload Policy
As Restic does not support parallel file upload, the configuration would not take effect, so we should output a warning when the user sets the `ParallelFilesUpload` value by using Restic to do a backup.
```go
if parallelFilesUpload > 0 {
log.Warnf("ParallelFilesUpload is set to %d, but Restic does not support parallel file uploads. Ignoring", parallelFilesUpload)
}
```
Roughly, the process is as follows:
1. Users pass the ParallelFilesUpload 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 Backup CR.
2. When users perform file system backups, UploaderConfig is passed to the PodVolumeBackup CR. When users use the Data-mover for backups, it is passed to the DataUpload CR.
3. The configuration will be stored in map[string]string type of field in CR.
3. Each respective controller within the CRs calls the uploader, and the ParallelFilesUpload from map 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, numerous zero bytes or empty blocks persist, occupying physical storage space. Sparse restore employs a more intelligent approach, including appropriately handling empty blocks, thereby achieving the correct system state. This write sparse files mechanism aims to enhance restore efficiency while maintaining restoration accuracy.
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
// UploaderConfigForRestore defines the configuration for the restore.
type UploaderConfigForRestore struct {
// WriteSparseFiles is a flag to indicate whether write files sparsely or not.
// +optional
// +nullable
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).
```go
fsOutput := &restore.FilesystemOutput{
WriteSparseFiles: uploaderutil.GetWriteSparseFiles(uploaderCfg),
}
```
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. The configuration will be stored in map[string]string type of field in CR.
4. Each respective controller within the CRs calls the uploader, and the WriteSparseFiles from map in CRs is passed to the uploader.
5. 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.
### Parallel Restore
Setting the parallelism of restore operations can improve the efficiency and speed of the restore process, especially when dealing with large amounts of data.
### Velero CLI
The Velero CLI will support a --parallel-files-download flag, allowing users to set the parallelism value when creating restores. when no value specified, the value of it would be the number of CPUs for the node that the node agent pod is running.
```bash
velero restore create --parallel-files-download $num
```
### UploaderConfig
below the sub-option parallel is added into UploaderConfig:
```go
type UploaderConfigForRestore struct {
// ParallelFilesDownload is the number of parallel for restore.
// +optional
ParallelFilesDownload int `json:"parallelFilesDownload,omitempty"`
}
```
#### Kopia Parallel Restore Policy
Velero Uploader can set restore policies when calling Kopia APIs. In the Kopia codebase, the structure for restore policies is defined as follows:
```go
// first get concurrrency from uploader config
restoreConcurrency, _ := uploaderutil.GetRestoreConcurrency(uploaderCfg)
// set restore concurrency into restore options
restoreOpt := restore.Options{
Parallel: restoreConcurrency,
}
// do restore with restore option
restore.Entry(..., restoreOpt)
```
#### Restic Parallel Restore Policy
Configurable parallel restore is not supported by restic, so we would return one error if the option is configured.
```go
restoreConcurrency, err := uploaderutil.GetRestoreConcurrency(uploaderCfg)
if err != nil {
return extraFlags, errors.Wrap(err, "failed to get uploader config")
}
if restoreConcurrency > 0 {
return extraFlags, errors.New("restic does not support parallel restore")
}
```
## 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.

View File

@@ -27,7 +27,7 @@ Moreover, we would like to create a general workflow to variations during the da
- Support different data accesses, i.e., file system level and block level
- Support different snapshot types, i.e., CSI snapshot, volume snapshot API from storage vendors
- Support different snapshot accesses, i.e., through PV generated from snapshots, and through direct access API from storage vendors
- Reuse the existing Velero generic data path as created in [Unified Repository design][1]
- Reuse the existing Velero generic data path as creatd in [Unified Repository design][1]
## Non-Goals
@@ -84,14 +84,14 @@ Below are actions from Velero and DMP:
**BIA Execute**
This is the existing logic in Velero. For a source PVC/PV, Velero delivers it to the corresponding BackupItemAction plugin, the plugin then takes the related actions to back it up.
For example, the existing CSI plugin takes a CSI snapshot to the volume represented by the PVC and then returns additional items (i.e., VolumeSnapshot, VolumeSnapshotContent and VolumeSnapshotClass) for Velero to further backup.
To support data movement, we will use BIA V2 which supports asynchronous operation management. Here is the Execute method from BIA V2:
To support data movement, we will use BIA V2 which supports asynchronized operation management. Here is the Execute method from BIA V2:
```
Execute(item runtime.Unstructured, backup *api.Backup) (runtime.Unstructured, []velero.ResourceIdentifier, string, []velero.ResourceIdentifier, error)
```
Besides ```additionalItem``` (as the 2nd return value), Execute method will return one more resource list called ```itemToUpdate```, which means the items to be updated and persisted when the async operation completes. For details, visit [general progress monitoring design][2].
Specifically, this mechanism will be used to persist DUCR into the persisted backup data, in another words, DUCR will be returned as ```itemToUpdate``` from Execute method. DUCR contains all the information the restore requires, so during restore, DUCR will be extracted from the backup data.
Additionally, in the same way, a DMP could add any other items into the persisted backup data.
Execute method also returns the ```operationID``` which uniquely identifies the asynchronous operation. This ```operationID``` is generated by plugins. The [general progress monitoring design][2] doesn't restrict the format of the ```operationID```, for Velero CSI plugin, the ```operationID``` is a combination of the backup CR UID and the source PVC (represented by the ```item``` parameter) UID.
Execute method also returns the ```operationID``` which uniquely identifies the asynchronized operation. This ```operationID``` is generated by plugins. The [general progress monitoring design][2] doesn't restrict the format of the ```operationID```, for Velero CSI plugin, the ```operationID``` is a combination of the backup CR UID and the source PVC (represented by the ```item``` parameter) UID.
**Create Snapshot**
The DMP creates a snapshot of the requested volume and deliver it to DM through DUCR. After that, the DMP leaves the snapshot and its related objects (e.g., VolumeSnapshot and VolumeSnapshotContent for CSI snapshot) to the DM, DM then has full control of the snapshot and its related objects, i.e., deciding whether to delete the snapshot or its related objects and when to do it.
@@ -397,7 +397,7 @@ Target volume information includes PVC and PV that represents the volume and the
The data mover information and backup repository information are the same with DataUpload CRD.
DataDownload CRD defines the same status as DataUpload CRD with nearly the same meanings.
Below is the full spec of DataDownload CRD:
Below is the full spec of DataUpload CRD:
```
apiVersion: apiextensions.k8s.io/v1alpha1
kind: CustomResourceDefinition
@@ -626,9 +626,10 @@ Therefore, we have below principles:
We will address the two principles step by step. As the first step, VBDMs parallelism is designed as below:
- We dont create the load balancing mechanism for the first step, we dont detect the accessibility of the volume/volume snapshot explicitly. Instead, we create the backupPod/restorePod under the help of Kubernetes, Kubernetes schedules the backupPod/restorePod to the appropriate node, then the data movement controller on that node will handle the DataUpload/DataDownload CR there, so the resource will be consumed from that node.
- We expose the configurable concurrency value per node, for details of how the concurrency number constraints various backups and restores which share VGDP, check the [node-agent concurrency design][3].
- We dont expose the configurable concurrency value in one node, instead, the concurrency value in value will be set to 1, that is, there is no concurrency in one node.
As for the resource consumption, it is related to the data scale of the data movement activity and it is charged to node-agent pods, so users should configure enough resource to node-agent pods.
Meanwhile, Pod Volume Backup/Restore are also running in node-agent pods, we dont restrict the concurrency of these two types. For example, in one node, one Pod Volume Backup and one DataUpload could run at the same time, in this case, the resource will be shared by the two activities.
## Progress Report
When a DUCR/DDCR is in InProgress phase, users could check the progress.
@@ -665,9 +666,6 @@ At present, VBDM doesn't support recovery, so it will follow the second rule.
## Kopia For Block Device
To work with block devices, VGDP will be updated. Today, when Kopia attempts to create a snapshot of the block device, it will error because kopia does not support this file type. Kopia does have a nice set of interfaces that are able to be extended though.
**Notice**
The Kopia block mode uploader only supports non-Windows platforms, because the block mode code invokes some system calls that are not present in the Windows platform.
To achieve the necessary information to determine the type of volume that is being used, we will need to pass in the volume mode in provider interface.
```go
@@ -691,8 +689,7 @@ type Provider interface {
tags map[string]string,
forceFull bool,
parentSnapshot string,
volMode uploader.PersistentVolumeMode,
uploaderCfg shared.UploaderConfig,
volMode uploader.PersistentVolumeMode,
updater uploader.ProgressUpdater) (string, bool, error)
RunRestore(
@@ -930,20 +927,12 @@ For 3, Velero leverage on DMs to decide how to save the log, but they will not g
## Installation
DMs need to be configured during installation so that they can be installed. Plugin DMs may have their own configuration, for VGDM, the only requirement is to install Velero node-agent.
Moreover, the DMP is also required during the installation.
From release-1.14, the `github.com/vmware-tanzu/velero-plugin-for-csi` repository, which is the Velero CSI plugin, is merged into the `github.com/vmware-tanzu/velero` repository.
The reason to merge the CSI plugin is:
* The VolumeSnapshot data mover depends on the CSI plugin, it's reasonabe to integrate them.
* This change reduces the Velero deploying complexity.
* This makes performance tuning easier in the future.
As a result, no need to install Velero CSI plugin anymore.
For example, to move CSI snapshot through VBDM, below is the installation script:
```
velero install \
--provider \
--image \
--plugins velero/velero-plugin-for-csi:xxx \
--features=EnableCSI \
--use-node-agent \
```
@@ -977,6 +966,5 @@ Restore command is kept as is.
[1]: ../Implemented/unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md
[2]: ../Implemented/general-progress-monitoring.md
[3]: ../node-agent-concurrency.md
[1]: ../unified-repo-and-kopia-integration/unified-repo-and-kopia-integration.md
[2]: ../general-progress-monitoring.md

214
go.mod
View File

@@ -1,178 +1,162 @@
module github.com/vmware-tanzu/velero
go 1.22.6
go 1.20
require (
cloud.google.com/go/storage v1.40.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.6.0
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2
github.com/aws/aws-sdk-go-v2 v1.24.1
github.com/aws/aws-sdk-go-v2/config v1.26.3
github.com/aws/aws-sdk-go-v2/credentials v1.16.14
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.11
github.com/aws/aws-sdk-go-v2/service/ec2 v1.143.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0
github.com/aws/aws-sdk-go-v2/service/sts v1.26.7
cloud.google.com/go/storage v1.30.1
github.com/Azure/azure-pipeline-go v0.2.3
github.com/Azure/azure-sdk-for-go v67.2.0+incompatible
github.com/Azure/azure-storage-blob-go v0.15.0
github.com/Azure/go-autorest/autorest v0.11.27
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8
github.com/Azure/go-autorest/autorest/to v0.3.0
github.com/aws/aws-sdk-go v1.44.253
github.com/bombsimon/logrusr/v3 v3.0.0
github.com/evanphx/json-patch/v5 v5.8.0
github.com/fatih/color v1.16.0
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/fatih/color v1.15.0
github.com/gobwas/glob v0.2.3
github.com/golang/protobuf v1.5.4
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.0
github.com/hashicorp/go-hclog v0.14.1
github.com/hashicorp/go-plugin v1.6.0
github.com/hashicorp/go-plugin v1.4.3
github.com/joho/godotenv v1.3.0
github.com/kopia/kopia v0.16.0
github.com/kubernetes-csi/external-snapshotter/client/v7 v7.0.0
github.com/kopia/kopia v0.13.0
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.30.0
github.com/onsi/gomega v1.20.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.19.0
github.com/prometheus/client_golang v1.15.0
github.com/robfig/cron v1.1.0
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.0
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/stretchr/testify v1.8.2
github.com/vmware-tanzu/crash-diagnostics v0.3.7
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/mod v0.17.0
golang.org/x/net v0.26.0
golang.org/x/oauth2 v0.19.0
golang.org/x/text v0.16.0
google.golang.org/api v0.172.0
google.golang.org/grpc v1.63.2
google.golang.org/protobuf v1.33.0
go.uber.org/zap v1.24.0
golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f
golang.org/x/mod v0.10.0
golang.org/x/net v0.17.0
golang.org/x/oauth2 v0.7.0
golang.org/x/text v0.14.0
google.golang.org/api v0.120.0
google.golang.org/grpc v1.56.3
google.golang.org/protobuf v1.30.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.29.0
k8s.io/apiextensions-apiserver v0.29.0
k8s.io/apimachinery v0.29.0
k8s.io/api v0.25.6
k8s.io/apiextensions-apiserver v0.24.2
k8s.io/apimachinery v0.25.6
k8s.io/cli-runtime v0.24.0
k8s.io/client-go v0.29.0
k8s.io/klog/v2 v2.110.1
k8s.io/client-go v0.25.6
k8s.io/klog/v2 v2.70.1
k8s.io/kube-aggregator v0.19.12
k8s.io/metrics v0.25.6
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/controller-runtime v0.17.2
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed
sigs.k8s.io/controller-runtime v0.12.2
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd
sigs.k8s.io/yaml v1.4.0
sigs.k8s.io/yaml v1.3.0
)
require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute v1.24.0 // indirect
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.19.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.7 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.10 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.6 // indirect
github.com/aws/smithy-go v1.19.0 // indirect
cloud.google.com/go/iam v0.13.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chmduquesne/rollinghash v4.0.0+incompatible // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-logr/zapr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/cronexpr v1.1.2 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/google/s2a-go v0.1.2 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.8.0 // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/klauspost/reedsolomon v1.12.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/klauspost/reedsolomon v1.11.7 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.69 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/minio/minio-go/v7 v7.0.52 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/mxk/go-vss v1.2.0 // indirect
github.com/natefinch/atomic v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.52.3 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rs/xid v1.4.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/vladimirvivien/gexe v0.1.1 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect
go.opentelemetry.io/otel/metric v1.25.0 // indirect
go.opentelemetry.io/otel/trace v1.25.0 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
go.starlark.net v0.0.0-20201006213952-227f4aabceb5 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/component-base v0.29.0 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
k8s.io/component-base v0.24.2 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)
replace github.com/kopia/kopia => github.com/project-velero/kopia v0.0.0-20240417031915-e07d5b7de567
replace github.com/kopia/kopia => github.com/project-velero/kopia v0.13.0-velero.1

616
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -12,11 +12,31 @@ run:
# exit code when at least one issue was found, default is 1
issues-exit-code: 1
# which dirs to skip: issues from them won't be reported;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but default dirs are skipped independently
# from this option's value (see skip-dirs-use-default).
# "/" will be replaced by current OS file path separator to properly work
# on Windows.
skip-dirs:
- test/*
- pkg/plugin/generated/*
# - autogenerated_by_my_lib
# default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs-use-default: true
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
# "/" will be replaced by current OS file path separator to properly work
# on Windows.
skip-files:
- ".*_test.go$"
# - lib/bad.go
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
# If invoked with -mod=readonly, the go command is disallowed from the implicit
# automatic updating of go.mod described above. Instead, it fails when any changes
@@ -36,9 +56,7 @@ run:
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
formats:
- format: colored-line-number
path: stdout
format: colored-line-number
# print lines of code with issue, default is true
print-issued-lines: true
@@ -142,8 +160,10 @@ linters-settings:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gomnd:
# the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.
checks: argument,case,condition,operation,return,assign
settings:
mnd:
# the list of enabled checks, see https://github.com/tommy-muehle/go-mnd/#checks for description.
checks: argument,case,condition,operation,return,assign
gomodguard:
allowed:
modules: # List of allowed modules
@@ -235,24 +255,6 @@ linters-settings:
rowserrcheck:
packages:
- github.com/jmoiron/sqlx
testifylint:
# TODO: enable them all
disable:
- bool-compare
- compares
- error-is-as
- error-nil
- expected-actual
- go-require
- float-compare
- require-error
- suite-dont-use-pkg
- suite-extra-assert-call
- suite-thelper
enable:
- empty
- len
- nil-compare
testpackage:
# regexp pattern to skip files
skip-regexp: (export|internal)_test\.go
@@ -300,10 +302,8 @@ linters:
- bodyclose
- dogsled
- durationcheck
- dupword
- errcheck
- exportloopref
- errchkjson
- goconst
- gofmt
- goheader
@@ -312,19 +312,14 @@ linters:
- gosec
- gosimple
- govet
- ginkgolinter
- importas
- ineffassign
- misspell
- nakedret
- nosprintfhostport
- nilerr
- noctx
- nolintlint
- revive
- staticcheck
- stylecheck
- testifylint
- revive
- typecheck
- unconvert
- unparam
@@ -339,34 +334,12 @@ issues:
- linters:
- staticcheck
text: "github.com/golang/protobuf/proto" # grpc-go still uses github.com/golang/protobuf/proto.
- linters:
- staticcheck
text: "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-06-01/storage" # Kopia still depends on this.
- linters:
- staticcheck
text: "DefaultVolumesToRestic" # No need to report deprecate for DefaultVolumesToRestic.
- path: ".*_test.go$"
linters:
- dupword
- errcheck
- goconst
- gosec
- govet
- staticcheck
- stylecheck
- unconvert
- unparam
- unused
- path: test/
linters:
- dupword
- errcheck
- goconst
- gosec
- gosimple
- nilerr
- staticcheck
- stylecheck
- unconvert
- unparam
- unused
# The list of ids of default excludes to include or disable. By default it's empty.
include:
@@ -381,15 +354,6 @@ issues:
# Show only new issues created after git revision `REV`
# new-from-rev: origin/main
# which dirs to skip: issues from them won't be reported;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but default dirs are skipped independently
# from this option's value (see skip-dirs-use-default).
# "/" will be replaced by current OS file path separator to properly work
# on Windows.
exclude-dirs:
- pkg/plugin/generated/*
severity:
# Default value is empty string.
# Set the default severity for issues. If severity rules are defined and the issues
@@ -413,4 +377,4 @@ severity:
rules:
- linters:
- dupl
severity: info
severity: info

View File

@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
FROM --platform=$TARGETPLATFORM golang:1.22.6-bookworm
FROM --platform=linux/amd64 golang:1.20.10-bullseye
ARG GOPROXY
@@ -21,16 +21,16 @@ ENV GO111MODULE=on
ENV GOPROXY=${GOPROXY}
# kubebuilder test bundle is separated from kubebuilder. Need to setup it for CI test.
RUN curl -sSLo envtest-bins.tar.gz https://go.kubebuilder.io/test-tools/1.22.1/linux/$(go env GOARCH) && \
RUN curl -sSLo envtest-bins.tar.gz https://go.kubebuilder.io/test-tools/1.22.1/linux/amd64 && \
mkdir /usr/local/kubebuilder && \
tar -C /usr/local/kubebuilder --strip-components=1 -zvxf envtest-bins.tar.gz
RUN wget --quiet https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.2.0/kubebuilder_linux_$(go env GOARCH) && \
mv kubebuilder_linux_$(go env GOARCH) /usr/local/kubebuilder/bin/kubebuilder && \
RUN wget --quiet https://github.com/kubernetes-sigs/kubebuilder/releases/download/v3.2.0/kubebuilder_linux_amd64 && \
mv kubebuilder_linux_amd64 /usr/local/kubebuilder/bin/kubebuilder && \
chmod +x /usr/local/kubebuilder/bin/kubebuilder
# get controller-tools
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.12.0
# get goimports (the revision is pinned so we don't indiscriminately update, but the particular commit
# is not important)
@@ -39,66 +39,26 @@ RUN go install golang.org/x/tools/cmd/goimports@11e9d9cc0042e6bd10337d4d2c3e5d92
# get protoc compiler and golang plugin
WORKDIR /root
RUN apt-get update && apt-get install -y unzip
# protobuf uses bazel cpunames except following
# if cpu == "systemz":
# cpu = "s390_64"
# elif cpu == "aarch64":
# cpu = "aarch_64"
# elif cpu == "ppc64":
# cpu = "ppcle_64"
# snippet from: https://github.com/protocolbuffers/protobuf/blob/d445953603e66eb8992a39b4e10fcafec8501f24/protobuf_release.bzl#L18-L24
# cpu names: https://github.com/bazelbuild/platforms/blob/main/cpu/BUILD
RUN ARCH=$(go env GOARCH) && \
if [ "$ARCH" = "s390x" ] ; then \
ARCH="s390_64"; \
elif [ "$ARCH" = "arm64" ] ; then \
ARCH="aarch_64"; \
elif [ "$ARCH" = "ppc64le" ] ; then \
ARCH="ppcle_64"; \
elif [ "$ARCH" = "ppc64" ] ; then \
ARCH="ppcle_64"; \
else \
ARCH=$(uname -m); \
fi && echo "ARCH=$ARCH" && \
wget --quiet https://github.com/protocolbuffers/protobuf/releases/download/v25.2/protoc-25.2-linux-$ARCH.zip && \
unzip protoc-25.2-linux-$ARCH.zip; \
rm *.zip && \
RUN wget --quiet https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protoc-3.14.0-linux-x86_64.zip && \
unzip protoc-3.14.0-linux-x86_64.zip && \
mv bin/protoc /usr/bin/protoc && \
mv include/google /usr/include && \
chmod a+x /usr/include/google && \
chmod a+x /usr/include/google/protobuf && \
chmod a+x /usr/include/google && \
chmod a+x /usr/include/google/protobuf && \
chmod a+r -R /usr/include/google && \
chmod +x /usr/bin/protoc
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.32.0
RUN go install github.com/golang/protobuf/protoc-gen-go@v1.4.3
# get goreleaser
# goreleaser name template per arch is basically goarch except for amd64 and 386 https://github.com/goreleaser/goreleaser/blob/ec8819a95c5527fae65e5cb41673f5bbc3245fda/.goreleaser.yaml#L167C1-L173C42
# {{- .ProjectName }}_
# {{- title .Os }}_
# {{- if eq .Arch "amd64" }}x86_64
# {{- else if eq .Arch "386" }}i386
# {{- else }}{{ .Arch }}{{ end }}
# {{- if .Arm }}v{{ .Arm }}{{ end -}}
RUN ARCH=$(go env GOARCH) && \
if [ "$ARCH" = "amd64" ] ; then \
ARCH="x86_64"; \
elif [ "$ARCH" = "386" ] ; then \
ARCH="i386"; \
elif [ "$ARCH" = "ppc64le" ] ; then \
ARCH="ppc64"; \
fi && \
wget --quiet "https://github.com/goreleaser/goreleaser/releases/download/v1.15.2/goreleaser_Linux_$ARCH.tar.gz" && \
tar xvf goreleaser_Linux_$ARCH.tar.gz; \
RUN wget --quiet https://github.com/goreleaser/goreleaser/releases/download/v1.15.2/goreleaser_Linux_x86_64.tar.gz && \
tar xvf goreleaser_Linux_x86_64.tar.gz && \
mv goreleaser /usr/bin/goreleaser && \
chmod +x /usr/bin/goreleaser
# get golangci-lint
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.57.2
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.51.0
# install kubectl
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/$(go env GOARCH)/kubectl
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
RUN chmod +x ./kubectl
RUN mv ./kubectl /usr/local/bin
# Fix the "dubious ownership" issue from git when running goreleaser.sh
RUN echo "[safe] \n\t directory = *" > /.gitconfig

View File

@@ -32,10 +32,6 @@ if [[ -z "${GOOS}" ]]; then
echo "GOOS must be set"
exit 1
fi
if [[ -z "${GOBIN}" ]]; then
echo "GOBIN must be set"
exit 1
fi
if [[ -z "${GOARCH}" ]]; then
echo "GOARCH must be set"
exit 1

View File

@@ -1,5 +1,5 @@
diff --git a/go.mod b/go.mod
index 5f939c481..1caa51275 100644
index 5f939c481..a2c584c4d 100644
--- a/go.mod
+++ b/go.mod
@@ -24,32 +24,32 @@ require (
@@ -9,16 +9,16 @@ index 5f939c481..1caa51275 100644
- golang.org/x/crypto v0.5.0
- golang.org/x/net v0.5.0
- golang.org/x/oauth2 v0.4.0
+ golang.org/x/crypto v0.21.0
+ golang.org/x/net v0.23.0
+ golang.org/x/crypto v0.17.0
+ golang.org/x/net v0.17.0
+ golang.org/x/oauth2 v0.7.0
golang.org/x/sync v0.1.0
- golang.org/x/sys v0.4.0
- golang.org/x/term v0.4.0
- golang.org/x/text v0.6.0
- google.golang.org/api v0.106.0
+ golang.org/x/sys v0.18.0
+ golang.org/x/term v0.18.0
+ golang.org/x/sys v0.15.0
+ golang.org/x/term v0.15.0
+ golang.org/x/text v0.14.0
+ google.golang.org/api v0.114.0
)
@@ -57,12 +57,12 @@ index 5f939c481..1caa51275 100644
- google.golang.org/protobuf v1.28.1 // indirect
+ google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+ google.golang.org/grpc v1.56.3 // indirect
+ google.golang.org/protobuf v1.33.0 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 026e1d2fa..27d4207f4 100644
index 026e1d2fa..8387b4e2f 100644
--- a/go.sum
+++ b/go.sum
@@ -1,13 +1,13 @@
@@ -126,8 +126,8 @@ index 026e1d2fa..27d4207f4 100644
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
-golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
+golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -137,8 +137,8 @@ index 026e1d2fa..27d4207f4 100644
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
-golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
-golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
@@ -153,13 +153,13 @@ index 026e1d2fa..27d4207f4 100644
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
-golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
+golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
+golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -208,8 +208,8 @@ index 026e1d2fa..27d4207f4 100644
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
-google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=

View File

@@ -14,12 +14,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
HACK_DIR=$(dirname "${BASH_SOURCE[0]}")
# Printing out cache status
golangci-lint cache status
# Enable GL_DEBUG line below for debug messages for golangci-lint
# export GL_DEBUG=loader,gocritic,env
CMD="golangci-lint run"
CMD="golangci-lint run -c $HACK_DIR/../golangci.yaml"
echo "Running $CMD"
eval $CMD

View File

@@ -21,9 +21,10 @@ set -o pipefail
export CGO_ENABLED=0
TARGETS=($(go list ./pkg/... ./internal/...| grep -vE "/pkg/builder|pkg/apis|pkg/test|pkg/generated|pkg/plugin/generated|mocks|internal/restartabletest"))
TARGETS=($(go list ./pkg/... | grep -v "github.com/vmware-tanzu/velero/pkg/builder"))
TARGETS+=(
./cmd/...
./internal/...
)
if [[ ${#@} -ne 0 ]]; then

View File

@@ -33,7 +33,7 @@ if ! command -v goimports > /dev/null; then
exit 1
fi
files="$(find . -type f -name '*.go' -not -path './.go/*' -not -path './vendor/*' -not -path './site/*' -not -path './.git/*' -not -path '*/generated/*' -not -name 'zz_generated*' -not -path '*/mocks/*')"
files="$(find . -type f -name '*.go' -not -path './.go/*' -not -path './vendor/*' -not -path './site/*' -not -path '*/generated/*' -not -name 'zz_generated*' -not -path '*/mocks/*')"
echo "${ACTION} gofmt"
output=$(gofmt "${MODE}" -s ${files})
if [[ -n "${output}" ]]; then

View File

@@ -19,7 +19,7 @@ HACK_DIR=$(dirname "${BASH_SOURCE}")
${HACK_DIR}/update-3generated-crd-code.sh
# ensure no changes to generated CRDs
if ! git diff --exit-code config/crd/v1/crds/crds.go config/crd/v2alpha1/crds/crds.go &> /dev/null; then
if [! git diff --exit-code config/crd/v1/crds/crds.go config/crd/v2alpha1/crds/crds.go >/dev/null]; then
# revert changes to state before running CRD generation to stay consistent
# with code-generator `--verify-only` option which discards generated changes
git checkout config/crd

View File

@@ -1,120 +0,0 @@
/*
Copyright 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 csi
import (
"context"
"fmt"
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/vmware-tanzu/velero/pkg/client"
plugincommon "github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/util/csi"
kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube"
)
// volumeSnapshotDeleteItemAction is a backup item action plugin for Velero.
type volumeSnapshotDeleteItemAction struct {
log logrus.FieldLogger
crClient crclient.Client
}
// AppliesTo returns information indicating that the
// VolumeSnapshotBackupItemAction should be invoked to backup
// VolumeSnapshots.
func (p *volumeSnapshotDeleteItemAction) AppliesTo() (velero.ResourceSelector, error) {
p.log.Debug("VolumeSnapshotBackupItemAction AppliesTo")
return velero.ResourceSelector{
IncludedResources: []string{"volumesnapshots.snapshot.storage.k8s.io"},
}, nil
}
func (p *volumeSnapshotDeleteItemAction) Execute(
input *velero.DeleteItemActionExecuteInput,
) error {
p.log.Info("Starting VolumeSnapshotDeleteItemAction for volumeSnapshot")
var vs snapshotv1api.VolumeSnapshot
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(
input.Item.UnstructuredContent(),
&vs,
); err != nil {
return errors.Wrapf(err, "failed to convert input.Item from unstructured")
}
// We don't want this DeleteItemAction plugin to delete VolumeSnapshot
// taken outside of Velero. So skip deleting VolumeSnapshot objects
// that were not created in the process of creating the Velero
// backup being deleted.
if !kubeutil.HasBackupLabel(&vs.ObjectMeta, input.Backup.Name) {
p.log.Info(
"VolumeSnapshot %s/%s was not taken by backup %s, skipping deletion",
vs.Namespace, vs.Name, input.Backup.Name,
)
return nil
}
p.log.Infof("Deleting VolumeSnapshot %s/%s", vs.Namespace, vs.Name)
if vs.Status != nil && vs.Status.BoundVolumeSnapshotContentName != nil {
// we patch the DeletionPolicy of the VolumeSnapshotContent
// to set it to Delete. This ensures that the volume snapshot
// in the storage provider is also deleted.
err := csi.SetVolumeSnapshotContentDeletionPolicy(
*vs.Status.BoundVolumeSnapshotContentName,
p.crClient,
)
if err != nil && !apierrors.IsNotFound(err) {
return errors.Wrapf(
err,
fmt.Sprintf("failed to patch DeletionPolicy of volume snapshot %s/%s",
vs.Namespace, vs.Name),
)
}
if apierrors.IsNotFound(err) {
return nil
}
}
err := p.crClient.Delete(context.TODO(), &vs)
if err != nil && !apierrors.IsNotFound(err) {
return err
}
return nil
}
func NewVolumeSnapshotDeleteItemAction(f client.Factory) plugincommon.HandlerInitializer {
return func(logger logrus.FieldLogger) (interface{}, error) {
crClient, err := f.KubebuilderClient()
if err != nil {
return nil, errors.WithStack(err)
}
return &volumeSnapshotDeleteItemAction{
log: logger,
crClient: crClient,
}, nil
}
}

View File

@@ -1,151 +0,0 @@
/*
Copyright 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 csi
import (
"context"
"fmt"
"testing"
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
)
func TestVSExecute(t *testing.T) {
tests := []struct {
name string
item runtime.Unstructured
vs *snapshotv1api.VolumeSnapshot
backup *velerov1api.Backup
createVS bool
expectErr bool
}{
{
name: "VolumeSnapshot doesn't have backup label",
item: velerotest.UnstructuredOrDie(
`
{
"apiVersion": "snapshot.storage.k8s.io/v1",
"kind": "VolumeSnapshot",
"metadata": {
"namespace": "ns",
"name": "foo"
}
}
`,
),
backup: builder.ForBackup("velero", "backup").Result(),
expectErr: false,
},
{
name: "VolumeSnapshot doesn't exist in the cluster",
vs: builder.ForVolumeSnapshot("foo", "bar").
ObjectMeta(builder.WithLabelsMap(
map[string]string{velerov1api.BackupNameLabel: "backup"},
)).Status().
BoundVolumeSnapshotContentName("vsc").
Result(),
backup: builder.ForBackup("velero", "backup").Result(),
expectErr: true,
},
{
name: "Normal case, VolumeSnapshot should be deleted",
vs: builder.ForVolumeSnapshot("foo", "bar").
ObjectMeta(builder.WithLabelsMap(
map[string]string{velerov1api.BackupNameLabel: "backup"},
)).Status().
BoundVolumeSnapshotContentName("vsc").
Result(),
backup: builder.ForBackup("velero", "backup").Result(),
expectErr: false,
createVS: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
crClient := velerotest.NewFakeControllerRuntimeClient(t)
logger := logrus.StandardLogger()
p := volumeSnapshotDeleteItemAction{log: logger, crClient: crClient}
if test.vs != nil {
vsMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(test.vs)
require.NoError(t, err)
test.item = &unstructured.Unstructured{Object: vsMap}
}
if test.createVS {
require.NoError(t, crClient.Create(context.TODO(), test.vs))
}
err := p.Execute(
&velero.DeleteItemActionExecuteInput{
Item: test.item,
Backup: test.backup,
},
)
if test.expectErr == false {
require.NoError(t, err)
}
})
}
}
func TestVSAppliesTo(t *testing.T) {
p := volumeSnapshotDeleteItemAction{
log: logrus.StandardLogger(),
}
selector, err := p.AppliesTo()
require.NoError(t, err)
require.Equal(
t,
velero.ResourceSelector{
IncludedResources: []string{"volumesnapshots.snapshot.storage.k8s.io"},
},
selector,
)
}
func TestNewVolumeSnapshotDeleteItemAction(t *testing.T) {
logger := logrus.StandardLogger()
crClient := velerotest.NewFakeControllerRuntimeClient(t)
f := &factorymocks.Factory{}
f.On("KubebuilderClient").Return(nil, fmt.Errorf(""))
plugin := NewVolumeSnapshotDeleteItemAction(f)
_, err := plugin(logger)
require.Error(t, err)
f1 := &factorymocks.Factory{}
f1.On("KubebuilderClient").Return(crClient, nil)
plugin1 := NewVolumeSnapshotDeleteItemAction(f1)
_, err1 := plugin1(logger)
require.NoError(t, err1)
}

View File

@@ -1,126 +0,0 @@
/*
Copyright 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 csi
import (
"context"
"fmt"
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/vmware-tanzu/velero/pkg/client"
plugincommon "github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/util/csi"
kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube"
)
// volumeSnapshotContentDeleteItemAction is a restore item action plugin for Velero
type volumeSnapshotContentDeleteItemAction struct {
log logrus.FieldLogger
crClient crclient.Client
}
// AppliesTo returns information indicating
// VolumeSnapshotContentRestoreItemAction action should be invoked
// while restoring VolumeSnapshotContent.snapshot.storage.k8s.io resources
func (p *volumeSnapshotContentDeleteItemAction) AppliesTo() (velero.ResourceSelector, error) {
return velero.ResourceSelector{
IncludedResources: []string{"volumesnapshotcontents.snapshot.storage.k8s.io"},
}, nil
}
func (p *volumeSnapshotContentDeleteItemAction) Execute(
input *velero.DeleteItemActionExecuteInput,
) error {
p.log.Info("Starting VolumeSnapshotContentDeleteItemAction")
var snapCont snapshotv1api.VolumeSnapshotContent
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(
input.Item.UnstructuredContent(),
&snapCont,
); err != nil {
return errors.Wrapf(err, "failed to convert VolumeSnapshotContent from unstructured")
}
// We don't want this DeleteItemAction plugin to delete
// VolumeSnapshotContent taken outside of Velero.
// So skip deleting VolumeSnapshotContent not have the backup name
// in its labels.
if !kubeutil.HasBackupLabel(&snapCont.ObjectMeta, input.Backup.Name) {
p.log.Info(
"VolumeSnapshotContent %s was not taken by backup %s, skipping deletion",
snapCont.Name,
input.Backup.Name,
)
return nil
}
p.log.Infof("Deleting VolumeSnapshotContent %s", snapCont.Name)
if err := csi.SetVolumeSnapshotContentDeletionPolicy(
snapCont.Name,
p.crClient,
); err != nil {
// #4764: Leave a warning when VolumeSnapshotContent cannot be found for deletion.
// Manual deleting VolumeSnapshotContent can cause this.
// It's tricky for Velero to handle this inconsistency.
// Even if Velero restores the VolumeSnapshotContent, CSI snapshot controller
// may not delete it correctly due to the snapshot represented by VolumeSnapshotContent
// already deleted on cloud provider.
if apierrors.IsNotFound(err) {
p.log.Warnf(
"VolumeSnapshotContent %s of backup %s cannot be found. May leave orphan snapshot %s on cloud provider.",
snapCont.Name, input.Backup.Name, *snapCont.Status.SnapshotHandle)
return nil
}
return errors.Wrapf(err, fmt.Sprintf(
"failed to set DeletionPolicy on volumesnapshotcontent %s. Skipping deletion",
snapCont.Name))
}
if err := p.crClient.Delete(
context.TODO(),
&snapCont,
); err != nil && !apierrors.IsNotFound(err) {
p.log.Infof("VolumeSnapshotContent %s not found", snapCont.Name)
return err
}
return nil
}
func NewVolumeSnapshotContentDeleteItemAction(
f client.Factory,
) plugincommon.HandlerInitializer {
return func(logger logrus.FieldLogger) (interface{}, error) {
crClient, err := f.KubebuilderClient()
if err != nil {
return nil, err
}
return &volumeSnapshotContentDeleteItemAction{
log: logger,
crClient: crClient,
}, nil
}
}

View File

@@ -1,142 +0,0 @@
/*
Copyright 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 csi
import (
"context"
"fmt"
"testing"
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v7/apis/volumesnapshot/v1"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
)
func TestVSCExecute(t *testing.T) {
snapshotHandleStr := "test"
tests := []struct {
name string
item runtime.Unstructured
vsc *snapshotv1api.VolumeSnapshotContent
backup *velerov1api.Backup
createVSC bool
expectErr bool
}{
{
name: "VolumeSnapshotContent doesn't have backup label",
item: velerotest.UnstructuredOrDie(
`
{
"apiVersion": "snapshot.storage.k8s.io/v1",
"kind": "VolumeSnapshotContent",
"metadata": {
"namespace": "ns",
"name": "foo"
}
}
`,
),
backup: builder.ForBackup("velero", "backup").Result(),
expectErr: false,
},
{
name: "VolumeSnapshotContent doesn't exist in the cluster, no error",
vsc: builder.ForVolumeSnapshotContent("bar").ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.BackupNameLabel: "backup"})).Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &snapshotHandleStr}).Result(),
backup: builder.ForBackup("velero", "backup").Result(),
expectErr: false,
},
{
name: "Normal case, VolumeSnapshot should be deleted",
vsc: builder.ForVolumeSnapshotContent("bar").ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.BackupNameLabel: "backup"})).Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: &snapshotHandleStr}).Result(),
backup: builder.ForBackup("velero", "backup").Result(),
expectErr: false,
createVSC: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
crClient := velerotest.NewFakeControllerRuntimeClient(t)
logger := logrus.StandardLogger()
p := volumeSnapshotContentDeleteItemAction{log: logger, crClient: crClient}
if test.vsc != nil {
vscMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(test.vsc)
require.NoError(t, err)
test.item = &unstructured.Unstructured{Object: vscMap}
}
if test.createVSC {
require.NoError(t, crClient.Create(context.TODO(), test.vsc))
}
err := p.Execute(
&velero.DeleteItemActionExecuteInput{
Item: test.item,
Backup: test.backup,
},
)
if test.expectErr == false {
require.NoError(t, err)
}
})
}
}
func TestVSCAppliesTo(t *testing.T) {
p := volumeSnapshotContentDeleteItemAction{
log: logrus.StandardLogger(),
}
selector, err := p.AppliesTo()
require.NoError(t, err)
require.Equal(
t,
velero.ResourceSelector{
IncludedResources: []string{"volumesnapshotcontents.snapshot.storage.k8s.io"},
},
selector,
)
}
func TestNewVolumeSnapshotContentDeleteItemAction(t *testing.T) {
logger := logrus.StandardLogger()
crClient := velerotest.NewFakeControllerRuntimeClient(t)
f := &factorymocks.Factory{}
f.On("KubebuilderClient").Return(nil, fmt.Errorf(""))
plugin := NewVolumeSnapshotContentDeleteItemAction(f)
_, err := plugin(logger)
require.Error(t, err)
f1 := &factorymocks.Factory{}
f1.On("KubebuilderClient").Return(crClient, nil)
plugin1 := NewVolumeSnapshotContentDeleteItemAction(f1)
_, err1 := plugin1(logger)
require.NoError(t, err1)
}

View File

@@ -119,7 +119,6 @@ func InvokeDeleteActions(ctx *Context) error {
if !action.Selector.Matches(labels.Set(obj.GetLabels())) {
continue
}
err = action.DeleteItemAction.Execute(&velero.DeleteItemActionExecuteInput{
Item: obj,
Backup: ctx.Backup,

View File

@@ -1,245 +0,0 @@
/*
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 (
"fmt"
"sync"
)
const (
HookSourceAnnotation = "annotation"
HookSourceSpec = "spec"
)
// hookKey identifies a backup/restore hook
type hookKey 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
}
// hookStatus records the execution status of a specific hook.
// hookStatus is extensible to accommodate additional fields as needs develop.
type hookStatus struct {
// HookFailed indicates if hook failed to execute.
hookFailed bool
// hookExecuted indicates if hook already execute.
hookExecuted bool
}
// HookTracker tracks all hooks' execution status in a single backup/restore.
type HookTracker struct {
lock *sync.RWMutex
// tracker records all hook info for a single backup/restore.
tracker map[hookKey]hookStatus
// hookAttemptedCnt indicates the number of attempted hooks.
hookAttemptedCnt int
// hookFailedCnt indicates the number of failed hooks.
hookFailedCnt int
// HookExecutedCnt indicates the number of executed hooks.
hookExecutedCnt int
// hookErrs records hook execution errors if any.
hookErrs []HookErrInfo
}
// NewHookTracker creates a hookTracker instance.
func NewHookTracker() *HookTracker {
return &HookTracker{
lock: &sync.RWMutex{},
tracker: make(map[hookKey]hookStatus),
}
}
// Add adds a hook to the hook tracker
// Add must precede the Record for each individual hook.
// In other words, a hook must be added to the tracker before its execution result is recorded.
func (ht *HookTracker) Add(podNamespace, podName, container, source, hookName string, hookPhase hookPhase) {
ht.lock.Lock()
defer ht.lock.Unlock()
key := hookKey{
podNamespace: podNamespace,
podName: podName,
hookSource: source,
container: container,
hookPhase: hookPhase,
hookName: hookName,
}
if _, ok := ht.tracker[key]; !ok {
ht.tracker[key] = hookStatus{
hookFailed: false,
hookExecuted: false,
}
ht.hookAttemptedCnt++
}
}
// Record records the hook's execution status
// Add must precede the Record for each individual hook.
// In other words, a hook must be added to the tracker before its execution result is recorded.
func (ht *HookTracker) Record(podNamespace, podName, container, source, hookName string, hookPhase hookPhase, hookFailed bool, hookErr error) error {
ht.lock.Lock()
defer ht.lock.Unlock()
key := hookKey{
podNamespace: podNamespace,
podName: podName,
hookSource: source,
container: container,
hookPhase: hookPhase,
hookName: hookName,
}
if _, ok := ht.tracker[key]; !ok {
return fmt.Errorf("hook not exist in hook tracker, hook: %+v", key)
}
if !ht.tracker[key].hookExecuted {
ht.tracker[key] = hookStatus{
hookFailed: hookFailed,
hookExecuted: true,
}
ht.hookExecutedCnt++
if hookFailed {
ht.hookFailedCnt++
ht.hookErrs = append(ht.hookErrs, HookErrInfo{Namespace: key.podNamespace, Err: hookErr})
}
}
return nil
}
// Stat returns the number of attempted hooks and failed hooks
func (ht *HookTracker) Stat() (hookAttemptedCnt int, hookFailedCnt int) {
ht.lock.RLock()
defer ht.lock.RUnlock()
return ht.hookAttemptedCnt, ht.hookFailedCnt
}
// IsComplete returns whether the execution of all hooks has finished or not
func (ht *HookTracker) IsComplete() bool {
ht.lock.RLock()
defer ht.lock.RUnlock()
return ht.hookAttemptedCnt == ht.hookExecutedCnt
}
// HooksErr returns hook execution errors
func (ht *HookTracker) HookErrs() []HookErrInfo {
ht.lock.RLock()
defer ht.lock.RUnlock()
return ht.hookErrs
}
// MultiHookTrackers tracks all hooks' execution status for multiple backups/restores.
type MultiHookTracker struct {
lock *sync.RWMutex
// trackers is a map that uses the backup/restore name as the key and stores a HookTracker as value.
trackers map[string]*HookTracker
}
// NewMultiHookTracker creates a multiHookTracker instance.
func NewMultiHookTracker() *MultiHookTracker {
return &MultiHookTracker{
lock: &sync.RWMutex{},
trackers: make(map[string]*HookTracker),
}
}
// Add adds a backup/restore hook to the tracker
func (mht *MultiHookTracker) Add(name, podNamespace, podName, container, source, hookName string, hookPhase hookPhase) {
mht.lock.Lock()
defer mht.lock.Unlock()
if _, ok := mht.trackers[name]; !ok {
mht.trackers[name] = NewHookTracker()
}
mht.trackers[name].Add(podNamespace, podName, container, source, hookName, hookPhase)
}
// Record records a backup/restore hook execution status
func (mht *MultiHookTracker) Record(name, podNamespace, podName, container, source, hookName string, hookPhase hookPhase, hookFailed bool, hookErr error) error {
mht.lock.RLock()
defer mht.lock.RUnlock()
var err error
if _, ok := mht.trackers[name]; ok {
err = mht.trackers[name].Record(podNamespace, podName, container, source, hookName, hookPhase, hookFailed, hookErr)
} else {
err = fmt.Errorf("the backup/restore not exist in hook tracker, backup/restore name: %s", name)
}
return err
}
// Stat returns the number of attempted hooks and failed hooks for a particular backup/restore
func (mht *MultiHookTracker) Stat(name string) (hookAttemptedCnt int, hookFailedCnt int) {
mht.lock.RLock()
defer mht.lock.RUnlock()
if _, ok := mht.trackers[name]; ok {
return mht.trackers[name].Stat()
}
return
}
// Delete removes the hook data for a particular backup/restore
func (mht *MultiHookTracker) Delete(name string) {
mht.lock.Lock()
defer mht.lock.Unlock()
delete(mht.trackers, name)
}
// IsComplete returns whether the execution of all hooks for a particular backup/restore has finished or not
func (mht *MultiHookTracker) IsComplete(name string) bool {
mht.lock.RLock()
defer mht.lock.RUnlock()
if _, ok := mht.trackers[name]; ok {
return mht.trackers[name].IsComplete()
}
return true
}
// HooksErr returns hook execution errors for a particular backup/restore
func (mht *MultiHookTracker) HookErrs(name string) []HookErrInfo {
mht.lock.RLock()
defer mht.lock.RUnlock()
if _, ok := mht.trackers[name]; ok {
return mht.trackers[name].HookErrs()
}
return nil
}

View File

@@ -1,197 +0,0 @@
/*
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 (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewHookTracker(t *testing.T) {
tracker := NewHookTracker()
assert.NotNil(t, tracker)
assert.Empty(t, tracker.tracker)
}
func TestHookTracker_Add(t *testing.T) {
tracker := NewHookTracker()
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
key := hookKey{
podNamespace: "ns1",
podName: "pod1",
container: "container1",
hookPhase: "",
hookSource: HookSourceAnnotation,
hookName: "h1",
}
_, ok := tracker.tracker[key]
assert.True(t, ok)
}
func TestHookTracker_Record(t *testing.T) {
tracker := NewHookTracker()
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
err := tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
key := hookKey{
podNamespace: "ns1",
podName: "pod1",
container: "container1",
hookPhase: "",
hookSource: HookSourceAnnotation,
hookName: "h1",
}
info := tracker.tracker[key]
assert.True(t, info.hookFailed)
assert.True(t, info.hookExecuted)
assert.Nil(t, err)
err = tracker.Record("ns2", "pod2", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
assert.NotNil(t, err)
err = tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", false, nil)
assert.Nil(t, err)
assert.True(t, info.hookFailed)
}
func TestHookTracker_Stat(t *testing.T) {
tracker := NewHookTracker()
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
tracker.Add("ns2", "pod2", "container1", HookSourceAnnotation, "h2", "")
tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
attempted, failed := tracker.Stat()
assert.Equal(t, 2, attempted)
assert.Equal(t, 1, failed)
}
func TestHookTracker_IsComplete(t *testing.T) {
tracker := NewHookTracker()
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre)
tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre, true, fmt.Errorf("err"))
assert.True(t, tracker.IsComplete())
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
assert.False(t, tracker.IsComplete())
}
func TestHookTracker_HookErrs(t *testing.T) {
tracker := NewHookTracker()
tracker.Add("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
tracker.Record("ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
hookErrs := tracker.HookErrs()
assert.Len(t, hookErrs, 1)
}
func TestMultiHookTracker_Add(t *testing.T) {
mht := NewMultiHookTracker()
mht.Add("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
key := hookKey{
podNamespace: "ns1",
podName: "pod1",
container: "container1",
hookPhase: "",
hookSource: HookSourceAnnotation,
hookName: "h1",
}
_, ok := mht.trackers["restore1"].tracker[key]
assert.True(t, ok)
}
func TestMultiHookTracker_Record(t *testing.T) {
mht := NewMultiHookTracker()
mht.Add("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
err := mht.Record("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
key := hookKey{
podNamespace: "ns1",
podName: "pod1",
container: "container1",
hookPhase: "",
hookSource: HookSourceAnnotation,
hookName: "h1",
}
info := mht.trackers["restore1"].tracker[key]
assert.True(t, info.hookFailed)
assert.True(t, info.hookExecuted)
assert.Nil(t, err)
err = mht.Record("restore1", "ns2", "pod2", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
assert.NotNil(t, err)
err = mht.Record("restore2", "ns2", "pod2", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
assert.NotNil(t, err)
}
func TestMultiHookTracker_Stat(t *testing.T) {
mht := NewMultiHookTracker()
mht.Add("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
mht.Add("restore1", "ns2", "pod2", "container1", HookSourceAnnotation, "h2", "")
mht.Record("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
mht.Record("restore1", "ns2", "pod2", "container1", HookSourceAnnotation, "h2", "", false, nil)
attempted, failed := mht.Stat("restore1")
assert.Equal(t, 2, attempted)
assert.Equal(t, 1, failed)
}
func TestMultiHookTracker_Delete(t *testing.T) {
mht := NewMultiHookTracker()
mht.Add("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
mht.Delete("restore1")
_, ok := mht.trackers["restore1"]
assert.False(t, ok)
}
func TestMultiHookTracker_IsComplete(t *testing.T) {
mht := NewMultiHookTracker()
mht.Add("backup1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre)
mht.Record("backup1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", PhasePre, true, fmt.Errorf("err"))
assert.True(t, mht.IsComplete("backup1"))
mht.Add("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
assert.False(t, mht.IsComplete("restore1"))
assert.True(t, mht.IsComplete("restore2"))
}
func TestMultiHookTracker_HookErrs(t *testing.T) {
mht := NewMultiHookTracker()
mht.Add("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "")
mht.Record("restore1", "ns1", "pod1", "container1", HookSourceAnnotation, "h1", "", true, fmt.Errorf("err"))
hookErrs := mht.HookErrs("restore1")
assert.Len(t, hookErrs, 1)
hookErrs2 := mht.HookErrs("restore2")
assert.Empty(t, hookErrs2)
}

View File

@@ -19,7 +19,6 @@ package hook
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
@@ -38,7 +37,6 @@ import (
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/podexec"
"github.com/vmware-tanzu/velero/pkg/restorehelper"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
"github.com/vmware-tanzu/velero/pkg/util/collections"
"github.com/vmware-tanzu/velero/pkg/util/kube"
)
@@ -63,7 +61,6 @@ const (
podRestoreHookOnErrorAnnotationKey = "post.hook.restore.velero.io/on-error"
podRestoreHookTimeoutAnnotationKey = "post.hook.restore.velero.io/exec-timeout"
podRestoreHookWaitTimeoutAnnotationKey = "post.hook.restore.velero.io/wait-timeout"
podRestoreHookWaitForReadyAnnotationKey = "post.hook.restore.velero.io/wait-for-ready"
podRestoreHookInitContainerImageAnnotationKey = "init.hook.restore.velero.io/container-image"
podRestoreHookInitContainerNameAnnotationKey = "init.hook.restore.velero.io/container-name"
podRestoreHookInitContainerCommandAnnotationKey = "init.hook.restore.velero.io/command"
@@ -82,7 +79,6 @@ type ItemHookHandler interface {
obj runtime.Unstructured,
resourceHooks []ResourceHook,
phase hookPhase,
hookTracker *HookTracker,
) error
}
@@ -201,7 +197,6 @@ func (h *DefaultItemHookHandler) HandleHooks(
obj runtime.Unstructured,
resourceHooks []ResourceHook,
phase hookPhase,
hookTracker *HookTracker,
) error {
// We only support hooks on pods right now
if groupResource != kuberesource.Pods {
@@ -223,29 +218,18 @@ func (h *DefaultItemHookHandler) HandleHooks(
hookFromAnnotations = getPodExecHookFromAnnotations(metadata.GetAnnotations(), "", log)
}
if hookFromAnnotations != nil {
hookTracker.Add(namespace, name, hookFromAnnotations.Container, HookSourceAnnotation, "", phase)
hookLog := log.WithFields(
logrus.Fields{
"hookSource": HookSourceAnnotation,
"hookSource": "annotation",
"hookType": "exec",
"hookPhase": phase,
},
)
hookFailed := false
var errExec error
if errExec = h.PodCommandExecutor.ExecutePodCommand(hookLog, obj.UnstructuredContent(), namespace, name, "<from-annotation>", hookFromAnnotations); errExec != nil {
hookLog.WithError(errExec).Error("Error executing hook")
hookFailed = true
}
errTracker := hookTracker.Record(namespace, name, hookFromAnnotations.Container, HookSourceAnnotation, "", phase, hookFailed, errExec)
if errTracker != nil {
hookLog.WithError(errTracker).Warn("Error recording the hook in hook tracker")
}
if errExec != nil && hookFromAnnotations.OnError == velerov1api.HookErrorModeFail {
return errExec
if err := h.PodCommandExecutor.ExecutePodCommand(hookLog, obj.UnstructuredContent(), namespace, name, "<from-annotation>", hookFromAnnotations); err != nil {
hookLog.WithError(err).Error("Error executing hook")
if hookFromAnnotations.OnError == velerov1api.HookErrorModeFail {
return err
}
}
return nil
@@ -253,8 +237,6 @@ func (h *DefaultItemHookHandler) HandleHooks(
labels := labels.Set(metadata.GetLabels())
// Otherwise, check for hooks defined in the backup spec.
// modeFailError records the error from the hook with "Fail" error mode
var modeFailError error
for _, resourceHook := range resourceHooks {
if !resourceHook.Selector.applicableTo(groupResource, namespace, labels) {
continue
@@ -266,34 +248,21 @@ func (h *DefaultItemHookHandler) HandleHooks(
} else {
hooks = resourceHook.Post
}
for _, hook := range hooks {
if groupResource == kuberesource.Pods {
if hook.Exec != nil {
hookTracker.Add(namespace, name, hook.Exec.Container, HookSourceSpec, resourceHook.Name, phase)
// The remaining hooks will only be executed if modeFailError is nil.
// Otherwise, execution will stop and only hook collection will occur.
if modeFailError == nil {
hookLog := log.WithFields(
logrus.Fields{
"hookSource": HookSourceSpec,
"hookType": "exec",
"hookPhase": phase,
},
)
hookFailed := false
err := h.PodCommandExecutor.ExecutePodCommand(hookLog, obj.UnstructuredContent(), namespace, name, resourceHook.Name, hook.Exec)
if err != nil {
hookLog.WithError(err).Error("Error executing hook")
hookFailed = true
if hook.Exec.OnError == velerov1api.HookErrorModeFail {
modeFailError = err
}
}
errTracker := hookTracker.Record(namespace, name, hook.Exec.Container, HookSourceSpec, resourceHook.Name, phase, hookFailed, err)
if errTracker != nil {
hookLog.WithError(errTracker).Warn("Error recording the hook in hook tracker")
hookLog := log.WithFields(
logrus.Fields{
"hookSource": "backupSpec",
"hookType": "exec",
"hookPhase": phase,
},
)
err := h.PodCommandExecutor.ExecutePodCommand(hookLog, obj.UnstructuredContent(), namespace, name, resourceHook.Name, hook.Exec)
if err != nil {
hookLog.WithError(err).Error("Error executing hook")
if hook.Exec.OnError == velerov1api.HookErrorModeFail {
return err
}
}
}
@@ -301,7 +270,7 @@ func (h *DefaultItemHookHandler) HandleHooks(
}
}
return modeFailError
return nil
}
// NoOpItemHookHandler is the an itemHookHandler for the Finalize controller where hooks don't run
@@ -313,7 +282,6 @@ func (h *NoOpItemHookHandler) HandleHooks(
obj runtime.Unstructured,
resourceHooks []ResourceHook,
phase hookPhase,
hookTracker *HookTracker,
) error {
return nil
}
@@ -509,23 +477,12 @@ func getPodExecRestoreHookFromAnnotations(annotations map[string]string, log log
}
}
waitForReadyString := annotations[podRestoreHookWaitForReadyAnnotationKey]
waitForReady := boolptr.False()
if waitForReadyString != "" {
var err error
*waitForReady, err = strconv.ParseBool(waitForReadyString)
if err != nil {
log.Warn(errors.Wrapf(err, "Unable to parse wait for ready %s, ignoring", waitForReadyString))
}
}
return &velerov1api.ExecRestoreHook{
Container: container,
Command: parseStringToCommand(commandValue),
OnError: onError,
ExecTimeout: metav1.Duration{Duration: execTimeout},
WaitTimeout: metav1.Duration{Duration: waitTimeout},
WaitForReady: waitForReady,
Container: container,
Command: parseStringToCommand(commandValue),
OnError: onError,
ExecTimeout: metav1.Duration{Duration: execTimeout},
WaitTimeout: metav1.Duration{Duration: waitTimeout},
}
}
@@ -540,11 +497,9 @@ type PodExecRestoreHook struct {
// container name. If an exec hook is defined in annotation that is used, else applicable exec
// hooks from the restore resource are accumulated.
func GroupRestoreExecHooks(
restoreName string,
resourceRestoreHooks []ResourceRestoreHook,
pod *corev1api.Pod,
log logrus.FieldLogger,
hookTrack *MultiHookTracker,
) (map[string][]PodExecRestoreHook, error) {
byContainer := map[string][]PodExecRestoreHook{}
@@ -561,11 +516,10 @@ func GroupRestoreExecHooks(
if hookFromAnnotation.Container == "" {
hookFromAnnotation.Container = pod.Spec.Containers[0].Name
}
hookTrack.Add(restoreName, metadata.GetNamespace(), metadata.GetName(), hookFromAnnotation.Container, HookSourceAnnotation, "<from-annotation>", hookPhase(""))
byContainer[hookFromAnnotation.Container] = []PodExecRestoreHook{
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: *hookFromAnnotation,
},
}
@@ -586,17 +540,12 @@ func GroupRestoreExecHooks(
named := PodExecRestoreHook{
HookName: rrh.Name,
Hook: *rh.Exec,
HookSource: HookSourceSpec,
}
// default to false if attr WaitForReady not set
if named.Hook.WaitForReady == nil {
named.Hook.WaitForReady = boolptr.False()
HookSource: "backupSpec",
}
// default to first container in pod if unset, without mutating resource restore hook
if named.Hook.Container == "" {
named.Hook.Container = pod.Spec.Containers[0].Name
}
hookTrack.Add(restoreName, metadata.GetNamespace(), metadata.GetName(), named.Hook.Container, HookSourceSpec, rrh.Name, hookPhase(""))
byContainer[named.Hook.Container] = append(byContainer[named.Hook.Container], named)
}
}

View File

@@ -36,7 +36,6 @@ import (
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/kuberesource"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
"github.com/vmware-tanzu/velero/pkg/util/collections"
)
@@ -108,7 +107,6 @@ func TestHandleHooksSkips(t *testing.T) {
},
}
hookTracker := NewHookTracker()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
podCommandExecutor := &velerotest.MockPodCommandExecutor{}
@@ -119,7 +117,7 @@ func TestHandleHooksSkips(t *testing.T) {
}
groupResource := schema.ParseGroupResource(test.groupResource)
err := h.HandleHooks(velerotest.NewLogger(), groupResource, test.item, test.hooks, PhasePre, hookTracker)
err := h.HandleHooks(velerotest.NewLogger(), groupResource, test.item, test.hooks, PhasePre)
assert.NoError(t, err)
})
}
@@ -486,8 +484,7 @@ func TestHandleHooks(t *testing.T) {
}
groupResource := schema.ParseGroupResource(test.groupResource)
hookTracker := NewHookTracker()
err := h.HandleHooks(velerotest.NewLogger(), groupResource, test.item, test.hooks, test.phase, hookTracker)
err := h.HandleHooks(velerotest.NewLogger(), groupResource, test.item, test.hooks, test.phase)
if test.expectedError != nil {
assert.EqualError(t, err, test.expectedError.Error())
@@ -727,8 +724,7 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookCommandAnnotationKey: "/usr/bin/foo",
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
},
},
{
@@ -737,8 +733,7 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookCommandAnnotationKey: `["a","b","c"]`,
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"a", "b", "c"},
WaitForReady: boolptr.False(),
Command: []string{"a", "b", "c"},
},
},
{
@@ -748,9 +743,8 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookOnErrorAnnotationKey: string(velerov1api.HookErrorModeContinue),
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
},
},
{
@@ -760,9 +754,8 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookOnErrorAnnotationKey: string(velerov1api.HookErrorModeFail),
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
},
},
{
@@ -773,10 +766,9 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookWaitTimeoutAnnotationKey: "1h",
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
ExecTimeout: metav1.Duration{Duration: 45 * time.Second},
WaitTimeout: metav1.Duration{Duration: time.Hour},
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
ExecTimeout: metav1.Duration{Duration: 45 * time.Second},
WaitTimeout: metav1.Duration{Duration: time.Hour},
},
},
{
@@ -786,9 +778,8 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookContainerAnnotationKey: "my-app",
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
Container: "my-app",
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
Container: "my-app",
},
},
{
@@ -799,10 +790,9 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookTimeoutAnnotationKey: "none",
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
Container: "my-app",
ExecTimeout: metav1.Duration{Duration: 0},
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
Container: "my-app",
ExecTimeout: metav1.Duration{Duration: 0},
},
},
{
@@ -813,10 +803,9 @@ func TestGetPodExecRestoreHookFromAnnotations(t *testing.T) {
podRestoreHookWaitTimeoutAnnotationKey: "none",
},
expected: &velerov1api.ExecRestoreHook{
Command: []string{"/usr/bin/foo"},
Container: "my-app",
ExecTimeout: metav1.Duration{Duration: 0},
WaitForReady: boolptr.False(),
Command: []string{"/usr/bin/foo"},
Container: "my-app",
ExecTimeout: metav1.Duration{Duration: 0},
},
},
}
@@ -853,7 +842,6 @@ func TestGroupRestoreExecHooks(t *testing.T) {
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeContinue),
podRestoreHookTimeoutAnnotationKey, "1s",
podRestoreHookWaitTimeoutAnnotationKey, "1m",
podRestoreHookWaitForReadyAnnotationKey, "true",
)).
Containers(&corev1api.Container{
Name: "container1",
@@ -863,14 +851,13 @@ func TestGroupRestoreExecHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
WaitForReady: boolptr.True(),
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
@@ -894,14 +881,13 @@ func TestGroupRestoreExecHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
WaitForReady: boolptr.False(),
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
@@ -935,14 +921,13 @@ func TestGroupRestoreExecHooks(t *testing.T) {
"container1": {
{
HookName: "hook1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
WaitForReady: boolptr.False(),
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
@@ -975,14 +960,13 @@ func TestGroupRestoreExecHooks(t *testing.T) {
"container1": {
{
HookName: "hook1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
WaitForReady: boolptr.False(),
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
@@ -1023,14 +1007,13 @@ func TestGroupRestoreExecHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
WaitForReady: boolptr.False(),
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
@@ -1122,12 +1105,11 @@ func TestGroupRestoreExecHooks(t *testing.T) {
RestoreHooks: []velerov1api.RestoreResourceHook{
{
Exec: &velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/aaa"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 4},
WaitTimeout: metav1.Duration{Duration: time.Minute * 4},
WaitForReady: boolptr.True(),
Container: "container1",
Command: []string{"/usr/bin/aaa"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 4},
WaitTimeout: metav1.Duration{Duration: time.Minute * 4},
},
},
},
@@ -1142,63 +1124,57 @@ func TestGroupRestoreExecHooks(t *testing.T) {
"container1": {
{
HookName: "hook1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
WaitForReady: boolptr.False(),
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
{
HookName: "hook1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/bar"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 2},
WaitTimeout: metav1.Duration{Duration: time.Minute * 2},
WaitForReady: boolptr.False(),
Container: "container1",
Command: []string{"/usr/bin/bar"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 2},
WaitTimeout: metav1.Duration{Duration: time.Minute * 2},
},
},
{
HookName: "hook2",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/aaa"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 4},
WaitTimeout: metav1.Duration{Duration: time.Minute * 4},
WaitForReady: boolptr.True(),
Container: "container1",
Command: []string{"/usr/bin/aaa"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 4},
WaitTimeout: metav1.Duration{Duration: time.Minute * 4},
},
},
},
"container2": {
{
HookName: "hook1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container2",
Command: []string{"/usr/bin/baz"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 3},
WaitTimeout: metav1.Duration{Duration: time.Second * 3},
WaitForReady: boolptr.False(),
Container: "container2",
Command: []string{"/usr/bin/baz"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second * 3},
WaitTimeout: metav1.Duration{Duration: time.Second * 3},
},
},
},
},
},
}
hookTracker := NewMultiHookTracker()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
actual, err := GroupRestoreExecHooks("restore1", tc.resourceRestoreHooks, tc.pod, velerotest.NewLogger(), hookTracker)
actual, err := GroupRestoreExecHooks(tc.resourceRestoreHooks, tc.pod, velerotest.NewLogger())
assert.Nil(t, err)
assert.Equal(t, tc.expected, actual)
})
@@ -1976,7 +1952,7 @@ func TestValidateContainer(t *testing.T) {
expectedError := fmt.Errorf("invalid InitContainer in restore hook, it doesn't have Command, Name or Image field")
// valid string should return nil as result.
assert.Nil(t, ValidateContainer([]byte(valid)))
assert.Equal(t, nil, ValidateContainer([]byte(valid)))
// noName string should return expected error as result.
assert.Equal(t, expectedError, ValidateContainer([]byte(noName)))
@@ -1987,495 +1963,3 @@ func TestValidateContainer(t *testing.T) {
// noCommand string should return expected error as result.
assert.Equal(t, expectedError, ValidateContainer([]byte(noCommand)))
}
func TestBackupHookTracker(t *testing.T) {
type podWithHook struct {
item runtime.Unstructured
hooks []ResourceHook
hookErrorsByContainer map[string]error
expectedPodHook *velerov1api.ExecHook
expectedPodHookError error
expectedError error
}
test1 := []struct {
name string
phase hookPhase
groupResource string
pods []podWithHook
hookTracker *HookTracker
expectedHookAttempted int
expectedHookFailed int
}{
{
name: "a pod with spec hooks, no error",
phase: PhasePre,
groupResource: "pods",
hookTracker: NewHookTracker(),
expectedHookAttempted: 2,
expectedHookFailed: 0,
pods: []podWithHook{
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name"
}
}`),
hooks: []ResourceHook{
{
Name: "hook1",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "1a",
Command: []string{"pre-1a"},
},
},
{
Exec: &velerov1api.ExecHook{
Container: "1b",
Command: []string{"pre-1b"},
},
},
},
},
},
},
},
},
{
name: "a pod with spec hooks and same container under different hook name, no error",
phase: PhasePre,
groupResource: "pods",
hookTracker: NewHookTracker(),
expectedHookAttempted: 4,
expectedHookFailed: 0,
pods: []podWithHook{
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name"
}
}`),
hooks: []ResourceHook{
{
Name: "hook1",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "1a",
Command: []string{"pre-1a"},
},
},
{
Exec: &velerov1api.ExecHook{
Container: "1b",
Command: []string{"pre-1b"},
},
},
},
},
{
Name: "hook2",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "1a",
Command: []string{"2a"},
},
},
{
Exec: &velerov1api.ExecHook{
Container: "2b",
Command: []string{"2b"},
},
},
},
},
},
},
},
},
{
name: "a pod with spec hooks, on error=fail",
phase: PhasePre,
groupResource: "pods",
hookTracker: NewHookTracker(),
expectedHookAttempted: 4,
expectedHookFailed: 2,
pods: []podWithHook{
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name"
}
}`),
hooks: []ResourceHook{
{
Name: "hook1",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "1a",
Command: []string{"1a"},
OnError: velerov1api.HookErrorModeContinue,
},
},
{
Exec: &velerov1api.ExecHook{
Container: "1b",
Command: []string{"1b"},
},
},
},
},
{
Name: "hook2",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "2",
Command: []string{"2"},
OnError: velerov1api.HookErrorModeFail,
},
},
},
},
{
Name: "hook3",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "3",
Command: []string{"3"},
},
},
},
},
},
hookErrorsByContainer: map[string]error{
"1a": errors.New("1a error, but continue"),
"2": errors.New("2 error, fail"),
},
},
},
},
{
name: "a pod with annotation and spec hooks",
phase: PhasePre,
groupResource: "pods",
hookTracker: NewHookTracker(),
expectedHookAttempted: 1,
expectedHookFailed: 0,
pods: []podWithHook{
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name",
"annotations": {
"hook.backup.velero.io/container": "c",
"hook.backup.velero.io/command": "/bin/ls"
}
}
}`),
expectedPodHook: &velerov1api.ExecHook{
Container: "c",
Command: []string{"/bin/ls"},
},
hooks: []ResourceHook{
{
Name: "hook1",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "1a",
Command: []string{"1a"},
OnError: velerov1api.HookErrorModeContinue,
},
},
{
Exec: &velerov1api.ExecHook{
Container: "1b",
Command: []string{"1b"},
},
},
},
},
},
},
},
},
{
name: "a pod with annotation, on error=fail",
phase: PhasePre,
groupResource: "pods",
hookTracker: NewHookTracker(),
expectedHookAttempted: 1,
expectedHookFailed: 1,
pods: []podWithHook{
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name",
"annotations": {
"hook.backup.velero.io/container": "c",
"hook.backup.velero.io/command": "/bin/ls",
"hook.backup.velero.io/on-error": "Fail"
}
}
}`),
expectedPodHook: &velerov1api.ExecHook{
Container: "c",
Command: []string{"/bin/ls"},
OnError: velerov1api.HookErrorModeFail,
},
expectedPodHookError: errors.New("pod hook error"),
},
},
},
{
name: "two pods, one with annotation, the other with spec",
phase: PhasePre,
groupResource: "pods",
hookTracker: NewHookTracker(),
expectedHookAttempted: 3,
expectedHookFailed: 1,
pods: []podWithHook{
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name",
"annotations": {
"hook.backup.velero.io/container": "c",
"hook.backup.velero.io/command": "/bin/ls",
"hook.backup.velero.io/on-error": "Fail"
}
}
}`),
expectedPodHook: &velerov1api.ExecHook{
Container: "c",
Command: []string{"/bin/ls"},
OnError: velerov1api.HookErrorModeFail,
},
expectedPodHookError: errors.New("pod hook error"),
},
{
item: velerotest.UnstructuredOrDie(`
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"namespace": "ns",
"name": "name"
}
}`),
hooks: []ResourceHook{
{
Name: "hook1",
Pre: []velerov1api.BackupResourceHook{
{
Exec: &velerov1api.ExecHook{
Container: "1a",
Command: []string{"pre-1a"},
},
},
{
Exec: &velerov1api.ExecHook{
Container: "1b",
Command: []string{"pre-1b"},
},
},
},
},
},
},
},
},
}
for _, test := range test1 {
t.Run(test.name, func(t *testing.T) {
podCommandExecutor := &velerotest.MockPodCommandExecutor{}
defer podCommandExecutor.AssertExpectations(t)
h := &DefaultItemHookHandler{
PodCommandExecutor: podCommandExecutor,
}
groupResource := schema.ParseGroupResource(test.groupResource)
hookTracker := test.hookTracker
for _, pod := range test.pods {
if pod.expectedPodHook != nil {
podCommandExecutor.On("ExecutePodCommand", mock.Anything, pod.item.UnstructuredContent(), "ns", "name", "<from-annotation>", pod.expectedPodHook).Return(pod.expectedPodHookError)
} else {
hookLoop:
for _, resourceHook := range pod.hooks {
for _, hook := range resourceHook.Pre {
hookError := pod.hookErrorsByContainer[hook.Exec.Container]
podCommandExecutor.On("ExecutePodCommand", mock.Anything, pod.item.UnstructuredContent(), "ns", "name", resourceHook.Name, hook.Exec).Return(hookError)
if hookError != nil && hook.Exec.OnError == velerov1api.HookErrorModeFail {
break hookLoop
}
}
for _, hook := range resourceHook.Post {
hookError := pod.hookErrorsByContainer[hook.Exec.Container]
podCommandExecutor.On("ExecutePodCommand", mock.Anything, pod.item.UnstructuredContent(), "ns", "name", resourceHook.Name, hook.Exec).Return(hookError)
if hookError != nil && hook.Exec.OnError == velerov1api.HookErrorModeFail {
break hookLoop
}
}
}
}
h.HandleHooks(velerotest.NewLogger(), groupResource, pod.item, pod.hooks, test.phase, hookTracker)
}
actualAtemptted, actualFailed := hookTracker.Stat()
assert.Equal(t, test.expectedHookAttempted, actualAtemptted)
assert.Equal(t, test.expectedHookFailed, actualFailed)
})
}
}
func TestRestoreHookTrackerAdd(t *testing.T) {
testCases := []struct {
name string
resourceRestoreHooks []ResourceRestoreHook
pod *corev1api.Pod
hookTracker *MultiHookTracker
expectedCnt int
}{
{
name: "neither spec hooks nor annotations hooks are set",
resourceRestoreHooks: nil,
pod: builder.ForPod("default", "my-pod").Result(),
hookTracker: NewMultiHookTracker(),
expectedCnt: 0,
},
{
name: "a hook specified in pod annotation",
resourceRestoreHooks: nil,
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
podRestoreHookContainerAnnotationKey, "container1",
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeContinue),
podRestoreHookTimeoutAnnotationKey, "1s",
podRestoreHookWaitTimeoutAnnotationKey, "1m",
podRestoreHookWaitForReadyAnnotationKey, "true",
)).
Containers(&corev1api.Container{
Name: "container1",
}).
Result(),
hookTracker: NewMultiHookTracker(),
expectedCnt: 1,
},
{
name: "two hooks specified in restore spec",
resourceRestoreHooks: []ResourceRestoreHook{
{
Name: "hook1",
Selector: ResourceHookSelector{},
RestoreHooks: []velerov1api.RestoreResourceHook{
{
Exec: &velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
{
Exec: &velerov1api.ExecRestoreHook{
Container: "container2",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
},
},
pod: builder.ForPod("default", "my-pod").
Containers(&corev1api.Container{
Name: "container1",
}, &corev1api.Container{
Name: "container2",
}).
Result(),
hookTracker: NewMultiHookTracker(),
expectedCnt: 2,
},
{
name: "both spec hooks and annotations hooks are set",
resourceRestoreHooks: []ResourceRestoreHook{
{
Name: "hook1",
Selector: ResourceHookSelector{},
RestoreHooks: []velerov1api.RestoreResourceHook{
{
Exec: &velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo2"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
},
},
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
podRestoreHookContainerAnnotationKey, "container1",
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeContinue),
podRestoreHookTimeoutAnnotationKey, "1s",
podRestoreHookWaitTimeoutAnnotationKey, "1m",
podRestoreHookWaitForReadyAnnotationKey, "true",
)).
Containers(&corev1api.Container{
Name: "container1",
}).
Result(),
hookTracker: NewMultiHookTracker(),
expectedCnt: 1,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, _ = GroupRestoreExecHooks("restore1", tc.resourceRestoreHooks, tc.pod, velerotest.NewLogger(), tc.hookTracker)
if _, ok := tc.hookTracker.trackers["restore1"]; !ok {
return
}
tracker := tc.hookTracker.trackers["restore1"].tracker
assert.Len(t, tracker, tc.expectedCnt)
})
}
}

View File

@@ -29,7 +29,6 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/podexec"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
"github.com/vmware-tanzu/velero/pkg/util/kube"
)
@@ -39,8 +38,6 @@ type WaitExecHookHandler interface {
log logrus.FieldLogger,
pod *v1.Pod,
byContainer map[string][]PodExecRestoreHook,
multiHookTracker *MultiHookTracker,
restoreName string,
) []error
}
@@ -52,11 +49,6 @@ type DefaultListWatchFactory struct {
PodsGetter cache.Getter
}
type HookErrInfo struct {
Namespace string
Err error
}
func (d *DefaultListWatchFactory) NewListWatch(namespace string, selector fields.Selector) cache.ListerWatcher {
return cache.NewListWatchFromClient(d.PodsGetter, "pods", namespace, selector)
}
@@ -75,8 +67,6 @@ func (e *DefaultWaitExecHookHandler) HandleHooks(
log logrus.FieldLogger,
pod *v1.Pod,
byContainer map[string][]PodExecRestoreHook,
multiHookTracker *MultiHookTracker,
restoreName string,
) []error {
if pod == nil {
return nil
@@ -136,8 +126,8 @@ func (e *DefaultWaitExecHookHandler) HandleHooks(
}
for containerName, hooks := range byContainer {
if !isContainerUp(newPod, containerName, hooks) {
podLog.Infof("Container %s is not up: post-restore hooks will not yet be executed", containerName)
if !isContainerRunning(newPod, containerName) {
podLog.Infof("Container %s is not running: post-restore hooks will not yet be executed", containerName)
continue
}
podMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(newPod)
@@ -167,14 +157,8 @@ func (e *DefaultWaitExecHookHandler) HandleHooks(
if hook.Hook.WaitTimeout.Duration != 0 && time.Since(waitStart) > hook.Hook.WaitTimeout.Duration {
err := fmt.Errorf("hook %s in container %s expired before executing", hook.HookName, hook.Hook.Container)
hookLog.Error(err)
errors = append(errors, err)
errTracker := multiHookTracker.Record(restoreName, newPod.Namespace, newPod.Name, hook.Hook.Container, hook.HookSource, hook.HookName, hookPhase(""), true, err)
if errTracker != nil {
hookLog.WithError(errTracker).Warn("Error recording the hook in hook tracker")
}
if hook.Hook.OnError == velerov1api.HookErrorModeFail {
errors = append(errors, err)
cancel()
return
}
@@ -185,24 +169,13 @@ func (e *DefaultWaitExecHookHandler) HandleHooks(
OnError: hook.Hook.OnError,
Timeout: hook.Hook.ExecTimeout,
}
hookFailed := false
var hookErr error
if hookErr = e.PodCommandExecutor.ExecutePodCommand(hookLog, podMap, pod.Namespace, pod.Name, hook.HookName, eh); hookErr != nil {
hookLog.WithError(hookErr).Error("Error executing hook")
hookErr = fmt.Errorf("hook %s in container %s failed to execute, err: %v", hook.HookName, hook.Hook.Container, hookErr)
errors = append(errors, hookErr)
hookFailed = true
}
errTracker := multiHookTracker.Record(restoreName, newPod.Namespace, newPod.Name, hook.Hook.Container, hook.HookSource, hook.HookName, hookPhase(""), hookFailed, hookErr)
if errTracker != nil {
hookLog.WithError(errTracker).Warn("Error recording the hook in hook tracker")
}
if hookErr != nil && hook.Hook.OnError == velerov1api.HookErrorModeFail {
cancel()
return
if err := e.PodCommandExecutor.ExecutePodCommand(hookLog, podMap, pod.Namespace, pod.Name, hook.HookName, eh); err != nil {
hookLog.WithError(err).Error("Error executing hook")
if hook.Hook.OnError == velerov1api.HookErrorModeFail {
errors = append(errors, err)
cancel()
return
}
}
}
delete(byContainer, containerName)
@@ -230,9 +203,10 @@ func (e *DefaultWaitExecHookHandler) HandleHooks(
podWatcher.Run(ctx.Done())
// There are some cases where this function could return with unexecuted hooks: the pod may
// be deleted, a hook could fail, or it may timeout waiting for
// be deleted, a hook with OnError mode Fail could fail, or it may timeout waiting for
// containers to become ready.
// Each unexecuted hook is logged as an error and this error will be returned from this function.
// Each unexecuted hook is logged as an error but only hooks with OnError mode Fail return
// an error from this function.
for _, hooks := range byContainer {
for _, hook := range hooks {
if hook.executed {
@@ -246,14 +220,10 @@ func (e *DefaultWaitExecHookHandler) HandleHooks(
"hookPhase": "post",
},
)
errTracker := multiHookTracker.Record(restoreName, pod.Namespace, pod.Name, hook.Hook.Container, hook.HookSource, hook.HookName, hookPhase(""), true, err)
if errTracker != nil {
hookLog.WithError(errTracker).Warn("Error recording the hook in hook tracker")
}
hookLog.Error(err)
errors = append(errors, err)
if hook.Hook.OnError == velerov1api.HookErrorModeFail {
errors = append(errors, err)
}
}
}
@@ -273,24 +243,14 @@ func podHasContainer(pod *v1.Pod, containerName string) bool {
return false
}
func isContainerUp(pod *v1.Pod, containerName string, hooks []PodExecRestoreHook) bool {
func isContainerRunning(pod *v1.Pod, containerName string) bool {
if pod == nil {
return false
}
var waitForReady bool
for _, hook := range hooks {
if boolptr.IsSetToTrue(hook.Hook.WaitForReady) {
waitForReady = true
break
}
}
for _, cs := range pod.Status.ContainerStatuses {
if cs.Name != containerName {
continue
}
if waitForReady {
return cs.Ready
}
return cs.State.Running != nil
}

View File

@@ -35,7 +35,6 @@ import (
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
)
type fakeListWatchFactory struct {
@@ -98,7 +97,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -167,7 +166,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -209,10 +208,10 @@ func TestWaitExecHandleHooks(t *testing.T) {
Result(),
},
},
expectedErrors: []error{errors.New("hook <from-annotation> in container container1 failed to execute, err: pod hook error")},
expectedErrors: []error{errors.New("pod hook error")},
},
{
name: "should return error when hook from annotation fails with on error mode continue",
name: "should return no error when hook from annotation fails with on error mode continue",
initialPod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
@@ -236,7 +235,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -278,7 +277,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
Result(),
},
},
expectedErrors: []error{errors.New("hook <from-annotation> in container container1 failed to execute, err: pod hook error")},
expectedErrors: nil,
},
{
name: "should return no error when hook from annotation executes after 10ms wait for container to start",
@@ -305,7 +304,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -391,7 +390,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -422,7 +421,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
},
},
{
name: "should return error when spec hook with wait timeout expires with OnError mode Continue",
name: "should return no error when spec hook with wait timeout expires with OnError mode Continue",
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
@@ -435,12 +434,12 @@ func TestWaitExecHandleHooks(t *testing.T) {
},
}).
Result(),
expectedErrors: []error{errors.New("hook my-hook-1 in container container1 in pod default/my-pod not executed: context deadline exceeded")},
expectedErrors: nil,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -471,7 +470,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -502,7 +501,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -515,8 +514,8 @@ func TestWaitExecHandleHooks(t *testing.T) {
sharedHooksContextTimeout: time.Millisecond,
},
{
name: "should return error when shared hooks context is canceled before spec hook with OnError mode Continue executes",
expectedErrors: []error{errors.New("hook my-hook-1 in container container1 in pod default/my-pod not executed: context deadline exceeded")},
name: "should return no error when shared hooks context is canceled before spec hook with OnError mode Continue executes",
expectedErrors: nil,
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
@@ -533,7 +532,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -574,7 +573,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
@@ -584,7 +583,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
"container2": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container2",
Command: []string{"/usr/bin/bar"},
@@ -710,6 +709,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
source := fcache.NewFakeControllerSource()
go func() {
// This is the state of the pod that will be seen by the AddFunc handler.
@@ -743,8 +743,7 @@ func TestWaitExecHandleHooks(t *testing.T) {
defer ctxCancel()
}
hookTracker := NewMultiHookTracker()
errs := h.HandleHooks(ctx, velerotest.NewLogger(), test.initialPod, test.byContainer, hookTracker, "restore1")
errs := h.HandleHooks(ctx, velerotest.NewLogger(), test.initialPod, test.byContainer)
// for i, ee := range test.expectedErrors {
require.Len(t, errs, len(test.expectedErrors))
@@ -791,13 +790,12 @@ func TestPodHasContainer(t *testing.T) {
}
}
func TestIsContainerUp(t *testing.T) {
func TestIsContainerRunning(t *testing.T) {
tests := []struct {
name string
pod *v1.Pod
container string
expect bool
hooks []PodExecRestoreHook
}{
{
name: "should return true when running",
@@ -811,49 +809,6 @@ func TestIsContainerUp(t *testing.T) {
},
}).
Result(),
hooks: []PodExecRestoreHook{},
},
{
name: "should return false when running but not ready",
container: "container1",
expect: false,
pod: builder.ForPod("default", "my-pod").
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
Ready: false,
}).
Result(),
hooks: []PodExecRestoreHook{
{
Hook: velerov1api.ExecRestoreHook{
WaitForReady: boolptr.True(),
},
},
},
},
{
name: "should return true when running and ready",
container: "container1",
expect: true,
pod: builder.ForPod("default", "my-pod").
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
Ready: true,
}).
Result(),
hooks: []PodExecRestoreHook{
{
Hook: velerov1api.ExecRestoreHook{
WaitForReady: boolptr.True(),
},
},
},
},
{
name: "should return false when no state is set",
@@ -865,7 +820,6 @@ func TestIsContainerUp(t *testing.T) {
State: v1.ContainerState{},
}).
Result(),
hooks: []PodExecRestoreHook{},
},
{
name: "should return false when waiting",
@@ -879,7 +833,6 @@ func TestIsContainerUp(t *testing.T) {
},
}).
Result(),
hooks: []PodExecRestoreHook{},
},
{
name: "should return true when running and first container is terminated",
@@ -899,12 +852,11 @@ func TestIsContainerUp(t *testing.T) {
},
}).
Result(),
hooks: []PodExecRestoreHook{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := isContainerUp(test.pod, test.container, test.hooks)
actual := isContainerRunning(test.pod, test.container)
assert.Equal(t, actual, test.expect)
})
}
@@ -997,286 +949,3 @@ func TestMaxHookWait(t *testing.T) {
})
}
}
func TestRestoreHookTrackerUpdate(t *testing.T) {
type change struct {
// delta to wait since last change applied or pod added
wait time.Duration
updated *v1.Pod
}
type expectedExecution struct {
hook *velerov1api.ExecHook
name string
error error
pod *v1.Pod
}
hookTracker1 := NewMultiHookTracker()
hookTracker1.Add("restore1", "default", "my-pod", "container1", HookSourceAnnotation, "<from-annotation>", hookPhase(""))
hookTracker2 := NewMultiHookTracker()
hookTracker2.Add("restore1", "default", "my-pod", "container1", HookSourceSpec, "my-hook-1", hookPhase(""))
hookTracker3 := NewMultiHookTracker()
hookTracker3.Add("restore1", "default", "my-pod", "container1", HookSourceSpec, "my-hook-1", hookPhase(""))
hookTracker3.Add("restore1", "default", "my-pod", "container2", HookSourceSpec, "my-hook-2", hookPhase(""))
hookTracker4 := NewMultiHookTracker()
hookTracker4.Add("restore1", "default", "my-pod", "container1", HookSourceSpec, "my-hook-1", hookPhase(""))
tests1 := []struct {
name string
initialPod *v1.Pod
groupResource string
byContainer map[string][]PodExecRestoreHook
expectedExecutions []expectedExecution
hookTracker *MultiHookTracker
expectedFailed int
}{
{
name: "a hook executes successfully",
initialPod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
podRestoreHookContainerAnnotationKey, "container1",
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeContinue),
podRestoreHookTimeoutAnnotationKey, "1s",
podRestoreHookWaitTimeoutAnnotationKey, "1m",
)).
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
groupResource: "pods",
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "<from-annotation>",
HookSource: HookSourceAnnotation,
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{Duration: time.Second},
WaitTimeout: metav1.Duration{Duration: time.Minute},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "<from-annotation>",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
Timeout: metav1.Duration{Duration: time.Second},
},
error: nil,
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("1")).
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
podRestoreHookContainerAnnotationKey, "container1",
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeContinue),
podRestoreHookTimeoutAnnotationKey, "1s",
podRestoreHookWaitTimeoutAnnotationKey, "1m",
)).
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
},
hookTracker: hookTracker1,
expectedFailed: 0,
},
{
name: "a hook with OnError mode Fail failed to execute",
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
WaitTimeout: metav1.Duration{Duration: time.Millisecond},
},
},
},
},
hookTracker: hookTracker2,
expectedFailed: 1,
},
{
name: "a hook with OnError mode Continue failed to execute",
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
WaitTimeout: metav1.Duration{Duration: time.Millisecond},
},
},
},
},
hookTracker: hookTracker4,
expectedFailed: 1,
},
{
name: "two hooks with OnError mode Continue failed to execute",
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container1",
}).
Containers(&v1.Container{
Name: "container2",
}).
// initially both are waiting
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container2",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
WaitTimeout: metav1.Duration{Duration: time.Millisecond},
},
},
},
"container2": {
{
HookName: "my-hook-2",
HookSource: HookSourceSpec,
Hook: velerov1api.ExecRestoreHook{
Container: "container2",
Command: []string{"/usr/bin/bar"},
OnError: velerov1api.HookErrorModeContinue,
WaitTimeout: metav1.Duration{Duration: time.Millisecond},
},
},
},
},
hookTracker: hookTracker3,
expectedFailed: 2,
},
{
name: "a hook was recorded before added to tracker",
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: HookSourceSpec,
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
WaitTimeout: metav1.Duration{Duration: time.Millisecond},
},
},
},
},
hookTracker: NewMultiHookTracker(),
expectedFailed: 0,
},
}
for _, test := range tests1 {
t.Run(test.name, func(t *testing.T) {
source := fcache.NewFakeControllerSource()
go func() {
// This is the state of the pod that will be seen by the AddFunc handler.
source.Add(test.initialPod)
}()
podCommandExecutor := &velerotest.MockPodCommandExecutor{}
defer podCommandExecutor.AssertExpectations(t)
h := &DefaultWaitExecHookHandler{
PodCommandExecutor: podCommandExecutor,
ListWatchFactory: &fakeListWatchFactory{source},
}
for _, e := range test.expectedExecutions {
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(e.pod)
assert.Nil(t, err)
podCommandExecutor.On("ExecutePodCommand", mock.Anything, obj, e.pod.Namespace, e.pod.Name, e.name, e.hook).Return(e.error)
}
ctx := context.Background()
_ = h.HandleHooks(ctx, velerotest.NewLogger(), test.initialPod, test.byContainer, test.hookTracker, "restore1")
_, actualFailed := test.hookTracker.Stat("restore1")
assert.Equal(t, test.expectedFailed, actualFailed)
})
}
}

View File

@@ -3,7 +3,7 @@ package resourcemodifiers
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch/v5"
jsonpatch "github.com/evanphx/json-patch"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"

View File

@@ -6,7 +6,7 @@ import (
"strconv"
"strings"
jsonpatch "github.com/evanphx/json-patch/v5"
jsonpatch "github.com/evanphx/json-patch"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

View File

@@ -1,25 +1,10 @@
/*
Copyright 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 resourcemodifiers
import (
"fmt"
"regexp"
jsonpatch "github.com/evanphx/json-patch/v5"
jsonpatch "github.com/evanphx/json-patch"
"github.com/gobwas/glob"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -86,22 +71,8 @@ func GetResourceModifiersFromConfig(cm *v1.ConfigMap) (*ResourceModifiers, error
func (p *ResourceModifiers) ApplyResourceModifierRules(obj *unstructured.Unstructured, groupResource string, scheme *runtime.Scheme, log logrus.FieldLogger) []error {
var errs []error
origin := obj
// If there are more than one rules, we need to keep the original object for condition matching
if len(p.ResourceModifierRules) > 1 {
origin = obj.DeepCopy()
}
for _, rule := range p.ResourceModifierRules {
matched, err := rule.match(origin, groupResource, log)
if err != nil {
errs = append(errs, err)
continue
} else if !matched {
continue
}
log.Infof("Applying resource modifier patch on %s/%s", origin.GetNamespace(), origin.GetName())
err = rule.applyPatch(obj, scheme, log)
err := rule.apply(obj, groupResource, scheme, log)
if err != nil {
errs = append(errs, err)
}
@@ -110,54 +81,59 @@ func (p *ResourceModifiers) ApplyResourceModifierRules(obj *unstructured.Unstruc
return errs
}
func (r *ResourceModifierRule) match(obj *unstructured.Unstructured, groupResource string, log logrus.FieldLogger) (bool, error) {
func (r *ResourceModifierRule) apply(obj *unstructured.Unstructured, groupResource string, scheme *runtime.Scheme, log logrus.FieldLogger) error {
ns := obj.GetNamespace()
if ns != "" {
namespaceInclusion := collections.NewIncludesExcludes().Includes(r.Conditions.Namespaces...)
if !namespaceInclusion.ShouldInclude(ns) {
return false, nil
return nil
}
}
g, err := glob.Compile(r.Conditions.GroupResource, '.')
if err != nil {
log.Errorf("Bad glob pattern of groupResource in condition, groupResource: %s, err: %s", r.Conditions.GroupResource, err)
return false, err
return err
}
if !g.Match(groupResource) {
return false, nil
return nil
}
if r.Conditions.ResourceNameRegex != "" {
match, err := regexp.MatchString(r.Conditions.ResourceNameRegex, obj.GetName())
if err != nil {
return false, errors.Errorf("error in matching regex %s", err.Error())
return errors.Errorf("error in matching regex %s", err.Error())
}
if !match {
return false, nil
return nil
}
}
if r.Conditions.LabelSelector != nil {
selector, err := metav1.LabelSelectorAsSelector(r.Conditions.LabelSelector)
if err != nil {
return false, errors.Errorf("error in creating label selector %s", err.Error())
return errors.Errorf("error in creating label selector %s", err.Error())
}
if !selector.Matches(labels.Set(obj.GetLabels())) {
return false, nil
return nil
}
}
match, err := matchConditions(obj, r.Conditions.Matches, log)
if err != nil {
return false, err
return err
} else if !match {
log.Info("Conditions do not match, skip it")
return false, nil
return nil
}
return true, nil
log.Infof("Applying resource modifier patch on %s/%s", obj.GetNamespace(), obj.GetName())
err = r.applyPatch(obj, scheme, log)
if err != nil {
return err
}
return nil
}
func matchConditions(u *unstructured.Unstructured, rules []MatchRule, _ logrus.FieldLogger) (bool, error) {

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcemodifiers
import (
@@ -428,6 +413,7 @@ func TestGetResourceModifiersFromConfig(t *testing.T) {
}
func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) {
pvcStandardSc := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
@@ -456,20 +442,6 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) {
},
}
pvcGoldSc := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "PersistentVolumeClaim",
"metadata": map[string]interface{}{
"name": "test-pvc",
"namespace": "foo",
},
"spec": map[string]interface{}{
"storageClassName": "gold",
},
},
}
deployNginxOneReplica := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
@@ -693,110 +665,6 @@ func TestResourceModifiers_ApplyResourceModifierRules(t *testing.T) {
wantErr: false,
wantObj: pvcPremiumSc.DeepCopy(),
},
{
name: "pvc with standard storage class should be patched to premium, even when rules are [standard => premium, premium => gold]",
fields: fields{
Version: "v1",
ResourceModifierRules: []ResourceModifierRule{
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "standard",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "premium",
},
},
},
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "premium",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "gold",
},
},
},
},
},
args: args{
obj: pvcStandardSc.DeepCopy(),
groupResource: "persistentvolumeclaims",
},
wantErr: false,
wantObj: pvcPremiumSc.DeepCopy(),
},
{
name: "pvc with standard storage class should be patched to gold, even when rules are [standard => premium, standard => gold]",
fields: fields{
Version: "v1",
ResourceModifierRules: []ResourceModifierRule{
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "standard",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "premium",
},
},
},
{
Conditions: Conditions{
GroupResource: "persistentvolumeclaims",
ResourceNameRegex: ".*",
Matches: []MatchRule{
{
Path: "/spec/storageClassName",
Value: "standard",
},
},
},
Patches: []JSONPatch{
{
Operation: "replace",
Path: "/spec/storageClassName",
Value: "gold",
},
},
},
},
},
args: args{
obj: pvcStandardSc.DeepCopy(),
groupResource: "persistentvolumeclaims",
},
wantErr: false,
wantObj: pvcGoldSc.DeepCopy(),
},
{
name: "nginx deployment: 1 -> 2 replicas",
fields: fields{

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcemodifiers
import (

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcemodifiers
import (

View File

@@ -1,44 +1,19 @@
/*
Copyright 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 resourcepolicies
import (
"context"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
type VolumeActionType string
const (
// currently only support configmap type of resource config
ConfigmapRefType string = "configmap"
// skip action implies the volume would be skipped from the backup operation
Skip VolumeActionType = "skip"
// fs-backup action implies that the volume would be backed up via file system copy method using the uploader(kopia/restic) configured by the user
FSBackup VolumeActionType = "fs-backup"
// snapshot action can have 3 different meaning based on velero configuration and backup spec - cloud provider based snapshots, local csi snapshots and datamover snapshots
Snapshot VolumeActionType = "snapshot"
ConfigmapRefType string = "configmap"
Skip VolumeActionType = "skip"
)
// Action defined as one action for a specific way of backup
@@ -50,16 +25,16 @@ type Action struct {
}
// volumePolicy defined policy to conditions to match Volumes and related action to handle matched Volumes
type VolumePolicy struct {
type volumePolicy struct {
// Conditions defined list of conditions to match Volumes
Conditions map[string]interface{} `yaml:"conditions"`
Action Action `yaml:"action"`
}
// resourcePolicies currently defined slice of volume policies to handle backup
type ResourcePolicies struct {
type resourcePolicies struct {
Version string `yaml:"version"`
VolumePolicies []VolumePolicy `yaml:"volumePolicies"`
VolumePolicies []volumePolicy `yaml:"volumePolicies"`
// we may support other resource policies in the future, and they could be added separately
// OtherResourcePolicies []OtherResourcePolicy
}
@@ -70,8 +45,8 @@ type Policies struct {
// OtherPolicies
}
func unmarshalResourcePolicies(yamlData *string) (*ResourcePolicies, error) {
resPolicies := &ResourcePolicies{}
func unmarshalResourcePolicies(yamlData *string) (*resourcePolicies, error) {
resPolicies := &resourcePolicies{}
err := decodeStruct(strings.NewReader(*yamlData), resPolicies)
if err != nil {
return nil, fmt.Errorf("failed to decode yaml data into resource policies %v", err)
@@ -79,7 +54,7 @@ func unmarshalResourcePolicies(yamlData *string) (*ResourcePolicies, error) {
return resPolicies, nil
}
func (p *Policies) BuildPolicy(resPolicies *ResourcePolicies) error {
func (p *Policies) buildPolicy(resPolicies *resourcePolicies) error {
for _, vp := range resPolicies.VolumePolicies {
con, err := unmarshalVolConditions(vp.Conditions)
if err != nil {
@@ -95,7 +70,6 @@ func (p *Policies) BuildPolicy(resPolicies *ResourcePolicies) error {
volP.conditions = append(volP.conditions, &storageClassCondition{storageClass: con.StorageClass})
volP.conditions = append(volP.conditions, &nfsCondition{nfs: con.NFS})
volP.conditions = append(volP.conditions, &csiCondition{csi: con.CSI})
volP.conditions = append(volP.conditions, &volumeTypeCondition{volumeTypes: con.VolumeTypes})
p.volumePolicies = append(p.volumePolicies, volP)
}
@@ -153,43 +127,7 @@ func (p *Policies) Validate() error {
return nil
}
func GetResourcePoliciesFromBackup(
backup velerov1api.Backup,
client crclient.Client,
logger logrus.FieldLogger,
) (resourcePolicies *Policies, err error) {
if backup.Spec.ResourcePolicy != nil &&
strings.EqualFold(backup.Spec.ResourcePolicy.Kind, ConfigmapRefType) {
policiesConfigMap := &v1.ConfigMap{}
err = client.Get(
context.Background(),
crclient.ObjectKey{Namespace: backup.Namespace, Name: backup.Spec.ResourcePolicy.Name},
policiesConfigMap,
)
if err != nil {
logger.Errorf("Fail to get ResourcePolicies %s ConfigMap with error %s.",
backup.Namespace+"/"+backup.Spec.ResourcePolicy.Name, err.Error())
return nil, fmt.Errorf("fail to get ResourcePolicies %s ConfigMap with error %s",
backup.Namespace+"/"+backup.Spec.ResourcePolicy.Name, err.Error())
}
resourcePolicies, err = getResourcePoliciesFromConfig(policiesConfigMap)
if err != nil {
logger.Errorf("Fail to read ResourcePolicies from ConfigMap %s with error %s.",
backup.Namespace+"/"+backup.Name, err.Error())
return nil, fmt.Errorf("fail to read the ResourcePolicies from ConfigMap %s with error %s",
backup.Namespace+"/"+backup.Name, err.Error())
} else if err = resourcePolicies.Validate(); err != nil {
logger.Errorf("Fail to validate ResourcePolicies in ConfigMap %s with error %s.",
backup.Namespace+"/"+backup.Name, err.Error())
return nil, fmt.Errorf("fail to validate ResourcePolicies in ConfigMap %s with error %s",
backup.Namespace+"/"+backup.Name, err.Error())
}
}
return resourcePolicies, nil
}
func getResourcePoliciesFromConfig(cm *v1.ConfigMap) (*Policies, error) {
func GetResourcePoliciesFromConfig(cm *v1.ConfigMap) (*Policies, error) {
if cm == nil {
return nil, fmt.Errorf("could not parse config from nil configmap")
}
@@ -208,7 +146,7 @@ func getResourcePoliciesFromConfig(cm *v1.ConfigMap) (*Policies, error) {
}
policies := &Policies{}
if err := policies.BuildPolicy(resPolicies); err != nil {
if err := policies.buildPolicy(resPolicies); err != nil {
return nil, errors.WithStack(err)
}

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcepolicies
import (
@@ -121,9 +106,9 @@ func TestLoadResourcePolicies(t *testing.T) {
}
func TestGetResourceMatchedAction(t *testing.T) {
resPolicies := &ResourcePolicies{
resPolicies := &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -136,7 +121,7 @@ func TestGetResourceMatchedAction(t *testing.T) {
},
},
{
Action: Action{Type: "snapshot"},
Action: Action{Type: "volume-snapshot"},
Conditions: map[string]interface{}{
"capacity": "10,100Gi",
"storageClass": []string{"gp2", "ebs-sc"},
@@ -147,7 +132,7 @@ func TestGetResourceMatchedAction(t *testing.T) {
},
},
{
Action: Action{Type: "fs-backup"},
Action: Action{Type: "file-system-backup"},
Conditions: map[string]interface{}{
"storageClass": []string{"gp2", "ebs-sc"},
"csi": interface{}(
@@ -179,10 +164,10 @@ func TestGetResourceMatchedAction(t *testing.T) {
storageClass: "ebs-sc",
csi: &csiVolumeSource{Driver: "aws.efs.csi.driver"},
},
expectedAction: &Action{Type: "snapshot"},
expectedAction: &Action{Type: "volume-snapshot"},
},
{
name: "mismatch all policies",
name: "dismatch all policies",
volume: &structuredVolume{
capacity: *resource.NewQuantity(50<<30, resource.BinarySI),
storageClass: "ebs-sc",
@@ -195,7 +180,7 @@ func TestGetResourceMatchedAction(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
policies := &Policies{}
err := policies.BuildPolicy(resPolicies)
err := policies.buildPolicy(resPolicies)
if err != nil {
t.Errorf("Failed to build policy with error %v", err)
}
@@ -231,15 +216,15 @@ func TestGetResourcePoliciesFromConfig(t *testing.T) {
}
// Call the function and check for errors
resPolicies, err := getResourcePoliciesFromConfig(cm)
resPolicies, err := GetResourcePoliciesFromConfig(cm)
assert.Nil(t, err)
// Check that the returned resourcePolicies object contains the expected data
assert.Equal(t, "v1", resPolicies.version)
assert.Len(t, resPolicies.volumePolicies, 1)
policies := ResourcePolicies{
policies := resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Conditions: map[string]interface{}{
"capacity": "0,10Gi",
@@ -251,7 +236,7 @@ func TestGetResourcePoliciesFromConfig(t *testing.T) {
},
}
p := &Policies{}
err = p.BuildPolicy(&policies)
err = p.buildPolicy(&policies)
if err != nil {
t.Fatalf("failed to build policy with error %v", err)
}
@@ -370,51 +355,6 @@ volumePolicies:
},
skip: false,
},
{
name: "match volume by types",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
volumeTypes:
- local
- hostPath
action:
type: skip`,
vol: &v1.PersistentVolume{
Spec: v1.PersistentVolumeSpec{
Capacity: v1.ResourceList{
v1.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: v1.PersistentVolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: "/mnt/data"},
},
},
},
skip: true,
},
{
name: "mismatch volume by types",
yamlData: `version: v1
volumePolicies:
- conditions:
capacity: "0,100Gi"
volumeTypes:
- local
action:
type: skip`,
vol: &v1.PersistentVolume{
Spec: v1.PersistentVolumeSpec{
Capacity: v1.ResourceList{
v1.ResourceStorage: resource.MustParse("1Gi"),
},
PersistentVolumeSource: v1.PersistentVolumeSource{
HostPath: &v1.HostPathVolumeSource{Path: "/mnt/data"},
},
},
},
skip: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -424,7 +364,7 @@ volumePolicies:
}
assert.Nil(t, err)
policies := &Policies{}
err = policies.BuildPolicy(resPolicies)
err = policies.buildPolicy(resPolicies)
assert.Nil(t, err)
action, err := policies.GetMatchAction(tc.vol)
assert.Nil(t, err)

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcepolicies
import (
@@ -47,7 +32,6 @@ type structuredVolume struct {
storageClass string
nfs *nFSVolumeSource
csi *csiVolumeSource
volumeType SupportedVolume
}
func (s *structuredVolume) parsePV(pv *corev1api.PersistentVolume) {
@@ -62,8 +46,6 @@ func (s *structuredVolume) parsePV(pv *corev1api.PersistentVolume) {
if csi != nil {
s.csi = &csiVolumeSource{Driver: csi.Driver}
}
s.volumeType = getVolumeTypeFromPV(pv)
}
func (s *structuredVolume) parsePodVolume(vol *corev1api.Volume) {
@@ -76,8 +58,6 @@ func (s *structuredVolume) parsePodVolume(vol *corev1api.Volume) {
if csi != nil {
s.csi = &csiVolumeSource{Driver: csi.Driver}
}
s.volumeType = getVolumeTypeFromVolume(vol)
}
type capacityCondition struct {

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcepolicies
import (
@@ -86,6 +71,7 @@ func TestCapacityIsInRange(t *testing.T) {
actual := test.capacity.isInRange(test.quantity)
assert.Equal(t, test.isInRange, actual)
})
}
}
@@ -140,6 +126,7 @@ func TestStorageClassConditionMatch(t *testing.T) {
}
func TestNFSConditionMatch(t *testing.T) {
tests := []struct {
name string
condition *nfsCondition
@@ -165,7 +152,7 @@ func TestNFSConditionMatch(t *testing.T) {
expectedMatch: true,
},
{
name: "server mismatch",
name: "server dismatch",
condition: &nfsCondition{&nFSVolumeSource{Server: "192.168.10.20", Path: ""}},
volume: setStructuredVolume(*resource.NewQuantity(0, resource.BinarySI), "", &nFSVolumeSource{Server: ""}, nil),
expectedMatch: false,
@@ -194,6 +181,7 @@ func TestNFSConditionMatch(t *testing.T) {
}
func TestCSIConditionMatch(t *testing.T) {
tests := []struct {
name string
condition *csiCondition

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcepolicies
import (
@@ -38,11 +23,10 @@ type nFSVolumeSource struct {
// volumeConditions defined the current format of conditions we parsed
type volumeConditions struct {
Capacity string `yaml:"capacity,omitempty"`
StorageClass []string `yaml:"storageClass,omitempty"`
NFS *nFSVolumeSource `yaml:"nfs,omitempty"`
CSI *csiVolumeSource `yaml:"csi,omitempty"`
VolumeTypes []SupportedVolume `yaml:"volumeTypes,omitempty"`
Capacity string `yaml:"capacity,omitempty"`
StorageClass []string `yaml:"storageClass,omitempty"`
NFS *nFSVolumeSource `yaml:"nfs,omitempty"`
CSI *csiVolumeSource `yaml:"csi,omitempty"`
}
func (c *capacityCondition) validate() error {
@@ -82,11 +66,7 @@ func decodeStruct(r io.Reader, s interface{}) error {
// validate check action format
func (a *Action) validate() error {
// validate Type
valid := false
if a.Type == Skip || a.Type == Snapshot || a.Type == FSBackup {
valid = true
}
if !valid {
if a.Type != Skip {
return fmt.Errorf("invalid action type %s", a.Type)
}

View File

@@ -1,18 +1,3 @@
/*
Copyright 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 resourcepolicies
import (
@@ -84,14 +69,14 @@ func TestCapacityConditionValidate(t *testing.T) {
func TestValidate(t *testing.T) {
testCases := []struct {
name string
res *ResourcePolicies
res *resourcePolicies
wantErr bool
}{
{
name: "unknown key in yaml",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -110,9 +95,9 @@ func TestValidate(t *testing.T) {
},
{
name: "error format of capacity",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -130,9 +115,9 @@ func TestValidate(t *testing.T) {
},
{
name: "error format of storageClass",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -150,9 +135,9 @@ func TestValidate(t *testing.T) {
},
{
name: "error format of csi",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -167,9 +152,9 @@ func TestValidate(t *testing.T) {
},
{
name: "unsupported version",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v2",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -186,9 +171,9 @@ func TestValidate(t *testing.T) {
},
{
name: "unsupported action",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "unsupported"},
Conditions: map[string]interface{}{
@@ -205,9 +190,9 @@ func TestValidate(t *testing.T) {
},
{
name: "error format of nfs",
res: &ResourcePolicies{
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -221,10 +206,10 @@ func TestValidate(t *testing.T) {
wantErr: true,
},
{
name: "supported format volume policies",
res: &ResourcePolicies{
name: "supported formart volume policies",
res: &resourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
VolumePolicies: []volumePolicy{
{
Action: Action{Type: "skip"},
Conditions: map[string]interface{}{
@@ -245,86 +230,11 @@ func TestValidate(t *testing.T) {
},
wantErr: false,
},
{
name: "supported format volume policies, action type snapshot",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "snapshot"},
Conditions: map[string]interface{}{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": interface{}(
map[string]interface{}{
"driver": "aws.efs.csi.driver",
}),
"nfs": interface{}(
map[string]interface{}{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies, action type fs-backup",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: "fs-backup"},
Conditions: map[string]interface{}{
"capacity": "0,10Gi",
"storageClass": []string{"gp2", "ebs-sc"},
"csi": interface{}(
map[string]interface{}{
"driver": "aws.efs.csi.driver",
}),
"nfs": interface{}(
map[string]interface{}{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
{
name: "supported format volume policies, action type fs-backup and snapshot",
res: &ResourcePolicies{
Version: "v1",
VolumePolicies: []VolumePolicy{
{
Action: Action{Type: Snapshot},
Conditions: map[string]interface{}{
"storageClass": []string{"gp2"},
},
},
{
Action: Action{Type: FSBackup},
Conditions: map[string]interface{}{
"nfs": interface{}(
map[string]interface{}{
"server": "192.168.20.90",
"path": "/mnt/data/",
}),
},
},
},
},
wantErr: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
policies := &Policies{}
err1 := policies.BuildPolicy(tc.res)
err1 := policies.buildPolicy(tc.res)
err2 := policies.Validate()
if tc.wantErr {

View File

@@ -1,247 +0,0 @@
/*
Copyright 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 resourcepolicies
import (
corev1api "k8s.io/api/core/v1"
)
type volumeTypeCondition struct {
volumeTypes []SupportedVolume
}
type SupportedVolume string
const (
AWSAzureDisk SupportedVolume = "awsAzureDisk"
AWSElasticBlockStore SupportedVolume = "awsElasticBlockStore"
AzureDisk SupportedVolume = "azureDisk"
AzureFile SupportedVolume = "azureFile"
Cinder SupportedVolume = "cinder"
CephFS SupportedVolume = "cephfs"
ConfigMap SupportedVolume = "configMap"
CSI SupportedVolume = "csi"
DownwardAPI SupportedVolume = "downwardAPI"
EmptyDir SupportedVolume = "emptyDir"
Ephemeral SupportedVolume = "ephemeral"
FC SupportedVolume = "fc"
Flocker SupportedVolume = "flocker"
FlexVolume SupportedVolume = "flexVolume"
GitRepo SupportedVolume = "gitRepo"
Glusterfs SupportedVolume = "glusterfs"
GCEPersistentDisk SupportedVolume = "gcePersistentDisk"
HostPath SupportedVolume = "hostPath"
ISCSI SupportedVolume = "iscsi"
Local SupportedVolume = "local"
NFS SupportedVolume = "nfs"
PhotonPersistentDisk SupportedVolume = "photonPersistentDisk"
PortworxVolume SupportedVolume = "portworxVolume"
Projected SupportedVolume = "projected"
Quobyte SupportedVolume = "quobyte"
RBD SupportedVolume = "rbd"
ScaleIO SupportedVolume = "scaleIO"
Secret SupportedVolume = "secret"
StorageOS SupportedVolume = "storageOS"
VsphereVolume SupportedVolume = "vsphereVolume"
)
func (v *volumeTypeCondition) match(s *structuredVolume) bool {
if len(v.volumeTypes) == 0 {
return true
}
for _, vt := range v.volumeTypes {
if vt == s.volumeType {
return true
}
}
return false
}
func (v *volumeTypeCondition) validate() error {
// validate by yamlv3
return nil
}
func getVolumeTypeFromPV(pv *corev1api.PersistentVolume) SupportedVolume {
if pv == nil {
return ""
}
if pv.Spec.AWSElasticBlockStore != nil {
return AWSElasticBlockStore
}
if pv.Spec.AzureDisk != nil {
return AzureDisk
}
if pv.Spec.AzureFile != nil {
return AzureFile
}
if pv.Spec.CephFS != nil {
return CephFS
}
if pv.Spec.Cinder != nil {
return Cinder
}
if pv.Spec.CSI != nil {
return CSI
}
if pv.Spec.FC != nil {
return FC
}
if pv.Spec.Flocker != nil {
return Flocker
}
if pv.Spec.FlexVolume != nil {
return FlexVolume
}
if pv.Spec.GCEPersistentDisk != nil {
return GCEPersistentDisk
}
if pv.Spec.Glusterfs != nil {
return Glusterfs
}
if pv.Spec.HostPath != nil {
return HostPath
}
if pv.Spec.ISCSI != nil {
return ISCSI
}
if pv.Spec.Local != nil {
return Local
}
if pv.Spec.NFS != nil {
return NFS
}
if pv.Spec.PhotonPersistentDisk != nil {
return PhotonPersistentDisk
}
if pv.Spec.PortworxVolume != nil {
return PortworxVolume
}
if pv.Spec.Quobyte != nil {
return Quobyte
}
if pv.Spec.RBD != nil {
return RBD
}
if pv.Spec.ScaleIO != nil {
return ScaleIO
}
if pv.Spec.StorageOS != nil {
return StorageOS
}
if pv.Spec.VsphereVolume != nil {
return VsphereVolume
}
return ""
}
func getVolumeTypeFromVolume(vol *corev1api.Volume) SupportedVolume {
if vol == nil {
return ""
}
if vol.AWSElasticBlockStore != nil {
return AWSElasticBlockStore
}
if vol.AzureDisk != nil {
return AzureDisk
}
if vol.AzureFile != nil {
return AzureFile
}
if vol.CephFS != nil {
return CephFS
}
if vol.Cinder != nil {
return Cinder
}
if vol.CSI != nil {
return CSI
}
if vol.FC != nil {
return FC
}
if vol.Flocker != nil {
return Flocker
}
if vol.FlexVolume != nil {
return FlexVolume
}
if vol.GCEPersistentDisk != nil {
return GCEPersistentDisk
}
if vol.GitRepo != nil {
return GitRepo
}
if vol.Glusterfs != nil {
return Glusterfs
}
if vol.ISCSI != nil {
return ISCSI
}
if vol.NFS != nil {
return NFS
}
if vol.Secret != nil {
return Secret
}
if vol.RBD != nil {
return RBD
}
if vol.DownwardAPI != nil {
return DownwardAPI
}
if vol.ConfigMap != nil {
return ConfigMap
}
if vol.Projected != nil {
return Projected
}
if vol.Ephemeral != nil {
return Ephemeral
}
if vol.FC != nil {
return FC
}
if vol.PhotonPersistentDisk != nil {
return PhotonPersistentDisk
}
if vol.PortworxVolume != nil {
return PortworxVolume
}
if vol.Quobyte != nil {
return Quobyte
}
if vol.ScaleIO != nil {
return ScaleIO
}
if vol.StorageOS != nil {
return StorageOS
}
if vol.VsphereVolume != nil {
return VsphereVolume
}
if vol.HostPath != nil {
return HostPath
}
if vol.EmptyDir != nil {
return EmptyDir
}
return ""
}

Some files were not shown because too many files have changed in this diff Show More