Compare commits

..

108 Commits

Author SHA1 Message Date
Nolan Brubaker
456eb19668 Changelogs for v1.5.2
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-10-20 13:37:45 -04:00
Carlisia Thompson
bd6a4d49e1 Fix version cmd getting nil pointer (#2996)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-10-20 13:34:41 -04:00
Antony S Bett
9675748c7c Fix BSL controller to avoid invoking init() on all BSLs regardless of ValidationFrequency (#2992)
Signed-off-by: Bett, Antony <antony.bett@dell.com>
2020-10-20 13:34:18 -04:00
Alay Patel
02cba19606 create CRB with velero-<namespace> (#2886)
* create CRB with velero-<namespace>

This will allow creating multiple instances of velero,
across two different namespaces

Signed-off-by: Alay Patel <alay1431@gmail.com>

* add changelog

Signed-off-by: Alay Patel <alay1431@gmail.com>

* add package var DefaultVeleroNamespace and use it wherever needed

Signed-off-by: Alay Patel <alay1431@gmail.com>
2020-10-20 13:33:59 -04:00
Scott Seago
89fb90285b restore proper lowercase/plural CRD resource (#2949)
* restore proper lowercase/plural CRD resource

This commit restores the proper resource string
"customresourcedefinitions" for CRD. The prior change to
"CustomResourceDefinition" was made because this was being used
in another place to populate the CRD "Kind" field in
remap_crd_version_action.go -- there, just use the correct Kind
string instead of pulling from Resource.

Signed-off-by: Scott Seago <sseago@redhat.com>

* add changelog

Signed-off-by: Scott Seago <sseago@redhat.com>
2020-10-20 13:33:47 -04:00
Nolan Brubaker
845d7ea5c1 Ensure PVs and PVCs remain bound when doing a restore (#3007)
* Only remove the UID from a PV's claimRef

The UID is the only part of a claimRef that might prevent it from being
rebound correctly on a restore. The namespace and name within the
claimRef should be preserved in order to ensure that the PV is claimed
by the correct PVC on restore.

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Remap PVs claimRef.namespace on relevant restores

When remapping namespaces, any included PVs need to have their claimRef
updated to point remapped namespaces to the new namespace name in order
to be bound to the correct PVC.

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Update tests and ensure claimRef namespace remaps

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Remove lowercased uid field from unstructured PV

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Fix issues that prevented PVs from being restored

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Add changelog

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Dynamically reprovision volumes without snapshots

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Update test for lower case uid field

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Remove stray debugging print statement

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Fix typo, remove extra code, add tests.

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-10-20 13:32:18 -04:00
Nolan Brubaker
87d86a45a6 Add changelog and docs for v1.5 release (#2941)
* Add changelog and docs for v1.5 release

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Fix markdown indentation

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Fix URLs with patch version

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Fix example link

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-09-16 17:17:30 -04:00
Carlisia Thompson
6e20eaaba8 Spruce up release instructions and release scripts (#2931)
* Update tag-release script

Signed-off-by: Carlisia <carlisia@vmware.com>

* Reorg release instructions

Signed-off-by: Carlisia <carlisia@vmware.com>

* Move "troubleshooting" to proper section

Signed-off-by: Carlisia <carlisia@vmware.com>

* Better formatting

Signed-off-by: Carlisia <carlisia@vmware.com>

* Fix sorcery

Signed-off-by: Carlisia <carlisia@vmware.com>

* Address code review

Signed-off-by: Carlisia <carlisia@vmware.com>

* More code reviews

Signed-off-by: Carlisia <carlisia@vmware.com>
2020-09-16 16:12:09 -04:00
Carlisia Thompson
afa552ca67 Fix url (#2933)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-09-11 17:26:56 -04:00
Carlisia Thompson
6f374b5709 Documentation for maintainers (#2932)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-09-11 16:53:33 -04:00
Carlisia Thompson
062a598d8e Update upgrading instructions to right version (#2930)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-09-11 07:57:38 -07:00
Ashish Amarnath
cfc4651078 🏃‍♂️ add shortnames for CRDs (#2911)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-09-10 12:28:17 -07:00
Bridget McErlean
d85d785cf0 Remove "exec restore hooks coming soon" line (#2929)
Now that Exec restore hooks have been added in #2804 and are available
in 1.5.0-rc1, we can remove the line that states that they are coming
soon.

Signed-off-by: Bridget McErlean <bmcerlean@vmware.com>
2020-09-10 12:25:24 -07:00
Ashish Amarnath
5caa97f335 📖 Fixing typos and markdown formatting (#2917)
* 📖 fix typo in resource-filtering page

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>

* 📖 fix markdown formatting

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-09-10 12:04:36 -07:00
Ashish Amarnath
6d729a90ca 🐛 fix 1.5 upgrade insturctions (#2926)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-09-10 13:46:32 -04:00
Andrew Reed
e53369d509 Document exec restore hooks (#2896)
Signed-off-by: Andrew Reed <andrew@replicated.com>
2020-09-10 11:24:10 -04:00
Carlisia Thompson
b60e6ff21e v1.5.0-rc.1 release (#2921)
* v1.5.0-rc.1 release

Signed-off-by: Carlisia <carlisia@vmware.com>

* Reviews

Signed-off-by: Carlisia <carlisia@vmware.com>

* Re-generate docs

Signed-off-by: Carlisia <carlisia@vmware.com>
2020-09-09 16:25:47 -07:00
Bridget McErlean
543678140b Update links to point to main branch (#2915)
A number of links still pointed to the old master branch and resulted in
404s. This updates those links to point to the new main branch.

Signed-off-by: Bridget McErlean <bmcerlean@vmware.com>
2020-09-09 12:11:57 -07:00
Bridget McErlean
696117365f Add Bridget to list of maintainers (#2916)
Signed-off-by: Bridget McErlean <bmcerlean@vmware.com>
2020-09-09 12:04:36 -07:00
Ashish Amarnath
44306e537e 📖 add restore hooks doc (#2862)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-09-08 17:36:31 -07:00
JenTing Hsiao
cd31141b93 Show format version on velero backup describe (#2901)
* Show format version on velero backup describe

Signed-off-by: JenTing Hsiao <jenting.hsiao@suse.com>

* Add changelog

Signed-off-by: JenTing Hsiao <jenting.hsiao@suse.com>
2020-09-08 16:08:56 -04:00
Andrew Reed
0547b1d945 Restore hooks exec (#2804)
* Exec hooks in restored pods

Signed-off-by: Andrew Reed <andrew@replicated.com>

* WaitExecHookHandler implements ItemHookHandler

This required adding a context.Context argument to the ItemHookHandler
interface which is unused by the DefaultItemHookHandler implementation.
It also means passing nil for the []ResourceHook argument since that
holds BackupResourceHook.

Signed-off-by: Andrew Reed <andrew@replicated.com>

* WaitExecHookHandler unit tests

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Changelog and go fmt

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Fix double import

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Default to first contaienr in pod

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Use constants for hook error modes in tests

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Revert to separate WaitExecHookHandler interface

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Negative tests for invalid timeout annotations

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Rename NamedExecRestoreHook PodExecRestoreHook

Also make field names more descriptive.

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Cleanup test names

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Separate maxHookWait and add unit tests

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Comment on maxWait <= 0

Also info log container is not running for hooks to execute in.
Also add context error to hooks not executed errors.

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Remove log about default for invalid timeout

There is no default wait or exec timeout.

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Linting

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Fix log message and rename controller to podWatcher

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Comment on exactly-once semantics for handler

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Fix logging and comments

Use filed logger for pod in handler.
Add comment about pod changes in unit tests.
Use kube util NamespaceAndName in messages.

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Fix maxHookWait

Signed-off-by: Andrew Reed <andrew@replicated.com>
2020-09-08 11:33:15 -07:00
Jonas Rosland
a179ae01ca Fix for docs redirects (#2895)
* Fixing redirects

Signed-off-by: jonasrosland <jrosland@vmware.com>

* Fix netlify config

Signed-off-by: jonasrosland <jrosland@vmware.com>

* Add previous redirects

Signed-off-by: jonasrosland <jrosland@vmware.com>

* Change netlify publish path

Signed-off-by: jonasrosland <jrosland@vmware.com>

* Add new redirect for restic

Signed-off-by: jonasrosland <jrosland@vmware.com>
2020-09-02 14:20:46 -07:00
Carlisia Thompson
be1cd03023 Refactor BSL related code (#2870)
* Refactor BSL related code

Signed-off-by: Carlisia <carlisia@vmware.com>

* Increase # of max concurrent reconciles

Signed-off-by: Carlisia <carlisia@vmware.com>

* Clean up for better, more precise interfaces

Signed-off-by: Carlisia <carlisia@vmware.com>

* Minor clean up - code reviews

Signed-off-by: Carlisia <carlisia@vmware.com>

* Address code review

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add import and fix CI

Signed-off-by: Carlisia <carlisia@vmware.com>
2020-09-02 13:12:37 -04:00
Ashish Amarnath
b5edac3c83 📖 update restore api types with init container restorehooks (#2855)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-09-02 13:11:57 -04:00
Pawan Prakash Sharma
debcbd2f8e fix: rename the PV if VolumeSnapshotter has modified the PV name (#2835)
* fix: rename the PV if VolumeSnapshotter has modified the PV name

When VolumeSnapshotter sets the PV name via SetVolumeID and PV is
not there in the cluster, velero does not rename the PV. Which causes
the pvc to be in the lost state as pvc points to the old PV but pv object
has been renamed by VolumeSnapshotter.

Signed-off-by: Pawan <pawan@mayadata.io>

* adding a test case for pv rename

Signed-off-by: Pawan <pawan@mayadata.io>
2020-09-01 14:25:13 -07:00
Carlisia Campos
c952932f1b Migrate ServerStatusRequest controller and resource to kubebuilder (#2838)
* Convert ServerStatusRequest controller to controller-runtime

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add select stm

Signed-off-by: Carlisia <carlisia@vmware.com>

* Fixed status patch bug

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add mgr start

Signed-off-by: Carlisia <carlisia@vmware.com>

* Trying to sync

Signed-off-by: Carlisia <carlisia@vmware.com>

* Clean async now

Signed-off-by: Carlisia <carlisia@vmware.com>

* Clean up + move context out

Signed-off-by: Carlisia <carlisia@vmware.com>

* Bug: not closing the channel

Signed-off-by: Carlisia <carlisia@vmware.com>

* Clean up some tests

Signed-off-by: Carlisia <carlisia@vmware.com>

* Much better way to fetch an update using a backoff loop

Signed-off-by: Carlisia <carlisia@vmware.com>

* Even better way to retry: use apimachinery lib

Signed-off-by: Carlisia <carlisia@vmware.com>

* Refactor controller + add test

Signed-off-by: Carlisia <carlisia@vmware.com>

* partially fix unit tests

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>

* Fix and add tests

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add changelog

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add ability to disable the controller + cleanups

Signed-off-by: Carlisia <carlisia@vmware.com>

* Fix bug w/ disabling controllers + fix test + clean up

Signed-off-by: Carlisia <carlisia@vmware.com>

* Move role.yaml to the correct folder

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add sample serverstatusrequest.yaml

Signed-off-by: Carlisia <carlisia@vmware.com>

* Add requeue + better formatting

Signed-off-by: Carlisia <carlisia@vmware.com>

* Increase # of max concurrent reconciles

Signed-off-by: Carlisia <carlisia@vmware.com>

Co-authored-by: Ashish Amarnath <ashisham@vmware.com>
2020-09-01 14:15:23 -07:00
Nolan Brubaker
aed504a0fd Fix git commands and add dry run mode as default to the tag-release.sh script. (#2875)
* Fix git commands and add missing comment

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Add dry-run mode to tag-release.sh

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Make if statement formatting more consistent

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Add documentaion for dry-run mode

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Better support for dry-run

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-09-01 12:59:05 -07:00
JenTing Hsiao
1513674548 fix EnableAPIGroupersions output log format (#2882)
Signed-off-by: JenTing Hsiao <jenting.hsiao@suse.com>
2020-09-01 13:50:44 -04:00
Jonas Rosland
9764845530 Add CII Best Practices badge to README (#2880)
Signed-off-by: jonasrosland <jrosland@vmware.com>
2020-08-31 17:33:03 -04:00
Jonas Rosland
1dcaa1bf75 Rename security policy file to show up accurately in the GitHub UI (#2879)
Signed-off-by: jonasrosland <jrosland@vmware.com>
2020-08-31 12:10:09 -04:00
Abigail McCarthy
ac50b457ad add hugo default TOC (#2866)
* add hugo default TOC

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* point contributors to style guide (#2872)

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* add hugo default TOC

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* remove unused links

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-28 14:06:11 -04:00
Abigail McCarthy
9cf35d9ba7 add new table shortcode (#2865)
* add new table shortcode

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* fix typo

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* update shortcode commentn

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* fix messed up table

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* fixing 2 more tables

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* update 1.4 supporteed providers

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* add note about links in tables

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-28 12:03:43 -04:00
Abigail McCarthy
36a4c28f61 point contributors to style guide (#2872)
Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-26 17:13:16 -07:00
Ashish Amarnath
474de24d48 📖 update documentation to push container images using docker buildx (#2854)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-25 15:40:01 -07:00
Abigail McCarthy
648582c85e Update release checklist to include more info around blog posts and r… (#2837)
* Update release checklist to include more info around blog posts and release announcements

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* updating links

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* update from review

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-25 15:37:22 -04:00
Abigail McCarthy
839a9646aa update docs to match style guide (#2861)
* update docs to match style guide

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* update web site guide

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-25 10:02:21 -07:00
Dylan Murray
7369e4d99e Check for errors on restic backup command (#2863)
* Check for errors on restic backup command

Signed-off-by: Dylan Murray <dymurray@redhat.com>

* Add changelog

Signed-off-by: Dylan Murray <dymurray@redhat.com>
2020-08-25 08:51:50 -07:00
Carlisia Campos
03bd6c85c8 Better var names (#2848)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-08-24 15:14:07 -04:00
Nolan Brubaker
f5d10c5474 Merge pull request #2853 from ashish-amarnath/fix-server-version
🐛  fix passing LDFLAGS across build stages
2020-08-21 18:18:34 -04:00
Ashish Amarnath
20ac603747 🐛 fix passing LDFLAGS across build stages
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-21 14:20:37 -07:00
Nolan Brubaker
45168087f1 v1.5.0-beta.1 changelog and docs (#2849)
* Add changelogs for v1.5.0-beta.1

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Add v1.5-pre docs

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-21 12:07:24 -07:00
Nolan Brubaker
97c14e34be Merge pull request #2844 from ashish-amarnath/1.5-upgrade-instructions
📖  document velero v1.5 upgrade instructions
2020-08-21 12:35:39 -04:00
Nolan Brubaker
718a94ad05 Invoke DeleteItemActions on backup deletion (#2815)
* Add serving and listing support

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-20 17:24:29 -07:00
Ashish Amarnath
89d4e4417f 📖 document velero v1.5 upgrade instructions
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-20 16:21:36 -07:00
Abigail McCarthy
71fd7cc5a7 add index files to api types folder (#2839)
* add index files to api tyypes folder

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* updating to using cascade

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-20 14:30:18 -07:00
Ashish Amarnath
d33982b811 🏃‍♂️remove go mod download from Dockerfile for build speedup (#2842)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-19 13:45:08 -07:00
Nolan Brubaker
e0098d8a69 Update the number of reviewers for PRs/add Bridget (#2843)
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-19 12:42:43 -07:00
Nolan Brubaker
e9ece0f7b5 Implement DeleteItemAction plugin support (#2808)
* Add DeleteItemAction struct & protobuf definition

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-18 12:16:26 -07:00
Steph Bman
d1a1d063e1 Create Velero security policy (#2797)
* Create securitypolicy.md

Creating the Security Policy documentation for Project Velero.
2020-08-18 11:28:14 -07:00
Ashish Amarnath
e6eb5372ea update image link in readme (#2827)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-18 11:06:16 -07:00
JenTing Hsiao
62b2a0e17f The EnableCSI flag on velero backup describe command only (#2817)
Signed-off-by: JenTing Hsiao <jenting.hsiao@suse.com>
2020-08-18 11:05:45 -07:00
Ashish Amarnath
9ed43f96c1 📖 update default-volumes-to-restic exclusion list (#2828)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-18 11:05:12 -07:00
Imran Pochi
52b6838004 docs: add metadata to resource-filtering.md (#2832)
This metadata is required by hugo to discover the content in the
documentation website, without which a page not found is shown to the
viewer.

Fixes: #2831

Signed-off-by: Imran Pochi <imran@kinvolk.io>
2020-08-18 11:02:49 -07:00
Benoit Gagnon
5d2c9e2ba1 Override logrus.ErrorKey when json logging is enabled (#2830)
* override logrus.ErrorKey when json logging is enabled

Signed-off-by: Benoit Gagnon <benoit.gagnon@ubisoft.com>

* document the logrus.ErrorKey override

Signed-off-by: Benoit Gagnon <benoit.gagnon@ubisoft.com>

* add changelog entry

Signed-off-by: Benoit Gagnon <benoit.gagnon@ubisoft.com>
2020-08-18 13:53:45 -04:00
runzexia
3a4e441af8 add kindfor func to get apiresource from gvk (#2764)
* add kindfor func to get apiresource from gvk

Signed-off-by: RyderXia <ryder.xia@sap.com>

* impl interface & changelog

Signed-off-by: RyderXia <ryder.xia@sap.com>
2020-08-17 15:52:33 -07:00
Tony Batard
c663ce15ab Hugo migration (#2720)
* Move files to a Hugo structure

Signed-off-by: Tony Batard <tbatard@pivotal.io>
2020-08-13 09:09:15 -07:00
Nolan Brubaker
681123596f Checkout code on builder image workflow (#2816)
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-12 17:55:53 -07:00
Phuong N. Hoang
14170b52a8 Enhance Backup to backup resources in specific order. (#2724)
Signed-off-by: Phuong Hoang <phuong.n.hoang@dell.com>

Co-authored-by: Phuong Hoang <phuong.n.hoang@dell.com>
2020-08-12 17:17:31 -07:00
Steph Bman
dd2d040fcf Create restore-hooks_product-requirements.md (#2699)
Restore Hooks Design Proposal

Signed-off-by: Stephanie Bauman <bstephanie@vmware.com>
Co-authored-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-12 16:13:52 -07:00
Ashish Amarnath
d4bbd7b817 🐛 Patch generated yaml for restore CRD as a hacky workaround (#2814)
* 🐛 Patch generated yaml for restore CRD as a hacky workaround

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>

* changelog

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-12 18:43:29 -04:00
Jason Scarano
827d5d34f5 Improve and clarify cmd help documentation, flags, and examples (#2736)
* capitalize `backup create` cmd comments & examples

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* update copyright and capitilize flags and comments

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* update copyright and capitilize flags and comments

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* update copyright and capitilize flags and comments

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* update backuplocation, restic, & restore cmd doc

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* fix local typo

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* update copyrights & capitalize pflag/help strings

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* update copyright in utils dir

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* Revert "update copyright in utils dir"

This reverts commit d116efe3a3.

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* revert copyright changes

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* restore missing file

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* revert copyright changes

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

* add cacert flag back

Signed-off-by: Jason Scarano <scaranoj@vmware.com>

Co-authored-by: Carlisia Campos <carlisia@vmware.com>
2020-08-12 18:13:44 -04:00
Abigail McCarthy
98a09bcbc5 add note about windows support (#2806)
* add note about windows support

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* adding to 1.4 docs and adjusting wording to be more clear

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-12 18:03:36 -04:00
Ashish Amarnath
9eca0fcbff Pass default-volumes-to-restic flag from create schedule to backup (#2776)
* Pass default-volumes-to-restic flag from create schedule to backup

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-12 12:09:07 -07:00
Nolan Brubaker
70e9391278 Add design doc for DeletionAction plugins (#2713)
* Add design doc for DeletionAction plugins

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-12 11:21:55 -07:00
Carlisia Campos
d7d6a85e46 Add an auto-rebase workflow (#2813)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-08-12 10:27:41 -07:00
Nolan Brubaker
7914138dd7 Merge pull request #2802 from ashish-amarnath/fix-restic-restore
🐛 Supply command to run restic-wait init container
2020-08-11 14:37:19 -04:00
Ashish Amarnath
e391e43192 🐛 Supply command to run restic-wait init container
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-11 11:05:30 -07:00
Nolan Brubaker
5b28d70e49 Switch event to use pull_request_target (#2807)
The pull_request_target event is like pull_request, but runs in the
context of the target repo (Velero, in this case), instead of the fork.
This allows us to use the GitHub token secret as expected.

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-08-11 10:57:16 -07:00
Ashish Amarnath
a68e5fc330 🏃‍♂️ Setup crd validation github action on k8s versions (#2805)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-11 10:45:12 -07:00
Ashish Amarnath
5d6da6517b Implement restore hooks injecting init containers into pod spec (#2787)
*  Implement restore hooks injecting init containers into pod spec

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-11 10:38:44 -07:00
Ashish Amarnath
9b9bb62968 🐛 Make init and exec restore hooks as omitempty in restore hookSpec (#2793)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-08-11 10:13:41 -07:00
Abigail McCarthy
4364a813c1 update docs to include cpu/memory defaults for restic (#2772)
* update docs to include cpu/memory defaults

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* fixes from review

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* updates from review

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* update to use kubectl patch command

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>

* update typos and add changes to 1.4 docs

Signed-off-by: Abigail McCarthy <mabigail@vmware.com>
2020-08-10 09:38:35 -07:00
Nolan Brubaker
6edf279bd8 Merge pull request #2803 from vmware-tanzu/dependabot/bundler/site/kramdown-2.3.0
Bump kramdown from 2.2.1 to 2.3.0 in /site
2020-08-10 12:21:40 -04:00
dependabot[bot]
1386a85657 Bump kramdown from 2.2.1 to 2.3.0 in /site
Bumps [kramdown](https://github.com/gettalong/kramdown) from 2.2.1 to 2.3.0.
- [Release notes](https://github.com/gettalong/kramdown/releases)
- [Changelog](https://github.com/gettalong/kramdown/blob/master/doc/news.page)
- [Commits](https://github.com/gettalong/kramdown/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-08 01:14:58 +00:00
Alex Punnen
0b87fbbde8 Update minio.md (#2799)
Added  option for --snapshot-location-config region as else it will give an error during backup - https://github.com/vmware-tanzu/velero-plugin-for-aws/issues/12

Signed-off-by: Alex Punnen <alexcpn@gmail.com>
2020-08-07 14:35:17 -07:00
Mike Tritabaugh
4e2f4bb6af Add resource filtering page (#2771)
* added resource filtering page

Signed-off-by: mtritabaugh <mtritabaugh@vmware.com>

* added resource filtering page to v1.4

Signed-off-by: mtritabaugh <mtritabaugh@vmware.com>

* change  to  per style guide

Signed-off-by: mtritabaugh <mtritabaugh@vmware.com>
2020-08-06 15:09:59 -07:00
Benoit Gagnon
0e8a7a23cb always use groupResource.String() when logging (fixes #2795) (#2796)
Signed-off-by: Benoit Gagnon <benoit.gagnon@ubisoft.com>
2020-08-06 10:10:59 -07:00
Piper Dougherty
19e65689ef Add the ability to set the allowPrivilegeEscalation property on the Restic restore helper via plugin ConfigMap (#2792)
* Add the ability to set the `allowPrivilegeEscalation` security context attribute on the Restic restore helper init container.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Add changelog.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Fix old tests and add tests for new allowPrivilegeEscalation config option.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Correct spelling in changelog.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Switch to boolptr type.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>

* Reorder imports for sanity.

Signed-off-by: Piper Dougherty <doughertypiper@gmail.com>
2020-08-06 13:08:36 -04:00
Rob Reus
6ac0398c7b Reverting change on 1.4 docs and re-applying to main docs (#2791)
Signed-off-by: Rob Reus <rob@devrobs.nl>
2020-08-04 14:11:52 -07:00
Rob Reus
db139cf07c Refactor image builds to use buildx for multi arch image building (#2754)
* Refactor image builds to use buildx for multi arch image building

Signed-off-by: Rob Reus <rob@devrobs.nl>

* Adding image build sanity checks to Makefile

Signed-off-by: Rob Reus <rob@devrobs.nl>

* Making locally building of docker images possible

Signed-off-by: Rob Reus <rob@devrobs.nl>

* Adding docs on building container images using buildx

Signed-off-by: Rob Reus <rob@devrobs.nl>

* Adding changelog and implementing feedback from PR

Signed-off-by: Rob Reus <rob@devrobs.nl>

* Making GOPROXY used in the build containers configurable

Signed-off-by: Rob Reus <rob@devrobs.nl>
2020-08-04 11:40:05 -07:00
Nolan Brubaker
4e05e81ca2 Merge pull request #2786 from skriss/upd-build-badge
update CI badge on README
2020-08-04 13:55:26 -04:00
Steve Kriss
c5a2137538 update CI badge on README
Signed-off-by: Steve Kriss <krisss@vmware.com>
2020-08-03 12:53:49 -06:00
JenTing Hsiao
1fdb647c7f Add cacert flag for velero backup-location create (#2778)
Signed-off-by: JenTing Hsiao <jenting.hsiao@suse.com>
2020-07-30 11:33:45 -07:00
Ashish Amarnath
9de644f1a4 Add types to implement restore hooks (#2761)
* Add types to implement restore hooks

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-29 13:29:40 -07:00
Carlisia Campos
5bafa9b317 Add JenTing Hsiao (#2768)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-07-29 12:41:28 -07:00
Carlisia Campos
fcf7f27967 Moved FAQ (#2769)
* Moved FAQ

Signed-off-by: Carlisia <carlisia@vmware.com>

* Better entry point

Signed-off-by: Carlisia <carlisia@vmware.com>
2020-07-29 10:16:32 -07:00
Ashish Amarnath
028818a053 exclude vols mounting secrets and configmaps from defaultVolumesToRestic (#2762)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-27 20:27:49 -07:00
Nolan Brubaker
94872ea2fc Add github token so action can actually auth (#2766)
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-27 14:35:26 -07:00
Ashish Amarnath
8e672408a2 📖 update VSC DeletionPolicy docs to be inline with code (#2765)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-27 13:42:38 -07:00
Nolan Brubaker
7005879f3f Fix YAML in auto-assign GitHub Action (#2759)
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-24 14:08:09 -07:00
Ashish Amarnath
bc25e789e0 Add constants for restore hook annotation keys (#2750)
* add annotation key constants for restore hooks

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-24 13:05:27 -07:00
Nolan Brubaker
cffb639380 Auto-assign github PR reviewers and assignee (#2758)
Use a GitHub Action to automatically assign GitHub PRs to the author, as
well as add reviewers.

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-24 12:58:44 -07:00
Andrew Reed
9011b192e9 Add hooks fields to restore context (#2755)
* Add hooks fields to restore context

Signed-off-by: Andrew Reed <andrew@replicated.com>

* Changelog

Signed-off-by: Andrew Reed <andrew@replicated.com>
2020-07-24 11:43:44 -07:00
Nolan Brubaker
bbcbde084d Create hook package (#2734)
* Move pkg/backup/item_hook_handler to internal/hoo

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>

* Add internal packages to test target

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-22 14:26:14 -07:00
Nolan Brubaker
e83ec79df3 Merge pull request #2751 from ashish-amarnath/fix-boilerplate
Use correct year for copyright
2020-07-22 15:32:24 -04:00
Ashish Amarnath
2636730ef2 fix copyright year
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-22 12:11:59 -07:00
Martin Odstrčilík
86efd1577e add support for setting SecurityContext (user, group) for restic restore (#2621)
* add support for setting SecurityContext (user, group) for restic restore

Signed-off-by: Martin Odstrcilik <martin.odstrcilik@gmail.com>
2020-07-22 12:10:25 -07:00
Ashish Amarnath
91ccc4adb2 Add metrics for restic back up operation (#2719)
* add metrics for restic back up operation

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>

* changelog

Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-22 15:07:52 -04:00
Ashish Amarnath
a63a82fcb0 📖 update csi docs to document volumesnapshotclass label (#2741)
Signed-off-by: Ashish Amarnath <ashisham@vmware.com>
2020-07-22 11:49:47 -07:00
Thejas Babu
d0d143e119 Add StartTimestamp and CompletionTimestamp in Restore Status (#2748)
Signed-off-by: thejas <thejasb99@gmail.com>
2020-07-22 11:40:39 -07:00
Carlisia Campos
c27c3cd56a Fix path + add helpful message (#2740)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-07-22 11:13:02 -07:00
Nolan Brubaker
84dbd13313 Move style guide to main (#2735)
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-21 11:30:05 -07:00
Nolan Brubaker
caeb4ae404 Update changelogs for v1.4.2 (#2705)
Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-21 11:14:41 -07:00
Carlisia Campos
e60d9f2821 Remove unneeded auto-generated files (#2732)
Signed-off-by: Carlisia <carlisia@vmware.com>
2020-07-20 15:37:27 -07:00
fvsqr
01e2dcb364 StorageGrid compatibility (#2712)
* remove explicit Accept-Encoding header

For StorageGrid compatibility the Accept-Encoding header should not be set, otherwise StorageGrid compresses the already compressed log files which are only decompressed by the client once

Signed-off-by: fvsqr <48791253+fvsqr@users.noreply.github.com>

* Removed explicit gzip Accept-Encoding header

For StorageGrid compatibility the Accept-Encoding header should not be set, otherwise StorageGrid compresses the already compressed log files which are only decompressed by the client once.
Unclear, how this affects Backup endpoints from Azure or GCP

Signed-off-by: fvsqr <48791253+fvsqr@users.noreply.github.com>

* Create 2712-fvsqr

Signed-off-by: fvsqr <48791253+fvsqr@users.noreply.github.com>
2020-07-20 13:11:26 -04:00
Marc Campbell
9189cffb1c Design proposal for Restore hooks (#2465)
* Add design proposal for restore hooks

Signed-off-by: Marc Campbell <marc.e.campbell@gmail.com>

* Add details to restore hooks design

Signed-off-by: Marc Campbell <marc.e.campbell@gmail.com>

* Restore initContainers and requested changes

Change post-restore exec hooks to wait for container running status
instead of pod ready status.
Add separate exec timeout and wait timeouts for post-restore exec hooks.

Signed-off-by: Marc Campbell <marc.e.campbell@gmail.com>

Co-authored-by: Andrew Reed <andrew@replicated.com>
2020-07-20 08:34:16 -07:00
Nolan Brubaker
f42c63af1b Address insensitive language (#2677)
* Change master to main in most uses

Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
2020-07-17 14:59:51 -07:00
2416 changed files with 86404 additions and 70229 deletions

3
.dockerignore Normal file
View File

@@ -0,0 +1,3 @@
.go/
.go.std/
site/

11
.github/auto_assign.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
addReviewers: true
addAssignees: author
# Set this to the length of the reviewers list because the default was not including everyone
numberOfReviewers: 4
reviewers:
- nrb
- ashish-amarnath
- carlisia
- zubron

16
.github/workflows/auto_assign_prs.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: 'Auto Assign PR Reviewers'
# pull_request_target means that this will run on pull requests, but in the context of the base repo.
# This should mean PRs from forks are supported.
on:
pull_request_target:
types: [opened, reopened, sychronized]
jobs:
add-reviews:
runs-on: ubuntu-latest
steps:
- uses: kentaro-m/auto-assign-action@v1.1.1
with:
configuration-path: ".github/auto_assign.yml"
repo-token: '${{ secrets.GITHUB_TOKEN }}'

View File

@@ -0,0 +1,20 @@
name: "Verify Velero CRDs on k8s 1.16.9"
on: [pull_request]
jobs:
kind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: engineerd/setup-kind@v0.4.0
with:
image: "kindest/node:v1.16.9"
- name: Testing
run: |
kubectl cluster-info
kubectl get pods -n kube-system
kubectl version
echo "current-context:" $(kubectl config current-context)
echo "environment-kubeconfig:" ${KUBECONFIG}
make local
./_output/bin/linux/amd64/velero install --crds-only --dry-run -oyaml | kubectl apply -f -

View File

@@ -0,0 +1,20 @@
name: "Verify Velero CRDs on k8s 1.17"
on: [pull_request]
jobs:
kind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: engineerd/setup-kind@v0.4.0
with:
image: "kindest/node:v1.17.0"
- name: Testing
run: |
kubectl cluster-info
kubectl get pods -n kube-system
kubectl version
echo "current-context:" $(kubectl config current-context)
echo "environment-kubeconfig:" ${KUBECONFIG}
make local
./_output/bin/linux/amd64/velero install --crds-only --dry-run -oyaml | kubectl apply -f -

View File

@@ -0,0 +1,20 @@
name: "Verify Velero CRDs on k8s 1.18.4"
on: [pull_request]
jobs:
kind:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: engineerd/setup-kind@v0.4.0
with:
image: "kindest/node:v1.18.4"
- name: Testing
run: |
kubectl cluster-info
kubectl get pods -n kube-system
kubectl version
echo "current-context:" $(kubectl config current-context)
echo "environment-kubeconfig:" ${KUBECONFIG}
make local
./_output/bin/linux/amd64/velero install --crds-only --dry-run -oyaml | kubectl apply -f -

View File

@@ -2,7 +2,7 @@ name: build-image
on:
push:
branches: [ master ]
branches: [ main ]
paths:
- 'hack/build-image/Dockerfile'
@@ -12,6 +12,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Build
run: make build-image

View File

@@ -1,8 +1,8 @@
name: Master CI
name: Main CI
on:
push:
branches: [ master ]
branches: [ main ]
tags:
- '*'
@@ -22,6 +22,13 @@ jobs:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Set up Docker Buildx
id: buildx
uses: crazy-max/ghaction-docker-buildx@v3
with:
buildx-version: latest
qemu-version: latest
- name: Build
run: make local

18
.github/workflows/rebase.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
on:
issue_comment:
types: [created]
name: Automatic Rebase
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@1.3.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

12
.gitignore vendored
View File

@@ -38,14 +38,8 @@ Tiltfile
.vscode
*.diff
# Jekyll compiled data
site/_site
site/.sass-cache
site/.jekyll
site/.jekyll-metadata
site/.jekyll-cache
site/.bundle
site/vendor
.ruby-version
# Hugo compiled data
site/public
site/resources
.vs

View File

@@ -1,10 +1,8 @@
## Current release:
* [CHANGELOG-1.4.md][14]
## Development release:
* [Unreleased Changes][0]
* [CHANGELOG-1.5.md][15]
## Older releases:
* [CHANGELOG-1.4.md][14]
* [CHANGELOG-1.3.md][13]
* [CHANGELOG-1.2.md][12]
* [CHANGELOG-1.1.md][11]
@@ -20,18 +18,19 @@
* [CHANGELOG-0.3.md][1]
[14]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-1.4.md
[13]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-1.3.md
[12]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-1.2.md
[11]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-1.1.md
[10]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-1.0.md
[9]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.11.md
[8]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.10.md
[7]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.9.md
[6]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.8.md
[5]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.7.md
[4]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.6.md
[3]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.5.md
[2]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.4.md
[1]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/CHANGELOG-0.3.md
[0]: https://github.com/vmware-tanzu/velero/blob/master/changelogs/unreleased
[15]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.5.md
[14]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.4.md
[13]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.3.md
[12]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.2.md
[11]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.1.md
[10]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-1.0.md
[9]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.11.md
[8]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.10.md
[7]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.9.md
[6]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.8.md
[5]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.7.md
[4]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.6.md
[3]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.5.md
[2]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.4.md
[1]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/CHANGELOG-0.3.md
[0]: https://github.com/vmware-tanzu/velero/blob/main/changelogs/unreleased

View File

@@ -1,3 +1,3 @@
# Contributing
Authors are expected to follow some guidelines when submitting PRs. Please see [our documentation](https://velero.io/docs/master/code-standards/) for details.
Authors are expected to follow some guidelines when submitting PRs. Please see [our documentation](https://velero.io/docs/main/code-standards/) for details.

61
Dockerfile Normal file
View File

@@ -0,0 +1,61 @@
# 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.
FROM --platform=$BUILDPLATFORM golang:1.14 as builder-env
ARG GOPROXY
ARG PKG
ARG VERSION
ARG GIT_SHA
ARG GIT_TREE_STATE
ENV CGO_ENABLED=0 \
GO111MODULE=on \
GOPROXY=${GOPROXY} \
LDFLAGS="-X ${PKG}/pkg/buildinfo.Version=${VERSION} -X ${PKG}/pkg/buildinfo.GitSHA=${GIT_SHA} -X ${PKG}/pkg/buildinfo.GitTreeState=${GIT_TREE_STATE}"
WORKDIR /go/src/github.com/vmware-tanzu/velero
COPY . /go/src/github.com/vmware-tanzu/velero
RUN apt-get update && apt-get install -y bzip2
FROM --platform=$BUILDPLATFORM builder-env as builder
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
ARG PKG
ARG BIN
ARG RESTIC_VERSION
ENV GOOS=${TARGETOS} \
GOARCH=${TARGETARCH} \
GOARM=${TARGETVARIANT}
RUN mkdir -p /output/usr/bin && \
bash ./hack/download-restic.sh && \
export GOARM=$( echo "${GOARM}" | cut -c2-) && \
go build -o /output/${BIN} \
-ldflags "${LDFLAGS}" ${PKG}/cmd/${BIN}
FROM ubuntu:focal
LABEL maintainer="Nolan Brubaker <brubakern@vmware.com>"
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /output /
USER nobody:nogroup

View File

@@ -1,33 +0,0 @@
# Copyright 2017, 2019 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.
FROM ubuntu:focal
LABEL maintainer="Nolan Brubaker <brubakern@vmware.com>"
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates wget bzip2 && \
wget --quiet https://github.com/restic/restic/releases/download/v0.9.6/restic_0.9.6_linux_amd64.bz2 && \
bunzip2 restic_0.9.6_linux_amd64.bz2 && \
mv restic_0.9.6_linux_amd64 /usr/bin/restic && \
chmod +x /usr/bin/restic && \
apt-get remove -y wget bzip2 && \
rm -rf /var/lib/apt/lists/*
ADD /bin/linux/amd64/velero /velero
USER nobody:nogroup
ENTRYPOINT ["/velero"]

View File

@@ -1,23 +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.
FROM arm32v7/ubuntu:focal
ADD /bin/linux/arm/restic /usr/bin/restic
ADD /bin/linux/arm/velero /velero
USER nobody:nogroup
ENTRYPOINT ["/velero"]

View File

@@ -1,23 +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.
FROM arm64v8/ubuntu:focal
ADD /bin/linux/arm64/restic /usr/bin/restic
ADD /bin/linux/arm64/velero /velero
USER nobody:nogroup
ENTRYPOINT ["/velero"]

View File

@@ -1,25 +0,0 @@
# Copyright 2019 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.
FROM ppc64le/ubuntu:focal
LABEL maintainer="Prajyot Parab <prajyot.parab@ibm.com>"
ADD /bin/linux/ppc64le/restic /usr/bin/restic
ADD /bin/linux/ppc64le/velero /velero
USER nobody:nogroup
ENTRYPOINT ["/velero"]

View File

@@ -1,23 +0,0 @@
# Copyright 2018, 2019 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.
FROM ubuntu:focal
LABEL maintainer="Nolan Brubaker <brubakern@vmware.com>"
ADD /bin/linux/amd64/velero-restic-restore-helper .
USER nobody:nogroup
ENTRYPOINT [ "/velero-restic-restore-helper" ]

View File

@@ -1,21 +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.
FROM arm32v7/ubuntu:focal
ADD /bin/linux/arm/velero-restic-restore-helper .
USER nobody:nogroup
ENTRYPOINT [ "/velero-restic-restore-helper" ]

View File

@@ -1,21 +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.
FROM arm64v8/ubuntu:focal
ADD /bin/linux/arm64/velero-restic-restore-helper .
USER nobody:nogroup
ENTRYPOINT [ "/velero-restic-restore-helper" ]

View File

@@ -1,23 +0,0 @@
# Copyright 2019 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.
FROM ppc64le/ubuntu:focal
LABEL maintainer="Prajyot Parab <prajyot.parab@ibm.com>"
ADD /bin/linux/ppc64le/velero-restic-restore-helper .
USER nobody:nogroup
ENTRYPOINT [ "/velero-restic-restore-helper" ]

View File

@@ -11,7 +11,7 @@ This document defines the project governance for Velero.
The following code repositories are governed by Velero community and maintained under the `vmware-tanzu\Velero` organization.
* **[Velero](https://github.com/vmware-tanzu/velero):** Main Velero codebase
* **[Helm Chart](https://github.com/vmware-tanzu/helm-charts/tree/master/charts/velero):** The Helm chart for the Velero server component
* **[Helm Chart](https://github.com/vmware-tanzu/helm-charts/tree/main/charts/velero):** The Helm chart for the Velero server component
* **[Velero CSI Plugin](https://github.com/vmware-tanzu/velero-plugin-for-csi):** This repository contains Velero plugins for snapshotting CSI backed PVCs using the CSI beta snapshot APIs
* **[Velero Plugin for vSphere](https://github.com/vmware-tanzu/velero-plugin-for-vsphere):** This repository contains the Velero Plugin for vSphere. This plugin is a volume snapshotter plugin that provides crash-consistent snapshots of vSphere block volumes and backup of volume data into S3 compatible storage.
* **[Velero Plugin for AWS](https://github.com/vmware-tanzu/velero-plugin-for-aws):** This repository contains the plugins to support running Velero on AWS, including the object store plugin and the volume snapshotter plugin
@@ -67,12 +67,12 @@ interested in implementing the proposal should be either deeply engaged in the
proposal process or be an author of the proposal.
The proposal should be documented as a separated markdown file pushed to the root of the
`design` folder in the [Velero](https://github.com/vmware-tanzu/velero/tree/master/design)
`design` folder in the [Velero](https://github.com/vmware-tanzu/velero/tree/main/design)
repository via PR. The name of the file should follow the name pattern `<short
meaningful words joined by '-'>_design.md`, e.g:
`restore-hooks-design.md`.
Use the [Proposal Template](https://github.com/vmware-tanzu/velero/blob/master/design/_template.md) as a starting point.
Use the [Proposal Template](https://github.com/vmware-tanzu/velero/blob/main/design/_template.md) as a starting point.
### Proposal Lifecycle

View File

@@ -1,6 +1,6 @@
# Velero Maintainers
[GOVERNANCE.md](https://github.com/vmware-tanzu/velero/blob/master/GOVERNANCE.md) describes governance guidelines and maintainer responsibilities.
[GOVERNANCE.md](https://github.com/vmware-tanzu/velero/blob/main/GOVERNANCE.md) describes governance guidelines and maintainer responsibilities.
## Maintainers
@@ -10,6 +10,7 @@
| Nolan Brubaker | [nrb](https://github.com/nrb) | [VMware](https://www.github.com/vmware/) |
| Ashish Amarnath | [ashish-amarnath](https://github.com/ashish-amarnath) | [VMware](https://www.github.com/vmware/) |
| Stephanie Bauman | [stephbman](https://github.com/stephbman) | [VMware](https://www.github.com/vmware/) |
| Bridget McErlean | [zubron](https://github.com/zubron) | [VMware](https://www.github.com/vmware/) |
## Emeritus Maintainers
* Adnan Abdulhussein ([prydonius](https://github.com/prydonius))
@@ -22,6 +23,6 @@
| ----------------------------- | :---------------------: |
| Technical Lead | Nolan Brubaker (nrb) |
| Kubernetes CSI Liaison | Nolan Brubaker (nrb), Ashish Amarnath (ashish-amarnath) |
| Deployment | Carlisia Campos (carlisia), Carlos Tadeu Panato Junior (cpanato) |
| Deployment | Carlisia Campos (carlisia), Carlos Tadeu Panato Junior (cpanato), JenTing Hsiao (jenting) |
| Community Management | Jonas Rosland (jonasrosland) |
| Product Management | Stephanie Bauman (stephbman) |

214
Makefile
View File

@@ -23,6 +23,9 @@ PKG := github.com/vmware-tanzu/velero
# Where to push the docker image.
REGISTRY ?= velero
# Image name
IMAGE ?= $(REGISTRY)/$(BIN)
# Build image handling. We push a build image for every changed version of
# /hack/build-image/Dockerfile. We tag the dockerfile with the short commit hash
# of the commit that changed it. When determining if there is a build image in
@@ -33,26 +36,49 @@ BUILDER_IMAGE_TAG := $(shell git log -1 --pretty=%h hack/build-image/Dockerfile)
BUILDER_IMAGE := $(REGISTRY)/build-image:$(BUILDER_IMAGE_TAG)
BUILDER_IMAGE_CACHED := $(shell docker images -q ${BUILDER_IMAGE} 2>/dev/null )
HUGO_IMAGE := hugo-builder
# Which architecture to build - see $(ALL_ARCH) for options.
# if the 'local' rule is being run, detect the ARCH from 'go env'
# if it wasn't specified by the caller.
local : ARCH ?= $(shell go env GOOS)-$(shell go env GOARCH)
ARCH ?= linux-amd64
VERSION ?= master
VERSION ?= main
TAG_LATEST ?= false
ifeq ($(TAG_LATEST), true)
IMAGE_TAGS ?= $(IMAGE):$(VERSION) $(IMAGE):latest
else
IMAGE_TAGS ?= $(IMAGE):$(VERSION)
endif
ifeq ($(shell docker buildx inspect 2>/dev/null | awk '/Status/ { print $$2 }'), running)
BUILDX_ENABLED ?= true
else
BUILDX_ENABLED ?= false
endif
define BUILDX_ERROR
buildx not enabled, refusing to run this recipe
see: https://velero.io/docs/main/build-from-source/#making-images-and-updating-velero for more info
endef
# The version of restic binary to be downloaded for power architecture
RESTIC_VERSION ?= 0.9.6
CLI_PLATFORMS ?= linux-amd64 linux-arm linux-arm64 darwin-amd64 windows-amd64 linux-ppc64le
CONTAINER_PLATFORMS ?= linux-amd64 linux-ppc64le linux-arm linux-arm64
MANIFEST_PLATFORMS ?= amd64 ppc64le arm arm64
BUILDX_PLATFORMS ?= $(subst -,/,$(ARCH))
BUILDX_OUTPUT_TYPE ?= docker
# set git sha and tree state
GIT_SHA = $(shell git rev-parse HEAD)
GIT_DIRTY = $(shell git status --porcelain 2> /dev/null)
ifneq ($(shell git status --porcelain 2> /dev/null),)
GIT_TREE_STATE ?= dirty
else
GIT_TREE_STATE ?= clean
endif
# The default linters used by lint and local-lint
LINTERS ?= "gosec,goconst,gofmt,goimports,unparam"
@@ -64,36 +90,7 @@ LINTERS ?= "gosec,goconst,gofmt,goimports,unparam"
platform_temp = $(subst -, ,$(ARCH))
GOOS = $(word 1, $(platform_temp))
GOARCH = $(word 2, $(platform_temp))
# Set default base image dynamically for each arch
ifeq ($(GOARCH),amd64)
DOCKERFILE ?= Dockerfile-$(BIN)
local-arch:
@echo "local environment for amd64 is up-to-date"
endif
ifeq ($(GOARCH),arm)
DOCKERFILE ?= Dockerfile-$(BIN)-arm
local-arch:
@mkdir -p _output/bin/linux/arm/
@wget -q -O - https://github.com/restic/restic/releases/download/v$(RESTIC_VERSION)/restic_$(RESTIC_VERSION)_linux_arm.bz2 | bunzip2 > _output/bin/linux/arm/restic
@chmod a+x _output/bin/linux/arm/restic
endif
ifeq ($(GOARCH),arm64)
DOCKERFILE ?= Dockerfile-$(BIN)-arm64
local-arch:
@mkdir -p _output/bin/linux/arm64/
@wget -q -O - https://github.com/restic/restic/releases/download/v$(RESTIC_VERSION)/restic_$(RESTIC_VERSION)_linux_arm64.bz2 | bunzip2 > _output/bin/linux/arm64/restic
@chmod a+x _output/bin/linux/arm64/restic
endif
ifeq ($(GOARCH),ppc64le)
DOCKERFILE ?= Dockerfile-$(BIN)-ppc64le
local-arch:
RESTIC_VERSION=$(RESTIC_VERSION) \
./hack/get-restic-ppc64le.sh
endif
MULTIARCH_IMAGE = $(REGISTRY)/$(BIN)
IMAGE ?= $(REGISTRY)/$(BIN)-$(GOARCH)
GOPROXY ?= https://proxy.golang.org
# If you want to build all binaries, see the 'all-build' rule.
# If you want to build all containers, see the 'all-containers' rule.
@@ -106,23 +103,11 @@ build-%:
@$(MAKE) --no-print-directory ARCH=$* build
@$(MAKE) --no-print-directory ARCH=$* build BIN=velero-restic-restore-helper
container-%:
@$(MAKE) --no-print-directory ARCH=$* container
@$(MAKE) --no-print-directory ARCH=$* container BIN=velero-restic-restore-helper
push-%:
@$(MAKE) --no-print-directory ARCH=$* push
@$(MAKE) --no-print-directory ARCH=$* push BIN=velero-restic-restore-helper
all-build: $(addprefix build-, $(CLI_PLATFORMS))
all-containers: $(addprefix container-, $(CONTAINER_PLATFORMS))
all-push: $(addprefix push-, $(CONTAINER_PLATFORMS))
all-manifests:
@$(MAKE) manifest
@$(MAKE) manifest BIN=velero-restic-restore-helper
all-containers: container-builder-env
@$(MAKE) --no-print-directory container
@$(MAKE) --no-print-directory container BIN=velero-restic-restore-helper
local: build-dirs
GOOS=$(GOOS) \
@@ -131,7 +116,7 @@ local: build-dirs
PKG=$(PKG) \
BIN=$(BIN) \
GIT_SHA=$(GIT_SHA) \
GIT_DIRTY="$(GIT_DIRTY)" \
GIT_TREE_STATE=$(GIT_TREE_STATE) \
OUTPUT_DIR=$$(pwd)/_output/bin/$(GOOS)/$(GOARCH) \
./hack/build.sh
@@ -146,13 +131,12 @@ _output/bin/$(GOOS)/$(GOARCH)/$(BIN): build-dirs
PKG=$(PKG) \
BIN=$(BIN) \
GIT_SHA=$(GIT_SHA) \
GIT_DIRTY=\"$(GIT_DIRTY)\" \
GIT_TREE_STATE=$(GIT_TREE_STATE) \
OUTPUT_DIR=/output/$(GOOS)/$(GOARCH) \
./hack/build.sh'"
TTY := $(shell tty -s && echo "-t")
# Example: make shell CMD="date > datefile"
shell: build-dirs build-env
@# bind-mount the Velero root dir in at /github.com/vmware-tanzu/velero
@@ -175,47 +159,36 @@ shell: build-dirs build-env
$(BUILDER_IMAGE) \
/bin/sh $(CMD)
DOTFILE_IMAGE = $(subst :,_,$(subst /,_,$(IMAGE))-$(VERSION))
container-builder-env:
ifneq ($(BUILDX_ENABLED), true)
$(error $(BUILDX_ERROR))
endif
@docker buildx build \
--target=builder-env \
--build-arg=GOPROXY=$(GOPROXY) \
--build-arg=PKG=$(PKG) \
--build-arg=VERSION=$(VERSION) \
--build-arg=GIT_SHA=$(GIT_SHA) \
--build-arg=GIT_TREE_STATE=$(GIT_TREE_STATE) \
-f Dockerfile .
all-containers:
$(MAKE) container
$(MAKE) container BIN=velero-restic-restore-helper
container: local-arch .container-$(DOTFILE_IMAGE) container-name
.container-$(DOTFILE_IMAGE): _output/bin/$(GOOS)/$(GOARCH)/$(BIN) $(DOCKERFILE)
@cp $(DOCKERFILE) _output/.dockerfile-$(BIN)-$(GOOS)-$(GOARCH)
@docker build --pull -t $(IMAGE):$(VERSION) -f _output/.dockerfile-$(BIN)-$(GOOS)-$(GOARCH) _output
@docker images -q $(IMAGE):$(VERSION) > $@
container-name:
container:
ifneq ($(BUILDX_ENABLED), true)
$(error $(BUILDX_ERROR))
endif
@docker buildx build --pull \
--output=type=$(BUILDX_OUTPUT_TYPE) \
--platform $(BUILDX_PLATFORMS) \
$(addprefix -t , $(IMAGE_TAGS)) \
--build-arg=PKG=$(PKG) \
--build-arg=BIN=$(BIN) \
--build-arg=VERSION=$(VERSION) \
--build-arg=GIT_SHA=$(GIT_SHA) \
--build-arg=GIT_TREE_STATE=$(GIT_TREE_STATE) \
--build-arg=RESTIC_VERSION=$(RESTIC_VERSION) \
-f Dockerfile .
@echo "container: $(IMAGE):$(VERSION)"
push: .push-$(DOTFILE_IMAGE) push-name
.push-$(DOTFILE_IMAGE): .container-$(DOTFILE_IMAGE)
@docker push $(IMAGE):$(VERSION)
ifeq ($(TAG_LATEST), true)
docker tag $(IMAGE):$(VERSION) $(IMAGE):latest
docker push $(IMAGE):latest
endif
@docker images -q $(IMAGE):$(VERSION) > $@
push-name:
@echo "pushed: $(IMAGE):$(VERSION)"
manifest: .manifest-$(MULTIARCH_IMAGE) manifest-name
.manifest-$(MULTIARCH_IMAGE):
@DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create $(MULTIARCH_IMAGE):$(VERSION) \
$(foreach arch, $(MANIFEST_PLATFORMS), $(MULTIARCH_IMAGE)-$(arch):$(VERSION))
@DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push --purge $(MULTIARCH_IMAGE):$(VERSION)
ifeq ($(TAG_LATEST), true)
@DOCKER_CLI_EXPERIMENTAL=enabled docker manifest create $(MULTIARCH_IMAGE):latest \
$(foreach arch, $(MANIFEST_PLATFORMS), $(MULTIARCH_IMAGE)-$(arch):latest)
@DOCKER_CLI_EXPERIMENTAL=enabled docker manifest push --purge $(MULTIARCH_IMAGE):latest
endif
manifest-name:
@echo "pushed: $(MULTIARCH_IMAGE):$(VERSION)"
SKIP_TESTS ?=
test: build-dirs
ifneq ($(SKIP_TESTS), 1)
@@ -266,21 +239,25 @@ build-env:
ifneq ($(shell git diff --quiet HEAD -- hack/build-image/Dockerfile; echo $$?), 0)
@echo "Local changes detected in hack/build-image/Dockerfile"
@echo "Preparing a new builder-image"
@make build-image
$(MAKE) build-image
else ifneq ($(BUILDER_IMAGE_CACHED),)
@echo "Using Cached Image: $(BUILDER_IMAGE)"
else
@echo "Trying to pull build-image: $(BUILDER_IMAGE)"
docker pull -q $(BUILDER_IMAGE) || make build-image
docker pull -q $(BUILDER_IMAGE) || $(MAKE) build-image
endif
build-image:
@# When we build a new image we just untag the old one.
@# This makes sure we don't leave the orphaned image behind.
@id=$$(docker image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null); \
cd hack/build-image && docker build --pull -t $(BUILDER_IMAGE) . ; \
new_id=$$(docker image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null); \
if [ "$$id" != "" ] && [ "$$id" != "$$new_id" ]; then \
$(eval old_id=$(shell docker image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null))
ifeq ($(BUILDX_ENABLED), true)
@cd hack/build-image && docker buildx build --build-arg=GOPROXY=$(GOPROXY) --output=type=docker --pull -t $(BUILDER_IMAGE) .
else
@cd hack/build-image && docker build --build-arg=GOPROXY=$(GOPROXY) --pull -t $(BUILDER_IMAGE) .
endif
$(eval new_id=$(shell docker image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null))
@if [ "$(old_id)" != "" ] && [ "$(old_id)" != "$(new_id)" ]; then \
docker rmi -f $$id || true; \
fi
@@ -289,6 +266,9 @@ push-build-image:
@# credentials needed to accomplish this.
docker push $(BUILDER_IMAGE)
build-image-hugo:
cd site && docker build --pull -t $(HUGO_IMAGE) .
clean:
# if we have a cached image then use it to run go clean --modcache
# this test checks if we there is an image id in the BUILDER_IMAGE_CACHED variable.
@@ -296,8 +276,8 @@ ifneq ($(strip $(BUILDER_IMAGE_CACHED)),)
$(MAKE) shell CMD="-c 'go clean --modcache'"
docker rmi -f $(BUILDER_IMAGE) || true
endif
rm -rf .container-* _output/.dockerfile-* .push-*
rm -rf .go _output
docker rmi $(HUGO_IMAGE)
.PHONY: modules
@@ -338,38 +318,16 @@ release:
GITHUB_TOKEN=$(GITHUB_TOKEN) \
RELEASE_NOTES_FILE=$(RELEASE_NOTES_FILE) \
PUBLISH=$(PUBLISH) \
./hack/goreleaser.sh'"
./hack/release-tools/goreleaser.sh'"
serve-docs:
serve-docs: build-image-hugo
docker run \
--rm \
-v "$$(pwd)/site:/srv/jekyll" \
-it -p 4000:4000 \
jekyll/jekyll \
jekyll serve --livereload --incremental
# gen-docs generates a new versioned docs directory under site/docs. It follows
# the following process:
# 1. Copies the contents of the most recently tagged docs directory into the new
# directory, to establish a useful baseline to diff against.
# 2. Adds all copied content from step 1 to git's staging area via 'git add'.
# 3. Replaces the contents of the new docs directory with the contents of the
# 'master' docs directory, updating any version-specific links (e.g. to a
# specific branch of the GitHub repository) to use the new version
# 4. Copies the previous version's ToC file and runs 'git add' to establish
# a useful baseline to diff against.
# 5. Replaces the content of the new ToC file with the master ToC.
# 6. Update site/_config.yml and site/_data/toc-mapping.yml to include entries
# for the new version.
#
# The unstaged changes in the working directory can now easily be diff'ed against the
# staged changes using 'git diff' to review all docs changes made since the previous
# tagged version. Once the unstaged changes are ready, they can be added to the
# staging area using 'git add' and then committed.
#
# To run gen-docs: "NEW_DOCS_VERSION=v1.4 VELERO_VERSION=v1.4.0 make gen-docs"
#
# **NOTE**: there are additional manual steps required to finalize the process of generating
# a new versioned docs site. The full process is documented in site/README-JEKYLL.md.
-v "$$(pwd)/site:/srv/hugo" \
-it -p 1313:1313 \
$(HUGO_IMAGE) \
hugo server --bind=0.0.0.0 --enableGitInfo=false
# gen-docs generates a new versioned docs directory under site/content/docs.
# Please read the documentation in the script for instructions on how to use it.
gen-docs:
@hack/gen-docs.sh
@hack/release-tools/gen-docs.sh

View File

@@ -1,6 +1,7 @@
![100]
[![Build Status][1]][2]
[![Build Status][1]][2] [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3811/badge)](https://bestpractices.coreinfrastructure.org/projects/3811)
## Overview
@@ -33,8 +34,8 @@ If you are ready to jump in and test, add code, or help with documentation, foll
See [the list of releases][6] to find out about feature changes.
[1]: https://github.com/vmware-tanzu/velero/workflows/Master%20CI/badge.svg
[2]: https://github.com/vmware-tanzu/velero/actions?query=workflow%3A"Master+CI"
[1]: https://github.com/vmware-tanzu/velero/workflows/Main%20CI/badge.svg
[2]: https://github.com/vmware-tanzu/velero/actions?query=workflow%3A"Main+CI"
[4]: https://github.com/vmware-tanzu/velero/issues
[6]: https://github.com/vmware-tanzu/velero/releases
[9]: https://kubernetes.io/docs/setup/
@@ -47,4 +48,4 @@ See [the list of releases][6] to find out about feature changes.
[29]: https://velero.io/docs/
[30]: https://velero.io/docs/troubleshooting
[31]: https://velero.io/docs/start-contributing
[100]: https://velero.io/docs/master/img/velero.png
[100]: https://velero.io/docs/main/img/velero.png

View File

@@ -7,7 +7,7 @@ This document provides a link to the [Velero Project board](https://app.zenhub.c
Discussion on the roadmap can take place in threads under [Issues](https://github.com/vmware-tanzu/velero/issues) or in [community meetings](https://velero.io/community/). Please open and comment on an issue if you want to provide suggestions, use cases, and feedback to an item in the roadmap. Please review the roadmap to avoid potential duplicated effort.
### How to add an item to the roadmap?
One of the most important aspects in any open source community is the concept of proposals. Large changes to the codebase and / or new features should be preceded by a [proposal](https://github.com/vmware-tanzu/velero/blob/master/GOVERNANCE.md#proposal-process) in our repo.
One of the most important aspects in any open source community is the concept of proposals. Large changes to the codebase and / or new features should be preceded by a [proposal](https://github.com/vmware-tanzu/velero/blob/main/GOVERNANCE.md#proposal-process) in our repo.
For smaller enhancements, you can open an issue to track that initiative or feature request.
We work with and rely on community feedback to focus our efforts to improve Velero and maintain a healthy roadmap.

128
SECURITY.md Normal file
View File

@@ -0,0 +1,128 @@
# Security Release Process
Velero is an open source tool with a growing community devoted to safe backup and restore, disaster recovery, and data migration of Kubernetes resources and persistent volumes. The community has adopted this security disclosure and response policy to ensure we responsibly handle critical issues.
## Supported Versions
The Velero project maintains the following [governance document](https://github.com/vmware-tanzu/velero/blob/main/GOVERNANCE.md), [release document](https://github.com/vmware-tanzu/velero/blob/f42c63af1b9af445e38f78a7256b1c48ef79c10e/site/docs/main/release-instructions.md), and [support document](https://velero.io/docs/main/support-process/). Please refer to these for release and related details. Only the most recent version of Velero is supported. Each [release](https://github.com/vmware-tanzu/velero/releases) includes information about upgrading to the latest version.
## Reporting a Vulnerability - Private Disclosure Process
Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be reported to Velero privately, to minimize attacks against current users of Velero before they are fixed. Vulnerabilities will be investigated and patched on the next patch (or minor) release as soon as possible. This information could be kept entirely internal to the project.
If you know of a publicly disclosed security vulnerability for Velero, please **IMMEDIATELY** contact the VMware Security Team (security@vmware.com).
**IMPORTANT: Do not file public issues on GitHub for security vulnerabilities**
To report a vulnerability or a security-related issue, please contact the VMware email address with the details of the vulnerability. The email will be fielded by the VMware Security Team and then shared with the Velero maintainers who have committer and release permissions. Emails will be addressed within 3 business days, including a detailed plan to investigate the issue and any potential workarounds to perform in the meantime. Do not report non-security-impacting bugs through this channel. Use [GitHub issues](https://github.com/vmware-tanzu/velero/issues/new/choose) instead.
## Proposed Email Content
Provide a descriptive subject line and in the body of the email include the following information:
* Basic identity information, such as your name and your affiliation or company.
* Detailed steps to reproduce the vulnerability (POC scripts, screenshots, and logs are all helpful to us).
* Description of the effects of the vulnerability on Velero and the related hardware and software configurations, so that the VMware Security Team can reproduce it.
* How the vulnerability affects Velero usage and an estimation of the attack surface, if there is one.
* List other projects or dependencies that were used in conjunction with Velero to produce the vulnerability.
## When to report a vulnerability
* When you think Velero has a potential security vulnerability.
* When you suspect a potential vulnerability but you are unsure that it impacts Velero.
* When you know of or suspect a potential vulnerability on another project that is used by Velero.
## Patch, Release, and Disclosure
The VMware Security Team will respond to vulnerability reports as follows:
1. The Security Team will investigate the vulnerability and determine its effects and criticality.
2. If the issue is not deemed to be a vulnerability, the Security Team will follow up with a detailed reason for rejection.
3. The Security Team will initiate a conversation with the reporter within 3 business days.
4. If a vulnerability is acknowledged and the timeline for a fix is determined, the Security Team will work on a plan to communicate with the appropriate community, including identifying mitigating steps that affected users can take to protect themselves until the fix is rolled out.
5. The Security Team will also create a [CVSS](https://www.first.org/cvss/specification-document) using the [CVSS Calculator](https://www.first.org/cvss/calculator/3.0). The Security Team makes the final call on the calculated CVSS; it is better to move quickly than making the CVSS perfect. Issues may also be reported to [Mitre](https://cve.mitre.org/) using this [scoring calculator](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator). The CVE will initially be set to private.
6. The Security Team will work on fixing the vulnerability and perform internal testing before preparing to roll out the fix.
7. The Security Team will provide early disclosure of the vulnerability by emailing the [Velero Distributors](https://groups.google.com/u/1/g/projectvelero-distributors) mailing list. Distributors can initially plan for the vulnerability patch ahead of the fix, and later can test the fix and provide feedback to the Velero team. See the section **Early Disclosure to Velero Distributors List** for details about how to join this mailing list.
8. A public disclosure date is negotiated by the VMware SecurityTeam, the bug submitter, and the distributors list. We prefer to fully disclose the bug as soon as possible once a user mitigation or patch is available. It is reasonable to delay disclosure when the bug or the fix is not yet fully understood, the solution is not well-tested, or for distributor coordination. The timeframe for disclosure is from immediate (especially if its already publicly known) to a few weeks. For a critical vulnerability with a straightforward mitigation, we expect the report date for the public disclosure date to be on the order of 14 business days. The VMware Security Team holds the final say when setting a public disclosure date.
9. Once the fix is confirmed, the Security Team will patch the vulnerability in the next patch or minor release, and backport a patch release into all earlier supported releases. Upon release of the patched version of Velero, we will follow the **Public Disclosure Process**.
## Public Disclosure Process
The Security Team publishes a [public advisory](https://github.com/vmware-tanzu/velero/security/advisories) to the Velero community via GitHub. In most cases, additional communication via Slack, Twitter, mailing lists, blog and other channels will assist in educating Velero users and rolling out the patched release to affected users.
The Security Team will also publish any mitigating steps users can take until the fix can be applied to their Velero instances. Velero distributors will handle creating and publishing their own security advisories.
## Mailing lists
* Use security@vmware.com to report security concerns to the VMware Security Team, who uses the list to privately discuss security issues and fixes prior to disclosure.
* Join the [Velero Distributors](https://groups.google.com/u/1/g/projectvelero-distributors) mailing list for early private information and vulnerability disclosure. Early disclosure may include mitigating steps and additional information on security patch releases. See below for information on how Velero distributors or vendors can apply to join this list.
## Early Disclosure to Velero Distributors List
The private list is intended to be used primarily to provide actionable information to multiple distributor projects at once. This list is not intended to inform individuals about security issues.
## Membership Criteria
To be eligible to join the [Velero Distributors](https://groups.google.com/u/1/g/projectvelero-distributors) mailing list, you should:
1. Be an active distributor of Velero.
2. Have a user base that is not limited to your own organization.
3. Have a publicly verifiable track record up to the present day of fixing security issues.
4. Not be a downstream or rebuild of another distributor.
5. Be a participant and active contributor in the Velero community.
6. Accept the Embargo Policy that is outlined below.
7. Have someone who is already on the list vouch for the person requesting membership on behalf of your distribution.
**The terms and conditions of the Embargo Policy apply to all members of this mailing list. A request for membership represents your acceptance to the terms and conditions of the Embargo Policy.**
## Embargo Policy
The information that members receive on the Velero Distributors mailing list must not be made public, shared, or even hinted at anywhere beyond those who need to know within your specific team, unless you receive explicit approval to do so from the VMware Security Team. This remains true until the public disclosure date/time agreed upon by the list. Members of the list and others cannot use the information for any reason other than to get the issue fixed for your respective distribution's users.
Before you share any information from the list with members of your team who are required to fix the issue, these team members must agree to the same terms, and only be provided with information on a need-to-know basis.
In the unfortunate event that you share information beyond what is permitted by this policy, you must urgently inform the VMware Security Team (security@vmware.com) of exactly what information was leaked and to whom. If you continue to leak information and break the policy outlined here, you will be permanently removed from the list.
## Requesting to Join
Send new membership requests to projectvelero-distributors@googlegroups.com. In the body of your request please specify how you qualify for membership and fulfill each criterion listed in the Membership Criteria section above.
## Confidentiality, integrity and availability
We consider vulnerabilities leading to the compromise of data confidentiality, elevation of privilege, or integrity to be our highest priority concerns. Availability, in particular in areas relating to DoS and resource exhaustion, is also a serious security concern. The VMware Security Team takes all vulnerabilities, potential vulnerabilities, and suspected vulnerabilities seriously and will investigate them in an urgent and expeditious manner.
Note that we do not currently consider the default settings for Velero to be secure-by-default. It is necessary for operators to explicitly configure settings, role based access control, and other resource related features in Velero to provide a hardened Velero environment. We will not act on any security disclosure that relates to a lack of safe defaults. Over time, we will work towards improved safe-by-default configuration, taking into account backwards compatibility.

View File

@@ -4,4 +4,4 @@ Thanks for trying out Velero! We welcome all feedback, find all the ways to conn
- [Velero Community](https://velero.io/community/)
You can find details on the Velero maintainers' support process [here](https://velero.io/docs/master/support-process/).
You can find details on the Velero maintainers' support process [here](https://velero.io/docs/main/support-process/).

View File

@@ -69,8 +69,8 @@ carefully to ensure a successful upgrade!**
- The `Config` CRD has been replaced by `BackupStorageLocation` and `VolumeSnapshotLocation` CRDs.
- The interface for external plugins (object/block stores, backup/restore item actions) has changed. If you have authored any custom plugins, they'll
need to be updated for v0.10.
- The [`ObjectStore.ListCommonPrefixes`](https://github.com/heptio/ark/blob/master/pkg/cloudprovider/object_store.go#L50) signature has changed to add a `prefix` parameter.
- Registering plugins has changed. Create a new plugin server with the `NewServer` function, and register plugins with the appropriate functions. See the [`Server`](https://github.com/heptio/ark/blob/master/pkg/plugin/server.go#L37) interface for details.
- The [`ObjectStore.ListCommonPrefixes`](https://github.com/vmware-tanzu/velero/blob/main/pkg/cloudprovider/object_store.go#L50) signature has changed to add a `prefix` parameter.
- Registering plugins has changed. Create a new plugin server with the `NewServer` function, and register plugins with the appropriate functions. See the [`Server`](https://github.com/vmware-tanzu/velero/blob/main/pkg/plugin/server.go#L37) interface for details.
- The organization of Ark data in object storage has changed. Existing data will need to be moved around to conform to the new layout.
### All Changes
@@ -89,7 +89,7 @@ need to be updated for v0.10.
- [ec013e6f](https://github.com/heptio/ark/commit/ec013e6f) Document upgrading plugins in the deployment
- [d6162e94](https://github.com/heptio/ark/commit/d6162e94) fix goreleaser bugs
- [a15df276](https://github.com/heptio/ark/commit/a15df276) Add correct link and change role
- [46bed015](https://github.com/heptio/ark/commit/46bed015) add 0.10 breaking changes warning to readme in master
- [46bed015](https://github.com/heptio/ark/commit/46bed015) add 0.10 breaking changes warning to readme in main
- [e3a7d6a2](https://github.com/heptio/ark/commit/e3a7d6a2) add content for issue 994
- [400911e9](https://github.com/heptio/ark/commit/400911e9) address docs issue #978
- [b818cc27](https://github.com/heptio/ark/commit/b818cc27) don't require a default provider VSL if there's only 1
@@ -247,7 +247,7 @@ need to be updated for v0.10.
- [5b89f7b6](https://github.com/heptio/ark/commit/5b89f7b6) Skip backup sync if it already exists in k8s
- [c6050845](https://github.com/heptio/ark/commit/c6050845) restore controller: switch to 'c' for receiver name
- [706ae07d](https://github.com/heptio/ark/commit/706ae07d) enable a schedule to be provided as the source for a restore
- [aea68414](https://github.com/heptio/ark/commit/aea68414) fix up Slack link in troubleshooting on master branch
- [aea68414](https://github.com/heptio/ark/commit/aea68414) fix up Slack link in troubleshooting on main branch
- [bb8e2e91](https://github.com/heptio/ark/commit/bb8e2e91) Document how to run the Ark server locally
- [dc84e591](https://github.com/heptio/ark/commit/dc84e591) Remove outdated namespace deletion content
- [23abbc9a](https://github.com/heptio/ark/commit/23abbc9a) fix paths

View File

@@ -137,7 +137,7 @@
### Highlights:
* Ark now has support for backing up and restoring Kubernetes volumes using a free open-source backup tool called [restic](https://github.com/restic/restic).
This provides users an out-of-the-box solution for backing up and restoring almost any type of Kubernetes volume, whether or not it has snapshot support
integrated with Ark. For more information, see the [documentation](https://github.com/heptio/ark/blob/master/docs/restic.md).
integrated with Ark. For more information, see the [documentation](https://github.com/vmware-tanzu/velero/blob/main/docs/restic.md).
* Support for Prometheus metrics has been added! View total number of backup attempts (including success or failure), total backup size in bytes, and backup
durations. More metrics coming in future releases!

View File

@@ -90,7 +90,7 @@ We fixed a large number of bugs and made some smaller usability improvements in
### All Changes
* Corrected the selfLink for Backup CR in site/docs/master/output-file-format.md (#2292, @RushinthJohn)
* Corrected the selfLink for Backup CR in site/docs/main/output-file-format.md (#2292, @RushinthJohn)
* Back up schema-less CustomResourceDefinitions as v1beta1, even if they are retrieved via the v1 endpoint. (#2264, @nrb)
* Bug fix: restic backup volume snapshot to the second location failed (#2244, @jenting)
* Added support of using PV name from volumesnapshotter('SetVolumeID') in case of PV renaming during the restore (#2216, @mynktl)

View File

@@ -1,3 +1,28 @@
## v1.4.2
### 2020-07-13
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.4.2
### Container Image
`velero/velero:v1.4.2`
### Documentation
https://velero.io/docs/v1.4/
### Upgrading
https://velero.io/docs/v1.4/upgrade-to-1.4/
### All Changes
* log a warning instead of erroring if an additional item returned from a plugin can't be found in the Kubernetes API (#2595, @skriss)
* Adjust restic default time out to 4 hours and base pod resource requests to 500m CPU/512Mi memory. (#2696, @nrb)
* capture version of the CRD prior before invoking the remap_crd_version backup item action (#2683, @ashish-amarnath)
## v1.4.1
This tag was created in code, but has no associated docker image due to misconfigured building infrastructure. v1.4.2 fixes this.
## v1.4.0
### 2020-05-26

103
changelogs/CHANGELOG-1.5.md Normal file
View File

@@ -0,0 +1,103 @@
## v1.5.2
### 2020-10-20
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.5.2
### Container Image
`velero/velero:v1.5.2`
### Documentation
https://velero.io/docs/v1.5/
### Upgrading
https://velero.io/docs/v1.5/upgrade-to-1.5/
### All Changes
* Fix BSL controller to avoid invoking init() on all BSLs regardless of ValidationFrequency (#2992, @betta1)
* cli: allow creating multiple instances of Velero across two different namespaces (#2886, @alaypatel07)
* Restore CRD Resource name to fix CRD wait functionality. (#2949, @sseago)
* Ensure that bound PVCs and PVs remain bound on restore. (#3007, @nrb)
## v1.5.1
### 2020-09-16
### Download
https://github.com/vmware-tanzu/velero/releases/tag/v1.5.1
### Container Image
`velero/velero:v1.5.1`
### Documentation
https://velero.io/docs/v1.5/
### Upgrading
https://velero.io/docs/v1.5/upgrade-to-1.5/
### Highlights
* Auto Volume Backup Using Restic with `--default-volumes-to-restic` flag
* DeleteItemAction plugins
* Code modernization
* Restore Hooks: InitContianer Restore Hooks and Exec Restore Hooks
### All Changes
* 🏃‍♂️ add shortnames for CRDs (#2911, @ashish-amarnath)
* Use format version instead of version on `velero backup describe` since version has been deprecated (#2901, @jenting)
* fix EnableAPIGroupersions output log format (#2882, @jenting)
* Convert ServerStatusRequest controller to kubebuilder (#2838, @carlisia)
* rename the PV if VolumeSnapshotter has modified the PV name (#2835, @pawanpraka1)
* Implement post-restore exec hooks in pod containers (#2804, @areed)
* Check for errors on restic backup command (#2863, @dymurray)
* 🐛 fix passing LDFLAGS across build stages (#2853, @ashish-amarnath)
* Feature: Invoke DeleteItemAction plugins based on backup contents when a backup is deleted. (#2815, @nrb)
* When JSON logging format is enabled, place error message at "error.message" instead of "error" for compatibility with Elasticsearch/ELK and the Elastic Common Schema (#2830, @bgagnon)
* discovery Helper support get GroupVersionResource and an APIResource from GroupVersionKind (#2764, @runzexia)
* Migrate site from Jekyll to Hugo (#2720, @tbatard)
* Add the DeleteItemAction plugin type (#2808, @nrb)
* 🐛 Manually patch the generated yaml for restore CRD as a hacky workaround (#2814, @ashish-amarnath)
* Setup crd validation github action on k8s versions (#2805, @ashish-amarnath)
* 🐛 Supply command to run restic-wait init container (#2802, @ashish-amarnath)
* Make init and exec restore hooks as optional in restore hookSpec (#2793, @ashish-amarnath)
* Implement restore hooks injecting init containers into pod spec (#2787, @ashish-amarnath)
* Pass default-volumes-to-restic flag from create schedule to backup (#2776, @ashish-amarnath)
* Enhance Backup to support backing up resources in specific orders and add --ordered-resources option to support this feature. (#2724, @phuong)
* Fix inconsistent type for the "resource" structured logging field (#2796, @bgagnon)
* Add the ability to set the allowPrivilegeEscalation flag in the securityContext for the Restic restore helper. (#2792, @doughepi)
* Add cacert flag for velero backup-location create (#2778, @jenting)
* Exclude volumes mounting secrets and configmaps from defaulting volume backups to restic (#2762, @ashish-amarnath)
* Add types to implement restore hooks (#2761, @ashish-amarnath)
* Add wait group and error channel for restore hooks to restore context. (#2755, @areed)
* Refactor image builds to use buildx for multi arch image building (#2754, @robreus)
* Add annotation key constants for restore hooks (#2750, @ashish-amarnath)
* Adds Start and CompletionTimestamp to RestoreStatus
Displays the Timestamps when issued a print or describe (#2748, @thejasbabu)
* Move pkg/backup/item_hook_handlers.go to internal/hook (#2734, @nrb)
* add metrics for restic back up operation (#2719, @ashish-amarnath)
* StorageGrid compatibility by removing explicit gzip accept header setting (#2712, @fvsqr)
* restic: add support for setting SecurityContext (runAsUser, runAsGroup) for restore (#2621, @jaygridley)
* Add backupValidationFailureTotal to metrics (#2714, @kathpeony)
* bump Kubernetes module dependencies to v0.18.4 to fix https://github.com/vmware-tanzu/velero/issues/2540 by adding code compatibility with kubernetes v1.18 (#2651, @laverya)
* Add a BSL controller to handle validation + update BSL status phase (validation removed from the server and no longer blocks when there's any invalid BSL) (#2674, @carlisia)
* updated acceptable values on cron schedule from 0-7 to 0-6 (#2676, @dthrasher)
* Improve velero download doc (#2660, @carlisia)
* Update basic-install and release-instructions documentation for Windows Chocolatey package (#2638, @adamrushuk)
* move CSI plugin out of prototype into beta (#2636, @ashish-amarnath)
* Add a new supported provider for an object storage plugin for Storj (#2635, @jessicagreben)
* Update basic-install.md documentation: Add windows cli installation option via chocolatey (#2629, @adamrushuk)
* Documentation: Update Jekyll to 4.1.0. Switch from redcarpet to kramdown for Markdown renderer (#2625, @tbatard)
* improve builder image handling so that we don't rebuild each `make shell` (#2620, @mauilion)
* first check if there are pending changed on the build-image dockerfile if so build it.
* then check if there is an image in the registry if so pull it.
* then build an image cause we don't have a cached image. (this handles the backward compat case.)
* fix make clean to clear go mod cache before removing dirs (for containerized builds)
* Add linter checks to Makefile (#2615, @tbatard)
* add a CI check for a changelog file (#2613, @ashish-amarnath)
* implement option to back up all volumes by default with restic (#2611, @ashish-amarnath)
* When a timeout string can't be parsed, log the error as a warning instead of silently consuming the error. (#2610, @nrb)
* Azure: support using `aad-pod-identity` auth when using restic (#2602, @skriss)
* log a warning instead of erroring if an additional item returned from a plugin can't be found in the Kubernetes API (#2595, @skriss)
* when creating new backup from schedule from cli, allow backup name to be automatically generated (#2569, @cblecker)
* Convert manifests + BSL api client to kubebuilder (#2561, @carlisia)
* backup/restore: reinstantiate backup store just before uploading artifacts to ensure credentials are up-to-date (#2550, @skriss)

View File

@@ -1 +0,0 @@
backup/restore: reinstantiate backup store just before uploading artifacts to ensure credentials are up-to-date

View File

@@ -1 +0,0 @@
Convert manifests + BSL api client to kubebuilder

View File

@@ -1 +0,0 @@
when creating new backup from schedule from cli, allow backup name to be automatically generated

View File

@@ -1 +0,0 @@
log a warning instead of erroring if an additional item returned from a plugin can't be found in the Kubernetes API

View File

@@ -1 +0,0 @@
Azure: support using `aad-pod-identity` auth when using restic

View File

@@ -1 +0,0 @@
When a timeout string can't be parsed, log the error as a warning instead of silently consuming the error.

View File

@@ -1 +0,0 @@
implement option to back up all volumes by default with restic

View File

@@ -1 +0,0 @@
add a CI check for a changelog file

View File

@@ -1 +0,0 @@
Add linter checks to Makefile

View File

@@ -1,6 +0,0 @@
improve builder image handling so that we don't rebuild each `make shell`
first check if there are pending changed on the build-image dockerfile if so build it.
then check if there is an image in the registry if so pull it.
then build an image cause we don't have a cached image. (this handles the backward compat case.)
fix make clean to clear go mod cache before removing dirs (for containerized builds)

View File

@@ -1,3 +0,0 @@
Documentation: Update Jekyll to 4.1.0
Switch from redcarpet to kramdown for Markdown renderer

View File

@@ -1 +0,0 @@
Update basic-install.md documentation: Add windows cli installation option via chocolatey

View File

@@ -1 +0,0 @@
Add a new supported provider for an object storage plugin for Storj

View File

@@ -1 +0,0 @@
move CSI plugin out of prototype into beta

View File

@@ -1 +0,0 @@
Update basic-install and release-instructions documentation for Windows Chocolatey package

View File

@@ -1 +0,0 @@
bump Kubernetes module dependencies to v0.18.4 to fix https://github.com/vmware-tanzu/velero/issues/2540 by adding code compatibility with kubernetes v1.18

View File

@@ -1 +0,0 @@
Improve velero download doc

View File

@@ -1 +0,0 @@
Add a BSL controller to handle validation + update BSL status phase (validation removed from the server and no longer blocks when there's any invalid BSL)

View File

@@ -1 +0,0 @@
updated acceptable values on cron schedule from 0-7 to 0-6

View File

@@ -1 +0,0 @@
capture version of the CRD prior before invoking the remap_crd_version backup item action

View File

@@ -1 +0,0 @@
Adjust restic default time out to 4 hours and base pod resource requests to 500m CPU/512Mi memory.

View File

@@ -1 +0,0 @@
Add backupValidationFailureTotal to metrics

View File

@@ -303,6 +303,15 @@ spec:
are ANDed.
type: object
type: object
orderedResources:
additionalProperties:
type: string
description: OrderedResources specifies the backup order of resources
of specific Kind. The map key is the Kind name and value is a list
of resource names separeted by commas. Each resource name has format
"namespace/resourcename". For cluster resources, simply use "resourcename".
nullable: true
type: object
snapshotVolumes:
description: SnapshotVolumes specifies whether to take cloud snapshots
of any PV's referenced in the set of objects included in the Backup.

View File

@@ -26,6 +26,8 @@ spec:
kind: BackupStorageLocation
listKind: BackupStorageLocationList
plural: backupstoragelocations
shortNames:
- bsl
singular: backupstoragelocation
preserveUnknownFields: false
scope: Namespaced

File diff suppressed because it is too large Load Diff

View File

@@ -318,6 +318,16 @@ spec:
are ANDed.
type: object
type: object
orderedResources:
additionalProperties:
type: string
description: OrderedResources specifies the backup order of resources
of specific Kind. The map key is the Kind name and value is a
list of resource names separeted by commas. Each resource name
has format "namespace/resourcename". For cluster resources, simply
use "resourcename".
nullable: true
type: object
snapshotVolumes:
description: SnapshotVolumes specifies whether to take cloud snapshots
of any PV's referenced in the set of objects included in the Backup.

View File

@@ -13,9 +13,13 @@ spec:
kind: ServerStatusRequest
listKind: ServerStatusRequestList
plural: serverstatusrequests
shortNames:
- ssr
singular: serverstatusrequest
preserveUnknownFields: false
scope: Namespaced
subresources:
status: {}
validation:
openAPIV3Schema:
description: ServerStatusRequest is a request to access current status information

File diff suppressed because one or more lines are too long

View File

@@ -26,3 +26,23 @@ rules:
- get
- patch
- update
- apiGroups:
- velero.io
resources:
- serverstatusrequests
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- velero.io
resources:
- serverstatusrequests/status
verbs:
- get
- patch
- update

View File

@@ -0,0 +1,25 @@
---
apiVersion: velero.io/v1
kind: ServerStatusRequest
metadata:
creationTimestamp: "2020-08-21T15:34:34Z"
generateName: velero-cli-
generation: 1
name: velero-cli-6wkzd
namespace: velero
resourceVersion: "544749"
selfLink: /apis/velero.io/v1/namespaces/velero/serverstatusrequests/velero-cli-6wkzd
uid: 335ea64e-1904-40ec-8106-1f2b22e9540e
spec: {}
status:
phase: Processed
plugins:
- kind: ObjectStore
name: velero.io/aws
- kind: VolumeSnapshotter
name: velero.io/aws
- kind: BackupItemAction
name: velero.io/crd-remap-version
- kind: BackupItemAction
name: velero.io/pod
processedTimestamp: "2020-08-21T15:34:34Z"

View File

@@ -276,7 +276,7 @@ The value for these flags will be stored as annotations.
#### Handling CA certs
In anticipation of a new configuration implementation to handle custom CA certs (as per design doc https://github.com/vmware-tanzu/velero/blob/master/design/custom-ca-support.md), a new flag `velero storage-location create/set --cacert-file mapStringString` is proposed. It sets the configuration to use for creating a secret containing a custom certificate for an S3 location of a plugin provider. Format is provider:path-to-file.
In anticipation of a new configuration implementation to handle custom CA certs (as per design doc https://github.com/vmware-tanzu/velero/blob/main/design/custom-ca-support.md), a new flag `velero storage-location create/set --cacert-file mapStringString` is proposed. It sets the configuration to use for creating a secret containing a custom certificate for an S3 location of a plugin provider. Format is provider:path-to-file.
See discussion https://github.com/vmware-tanzu/velero/pull/2259#discussion_r384700723 for more clarification.
@@ -370,4 +370,4 @@ https://github.com/jpeach/contour/tree/1c575c772e9fd747fba72ae41ab99bdae7a01864/
## Security Considerations
N/A
N/A

View File

@@ -306,16 +306,16 @@ Without these objects, the provider-level snapshots cannot be located in order t
[1]: https://kubernetes.io/blog/2018/10/09/introducing-volume-snapshot-alpha-for-kubernetes/
[2]: https://github.com/kubernetes-csi/external-snapshotter/blob/master/pkg/apis/volumesnapshot/v1alpha1/types.go#L41
[3]: https://github.com/kubernetes-csi/external-snapshotter/blob/master/pkg/apis/volumesnapshot/v1alpha1/types.go#L161
[4]: https://github.com/heptio/velero/blob/master/pkg/volume/snapshot.go#L21
[5]: https://github.com/heptio/velero/blob/master/pkg/apis/velero/v1/pod_volume_backup.go#L88
[4]: https://github.com/heptio/velero/blob/main/pkg/volume/snapshot.go#L21
[5]: https://github.com/heptio/velero/blob/main/pkg/apis/velero/v1/pod_volume_backup.go#L88
[6]: https://github.com/heptio/velero-csi-plugin/
[7]: https://github.com/heptio/velero/blob/master/pkg/plugin/velero/volume_snapshotter.go#L26
[8]: https://github.com/heptio/velero/blob/master/pkg/controller/backup_controller.go#L560
[9]: https://github.com/heptio/velero/blob/master/pkg/persistence/object_store.go#L46
[10]: https://github.com/heptio/velero/blob/master/pkg/apis/velero/v1/labels_annotations.go#L21
[11]: https://github.com/heptio/velero/blob/master/pkg/cmd/server/server.go#L471
[12]: https://github.com/heptio/velero/blob/master/pkg/cmd/util/output/backup_describer.go
[13]: https://github.com/heptio/velero/blob/master/pkg/cmd/util/output/backup_describer.go#L214
[7]: https://github.com/heptio/velero/blob/main/pkg/plugin/velero/volume_snapshotter.go#L26
[8]: https://github.com/heptio/velero/blob/main/pkg/controller/backup_controller.go#L560
[9]: https://github.com/heptio/velero/blob/main/pkg/persistence/object_store.go#L46
[10]: https://github.com/heptio/velero/blob/main/pkg/apis/velero/v1/labels_annotations.go#L21
[11]: https://github.com/heptio/velero/blob/main/pkg/cmd/server/server.go#L471
[12]: https://github.com/heptio/velero/blob/main/pkg/cmd/util/output/backup_describer.go
[13]: https://github.com/heptio/velero/blob/main/pkg/cmd/util/output/backup_describer.go#L214
[14]: https://github.com/kubernetes/kubernetes/blob/8ea9edbb0290e9de1e6d274e816a4002892cca6f/pkg/controller/volume/persistentvolume/util/util.go#L69
[15]: https://github.com/kubernetes/kubernetes/pull/30285
[16]: https://github.com/kubernetes/kubernetes/blob/master/pkg/apis/core/types.go#L237

View File

@@ -73,8 +73,8 @@ This same approach can be taken for CA bundles. The bundle can be stored in a
secret which is referenced on the BSL and written to a temp file prior to
invoking Restic.
[1](https://github.com/vmware-tanzu/velero/blob/master/pkg/restic/repository_manager.go#L238-L245)
[2](https://github.com/vmware-tanzu/velero/blob/master/pkg/restic/common.go#L168-L203)
[1](https://github.com/vmware-tanzu/velero/blob/main/pkg/restic/repository_manager.go#L238-L245)
[2](https://github.com/vmware-tanzu/velero/blob/main/pkg/restic/common.go#L168-L203)
## Detailed Design
@@ -126,7 +126,7 @@ would look like:
$ velero client config set cacert PATH
```
[1]: https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/master/velero-plugin-for-aws/object_store.go#L135
[2]: https://github.com/vmware-tanzu/velero/blob/master/pkg/restic/command.go#L47
[3]: https://github.com/restic/restic/blob/master/internal/backend/http_transport.go#L81
[4]: https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/master/velero-plugin-for-aws/object_store.go#L154
[1]: https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/main/velero-plugin-for-aws/object_store.go#L135
[2]: https://github.com/vmware-tanzu/velero/blob/main/pkg/restic/command.go#L47
[3]: https://github.com/restic/restic/blob/main/internal/backend/http_transport.go#L81
[4]: https://github.com/vmware-tanzu/velero-plugin-for-aws/blob/main/velero-plugin-for-aws/object_store.go#L154

View File

@@ -0,0 +1,199 @@
# Delete Item Action Plugins
## Abstract
Velero should provide a way to delete items created during a backup, with a model and interface similar to that of BackupItemAction and RestoreItemAction plugins.
These plugins would be invoked when a backup is deleted, and would receive items from within the backup tarball.
## Background
As part of Container Storage Interface (CSI) snapshot support, Velero added a new pattern for backing up and restoring snapshots via BackupItemAction and RestoreItemAction plugins.
When others have tried to use this pattern, however, they encountered issues with deleting the resources made in their own ItemAction plugins, as Velero does not expose any sort of extension at backup deletion time.
These plugins largely seek to delete resources that exist outside of Kubernetes.
This design seeks to provide the missing extension point.
## Goals
- Provide a DeleteItemAction API for plugins to implement
- Update Velero backup deletion logic to invoke registered DeleteItemAction plugins.
## Non Goals
- Specific implementations of hte DeleteItemAction API beyond test cases.
- Rollback of DeleteItemAction execution.
## High-Level Design
The DeleteItemAction plugin API will closely resemble the RestoreItemAction plugin design, in that plugins will receive the Velero `Backup` Go struct that is being deleted and a matching Kubernetes resource extracted from the backup tarball.
The Velero backup deletion process will be modified so that if there are any DeleteItemAction plugins registered, the backup tarball will be downloaded and extracted, similar to how restore logic works now.
Then, each item in the backup tarball will be iterated over to see if a DeleteItemAction plugin matches for it.
If a DeleteItemAction plugin matches, the `Backup` and relevant item will be passed to the DeleteItemAction.
The DeleteItemAction plugins will be run _first_ in the backup deletion process, before deleting snapshots from storage or `Restore`s from the Kubernetes API server.
DeleteItemAction plugins *cannot* rollback their actions.
This is because there is currently no way to recover other deleted components of a backup, such as volume/restic snapshots or other DeleteItemAction resources.
DeleteItemAction plugins will be run in alphanumeric order based on their registered names.
## Detailed Design
### New types
The `DeleteItemAction` interface is as follows:
```go
// DeleteItemAction is an actor that performs an action based on an item in a backup that is being deleted.
type DeleteItemAction interface {
// AppliesTo returns information about which resources this action should be invoked for.
// A DeleteItemAction's Execute function will only be invoked on items that match the returned
// selector. A zero-valued ResourceSelector matches all resources.
AppliesTo() (ResourceSelector, error)
// Execute allows the ItemAction to perform arbitrary logic with the item being deleted.
Execute(DeleteItemActionInput) error
}
```
The `DeleteItemActionInput` type is defined as follows:
```go
type DeleteItemActionInput struct {
// Item is the item taken from the pristine backed up version of resource.
Item runtime.Unstructured
// Backup is the representation of the backup resource processed by Velero.
Backup *api.Backup
}
```
Both `DeleteItemAction` and `DeleteItemActionInput` will be defined in `pkg/plugin/velero/delete_item_action.go`.
### Generate protobuf definitions and client/servers
In `pkg/plugin/proto`, add `DeleteItemAction.proto`.
Protobuf definitions will be necessary for:
```protobuf
message DeleteItemActionExecuteRequest {
...
}
message DeleteItemActionExecuteResponse {
...
}
message DeleteItemActionAppliesToRequest {
...
}
message DeleteItemActionAppliesToResponse {
...
}
service DeleteItemAction {
rpc AppliesTo(DeleteItemActionAppliesToRequest) returns (DeleteItemActionAppliesToResponse)
rpc Execute(DeleteItemActionExecuteRequest) returns (DeleteItemActionExecuteResponse)
}
```
Once these are written, then a client and server implementation can be written in `pkg/plugin/framework/delete_item_action_client.go` and `pkg/plugin/framework/delete_item_action_server.go`, respectively.
These should be largely the same as the client and server implementations for `RestoreItemAction` and `BackupItemAction` plugins.
### Restartable delete plugins
Similar to `RestoreItemAction` and `BackupItemAction` plugins, restartable processes will need to be implemented.
In `pkg/plugin/clientmgmt`, add `restartable_delete_item_action.go`, creating the following unexported type:
```go
type restartableDeleteItemAction struct {
key kindAndName
sharedPluginProcess RestartableProcess
config map[string]string
}
// newRestartableDeleteItemAction returns a new restartableDeleteItemAction.
func newRestartableDeleteItemAction(name string, sharedPluginProcess RestartableProcess) *restartableDeleteItemAction {
// ...
}
// getDeleteItemAction returns the delete item action for this restartableDeleteItemAction. It does *not* restart the
// plugin process.
func (r *restartableDeleteItemAction) getDeleteItemAction() (velero.DeleteItemAction, error) {
// ...
}
// getDelegate restarts the plugin process (if needed) and returns the delete item action for this restartableDeleteItemAction.
func (r *restartableDeleteItemAction) getDelegate() (velero.DeleteItemAction, error) {
// ...
}
// AppliesTo restarts the plugin's process if needed, then delegates the call.
func (r *restartableDeleteItemAction) AppliesTo() (velero.ResourceSelector, error) {
// ...
}
// Execute restarts the plugin's process if needed, then delegates the call.
func (r *restartableDeleteItemAction) Execute(input *velero.DeleteItemActionInput) (error) {
// ...
}
```
This file will be very similar in structure to
### Plugin manager changes
Add the following methods to `pkg/plugin/clientmgmt/manager.go`'s `Manager` interface:
```go
type Manager interface {
...
// Get DeleteItemAction returns a DeleteItemAction plugin for name.
GetDeleteItemAction(name string) (DeleteItemAction, error)
// GetDeteteItemActions returns the all DeleteItemAction plugins.
GetDeleteItemActions() ([]DeleteItemAction, error)
}
```
The unexported `manager` type should implement both the `GetDeleteItemAction` and `GetDeleteItemActions`.
Both of these methods should have the same exception for `velero.io/`-prefixed plugins that all other types do.
`GetDeleteItemAction` and `GetDeleteItemActions` will invoke the `restartableDeleteItemAction` implementations.
### Deletion controller modifications
`pkg/controller/backup_deletion_controller.go` will be updated to have plugin management invoked.
In `processRequest`, before deleting snapshots, get any registered `DeleteItemAction` plugins.
If there are none, proceed as normal.
If there are one or more, download the backup tarball from backup storage, untar it to temporary storage, and iterate through the items, matching them to the applicable plugins.
## Alternatives Considered
Another proposal for higher level `DeleteItemActions` was initially included, which would require implementors to individually download the backup tarball themselves.
While this may be useful long term, it is not a good fit for the current goals as each plugin would be re-implementing a lot of boilerplate.
See the deletion-plugins.md file for this alternative proposal in more detail.
The `VolumeSnapshotter` interface is not generic enough to meet the requirements here, as it is specifically for taking snapshots of block devices.
## Security Considerations
By their nature, `DeleteItemAction` plugins will be deleting data, which would normally be a security concern.
However, these will only be invoked in two situations: either when a `BackupDeleteRequest` is sent via a user with the `velero` CLI or some other management system, or when a Velero `Backup` expires by going over its TTL.
Because of this, the data deletion is not a concern.
## Compatibility
In terms of backwards compatibility, this design should stay compatible with most Velero installations that are upgrading.
If not DeleteItemAction plugins are present, then the backup deletion process should proceed the same way it worked prior to their inclusion.
## Implementation
The implementation dependencies are, roughly, in the order as they are described in the [Detailed Design](#detailed-design) section.
## Open Issues

View File

@@ -0,0 +1,82 @@
# Deletion Plugins
Status: Alternative Proposal
## Abstract
Velero should introduce a new type of plugin that runs when a backup is deleted.
These plugins will delete any external resources associated with the backup so that they will not be left orphaned.
## Background
With the CSI plugin, Velero developers introduced a pattern of using BackupItemAction and RestoreItemAction plugins tied to PersistentVolumeClaims to create other resources to complete a backup.
In the CSI plugin case, Velero does clean up of these other resources, which are Kubernetes Custom Resources, within the core Velero server.
However, for external plugins that wish to use this same pattern, this is not a practical solution.
Velero's core cannot be extended for all possible Custom Resources, and not external resources that get created are Kubernetes Custom Resources.
Therefore, Velero needs some mechanism that allows plugin authors who have created resources within a BackupItemAction or RestoreItemAction plugin to ensure those resources are deleted, regardless of what system those resources reside in.
## Goals
- Provide a new plugin type in Velero that is invoked when a backup is deleted.
## Non Goals
- Implementations of specific deletion plugins.
- Rollback of deletion plugin execution.
## High-Level Design
Velero will provide a new plugin type that is similar to its existing plugin architecture.
These plugins will be referred to as `DeleteAction` plugins.
`DeleteAction` plugins will receive the `Backup` CustomResource being deleted on execution.
`DeleteAction` plugins cannot prevent deletion of an item.
This is because multiple `DeleteAction` plugins can be registered, and this proposal does not include rollback and undoing of a deletion action.
Thus, if multiple `DeleteAction` plugins have already run but another would request the deletion of a backup stopped, the backup that's retained would be inconsistent.
`DeleteActions` will apply to `Backup`s based on a label on the `Backup` itself.
In order to ensure that `Backup`s don't execute `DeleteAction` plugins that are not relevant to them, `DeleteAction` plugins can register an `AppliesTo` function which will define a label selector on Velero backups.
`DeleteActions` will be run in alphanumerical order by plugin name.
This order is somewhat arbitrary, but will be used to give authors and users a somewhat predictable order of events.
## Detailed Design
The `DeleteAction` plugins will implement the following Go interface, defined in `pkg/plugin/velero/deletion_action.go`:
```go
type DeleteAction struct {
// AppliesTo will match the DeleteAction plugin against Velero Backups that it should operate against.
AppliesTo()
// Execute runs the custom plugin logic and may connect to external services.
Execute(backup *api.backup) error
}
```
The following methods would be added to the `clientmgmt.Manager` interface in `pkg/pluginclientmgmt/manager.go`:
```
type Manager interface {
...
// GetDeleteActions returns the registered DeleteActions.
//TODO: do we need to get these by name, or can we get them all?
GetDeleteActions([]velero.DeleteAction, error)
...
```
## Alternatives Considered
TODO
## Security Considerations
TODO
## Compatibility
Backwards compatibility should be straight-forward; if there are no installed `DeleteAction` plugins, then the backup deletion process will proceed as it does today.
## Implementation
TODO
## Open Issues
In order to add a custom label to the backup, the backup must be modifiable inside of the `BackupItemActon` and `RestoreItemAction` plugins, which it currently is not. A work around for now is for the user to apply a label to the backup at creation time, but that is not ideal.

View File

@@ -3,7 +3,7 @@
Status: Accepted
Some features may take a while to get fully implemented, and we don't necessarily want to have long-lived feature branches
A simple feature flag implementation allows code to be merged into master, but not used unless a flag is set.
A simple feature flag implementation allows code to be merged into main, but not used unless a flag is set.
## Goals

View File

@@ -154,7 +154,7 @@ In order to know the CR created for the particular backup of a volume, Velero ad
- `velero.io/pv-name` with value as volume that is undergoing backup
Backup name being unique won't cause issues like duplicates in identifying the CR.
Labels will be set with the value returned from `GetValidName` function. (https://github.com/vmware-tanzu/velero/blob/master/pkg/label/label.go#L35).
Labels will be set with the value returned from `GetValidName` function. (https://github.com/vmware-tanzu/velero/blob/main/pkg/label/label.go#L35).
If Plugin supports showing progress of the operation it is performing, it does following:
- finds the VolumePluginBackup CR related to this backup operation by using `tags` passed in CreateSnapshot call
@@ -281,7 +281,7 @@ In order to know the CR created for the particular restore of a volume, Velero a
- `velero.io/snapshot-id` with value as snapshot id that need to be restored
- `velero.io/provider` with value as `Provider` in `VolumeSnapshotLocation`
Labels will be set with the value returned from `GetValidName` function. (https://github.com/vmware-tanzu/velero/blob/master/pkg/label/label.go#L35).
Labels will be set with the value returned from `GetValidName` function. (https://github.com/vmware-tanzu/velero/blob/main/pkg/label/label.go#L35).
Plugin will be able to identify CR by using snapshotID that it received as parameter of CreateVolumeFromSnapshot API, and plugin's Provider name.
It updates the progress of restore operation regularly if plugin supports feature of showing progress.
@@ -376,7 +376,7 @@ In order to know the CR created for the particular backup of a volume, volume sn
Backup name being unique won't cause issues like duplicates in identifying the CR.
Plugin need to sanitize the value that can be set for above labels. Label need to be set with the value returned from `GetValidName` function. (https://github.com/vmware-tanzu/velero/blob/master/pkg/label/label.go#L35).
Plugin need to sanitize the value that can be set for above labels. Label need to be set with the value returned from `GetValidName` function. (https://github.com/vmware-tanzu/velero/blob/main/pkg/label/label.go#L35).
Though no restrictions are required on the name of CR, as a general practice, volume snapshotter can name this CR with the value same as return value of CreateSnapshot.

View File

@@ -32,14 +32,14 @@ It will also update the `spec.volumeName` of the related persistent volume claim
## Detailed Design
In `pkg/restore/restore.go`, around [line 872](https://github.com/heptio/velero/blob/master/pkg/restore/restore.go#L872), Velero has special-case code for persistent volumes.
In `pkg/restore/restore.go`, around [line 872](https://github.com/vmware-tanzu/velero/blob/main/pkg/restore/restore.go#L872), Velero has special-case code for persistent volumes.
This code will be updated to check for the two preconditions described in the previous section.
If the preconditions are met, the object will be given a new name.
The persistent volume will also be annotated with the original name, e.g. `velero.io/original-pv-name=NAME`.
Importantly, the name change will occur **before** [line 890](https://github.com/heptio/velero/blob/master/pkg/restore/restore.go#L890), where Velero checks to see if it should restore the persistent volume.
Importantly, the name change will occur **before** [line 890](https://github.com/vmware-tanzu/velero/blob/main/pkg/restore/restore.go#L890), where Velero checks to see if it should restore the persistent volume.
Additionally, the old and new persistent volume names will be recorded in a new field that will be added to the `context` struct, `renamedPVs map[string]string`.
In the special-case code for persistent volume claims starting on [line 987](https://github.com/heptio/velero/blob/master/pkg/restore/restore.go#L987), Velero will check to see if the claimed persistent volume has been renamed by looking in `ctx.renamedPVs`.
In the special-case code for persistent volume claims starting on [line 987](https://github.com/heptio/velero/blob/main/pkg/restore/restore.go#L987), Velero will check to see if the claimed persistent volume has been renamed by looking in `ctx.renamedPVs`.
If so, Velero will update the persistent volume claim's `spec.volumeName` to the new name.
## Alternatives Considered

143
design/restore-hooks.md Normal file
View File

@@ -0,0 +1,143 @@
# Restore Hooks
This document proposes a solution that allows a user to specify Restore Hooks, much like Backup Hooks, that can be executed during the restore process.
## Goals
- Enable custom commands to be run during a restore in order to mirror the commands that are available to the backup process.
- Provide observability into the result of commands run in restored pods.
## Non Goals
- Handling any application specific scenarios (postgres, mongo, etc)
## Background
Velero supports Backup Hooks to execute commands before and/or after a backup.
This enables a user to, among other things, prepare data to be backed up without having to freeze an in-use volume.
An example of this would be to attach an empty volume to a Postgres pod, use a backup hook to execute `pg_dump` from the data volume, and back up the volume containing the export.
The problem is that there's no easy or automated way to include an automated restore process.
After a restore with the example configuration above, the postgres pod will be empty, but there will be a need to manually exec in and run `pg_restore`.
## High-Level Design
The Restore spec will have a `spec.hooks` section matching the same section on the Backup spec except no `pre` hooks can be defined - only `post`.
Annotations comparable to the annotations used during backup can also be set on pods.
For each restored pod, the Velero server will check if there are any hooks applicable to the pod.
If a restored pod has any applicable hooks, Velero will wait for the container where the hook is to be executed to reach status Running.
The Restore log will include the results of each post-restore hook and the Restore object status will incorporate the results of hooks.
The Restore log will include the results of each hook and the Restore object status will incorporate the results of hooks.
A new section at `spec.hooks.resources.initContainers` will allow for injecting initContainers into restored pods.
Annotations can be set as an alternative to defining the initContainers in the Restore object.
## Detailed Design
Post-restore hooks can be defined by annotation and/or by an array of resource hooks in the Restore spec.
The following annotations are supported:
- post.hook.restore.velero.io/container
- post.hook.restore.velero.io/command
- post.hook.restore.velero.io/on-error
- post.hook.restore.velero.io/exec-timeout
- post.hook.restore.velero.io/wait-timeout
Init restore hooks can be defined by annotation and/or in the new `initContainers` section in the Restore spec.
The initContainers schema is `pod.spec.initContainers`.
The following annotations are supported:
- init.hook.restore.velero.io/timeout
- init.hook.restore.velero.io/initContainers
This is an example of defining hooks in the Restore spec.
```yaml
apiVersion: velero.io/v1
kind: Restore
spec:
...
hooks:
resources:
-
name: my-hook
includedNamespaces:
- '*'
excludedNamespaces:
- some-namespace
includedResources:
- pods
excludedResources: []
labelSelector:
matchLabels:
app: velero
component: server
post:
-
exec:
container: postgres
command:
- /bin/bash
- -c
- rm /docker-entrypoint-initdb.d/dump.sql
onError: Fail
timeout: 10s
readyTimeout: 60s
init:
timeout: 120s
initContainers:
- name: restore
image: postgres:12
command: ["/bin/bash", "-c", "mv /backup/dump.sql /docker-entrypoint-initdb.d/"]
volumeMounts:
- name: backup
mountPath: /backup
```
As with Backups, if an annotation is defined on a pod then no hooks from the Restore spec will be applied.
### Implementation
The types and function in pkg/backup/item_hook_handler.go will be moved to a new package (pkg/hooks) and exported so they can be used for both backups and restores.
The post-restore hooks implementation will closely follow the design of restoring pod volumes with restic.
The pkg/restore.context type will have new fields `hooksWaitGroup` and `hooksErrs` comparable to `resticWaitGroup` and `resticErr`.
The pkg/restore.context.execute function will start a goroutine for each pod with applicable hooks and then continue with restoring other items.
Each hooks goroutine will create a pkg/util/hooks.ItemHookHandler for each pod and send any error on the context.hooksErrs channel.
The ItemHookHandler already includes stdout and stderr and other metadata in the Backup log so the same logs will automatically be added to the Restore log (passed as the first argument to the ItemHookhandler.HandleHooks method.)
The pkg/restore.context.execute function will wait for the hooksWaitGroup before returning.
Any errors received on context.hooksErrs will be added to errs.Velero.
One difference compared to the restic restore design is that any error on the context.hooksErrs channel will cancel the context of all hooks, since errors are only reported on this channel if the hook specified `onError: Fail`.
However, canceling the hooks goroutines will not cancel the restic goroutines.
In practice the restic goroutines will complete before the hooks since the hooks do not run until a pod is ready, but it's possible a hook will be executed and fail while a different pod is still in the pod volume restore phase.
Failed hooks with `onError: Continue` will appear in the Restore log but will not affect the status of the parent Restore.
Failed hooks with `onError: Fail` will cause the parent Restore to have status Partially Failed.
If initContainers are specified for a pod, Velero will inject the containers into the beginning of the pod's initContainers list.
If a restic initContainer is also being injected, the restore initContainers will be injected directly after the restic initContainer.
The restore will use a RestoreItemAction to inject the initContainers.
Stdout and stderr of the restore initContainers will not be added to the Restore logs.
InitContainers that fail will not affect the parent Restore's status.
## Alternatives Considered
Wait for all restored Pods to report Ready, then execute the first hook in all applicable Pods simultaneously, then proceed to the next hook, etc.
That could introduce deadlock, e.g. if an API pod cannot be ready until the DB pod is restored.
Put the restore hooks on the Backup spec as a third lifecycle event named `restore` along with `pre` and `post`.
That would be confusing since `pre` and `post` would appear in the Backup log but `restore` would only be in the Restore log.
Execute restore hooks in parallel for each Pod.
That would not match the behavior of Backups.
Wait for PodStatus ready before executing the post-restore hooks in any container.
There are cases where the pod should not report itself ready until after the restore hook has run.
Include the logs from initContainers in the Restore log.
Unlike exec hooks where stdout and stderr are permanently lost if not added to the Restore log, the logs of the injected initContainers are available through the K8s API with kubectl or another client.
## Security Considerations
Stdout or stderr in the Restore log may contain sensitive information, but the same risk already exists for Backup hooks.

11
go.mod
View File

@@ -21,22 +21,25 @@ require (
github.com/kubernetes-csi/external-snapshotter/v2 v2.2.0-rc1
github.com/onsi/ginkgo v1.13.0
github.com/onsi/gomega v1.10.1
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v1.0.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.5.1
github.com/robfig/cron v1.1.0
github.com/sirupsen/logrus v1.4.2
github.com/spf13/afero v1.2.2
github.com/spf13/cobra v0.0.5
github.com/spf13/cobra v0.0.6
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7
google.golang.org/grpc v1.28.0
google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485 // indirect
google.golang.org/grpc v1.31.0
google.golang.org/protobuf v1.25.0 // indirect
k8s.io/api v0.18.4
k8s.io/apiextensions-apiserver v0.18.4
k8s.io/apimachinery v0.18.4
k8s.io/cli-runtime v0.18.4
k8s.io/client-go v0.18.4
k8s.io/klog v1.0.0
sigs.k8s.io/cluster-api v0.3.8
sigs.k8s.io/controller-runtime v0.6.1
)

138
go.sum
View File

@@ -14,16 +14,12 @@ github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/azure-sdk-for-go v42.0.0+incompatible h1:yz6sFf5bHZ+gEOQVuK5JhPqTTAmv+OvSLSaqgzqaCwY=
github.com/Azure/azure-sdk-for-go v42.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
github.com/Azure/go-autorest/autorest v0.9.6 h1:5YWtOnckcudzIw8lPPBcWOnmIFWMtHci1ZWAZulMSx0=
github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk=
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
@@ -31,12 +27,10 @@ github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwp
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
@@ -55,25 +49,28 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA=
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/hcsshim v0.0.0-20190417211021-672e52e9209d/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o=
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Rican7/retry v0.1.0/go.mod h1:FgOROf8P5bebcC1DS0PdOQiqGUridaZvikzUmkFW6gg=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053/go.mod h1:xW8sBma2LE3QxFSzCnH9qe6gAE2yO9GvQaWwX89HxbE=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -89,19 +86,25 @@ github.com/bazelbuild/buildtools v0.0.0-20190731111112-f720930ceb60/go.mod h1:5J
github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU=
github.com/bazelbuild/rules_go v0.0.0-20190719190356-6dae44dc5cab/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/caddyserver/caddy v1.0.3 h1:i9gRhBgvc5ifchwWtSe7pDpsdS9+Q0Rw9oYQmYUTw1w=
github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/prettybench v0.0.0-20150116022406-03b8cfe5406c/go.mod h1:Xe6ZsFhtM8HrDku0pxJ3/Lr51rwykrzgFwpmTzleatY=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/checkpoint-restore/go-criu v0.0.0-20181120144056-17b0214f6c48/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
@@ -118,17 +121,25 @@ github.com/containerd/containerd v1.0.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
github.com/containerd/typeurl v0.0.0-20190228175220-2a93cfde8c20/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
github.com/coredns/corefile-migration v1.0.6/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E=
github.com/coredns/corefile-migration v1.0.7 h1:T2eOj/NKN1Q1W1bD9MFeZiBYryS0JlWT6aROAvVWFSs=
github.com/coredns/corefile-migration v1.0.7/go.mod h1:OFwBp/Wc9dJt5cAZzHWMNhK1r5L0p0jDwIBc6j8NC8E=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -137,9 +148,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.3.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
@@ -150,7 +163,10 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ
github.com/docker/spdystream v0.0.0-20170912183627-bc6354cbbc29 h1:llBx5m8Gk0lrAaiLud2wktkX/e8haX7Ru0oVfQqtZQ4=
github.com/docker/spdystream v0.0.0-20170912183627-bc6354cbbc29/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/drone/envsubst v1.0.3-0.20200709223903-efdb65b94e5a h1:pf3CyiWgjOLL7cjFos89AEOPCWSOoQt7tgbEk/SvBAg=
github.com/drone/envsubst v1.0.3-0.20200709223903-efdb65b94e5a/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
@@ -182,8 +198,10 @@ github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG
github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
@@ -277,6 +295,7 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
@@ -300,14 +319,19 @@ github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAO
github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8=
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/cadvisor v0.35.0/go.mod h1:1nql6U13uTHaLYB8rLS5x9IJc2qT6Xd/Tr1sTX6NE48=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
@@ -326,17 +350,24 @@ github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTV
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
@@ -349,6 +380,7 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
@@ -366,10 +398,12 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@@ -412,6 +446,7 @@ github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H7
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -424,6 +459,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
@@ -443,6 +479,7 @@ github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
@@ -467,6 +504,7 @@ github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -485,6 +523,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v1.0.0-rc10/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@@ -492,28 +532,39 @@ github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/ffjson v0.0.0-20180717144149-af8b230fcd20/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
@@ -525,6 +576,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
@@ -534,6 +586,7 @@ github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -542,20 +595,25 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -564,6 +622,9 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -573,12 +634,17 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
@@ -592,10 +658,14 @@ github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv
github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netns v0.0.0-20171111001504-be1fbeda1936/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
@@ -669,6 +739,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -681,8 +752,9 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -722,6 +794,8 @@ golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -789,8 +863,9 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -799,25 +874,34 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191220175831-5c49e3ecc1c1 h1:PlscBL5CvF+v1mNR82G+i4kACGq2JQvKDnNq7LSS65o=
google.golang.org/genproto v0.0.0-20191220175831-5c49e3ecc1c1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485 h1:wTk5DQB3+1darAz4Ldomo0r5bUOCKX7gilxQ4sb2kno=
google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -831,6 +915,8 @@ gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
@@ -842,9 +928,11 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/gotestsum v0.3.5/go.mod h1:Mnf3e5FUzXbkCfynWBGOwLssY7gTQgCHObK9tMpAriY=
@@ -861,14 +949,17 @@ k8s.io/apiextensions-apiserver v0.18.4 h1:Y3HGERmS8t9u12YNUFoOISqefaoGRuTc43AYCL
k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio=
k8s.io/apimachinery v0.18.4 h1:ST2beySjhqwJoIFk6p7Hp5v5O0hYY6Gngq/gUYXTPIA=
k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
k8s.io/apiserver v0.18.4 h1:pn1jSQkfboPSirZopkVpEdLW4FcQLnYMaIY8LFxxj30=
k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8=
k8s.io/cli-runtime v0.18.4 h1:IUx7quIOb4gbQ4M+B1ksF/PTBovQuL5tXWzplX3t+FM=
k8s.io/cli-runtime v0.18.4/go.mod h1:9/hS/Cuf7NVzWR5F/5tyS6xsnclxoPLVtwhnkJG1Y4g=
k8s.io/client-go v0.18.4 h1:un55V1Q/B3JO3A76eS0kUSywgGK/WR3BQ8fHQjNa6Zc=
k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g=
k8s.io/cloud-provider v0.18.4/go.mod h1:JdI6cuSFPSPANEciv0v5qfwztkeyFCVc1S3krLYrw0E=
k8s.io/cluster-bootstrap v0.18.4 h1:TlH1HzHdANqE4d4Gw/9eENtGkEmAQVq8e4VGYPRupfc=
k8s.io/cluster-bootstrap v0.18.4/go.mod h1:hNG705ec9SMN2BGlJ81R2CnyJjNKfROtAxvI9JXZdiM=
k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
k8s.io/component-base v0.18.4 h1:Kr53Fp1iCGNsl9Uv4VcRvLy7YyIqi9oaJOQ7SXtKI98=
k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk=
k8s.io/cri-api v0.18.4/go.mod h1:OJtpjDvfsKoLGhvcc0qfygved0S0dGX56IJzPbqTG1s=
k8s.io/csi-translation-lib v0.18.4/go.mod h1:FTci2m8/3oN8E+8OyblBXei8w4mwbiH4boNPeob4piE=
@@ -897,8 +988,9 @@ k8s.io/repo-infra v0.0.1-alpha.1/go.mod h1:wO1t9WaB99V80ljbeENTnayuEEwNZt7gECYh/
k8s.io/sample-apiserver v0.18.4/go.mod h1:j5XH5FUmMd/ztoz+9ch0+hL+lsvWdgxnTV7l3P3Ijoo=
k8s.io/system-validators v1.0.4/go.mod h1:HgSgTg4NAGNoYYjKsUyk52gdNi2PVDswQ9Iyn66R7NI=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE=
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20200619165400-6e3d28b6ed19 h1:7Nu2dTj82c6IaWvL7hImJzcXoTPz1MsSCH7r+0m6rfo=
k8s.io/utils v0.0.0-20200619165400-6e3d28b6ed19/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
@@ -912,8 +1004,12 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
sigs.k8s.io/cluster-api v0.3.8 h1:YYaAzXP+bHzqIQTJoJXMIT4QN4MjIep9NnxwBDPjiD8=
sigs.k8s.io/cluster-api v0.3.8/go.mod h1:j2beYKyad77JkeGaiv4l2obt81C3eqxfZGFDqX0YWjs=
sigs.k8s.io/controller-runtime v0.5.9/go.mod h1:UI/unU7Q+mo/rWBrND0NAaVNj/Xjh/+aqSv/M3njpmo=
sigs.k8s.io/controller-runtime v0.6.1 h1:LcK2+nk0kmaOnKGN+vBcWHqY5WDJNJNB/c5pW+sU8fc=
sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A=
sigs.k8s.io/kind v0.7.1-0.20200303021537-981bd80d3802/go.mod h1:HIZ3PWUezpklcjkqpFbnYOqaqsAE1JeCTEwkgvPLXjk=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E=

View File

@@ -14,9 +14,11 @@
FROM golang:1.14
ARG GOPROXY
ENV GO111MODULE=on
# Use a proxy for go modules to reduce the likelihood of various hosts being down and breaking the build
ENV GOPROXY=https://proxy.golang.org
ENV GOPROXY=${GOPROXY}
# get code-generation tools (for now keep in GOPATH since they're not fully modules-compatible yet)
RUN mkdir -p /go/src/k8s.io
@@ -54,4 +56,9 @@ RUN wget --quiet https://github.com/goreleaser/goreleaser/releases/download/v0.1
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.27.0
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.27.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/amd64/kubectl
RUN chmod +x ./kubectl
RUN mv ./kubectl /usr/local/bin

View File

@@ -2,6 +2,8 @@
# Copyright 2016 The Kubernetes Authors.
#
# Modifications 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
@@ -18,40 +20,39 @@ set -o errexit
set -o nounset
set -o pipefail
if [ -z "${PKG}" ]; then
if [[ -z "${PKG}" ]]; then
echo "PKG must be set"
exit 1
fi
if [ -z "${BIN}" ]; then
if [[ -z "${BIN}" ]]; then
echo "BIN must be set"
exit 1
fi
if [ -z "${GOOS}" ]; then
if [[ -z "${GOOS}" ]]; then
echo "GOOS must be set"
exit 1
fi
if [ -z "${GOARCH}" ]; then
if [[ -z "${GOARCH}" ]]; then
echo "GOARCH must be set"
exit 1
fi
if [ -z "${VERSION}" ]; then
if [[ -z "${VERSION}" ]]; then
echo "VERSION must be set"
exit 1
fi
if [ -z "${GIT_SHA}" ]; then
if [[ -z "${GIT_SHA}" ]]; then
echo "GIT_SHA must be set"
exit 1
fi
export CGO_ENABLED=0
if [[ -z "${GIT_DIRTY}" ]]; then
GIT_TREE_STATE=clean
else
GIT_TREE_STATE=dirty
if [[ -z "${GIT_TREE_STATE}" ]]; then
echo "GIT_TREE_STATE must be set"
exit 1
fi
export CGO_ENABLED=0
LDFLAGS="-X ${PKG}/pkg/buildinfo.Version=${VERSION}"
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.GitSHA=${GIT_SHA}"
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.GitTreeState=${GIT_TREE_STATE}"

View File

@@ -14,9 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# docker-push is invoked by the CI/CD system to deploy docker images to Docker Hub.
# It will build images for all commits to master and all git tags.
# The highest, non-prerelease semantic version will also be given the `latest` tag.
set +x
@@ -37,7 +34,7 @@ if ls ${change_log_file} 1> /dev/null 2>&1; then
echo "changelog for PR ${pr_number} exists"
exit 0
else
echo "PR ${pr_number} is missing a changelog. Please refer https://velero.io/docs/master/code-standards/#adding-a-changelog and add a changelog."
echo "PR ${pr_number} is missing a changelog. Please refer https://velero.io/docs/main/code-standards/#adding-a-changelog and add a changelog."
exit 1
fi

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# Copyright 2019 the Velero contributors.
# 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.
@@ -15,7 +15,7 @@
# limitations under the License.
# docker-push is invoked by the CI/CD system to deploy docker images to Docker Hub.
# It will build images for all commits to master and all git tags.
# It will build images for all commits to main and all git tags.
# The highest, non-prerelease semantic version will also be given the `latest` tag.
set +x
@@ -56,34 +56,43 @@ elif [[ "$triggeredBy" == "tags" ]]; then
TAG=$(echo $GITHUB_REF | cut -d / -f 3)
fi
if [[ "$BRANCH" == "master" ]]; then
if [[ "$BRANCH" == "main" ]]; then
VERSION="$BRANCH"
elif [[ ! -z "$TAG" ]]; then
# Explicitly checkout tags when building from a git tag.
# This is not needed when building from master
# This is not needed when building from main
git fetch --tags
# Calculate the latest release if there's a tag.
highest_release
VERSION="$TAG"
else
echo "We're not on master and we're not building a tag, exit early."
echo "We're not on main and we're not building a tag, exit early."
exit 0
fi
# Assume we're not tagging `latest` by default, and never on master.
# Assume we're not tagging `latest` by default, and never on main.
TAG_LATEST=false
if [[ "$BRANCH" == "master" ]]; then
echo "Building master, not tagging latest."
if [[ "$BRANCH" == "main" ]]; then
echo "Building main, not tagging latest."
elif [[ "$TAG" == "$HIGHEST" ]]; then
TAG_LATEST=true
fi
if [[ -z "$BUILDX_PLATFORMS" ]]; then
BUILDX_PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7,linux/ppc64le"
fi
# Debugging info
echo "Highest tag found: $HIGHEST"
echo "BRANCH: $BRANCH"
echo "TAG: $TAG"
echo "TAG_LATEST: $TAG_LATEST"
echo "BUILDX_PLATFORMS: $BUILDX_PLATFORMS"
echo "Building and pushing container images."
VERSION="$VERSION" TAG_LATEST="$TAG_LATEST" make all-containers all-push all-manifests
VERSION="$VERSION" \
TAG_LATEST="$TAG_LATEST" \
BUILDX_PLATFORMS="$BUILDX_PLATFORMS" \
BUILDX_OUTPUT_TYPE="registry" \
make all-containers

54
hack/download-restic.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
# 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.
set -o errexit
set -o nounset
set -o pipefail
if [[ -z "${BIN}" ]]; then
echo "BIN must be set"
exit 1
fi
if [[ "${BIN}" != "velero" ]]; then
echo "${BIN} does not need the restic binary"
exit 0
fi
if [[ -z "${GOOS}" ]]; then
echo "GOOS must be set"
exit 1
fi
if [[ -z "${GOARCH}" ]]; then
echo "GOARCH must be set"
exit 1
fi
if [[ -z "${RESTIC_VERSION}" ]]; then
echo "RESTIC_VERSION must be set"
exit 1
fi
# TODO: when the new restic version is released, make ppc64le to be also downloaded from their github releases.
# This has been merged and will be applied to next release: https://github.com/restic/restic/pull/2342
if [[ "${GOARCH}" = "ppc64le" ]]; then
wget --timeout=1 --tries=5 --quiet https://oplab9.parqtec.unicamp.br/pub/ppc64el/restic/restic-${RESTIC_VERSION} -O /output/usr/bin/restic
else
wget --quiet https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_${GOOS}_${GOARCH}.bz2
bunzip2 restic_${RESTIC_VERSION}_${GOOS}_${GOARCH}.bz2
mv restic_${RESTIC_VERSION}_${GOOS}_${GOARCH} /output/usr/bin/restic
fi
chmod +x /output/usr/bin/restic

View File

@@ -1,108 +0,0 @@
#!/bin/bash
# Copyright 2019 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.
# gen-docs.sh is used for the "make gen-docs" target. See additional
# documentation in the Makefile.
set -o errexit
set -o nounset
set -o pipefail
# don't run if there's already a directory for the target docs version
if [[ -d site/docs/$NEW_DOCS_VERSION ]]; then
echo "ERROR: site/docs/$NEW_DOCS_VERSION already exists"
exit 1
fi
# get the alphabetically last item in site/docs to use as PREVIOUS_DOCS_VERSION
# if not explicitly specified by the user
if [[ -z "${PREVIOUS_DOCS_VERSION:-}" ]]; then
echo "PREVIOUS_DOCS_VERSION was not specified, getting the latest version"
PREVIOUS_DOCS_VERSION=$(ls -1 site/docs/ | tail -n 1)
fi
# make a copy of the previous versioned docs dir
echo "Creating copy of docs directory site/docs/$PREVIOUS_DOCS_VERSION in site/docs/$NEW_DOCS_VERSION"
cp -r site/docs/${PREVIOUS_DOCS_VERSION}/ site/docs/${NEW_DOCS_VERSION}/
# 'git add' the previous version's docs as-is so we get a useful diff when we copy the master docs in
echo "Running 'git add' for previous version's doc contents to use as a base for diff"
git add site/docs/${NEW_DOCS_VERSION}
# now copy the contents of site/docs/master into the same directory so we can get a nice
# git diff of what changed since previous version
echo "Copying site/docs/master/ to site/docs/${NEW_DOCS_VERSION}/"
rm -rf site/docs/${NEW_DOCS_VERSION}/ && cp -r site/docs/master/ site/docs/${NEW_DOCS_VERSION}/
# make a copy of the previous versioned ToC
NEW_DOCS_TOC="$(echo ${NEW_DOCS_VERSION} | tr . -)-toc"
PREVIOUS_DOCS_TOC="$(echo ${PREVIOUS_DOCS_VERSION} | tr . -)-toc"
echo "Creating copy of site/_data/$PREVIOUS_DOCS_TOC.yml at site/_data/$NEW_DOCS_TOC.yml"
cp site/_data/$PREVIOUS_DOCS_TOC.yml site/_data/$NEW_DOCS_TOC.yml
# 'git add' the previous version's ToC content as-is so we get a useful diff when we copy the master ToC in
echo "Running 'git add' for previous version's ToC to use as a base for diff"
git add site/_data/$NEW_DOCS_TOC.yml
# now copy the master ToC so we can get a nice git diff of what changed since previous version
echo "Copying site/_data/master-toc.yml to site/_data/$NEW_DOCS_TOC.yml"
rm site/_data/$NEW_DOCS_TOC.yml && cp site/_data/master-toc.yml site/_data/$NEW_DOCS_TOC.yml
# replace known version-specific links -- the sed syntax is slightly different in OS X and Linux,
# so check which OS we're running on.
if [[ $(uname) == "Darwin" ]]; then
echo "[OS X] updating version-specific links"
find site/docs/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i '' "s|https://velero.io/docs/master|https://velero.io/docs/$VELERO_VERSION|g"
find site/docs/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i '' "s|https://github.com/vmware-tanzu/velero/blob/master|https://github.com/vmware-tanzu/velero/blob/$VELERO_VERSION|g"
echo "[OS X] Updating latest version in _config.yml"
sed -i '' "s/latest: ${PREVIOUS_DOCS_VERSION}/latest: ${NEW_DOCS_VERSION}/" site/_config.yml
# newlines and lack of indentation are requirements for this sed syntax
# which is doing an append
echo "[OS X] Adding latest version to versions list in _config.yml"
sed -i '' "/- master/a\\
- ${NEW_DOCS_VERSION}
" site/_config.yml
echo "[OS X] Adding ToC mapping entry"
sed -i '' "/master: master-toc/a\\
${NEW_DOCS_VERSION}: ${NEW_DOCS_TOC}
" site/_data/toc-mapping.yml
else
echo "[Linux] updating version-specific links"
find site/docs/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i'' "s|https://velero.io/docs/master|https://velero.io/docs/$VELERO_VERSION|g"
find site/docs/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i'' "s|https://github.com/vmware-tanzu/velero/blob/master|https://github.com/vmware-tanzu/velero/blob/$VELERO_VERSION|g"
echo "[Linux] Updating latest version in _config.yml"
sed -i'' "s/latest: ${PREVIOUS_DOCS_VERSION}/latest: ${NEW_DOCS_VERSION}/" site/_config.yml
echo "[Linux] Adding latest version to versions list in _config.yml"
sed -i'' "/- master/a - ${NEW_DOCS_VERSION}" site/_config.yml
echo "[Linux] Adding ToC mapping entry"
sed -i'' "/master: master-toc/a ${NEW_DOCS_VERSION}: ${NEW_DOCS_TOC}" site/_data/toc-mapping.yml
fi
echo "Success! site/docs/$NEW_DOCS_VERSION has been created."
echo ""
echo "The next steps are:"
echo " 1. Consult site/README-JEKYLL.md for further manual steps required to finalize the new versioned docs generation."
echo " 2. Run a 'git diff' to review all changes made to the docs since the previous version."
echo " 3. Make any manual changes/corrections necessary."
echo " 4. Run 'git add' to stage all unstaged changes, then 'git commit'."

View File

@@ -1,34 +0,0 @@
#!/bin/bash
#
# Copyright 2019 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.
set -o errexit
set -o nounset
set -o pipefail
if [ -z "${RESTIC_VERSION}" ]; then
echo "RESTIC_VERSION must be set"
exit 1
fi
if [ ! -d "_output/bin/linux/ppc64le/" ]; then
mkdir -p _output/bin/linux/ppc64le/
fi
wget --quiet https://oplab9.parqtec.unicamp.br/pub/ppc64el/restic/restic-${RESTIC_VERSION}
mv restic-${RESTIC_VERSION} _output/bin/linux/ppc64le/restic
chmod +x _output/bin/linux/ppc64le/restic

View File

@@ -22,13 +22,13 @@ import (
"regexp"
)
// This regex should match both our GA format (example: v1.4.3) and pre-release format (v1.2.4-beta.2)
// This regex should match both our GA format (example: v1.4.3) and pre-release formats (v1.2.4-beta.2, v1.5.0-rc.1)
// The following sub-capture groups are defined:
// major
// minor
// patch
// prerelease (this will be alpha/beta followed by a ".", followed by 1 or more digits (alpha.5)
var release_regex *regexp.Regexp = regexp.MustCompile("^v(?P<major>[[:digit:]]+)\\.(?P<minor>[[:digit:]]+)\\.(?P<patch>[[:digit:]]+)(-{1}(?P<prerelease>(alpha|beta)\\.[[:digit:]]+))*")
// prerelease (this will be alpha/beta/rc followed by a ".", followed by 1 or more digits (alpha.5)
var release_regex *regexp.Regexp = regexp.MustCompile("^v(?P<major>[[:digit:]]+)\\.(?P<minor>[[:digit:]]+)\\.(?P<patch>[[:digit:]]+)(-{1}(?P<prerelease>(alpha|beta|rc)\\.[[:digit:]]+))*")
// This small program exists because checking the VELERO_VERSION rules in bash is difficult, and difficult to test for correctness.
// Calling it with --verify will verify whether or not the VELERO_VERSION environment variable is a valid version string, without parsing for its components.

142
hack/release-tools/gen-docs.sh Executable file
View File

@@ -0,0 +1,142 @@
#!/bin/bash
# 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.
# gen-docs.sh is used for the "make gen-docs" target. It generates a new
# versioned docs directory under site/content/docs. It follows
# the following process:
# 1. Copies the contents of the most recently tagged docs directory into the new
# directory, to establish a useful baseline to diff against.
# 2. Adds all copied content from step 1 to git's staging area via 'git add'.
# 3. Replaces the contents of the new docs directory with the contents of the
# 'main' docs directory, updating any version-specific links (e.g. to a
# specific branch of the GitHub repository) to use the new version
# 4. Copies the previous version's ToC file and runs 'git add' to establish
# a useful baseline to diff against.
# 5. Replaces the content of the new ToC file with the main ToC.
# 6. Update site/config.yaml and site/_data/toc-mapping.yml to include entries
# for the new version.
#
# The unstaged changes in the working directory can now easily be diff'ed against the
# staged changes using 'git diff' to review all docs changes made since the previous
# tagged version. Once the unstaged changes are ready, they can be added to the
# staging area using 'git add' and then committed.
#
# NEW_DOCS_VERSION defines the version that the docs will be tagged with
# (i.e. whats in the URL, what shows up in the version dropdown on the site).
# This should be formatted as either v1.4 (for any GA release, including minor), or v1.5.0-beta.1/v1.5.0-rc.1 (for an alpha/beta/RC).
# To run gen-docs: "VELERO_VERSION=v1.4.0 NEW_DOCS_VERSION=v1.4 PREVIOUS_DOCS_VERSION= make gen-docs"
# Note: if PREVIOUS_DOCS_VERSION is not set, the script will copy from the
# latest version.
#
# **NOTE**: there are additional manual steps required to finalize the process of generating
# a new versioned docs site. The full process is documented in site/README-HUGO.md
set -o errexit
set -o nounset
set -o pipefail
DOCS_DIRECTORY=site/content/docs
DATA_DOCS_DIRECTORY=site/data/docs
CONFIG_FILE=site/config.yaml
MAIN_BRANCH=main
# don't run if there's already a directory for the target docs version
if [[ -d $DOCS_DIRECTORY/$NEW_DOCS_VERSION ]]; then
echo "ERROR: $DOCS_DIRECTORY/$NEW_DOCS_VERSION already exists"
exit 1
fi
# get the alphabetically last item in $DOCS_DIRECTORY to use as PREVIOUS_DOCS_VERSION
# if not explicitly specified by the user
if [[ -z "${PREVIOUS_DOCS_VERSION:-}" ]]; then
echo "PREVIOUS_DOCS_VERSION was not specified, getting the latest version"
PREVIOUS_DOCS_VERSION=$(ls -1 $DOCS_DIRECTORY/ | tail -n 1)
fi
# make a copy of the previous versioned docs dir
echo "Creating copy of docs directory $DOCS_DIRECTORY/$PREVIOUS_DOCS_VERSION in $DOCS_DIRECTORY/$NEW_DOCS_VERSION"
cp -r $DOCS_DIRECTORY/${PREVIOUS_DOCS_VERSION}/ $DOCS_DIRECTORY/${NEW_DOCS_VERSION}/
# 'git add' the previous version's docs as-is so we get a useful diff when we copy the $MAIN_BRANCH docs in
echo "Running 'git add' for previous version's doc contents to use as a base for diff"
git add -f $DOCS_DIRECTORY/${NEW_DOCS_VERSION}
# now copy the contents of $DOCS_DIRECTORY/$MAIN_BRANCH into the same directory so we can get a nice
# git diff of what changed since previous version
echo "Copying $DOCS_DIRECTORY/$MAIN_BRANCH/ to $DOCS_DIRECTORY/${NEW_DOCS_VERSION}/"
rm -rf $DOCS_DIRECTORY/${NEW_DOCS_VERSION}/ && cp -r $DOCS_DIRECTORY/$MAIN_BRANCH/ $DOCS_DIRECTORY/${NEW_DOCS_VERSION}/
# make a copy of the previous versioned ToC
NEW_DOCS_TOC="$(echo ${NEW_DOCS_VERSION} | tr . -)-toc"
PREVIOUS_DOCS_TOC="$(echo ${PREVIOUS_DOCS_VERSION} | tr . -)-toc"
echo "Creating copy of $DATA_DOCS_DIRECTORY/$PREVIOUS_DOCS_TOC.yml at $DATA_DOCS_DIRECTORY/$NEW_DOCS_TOC.yml"
cp $DATA_DOCS_DIRECTORY/$PREVIOUS_DOCS_TOC.yml $DATA_DOCS_DIRECTORY/$NEW_DOCS_TOC.yml
# 'git add' the previous version's ToC content as-is so we get a useful diff when we copy the $MAIN_BRANCH ToC in
echo "Running 'git add' for previous version's ToC to use as a base for diff"
git add $DATA_DOCS_DIRECTORY/$NEW_DOCS_TOC.yml
# now copy the $MAIN_BRANCH ToC so we can get a nice git diff of what changed since previous version
echo "Copying $DATA_DOCS_DIRECTORY/$MAIN_BRANCH-toc.yml to $DATA_DOCS_DIRECTORY/$NEW_DOCS_TOC.yml"
rm $DATA_DOCS_DIRECTORY/$NEW_DOCS_TOC.yml && cp $DATA_DOCS_DIRECTORY/$MAIN_BRANCH-toc.yml $DATA_DOCS_DIRECTORY/$NEW_DOCS_TOC.yml
# replace known version-specific links -- the sed syntax is slightly different in OS X and Linux,
# so check which OS we're running on.
if [[ $(uname) == "Darwin" ]]; then
echo "[OS X] updating version-specific links"
find $DOCS_DIRECTORY/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i '' "s|https://velero.io/docs/$MAIN_BRANCH|https://velero.io/docs/$VELERO_VERSION|g"
find $DOCS_DIRECTORY/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i '' "s|https://github.com/vmware-tanzu/velero/blob/$MAIN_BRANCH|https://github.com/vmware-tanzu/velero/blob/$VELERO_VERSION|g"
find $DOCS_DIRECTORY/${NEW_DOCS_VERSION} -type f -name "_index.md" | xargs sed -i '' "s|version: $MAIN_BRANCH|version: $NEW_DOCS_VERSION|g"
echo "[OS X] Updating latest version in $CONFIG_FILE"
sed -i '' "s/latest: ${PREVIOUS_DOCS_VERSION}/latest: ${NEW_DOCS_VERSION}/" $CONFIG_FILE
# newlines and lack of indentation are requirements for this sed syntax
# which is doing an append
echo "[OS X] Adding latest version to versions list in $CONFIG_FILE"
sed -i '' "/- $MAIN_BRANCH/a\\
\ \ \ \ - ${NEW_DOCS_VERSION}
" $CONFIG_FILE
echo "[OS X] Adding ToC mapping entry"
sed -i '' "/$MAIN_BRANCH: $MAIN_BRANCH-toc/a\\
${NEW_DOCS_VERSION}: ${NEW_DOCS_TOC}
" $DATA_DOCS_DIRECTORY/toc-mapping.yml
else
echo "[Linux] updating version-specific links"
find $DOCS_DIRECTORY/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i'' "s|https://velero.io/docs/$MAIN_BRANCH|https://velero.io/docs/$VELERO_VERSION|g"
find $DOCS_DIRECTORY/${NEW_DOCS_VERSION} -type f -name "*.md" | xargs sed -i'' "s|https://github.com/vmware-tanzu/velero/blob/$MAIN_BRANCH|https://github.com/vmware-tanzu/velero/blob/$VELERO_VERSION|g"
echo "[Linux] Updating latest version in $CONFIG_FILE"
sed -i'' "s/latest: ${PREVIOUS_DOCS_VERSION}/latest: ${NEW_DOCS_VERSION}/" $CONFIG_FILE
echo "[Linux] Adding latest version to versions list in $CONFIG_FILE"
sed -i'' "/- $MAIN_BRANCH/a - ${NEW_DOCS_VERSION}" $CONFIG_FILE
echo "[Linux] Adding ToC mapping entry"
sed -i'' "/$MAIN_BRANCH: $MAIN_BRANCH-toc/a ${NEW_DOCS_VERSION}: ${NEW_DOCS_TOC}" $DATA_DOCS_DIRECTORY/toc-mapping.yml
fi
echo "Success! $DOCS_DIRECTORY/$NEW_DOCS_VERSION has been created."
echo ""
echo "The next steps are:"
echo " 1. Consult site/README-HUGO.md for further manual steps required to finalize the new versioned docs generation."
echo " 2. Run a 'git diff' to review all changes made to the docs since the previous version."
echo " 3. Make any manual changes/corrections necessary."
echo " 4. Run 'git add' to stage all unstaged changes, then 'git commit'."

View File

@@ -36,14 +36,16 @@ else
export GIT_TREE_STATE=dirty
fi
# $PUBLISH must explicitly be set to 'true' for goreleaser
# $PUBLISH must explicitly be set to 'TRUE' for goreleaser
# to publish the release to GitHub.
if [[ "${PUBLISH:-}" != "true" ]]; then
if [[ "${PUBLISH:-}" != "TRUE" ]]; then
echo "Not set to publish"
goreleaser release \
--rm-dist \
--release-notes="${RELEASE_NOTES_FILE}" \
--skip-publish
else
echo "Getting ready to publish"
goreleaser release \
--rm-dist \
--release-notes="${RELEASE_NOTES_FILE}"

View File

@@ -15,9 +15,24 @@
# limitations under the License.
# This script will do the necessary checks and actions to create a release of Velero.
# It will first validate that all prerequisites are met, then verify the version string is what the user expects.
# A git tag will be created and pushed to GitHub, and GoReleaser will be invoked.
# This script will do the necessary checks and actions to create a release of Velero. It will:
# - validate that all prerequisites are met
# - verify the version string is what the user expects.
# - create a git tag
# - push the created git tag to GitHub
# - run GoReleaser
# The following variables are needed:
# - $VELERO_VERSION: defines the tag of Velero that any https://github.com/vmware-tanzu/velero/...
# links in the docs should redirect to.
# - $publish: TRUE/FALSE value where FALSE (or not including it) will indicate a dry-run, and TRUE, or simply adding 'publish',
# will tag the release with the $VELERO_VERSION and push the tag to a remote named 'upstream'.
# - $GITHUB_TOKEN: Needed to run the goreleaser process to generate a GitHub release.
# Use https://github.com/settings/tokens/new?scopes=repo if you don't already have a token.
# Regenerate an existing token: https://github.com/settings/tokens.
# You may regenerate the token for every release if you prefer.
# See https://goreleaser.com/environment/ for more details.
# This script is meant to be a combination of documentation and executable.
# If you have questions at any point, please stop and ask!
@@ -25,12 +40,25 @@
# Directory in which the script itself resides, so we can use it for calling programs that are in the same directory.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
# Parse out the branch we're on so we can switch back to it at the end of a dry-run, where we delete the tag. Requires git v1.8.1+
upstream_branch=$(git symbolic-ref --short HEAD)
function tag_and_push() {
echo "Tagging and pushing $VELERO_VERSION"
git tag $VELERO_VERSION
git push $VELERO_VERSION
echo "Tagging $VELERO_VERSION"
git tag $VELERO_VERSION || true
if [[ $publish == "TRUE" ]]; then
echo "Pushing $VELERO_VERSION"
git push upstream $VELERO_VERSION
fi
}
# Default to a dry-run mode
publish=FALSE
if [[ "$1" = "publish" ]]; then
publish=TRUE
fi
# For now, have the person doing the release pass in the VELERO_VERSION variable as an environment variable.
# In the future, we might be able to inspect git via `git describe --abbrev=0` to get a hint for it.
if [[ -z "$VELERO_VERSION" ]]; then
@@ -44,7 +72,7 @@ if [[ -z "$GITHUB_TOKEN" ]]; then
exit 1
fi
Ensure that we have a clean working tree before we let any changes happen, especially important for cutting release branches.
# Ensure that we have a clean working tree before we let any changes happen, especially important for cutting release branches.
if [[ -n $(git status --short) ]]; then
echo "Your git working directory is dirty! Please clean up untracked files and stash any changes before proceeding."
exit 3
@@ -63,13 +91,19 @@ printf "Based on this, the following assumptions have been made: \n"
[[ "$VELERO_PATCH" != 0 ]] && printf "*\t This is a patch release.\n"
# $VELERO_PRERELEASE gets populated by the chk_version.go script that parses and verifies the given version format
# -n is "string is non-empty"
[[ -n $VELERO_PRERELEASE ]] && printf "*\t This is a pre-release.\n"
# -z is "string is empty"
[[ -z $VELERO_PRERELEASE ]] && printf "*\t This is a GA release.\n"
echo "If this is all correct, press enter/return to proceed to TAG THE RELEASE and UPLOAD THE TAG TO GITHUB."
if [[ $publish == "TRUE" ]]; then
echo "If this is all correct, press enter/return to proceed to TAG THE RELEASE and UPLOAD THE TAG TO GITHUB."
else
echo "If this is all correct, press enter/return to proceed to TAG THE RELEASE and PROCEED WITH THE DRY-RUN."
fi
echo "Otherwise, press ctrl-c to CANCEL the process without making any changes."
read -p "Ready to continue? "
@@ -77,8 +111,9 @@ read -p "Ready to continue? "
echo "Alright, let's go."
echo "Pulling down all git tags and branches before doing any work."
git fetch upstream --all --tags
git fetch upstream --tags
# $VELERO_PATCH gets populated by the chk_version.go scrip that parses and verifies the given version format
# If we've got a patch release, we'll need to create a release branch for it.
if [[ "$VELERO_PATCH" > 0 ]]; then
release_branch_name=release-$VELERO_MAJOR.$VELERO_MINOR
@@ -95,24 +130,38 @@ if [[ "$VELERO_PATCH" > 0 ]]; then
echo "Now you'll need to cherry-pick any relevant git commits into this release branch."
echo "Either pause this script with ctrl-z, or open a new terminal window and do the cherry-picking."
read -p "Press enter when you're done cherry-picking. THIS WILL MAKE A TAG PUSH THE BRANCH TO UPSTREAM"
if [[ $publish == "TRUE" ]]; then
read -p "Press enter when you're done cherry-picking. THIS WILL MAKE A TAG PUSH THE BRANCH TO upstream"
else
read -p "Press enter when you're done cherry-picking."
fi
# TODO can/should we add a way to review the cherry-picked commits before the push?
echo "Pushing $release_branch_name to upstream remote"
git push --set-upstream upstream/$release_branch_name $release_branch_name
if [[ $publish == "TRUE" ]]; then
echo "Pushing $release_branch_name to upstream remote"
git push --set-upstream upstream/$release_branch_name $release_branch_name
fi
tag_and_push
else
echo "Checking out upstream/master."
git checkout upstream/master
echo "Checking out upstream/main."
git checkout upstream/main
tag_and_push
fi
echo "Invoking Goreleaser to create the GitHub release."
RELEASE_NOTES_FILE=changelogs/CHANGELOG-$VELERO_MAJOR.$VELERO_MINOR.md \
PUBLISH=TRUE \
PUBLISH=$publish \
make release
if [[ $publish == "FALSE" ]]; then
# Delete the local tag so we don't potentially conflict when it's re-run for real.
# This also means we won't have to just ignore existing tags in tag_and_push, which could be a problem if there's an existing tag.
echo "Dry run complete. Deleting git tag $VELERO_VERSION"
git checkout $upstream_branch
git tag -d $VELERO_VERSION
fi

View File

@@ -0,0 +1,3 @@
[
{ "op": "replace", "path": "/spec/validation/openAPIV3Schema/properties/spec/properties/hooks/properties/resources/items/properties/postHooks/items/properties/init/properties/initContainers/items/properties/ports/items/required", "value": [ "containerPort", "protocol"] }
]

View File

@@ -1,6 +1,7 @@
#!/bin/bash
# Copyright 2016 The Kubernetes Authors.
# Modifications 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.
@@ -23,6 +24,7 @@ export CGO_ENABLED=0
TARGETS=(
./cmd/...
./pkg/...
./internal/...
)
if [[ ${#@} -ne 0 ]]; then

View File

@@ -52,4 +52,13 @@ controller-gen \
paths=./pkg/controller/... \
output:crd:artifacts:config=config/crd/bases
# this is a super hacky workaround for https://github.com/kubernetes/kubernetes/issues/91395
# which a result of fixing the validation on CRD objects. The validation ensures the fields that are list map keys, are either marked
# as required or have default values to ensure merging of list map items work as expected.
# With "containerPort" and "protocol" being considered as x-kubernetes-list-map-keys in the container ports, and "protocol" was not
# a required field, the CRD would fail validation with errors similar to the one reported in https://github.com/kubernetes/kubernetes/issues/91395.
# once controller-gen (above) is able to generate CRDs with `protocol` as a required field, this hack can be removed.
kubectl patch -f config/crd/bases/velero.io_restores.yaml -p "$(cat hack/restore-crd-patch.json)" --type=json --local=true -o yaml > /tmp/velero.io_restores-yaml.patched
mv /tmp/velero.io_restores-yaml.patched config/crd/bases/velero.io_restores.yaml
go generate ./config/crd/crds

View File

@@ -22,8 +22,8 @@ ${HACK_DIR}/update-generated-crd-code.sh --verify-only
if ! git diff --exit-code config/crd/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/bases
git checkout config/crd
echo "CRD verification - failed! Generated CRDs are out-of-date, please run 'make update'."
echo "CRD verification - failed! Generated CRDs are out-of-date, please run 'make update' and 'git add' the generated file(s)."
exit 1
fi

View File

@@ -0,0 +1,199 @@
/*
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 delete
import (
"io"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/archive"
"github.com/vmware-tanzu/velero/pkg/discovery"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/util/collections"
"github.com/vmware-tanzu/velero/pkg/util/filesystem"
)
// Context provides the necessary environment to run DeleteItemAction plugins
type Context struct {
Backup *velerov1api.Backup
BackupReader io.Reader
Actions []velero.DeleteItemAction
Filesystem filesystem.Interface
Log logrus.FieldLogger
DiscoveryHelper discovery.Helper
resolvedActions []resolvedAction
}
func InvokeDeleteActions(ctx *Context) error {
var err error
ctx.resolvedActions, err = resolveActions(ctx.Actions, ctx.DiscoveryHelper)
// No actions installed and no error means we don't have to continue;
// just do the backup deletion without worrying about plugins.
if len(ctx.resolvedActions) == 0 && err == nil {
ctx.Log.Debug("No delete item actions present, proceeding with rest of backup deletion process")
return nil
} else if err != nil {
return errors.Wrapf(err, "error resolving actions")
}
// get items out of backup tarball into a temp directory
dir, err := archive.NewExtractor(ctx.Log, ctx.Filesystem).UnzipAndExtractBackup(ctx.BackupReader)
if err != nil {
return errors.Wrapf(err, "error extracting backup")
}
defer ctx.Filesystem.RemoveAll(dir)
ctx.Log.Debugf("Downloaded and extracted the backup file to: %s", dir)
backupResources, err := archive.NewParser(ctx.Log, ctx.Filesystem).Parse(dir)
processdResources := sets.NewString()
ctx.Log.Debugf("Trying to reconcile resource names with Kube API server.")
// Transform resource names based on what's canonical in the API server.
for resource := range backupResources {
gvr, _, err := ctx.DiscoveryHelper.ResourceFor(schema.ParseGroupResource(resource).WithVersion(""))
if err != nil {
return errors.Wrapf(err, "failed to resolve resource into complete group/version/resource: %v", resource)
}
groupResource := gvr.GroupResource()
// We've already seen this group/resource, so don't process it again.
if processdResources.Has(groupResource.String()) {
continue
}
// Get a list of all items that exist for this resource
resourceList := backupResources[groupResource.String()]
if resourceList == nil {
// After canonicalization from the API server, the resources may not exist in the tarball
// Skip them if that's the case.
continue
}
// Iterate over all items, grouped by namespace.
for namespace, items := range resourceList.ItemsByNamespace {
nsLog := ctx.Log.WithField("namespace", namespace)
nsLog.Info("Starting to check for items in namespace")
// Filter applicable actions based on namespace only once per namespace.
actions := ctx.getApplicableActions(groupResource, namespace)
// Process individual items from the backup
for _, item := range items {
itemPath := archive.GetItemFilePath(dir, resource, namespace, item)
// obj is the Unstructured item from the backup
obj, err := archive.Unmarshal(ctx.Filesystem, itemPath)
if err != nil {
return errors.Wrapf(err, "Could not unmarshal item: %v", item)
}
itemLog := nsLog.WithField("item", obj.GetName())
itemLog.Infof("invoking DeleteItemAction plugins")
for _, action := range actions {
if !action.selector.Matches(labels.Set(obj.GetLabels())) {
continue
}
err = action.Execute(&velero.DeleteItemActionExecuteInput{
Item: obj,
Backup: ctx.Backup,
})
// Since we want to keep looping even on errors, log them instead of just returning.
if err != nil {
itemLog.WithError(err).Error("plugin error")
}
}
}
}
}
return nil
}
// getApplicableActions takes resolved DeleteItemActions and filters them for a given group/resource and namespace.
func (ctx *Context) getApplicableActions(groupResource schema.GroupResource, namespace string) []resolvedAction {
var actions []resolvedAction
for _, action := range ctx.resolvedActions {
if !action.resourceIncludesExcludes.ShouldInclude(groupResource.String()) {
continue
}
if namespace != "" && !action.namespaceIncludesExcludes.ShouldInclude(namespace) {
continue
}
if namespace == "" && !action.namespaceIncludesExcludes.IncludeEverything() {
continue
}
actions = append(actions, action)
}
return actions
}
// resolvedActions are DeleteItemActions decorated with resource/namespace include/exclude collections, as well as label selectors for easy comparison.
type resolvedAction struct {
velero.DeleteItemAction
resourceIncludesExcludes *collections.IncludesExcludes
namespaceIncludesExcludes *collections.IncludesExcludes
selector labels.Selector
}
// resolveActions resolves the AppliesTo ResourceSelectors of DeleteItemActions plugins against the Kubernetes discovery API for fully-qualified names.
func resolveActions(actions []velero.DeleteItemAction, helper discovery.Helper) ([]resolvedAction, error) {
var resolved []resolvedAction
for _, action := range actions {
resourceSelector, err := action.AppliesTo()
if err != nil {
return nil, err
}
resources := collections.GetResourceIncludesExcludes(helper, resourceSelector.IncludedResources, resourceSelector.ExcludedResources)
namespaces := collections.NewIncludesExcludes().Includes(resourceSelector.IncludedNamespaces...).Excludes(resourceSelector.ExcludedNamespaces...)
selector := labels.Everything()
if resourceSelector.LabelSelector != "" {
if selector, err = labels.Parse(resourceSelector.LabelSelector); err != nil {
return nil, err
}
}
res := resolvedAction{
DeleteItemAction: action,
resourceIncludesExcludes: resources,
namespaceIncludesExcludes: namespaces,
selector: selector,
}
resolved = append(resolved, res)
}
return resolved, nil
}

View File

@@ -0,0 +1,268 @@
/*
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 delete
import (
"context"
"io"
"sort"
"testing"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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"
"github.com/vmware-tanzu/velero/pkg/discovery"
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
"github.com/vmware-tanzu/velero/pkg/test"
kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube"
)
func TestInvokeDeleteItemActionsRunForCorrectItems(t *testing.T) {
// Declare test-singleton objects.
fs := test.NewFakeFileSystem()
log := logrus.StandardLogger()
tests := []struct {
name string
backup *velerov1api.Backup
apiResources []*test.APIResource
tarball io.Reader
actions map[*recordResourcesAction][]string // recordResourceActions are the plugins that will capture item ids, the []string values are the ids we'll test against.
}{
{
name: "single action with no selector runs for all items",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).
AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result(), builder.ForPersistentVolume("pv-2").Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction): {"ns-1/pod-1", "ns-2/pod-2", "pv-1", "pv-2"},
},
},
{
name: "single action with a resource selector for namespaced resources runs only for matching resources",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).
AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result(), builder.ForPersistentVolume("pv-2").Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction).ForResource("pods"): {"ns-1/pod-1", "ns-2/pod-2"},
},
},
{
name: "single action with a resource selector for cluster-scoped resources runs only for matching resources",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).
AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result(), builder.ForPersistentVolume("pv-2").Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction).ForResource("persistentvolumes"): {"pv-1", "pv-2"},
},
},
{
name: "single action with a namespace selector runs only for resources in that namespace",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).
AddItems("persistentvolumeclaims", builder.ForPersistentVolumeClaim("ns-1", "pvc-1").Result(), builder.ForPersistentVolumeClaim("ns-2", "pvc-2").Result()).
AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result(), builder.ForPersistentVolume("pv-2").Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVCs(), test.PVs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction).ForNamespace("ns-1"): {"ns-1/pod-1", "ns-1/pvc-1"},
},
},
{
name: "multiple actions, each with a different resource selector using short name, run for matching resources",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").Result(), builder.ForPod("ns-2", "pod-2").Result()).
AddItems("persistentvolumeclaims", builder.ForPersistentVolumeClaim("ns-1", "pvc-1").Result(), builder.ForPersistentVolumeClaim("ns-2", "pvc-2").Result()).
AddItems("persistentvolumes", builder.ForPersistentVolume("pv-1").Result(), builder.ForPersistentVolume("pv-2").Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVCs(), test.PVs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction).ForResource("po"): {"ns-1/pod-1", "ns-2/pod-2"},
new(recordResourcesAction).ForResource("pv"): {"pv-1", "pv-2"},
},
},
{
name: "actions with selectors that don't match anything don't run for any resources",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").Result()).
AddItems("persistentvolumeclaims", builder.ForPersistentVolumeClaim("ns-2", "pvc-2").Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVCs(), test.PVs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction).ForNamespace("ns-1").ForResource("persistentvolumeclaims"): nil,
new(recordResourcesAction).ForNamespace("ns-2").ForResource("pods"): nil,
},
},
{
name: "single action with label selector runs only for those items",
backup: builder.ForBackup("velero", "velero").Result(),
tarball: test.NewTarWriter(t).
AddItems("pods", builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("app", "app1")).Result(), builder.ForPod("ns-2", "pod-2").Result()).
AddItems("persistentvolumeclaims", builder.ForPersistentVolumeClaim("ns-1", "pvc-1").Result(), builder.ForPersistentVolumeClaim("ns-2", "pvc-2").ObjectMeta(builder.WithLabels("app", "app1")).Result()).
Done(),
apiResources: []*test.APIResource{test.Pods(), test.PVCs()},
actions: map[*recordResourcesAction][]string{
new(recordResourcesAction).ForLabelSelector("app=app1"): {"ns-1/pod-1", "ns-2/pvc-2"},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// test harness contains the fake API server/discovery client
h := newHarness(t)
for _, r := range tc.apiResources {
h.addResource(t, r)
}
// Get the plugins out of the map in order to use them.
actions := []velero.DeleteItemAction{}
for action := range tc.actions {
actions = append(actions, action)
}
c := &Context{
Backup: tc.backup,
BackupReader: tc.tarball,
Filesystem: fs,
DiscoveryHelper: h.discoveryHelper,
Actions: actions,
Log: log,
}
err := InvokeDeleteActions(c)
require.NoError(t, err)
// Compare the plugins against the ids that we wanted.
for action, want := range tc.actions {
sort.Strings(want)
sort.Strings(action.ids)
assert.Equal(t, want, action.ids)
}
})
}
}
// TODO: unify this with the test harness in pkg/restore/restore_test.go
type harness struct {
*test.APIServer
discoveryHelper discovery.Helper
}
func newHarness(t *testing.T) *harness {
t.Helper()
apiServer := test.NewAPIServer(t)
log := logrus.StandardLogger()
discoveryHelper, err := discovery.NewHelper(apiServer.DiscoveryClient, log)
require.NoError(t, err)
return &harness{
APIServer: apiServer,
discoveryHelper: discoveryHelper,
}
}
// addResource adds an APIResource and it's items to a faked API server for testing.
func (h *harness) addResource(t *testing.T, resource *test.APIResource) {
t.Helper()
h.DiscoveryClient.WithAPIResource(resource)
require.NoError(t, h.discoveryHelper.Refresh())
for _, item := range resource.Items {
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(item)
require.NoError(t, err)
unstructuredObj := &unstructured.Unstructured{Object: obj}
if resource.Namespaced {
_, err = h.DynamicClient.Resource(resource.GVR()).Namespace(item.GetNamespace()).Create(context.TODO(), unstructuredObj, metav1.CreateOptions{})
} else {
_, err = h.DynamicClient.Resource(resource.GVR()).Create(context.TODO(), unstructuredObj, metav1.CreateOptions{})
}
require.NoError(t, err)
}
}
// recordResourcesAction is a delete item action that can be configured to run
// for specific resources/namespaces and simply record the items that is is
// executed for.
type recordResourcesAction struct {
selector velero.ResourceSelector
ids []string
}
func (a *recordResourcesAction) AppliesTo() (velero.ResourceSelector, error) {
return a.selector, nil
}
func (a *recordResourcesAction) Execute(input *velero.DeleteItemActionExecuteInput) error {
metadata, err := meta.Accessor(input.Item)
if err != nil {
return err
}
a.ids = append(a.ids, kubeutil.NamespaceAndName(metadata))
return nil
}
func (a *recordResourcesAction) ForResource(resource string) *recordResourcesAction {
a.selector.IncludedResources = append(a.selector.IncludedResources, resource)
return a
}
func (a *recordResourcesAction) ForNamespace(namespace string) *recordResourcesAction {
a.selector.IncludedNamespaces = append(a.selector.IncludedNamespaces, namespace)
return a
}
func (a *recordResourcesAction) ForLabelSelector(selector string) *recordResourcesAction {
a.selector.LabelSelector = selector
return a
}
func TestInvokeDeleteItemActionsWithNoPlugins(t *testing.T) {
c := &Context{
Backup: builder.ForBackup("velero", "velero").Result(),
Log: logrus.StandardLogger(),
// No other fields are set on the assumption that if 0 actions are present,
// the backup tarball and file system being empty will produce no errors.
}
err := InvokeDeleteActions(c)
require.NoError(t, err)
}

View File

@@ -0,0 +1,520 @@
/*
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 (
"encoding/json"
"fmt"
"strings"
"time"
uuid "github.com/gofrs/uuid"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
corev1api "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/podexec"
"github.com/vmware-tanzu/velero/pkg/restic"
"github.com/vmware-tanzu/velero/pkg/util/collections"
"github.com/vmware-tanzu/velero/pkg/util/kube"
)
type hookPhase string
const (
PhasePre hookPhase = "pre"
PhasePost hookPhase = "post"
)
const (
// Backup hook annotations
podBackupHookContainerAnnotationKey = "hook.backup.velero.io/container"
podBackupHookCommandAnnotationKey = "hook.backup.velero.io/command"
podBackupHookOnErrorAnnotationKey = "hook.backup.velero.io/on-error"
podBackupHookTimeoutAnnotationKey = "hook.backup.velero.io/timeout"
// Restore hook annotations
podRestoreHookContainerAnnotationKey = "post.hook.restore.velero.io/container"
podRestoreHookCommandAnnotationKey = "post.hook.restore.velero.io/command"
podRestoreHookOnErrorAnnotationKey = "post.hook.restore.velero.io/on-error"
podRestoreHookTimeoutAnnotationKey = "post.hook.restore.velero.io/exec-timeout"
podRestoreHookWaitTimeoutAnnotationKey = "post.hook.restore.velero.io/wait-timeout"
podRestoreHookInitContainerImageAnnotationKey = "init.hook.restore.velero.io/container-image"
podRestoreHookInitContainerNameAnnotationKey = "init.hook.restore.velero.io/container-name"
podRestoreHookInitContainerCommandAnnotationKey = "init.hook.restore.velero.io/command"
podRestoreHookInitContainerTimeoutAnnotationKey = "init.hook.restore.velero.io/timeout"
)
// ItemHookHandler invokes hooks for an item.
type ItemHookHandler interface {
// HandleHooks invokes hooks for an item. If the item is a pod and the appropriate annotations exist
// to specify a hook, that is executed. Otherwise, this looks at the backup context's Backup to
// determine if there are any hooks relevant to the item, taking into account the hook spec's
// namespaces, resources, and label selector.
HandleHooks(
log logrus.FieldLogger,
groupResource schema.GroupResource,
obj runtime.Unstructured,
resourceHooks []ResourceHook,
phase hookPhase,
) error
}
// ItemRestoreHookHandler invokes restore hooks for an item
type ItemRestoreHookHandler interface {
HandleRestoreHooks(
log logrus.FieldLogger,
groupResource schema.GroupResource,
obj runtime.Unstructured,
rh []ResourceRestoreHook,
) (runtime.Unstructured, error)
}
// InitContainerRestoreHookHandler is the restore hook handler to add init containers to restored pods.
type InitContainerRestoreHookHandler struct{}
// HandleRestoreHooks runs the restore hooks for an item.
// If the item is a pod, then hooks are chosen to be run as follows:
// If the pod has the appropriate annotations specifying the hook action, then hooks from the annotation are run
// Otherwise, the supplied ResourceRestoreHooks are applied.
func (i *InitContainerRestoreHookHandler) HandleRestoreHooks(
log logrus.FieldLogger,
groupResource schema.GroupResource,
obj runtime.Unstructured,
resourceRestoreHooks []ResourceRestoreHook,
) (runtime.Unstructured, error) {
// We only support hooks on pods right now
if groupResource != kuberesource.Pods {
return nil, nil
}
metadata, err := meta.Accessor(obj)
if err != nil {
return nil, errors.Wrap(err, "unable to get a metadata accessor")
}
pod := new(corev1api.Pod)
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), pod); err != nil {
return nil, errors.WithStack(err)
}
initContainers := []corev1api.Container{}
// If this pod had pod volumes backed up using restic, then we want to the pod volumes restored prior to
// running the restore hook init containers. This allows the restore hook init containers to prepare the
// restored data to be consumed by the application container(s).
// So if there is a "resitc-wait" init container already on the pod at index 0, we'll preserve that and run
// it before running any other init container.
if len(pod.Spec.InitContainers) > 0 && pod.Spec.InitContainers[0].Name == restic.InitContainer {
initContainers = append(initContainers, pod.Spec.InitContainers[0])
pod.Spec.InitContainers = pod.Spec.InitContainers[1:]
}
hooksFromAnnotations := getInitRestoreHookFromAnnotation(kube.NamespaceAndName(pod), metadata.GetAnnotations(), log)
if hooksFromAnnotations != nil {
log.Infof("Handling InitRestoreHooks from pod annotaions")
initContainers = append(initContainers, hooksFromAnnotations.InitContainers...)
} else {
log.Infof("Handling InitRestoreHooks from RestoreSpec")
// pod did not have the annotations appropriate for restore hooks
// running applicable ResourceRestoreHooks supplied.
namespace := metadata.GetNamespace()
labels := labels.Set(metadata.GetLabels())
for _, rh := range resourceRestoreHooks {
if !rh.Selector.applicableTo(groupResource, namespace, labels) {
continue
}
for _, hook := range rh.RestoreHooks {
if hook.Init != nil {
initContainers = append(initContainers, hook.Init.InitContainers...)
}
}
}
}
pod.Spec.InitContainers = append(initContainers, pod.Spec.InitContainers...)
log.Infof("Returning pod %s/%s with %d init container(s)", pod.Namespace, pod.Name, len(pod.Spec.InitContainers))
podMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pod)
if err != nil {
return nil, errors.WithStack(err)
}
return &unstructured.Unstructured{Object: podMap}, nil
}
// DefaultItemHookHandler is the default itemHookHandler.
type DefaultItemHookHandler struct {
PodCommandExecutor podexec.PodCommandExecutor
}
func (h *DefaultItemHookHandler) HandleHooks(
log logrus.FieldLogger,
groupResource schema.GroupResource,
obj runtime.Unstructured,
resourceHooks []ResourceHook,
phase hookPhase,
) error {
// We only support hooks on pods right now
if groupResource != kuberesource.Pods {
return nil
}
metadata, err := meta.Accessor(obj)
if err != nil {
return errors.Wrap(err, "unable to get a metadata accessor")
}
namespace := metadata.GetNamespace()
name := metadata.GetName()
// If the pod has the hook specified via annotations, that takes priority.
hookFromAnnotations := getPodExecHookFromAnnotations(metadata.GetAnnotations(), phase, log)
if phase == PhasePre && hookFromAnnotations == nil {
// See if the pod has the legacy hook annotation keys (i.e. without a phase specified)
hookFromAnnotations = getPodExecHookFromAnnotations(metadata.GetAnnotations(), "", log)
}
if hookFromAnnotations != nil {
hookLog := log.WithFields(
logrus.Fields{
"hookSource": "annotation",
"hookType": "exec",
"hookPhase": phase,
},
)
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
}
labels := labels.Set(metadata.GetLabels())
// Otherwise, check for hooks defined in the backup spec.
for _, resourceHook := range resourceHooks {
if !resourceHook.Selector.applicableTo(groupResource, namespace, labels) {
continue
}
var hooks []velerov1api.BackupResourceHook
if phase == PhasePre {
hooks = resourceHook.Pre
} else {
hooks = resourceHook.Post
}
for _, hook := range hooks {
if groupResource == kuberesource.Pods {
if hook.Exec != nil {
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
}
}
}
}
}
}
return nil
}
func phasedKey(phase hookPhase, key string) string {
if phase != "" {
return fmt.Sprintf("%v.%v", phase, key)
}
return string(key)
}
func getHookAnnotation(annotations map[string]string, key string, phase hookPhase) string {
return annotations[phasedKey(phase, key)]
}
// getPodExecHookFromAnnotations returns an ExecHook based on the annotations, as long as the
// 'command' annotation is present. If it is absent, this returns nil.
// If there is an error in parsing a supplied timeout, it is logged.
func getPodExecHookFromAnnotations(annotations map[string]string, phase hookPhase, log logrus.FieldLogger) *velerov1api.ExecHook {
commandValue := getHookAnnotation(annotations, podBackupHookCommandAnnotationKey, phase)
if commandValue == "" {
return nil
}
container := getHookAnnotation(annotations, podBackupHookContainerAnnotationKey, phase)
onError := velerov1api.HookErrorMode(getHookAnnotation(annotations, podBackupHookOnErrorAnnotationKey, phase))
if onError != velerov1api.HookErrorModeContinue && onError != velerov1api.HookErrorModeFail {
onError = ""
}
var timeout time.Duration
timeoutString := getHookAnnotation(annotations, podBackupHookTimeoutAnnotationKey, phase)
if timeoutString != "" {
if temp, err := time.ParseDuration(timeoutString); err == nil {
timeout = temp
} else {
log.Warn(errors.Wrapf(err, "Unable to parse provided timeout %s, using default", timeoutString))
}
}
return &velerov1api.ExecHook{
Container: container,
Command: parseStringToCommand(commandValue),
OnError: onError,
Timeout: metav1.Duration{Duration: timeout},
}
}
func parseStringToCommand(commandValue string) []string {
var command []string
// check for json array
if commandValue[0] == '[' {
if err := json.Unmarshal([]byte(commandValue), &command); err != nil {
command = []string{commandValue}
}
} else {
command = append(command, commandValue)
}
return command
}
type ResourceHookSelector struct {
Namespaces *collections.IncludesExcludes
Resources *collections.IncludesExcludes
LabelSelector labels.Selector
}
// ResourceHook is a hook for a given resource.
type ResourceHook struct {
Name string
Selector ResourceHookSelector
Pre []velerov1api.BackupResourceHook
Post []velerov1api.BackupResourceHook
}
func (r ResourceHookSelector) applicableTo(groupResource schema.GroupResource, namespace string, labels labels.Set) bool {
if r.Namespaces != nil && !r.Namespaces.ShouldInclude(namespace) {
return false
}
if r.Resources != nil && !r.Resources.ShouldInclude(groupResource.String()) {
return false
}
if r.LabelSelector != nil && !r.LabelSelector.Matches(labels) {
return false
}
return true
}
// ResourceRestoreHook is a restore hook for a given resource.
type ResourceRestoreHook struct {
Name string
Selector ResourceHookSelector
RestoreHooks []velerov1api.RestoreResourceHook
}
func getInitRestoreHookFromAnnotation(podName string, annotations map[string]string, log logrus.FieldLogger) *velerov1api.InitRestoreHook {
containerImage := annotations[podRestoreHookInitContainerImageAnnotationKey]
containerName := annotations[podRestoreHookInitContainerNameAnnotationKey]
command := annotations[podRestoreHookInitContainerCommandAnnotationKey]
if containerImage == "" {
log.Infof("Pod %s has no %s annotation, no initRestoreHook in annotation", podName, podRestoreHookInitContainerImageAnnotationKey)
return nil
}
if command == "" {
log.Infof("RestoreHook init contianer for pod %s is using container's default entrypoint", podName, containerImage)
}
if containerName == "" {
uid, err := uuid.NewV4()
uuidStr := "deadfeed"
if err != nil {
log.Errorf("Failed to generate UUID for container name")
} else {
uuidStr = strings.Split(uid.String(), "-")[0]
}
containerName = fmt.Sprintf("velero-restore-init-%s", uuidStr)
log.Infof("Pod %s has no %s annotation, using generated name %s for initContainer", podName, podRestoreHookInitContainerNameAnnotationKey, containerName)
}
return &velerov1api.InitRestoreHook{
InitContainers: []corev1api.Container{
{
Image: containerImage,
Name: containerName,
Command: parseStringToCommand(command),
},
},
}
}
// GetRestoreHooksFromSpec returns a list of ResourceRestoreHooks from the restore Spec.
func GetRestoreHooksFromSpec(hooksSpec *velerov1api.RestoreHooks) ([]ResourceRestoreHook, error) {
if hooksSpec == nil {
return []ResourceRestoreHook{}, nil
}
restoreHooks := make([]ResourceRestoreHook, 0, len(hooksSpec.Resources))
for _, rs := range hooksSpec.Resources {
rh := ResourceRestoreHook{
Name: rs.Name,
Selector: ResourceHookSelector{
Namespaces: collections.NewIncludesExcludes().Includes(rs.IncludedNamespaces...).Excludes(rs.ExcludedNamespaces...),
// these hooks ara applicable only to pods.
// TODO: resolve the pods resource via discovery?
Resources: collections.NewIncludesExcludes().Includes(kuberesource.Pods.Resource),
},
// TODO does this work for ExecRestoreHook as well?
RestoreHooks: rs.PostHooks,
}
if rs.LabelSelector != nil {
ls, err := metav1.LabelSelectorAsSelector(rs.LabelSelector)
if err != nil {
return nil, errors.WithStack(err)
}
rh.Selector.LabelSelector = ls
}
restoreHooks = append(restoreHooks, rh)
}
return restoreHooks, nil
}
// getPodExecRestoreHookFromAnnotations returns an ExecRestoreHook based on restore annotations, as
// long as the 'command' annotation is present. If it is absent, this returns nil.
func getPodExecRestoreHookFromAnnotations(annotations map[string]string, log logrus.FieldLogger) *velerov1api.ExecRestoreHook {
commandValue := annotations[podRestoreHookCommandAnnotationKey]
if commandValue == "" {
return nil
}
container := annotations[podRestoreHookContainerAnnotationKey]
onError := velerov1api.HookErrorMode(annotations[podRestoreHookOnErrorAnnotationKey])
if onError != velerov1api.HookErrorModeContinue && onError != velerov1api.HookErrorModeFail {
onError = ""
}
var execTimeout time.Duration
execTimeoutString := annotations[podRestoreHookTimeoutAnnotationKey]
if execTimeoutString != "" {
if temp, err := time.ParseDuration(execTimeoutString); err == nil {
execTimeout = temp
} else {
log.Warn(errors.Wrapf(err, "Unable to parse exec timeout %s, ignoring", execTimeoutString))
}
}
var waitTimeout time.Duration
waitTimeoutString := annotations[podRestoreHookWaitTimeoutAnnotationKey]
if waitTimeoutString != "" {
if temp, err := time.ParseDuration(waitTimeoutString); err == nil {
waitTimeout = temp
} else {
log.Warn(errors.Wrapf(err, "Unable to parse wait timeout %s, ignoring", waitTimeoutString))
}
}
return &velerov1api.ExecRestoreHook{
Container: container,
Command: parseStringToCommand(commandValue),
OnError: onError,
ExecTimeout: metav1.Duration{Duration: execTimeout},
WaitTimeout: metav1.Duration{Duration: waitTimeout},
}
}
type PodExecRestoreHook struct {
HookName string
HookSource string
Hook velerov1api.ExecRestoreHook
executed bool
}
// GroupRestoreExecHooks returns a list of hooks to be executed in a pod grouped by
// 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(
resourceRestoreHooks []ResourceRestoreHook,
pod *corev1api.Pod,
log logrus.FieldLogger,
) (map[string][]PodExecRestoreHook, error) {
byContainer := map[string][]PodExecRestoreHook{}
if pod == nil || len(pod.Spec.Containers) == 0 {
return byContainer, nil
}
metadata, err := meta.Accessor(pod)
if err != nil {
return nil, errors.WithStack(err)
}
hookFromAnnotation := getPodExecRestoreHookFromAnnotations(metadata.GetAnnotations(), log)
if hookFromAnnotation != nil {
// default to first container in pod if unset
if hookFromAnnotation.Container == "" {
hookFromAnnotation.Container = pod.Spec.Containers[0].Name
}
byContainer[hookFromAnnotation.Container] = []PodExecRestoreHook{
{
HookName: "<from-annotation>",
HookSource: "annotation",
Hook: *hookFromAnnotation,
},
}
return byContainer, nil
}
// No hook found on pod's annotations so check for applicable hooks from the restore spec
labels := metadata.GetLabels()
namespace := metadata.GetNamespace()
for _, rrh := range resourceRestoreHooks {
if !rrh.Selector.applicableTo(kuberesource.Pods, namespace, labels) {
continue
}
for _, rh := range rrh.RestoreHooks {
if rh.Exec == nil {
continue
}
named := PodExecRestoreHook{
HookName: rrh.Name,
Hook: *rh.Exec,
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
}
byContainer[named.Hook.Container] = append(byContainer[named.Hook.Container], named)
}
}
return byContainer, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,275 @@
/*
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 (
"context"
"fmt"
"time"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/podexec"
"github.com/vmware-tanzu/velero/pkg/util/kube"
)
type WaitExecHookHandler interface {
HandleHooks(
ctx context.Context,
log logrus.FieldLogger,
pod *v1.Pod,
byContainer map[string][]PodExecRestoreHook,
) []error
}
type ListWatchFactory interface {
NewListWatch(namespace string, selector fields.Selector) cache.ListerWatcher
}
type DefaultListWatchFactory struct {
PodsGetter cache.Getter
}
func (d *DefaultListWatchFactory) NewListWatch(namespace string, selector fields.Selector) cache.ListerWatcher {
return cache.NewListWatchFromClient(d.PodsGetter, "pods", namespace, selector)
}
var _ ListWatchFactory = &DefaultListWatchFactory{}
type DefaultWaitExecHookHandler struct {
ListWatchFactory ListWatchFactory
PodCommandExecutor podexec.PodCommandExecutor
}
var _ WaitExecHookHandler = &DefaultWaitExecHookHandler{}
func (e *DefaultWaitExecHookHandler) HandleHooks(
ctx context.Context,
log logrus.FieldLogger,
pod *v1.Pod,
byContainer map[string][]PodExecRestoreHook,
) []error {
if pod == nil {
return nil
}
// If hooks are defined for a container that does not exist in the pod log a warning and discard
// those hooks to avoid waiting for a container that will never become ready. After that if
// there are no hooks left to be executed return immediately.
for containerName := range byContainer {
if !podHasContainer(pod, containerName) {
log.Warningf("Pod %s does not have container %s: discarding post-restore exec hooks", kube.NamespaceAndName(pod), containerName)
delete(byContainer, containerName)
}
}
if len(byContainer) == 0 {
return nil
}
// Every hook in every container can have its own wait timeout. Rather than setting up separate
// contexts for each, find the largest wait timeout for any hook that should be executed in
// the pod and watch the pod for up to that long. Before executing any hook in a container,
// check if that hook has a timeout and skip execution if expired.
ctx, cancel := context.WithCancel(ctx)
maxWait := maxHookWait(byContainer)
// If no hook has a wait timeout then this function will continue waiting for containers to
// become ready until the shared hook context is canceled.
if maxWait > 0 {
ctx, cancel = context.WithTimeout(ctx, maxWait)
}
waitStart := time.Now()
var errors []error
// The first time this handler is called after a container starts running it will execute all
// pending hooks for that container. Subsequent invocations of this handler will never execute
// hooks in that container. It uses the byContainer map to keep track of which containers have
// not yet been observed to be running. It relies on the Informer not to be called concurrently.
// When a container is observed running and its hooks are executed, the container is deleted
// from the byContainer map. When the map is empty the watch is ended.
handler := func(newObj interface{}) {
newPod, ok := newObj.(*v1.Pod)
if !ok {
return
}
podLog := log.WithFields(
logrus.Fields{
"pod": kube.NamespaceAndName(newPod),
},
)
if newPod.Status.Phase == v1.PodSucceeded || newPod.Status.Phase == v1.PodFailed {
err := fmt.Errorf("Pod entered phase %s before some post-restore exec hooks ran", newPod.Status.Phase)
podLog.Warning(err)
cancel()
return
}
for containerName, hooks := range byContainer {
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)
if err != nil {
podLog.WithError(err).Error("error unstructuring pod")
cancel()
return
}
// Sequentially run all hooks for the ready container. The container's hooks are not
// removed from the byContainer map until all have completed so that if one fails
// remaining unexecuted hooks can be handled by the outer function.
for i, hook := range hooks {
// This indicates to the outer function not to handle this hook as unexecuted in
// case of terminating before deleting this container's slice of hooks from the
// byContainer map.
byContainer[containerName][i].executed = true
hookLog := podLog.WithFields(
logrus.Fields{
"hookSource": hook.HookSource,
"hookType": "exec",
"hookPhase": "post",
},
)
// Check the individual hook's wait timeout is not expired
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)
if hook.Hook.OnError == velerov1api.HookErrorModeFail {
errors = append(errors, err)
cancel()
return
}
}
eh := &velerov1api.ExecHook{
Container: hook.Hook.Container,
Command: hook.Hook.Command,
OnError: hook.Hook.OnError,
Timeout: hook.Hook.ExecTimeout,
}
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)
}
if len(byContainer) == 0 {
cancel()
}
}
selector := fields.OneTermEqualSelector("metadata.name", pod.Name)
lw := e.ListWatchFactory.NewListWatch(pod.Namespace, selector)
_, podWatcher := cache.NewInformer(lw, pod, 0, cache.ResourceEventHandlerFuncs{
AddFunc: handler,
UpdateFunc: func(_, newObj interface{}) {
handler(newObj)
},
DeleteFunc: func(obj interface{}) {
err := fmt.Errorf("Pod %s deleted before all hooks were executed", kube.NamespaceAndName(pod))
log.Error(err)
cancel()
},
})
podWatcher.Run(ctx.Done())
// There are some cases where this function could return with unexecuted hooks: the pod may
// 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 but only hooks with OnError mode Fail return
// an error from this function.
for _, hooks := range byContainer {
for _, hook := range hooks {
if hook.executed {
continue
}
err := fmt.Errorf("Hook %s in container %s in pod %s not executed: %v", hook.HookName, hook.Hook.Container, kube.NamespaceAndName(pod), ctx.Err())
hookLog := log.WithFields(
logrus.Fields{
"hookSource": hook.HookSource,
"hookType": "exec",
"hookPhase": "post",
},
)
hookLog.Error(err)
if hook.Hook.OnError == velerov1api.HookErrorModeFail {
errors = append(errors, err)
}
}
}
return errors
}
func podHasContainer(pod *v1.Pod, containerName string) bool {
if pod == nil {
return false
}
for _, c := range pod.Spec.Containers {
if c.Name == containerName {
return true
}
}
return false
}
func isContainerRunning(pod *v1.Pod, containerName string) bool {
if pod == nil {
return false
}
for _, cs := range pod.Status.ContainerStatuses {
if cs.Name != containerName {
continue
}
return cs.State.Running != nil
}
return false
}
// maxHookWait returns 0 to mean wait indefinitely. Any hook without a wait timeout will cause this
// function to return 0.
func maxHookWait(byContainer map[string][]PodExecRestoreHook) time.Duration {
var maxWait time.Duration
for _, hooks := range byContainer {
for _, hook := range hooks {
if hook.Hook.WaitTimeout.Duration <= 0 {
return 0
}
if hook.Hook.WaitTimeout.Duration > maxWait {
maxWait = hook.Hook.WaitTimeout.Duration
}
}
}
return maxWait
}

View File

@@ -0,0 +1,949 @@
/*
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 (
"context"
"testing"
"time"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
fcache "k8s.io/client-go/tools/cache/testing"
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"
)
type fakeListWatchFactory struct {
lw cache.ListerWatcher
}
func (f *fakeListWatchFactory) NewListWatch(ns string, selector fields.Selector) cache.ListerWatcher {
return f.lw
}
var _ ListWatchFactory = &fakeListWatchFactory{}
func TestWaitExecHandleHooks(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
}
tests := []struct {
name string
// Used as argument to HandleHooks and first state added to ListerWatcher
initialPod *v1.Pod
groupResource string
byContainer map[string][]PodExecRestoreHook
expectedExecutions []expectedExecution
expectedErrors []error
// changes represents the states of the pod over time. It can be used to test a container
// becoming ready at some point after it is first observed by the controller.
changes []change
sharedHooksContextTimeout time.Duration
}{
{
name: "should return no error when hook from annotation 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: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{time.Second},
WaitTimeout: metav1.Duration{time.Minute},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "<from-annotation>",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
Timeout: metav1.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(),
},
},
expectedErrors: nil,
},
{
name: "should return an error when hook from annotation fails with on error mode fail",
initialPod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
podRestoreHookContainerAnnotationKey, "container1",
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeFail),
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: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
ExecTimeout: metav1.Duration{time.Second},
WaitTimeout: metav1.Duration{time.Minute},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "<from-annotation>",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
Timeout: metav1.Duration{time.Second},
},
error: errors.New("pod hook error"),
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("1")).
ObjectMeta(builder.WithAnnotations(
podRestoreHookCommandAnnotationKey, "/usr/bin/foo",
podRestoreHookContainerAnnotationKey, "container1",
podRestoreHookOnErrorAnnotationKey, string(velerov1api.HookErrorModeFail),
podRestoreHookTimeoutAnnotationKey, "1s",
podRestoreHookWaitTimeoutAnnotationKey, "1m",
)).
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
},
expectedErrors: []error{errors.New("pod hook error")},
},
{
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",
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: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{time.Second},
WaitTimeout: metav1.Duration{time.Minute},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "<from-annotation>",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
Timeout: metav1.Duration{time.Second},
},
error: errors.New("pod hook error"),
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(),
},
},
expectedErrors: nil,
},
{
name: "should return no error when hook from annotation executes after 10ms wait for container to start",
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{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
groupResource: "pods",
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "<from-annotation>",
HookSource: "annotation",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
ExecTimeout: metav1.Duration{time.Second},
WaitTimeout: metav1.Duration{time.Minute},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "<from-annotation>",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
Timeout: metav1.Duration{time.Second},
},
error: nil,
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("2")).
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(),
},
},
expectedErrors: nil,
changes: []change{
{
wait: 10 * time.Millisecond,
updated: 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(),
},
},
},
{
name: "should return no error when hook from spec executes successfully",
groupResource: "pods",
initialPod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
expectedErrors: nil,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "my-hook-1",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
},
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("1")).
Containers(&v1.Container{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
},
},
{
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{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
expectedErrors: nil,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
WaitTimeout: metav1.Duration{time.Millisecond},
},
},
},
},
expectedExecutions: []expectedExecution{},
},
{
name: "should return an error when spec hook with wait timeout expires with OnError mode Fail",
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(),
expectedErrors: []error{errors.New("Hook my-hook-1 in container container1 in pod default/my-pod not executed: context deadline exceeded")},
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
WaitTimeout: metav1.Duration{time.Millisecond},
},
},
},
},
expectedExecutions: []expectedExecution{},
},
{
name: "should return an error when shared hooks context is canceled before spec hook with OnError mode Fail executes",
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(),
expectedErrors: []error{errors.New("Hook my-hook-1 in container container1 in pod default/my-pod not executed: context deadline exceeded")},
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeFail,
},
},
},
},
expectedExecutions: []expectedExecution{},
sharedHooksContextTimeout: time.Millisecond,
},
{
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{
Name: "container1",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
OnError: velerov1api.HookErrorModeContinue,
},
},
},
},
expectedExecutions: []expectedExecution{},
sharedHooksContextTimeout: time.Millisecond,
},
{
name: "shoudl return no error with 2 spec hooks in 2 different containers, 1st container starts running after 10ms, 2nd container after 20ms, both succeed",
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(),
expectedErrors: nil,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
},
},
},
"container2": {
{
HookName: "my-hook-1",
HookSource: "backupSpec",
Hook: velerov1api.ExecRestoreHook{
Container: "container2",
Command: []string{"/usr/bin/bar"},
},
},
},
},
expectedExecutions: []expectedExecution{
{
name: "my-hook-1",
hook: &velerov1api.ExecHook{
Container: "container1",
Command: []string{"/usr/bin/foo"},
},
error: nil,
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("2")).
Containers(&v1.Container{
Name: "container1",
}).
Containers(&v1.Container{
Name: "container2",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
// container 2 is still waiting when the first hook executes in container1
ContainerStatuses(&v1.ContainerStatus{
Name: "container2",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
},
{
name: "my-hook-1",
hook: &velerov1api.ExecHook{
Container: "container2",
Command: []string{"/usr/bin/bar"},
},
error: nil,
pod: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("3")).
Containers(&v1.Container{
Name: "container1",
}).
Containers(&v1.Container{
Name: "container2",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container2",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
},
changes: []change{
// 1st modification: container1 starts running, resourceVersion 2, container2 still waiting
{
wait: 10 * time.Millisecond,
updated: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("2")).
Containers(&v1.Container{
Name: "container1",
}).
Containers(&v1.Container{
Name: "container2",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container2",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
},
// 2nd modification: container2 starts running, resourceVersion 3
{
wait: 10 * time.Millisecond,
updated: builder.ForPod("default", "my-pod").
ObjectMeta(builder.WithResourceVersion("3")).
Containers(&v1.Container{
Name: "container1",
}).
Containers(&v1.Container{
Name: "container2",
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
ContainerStatuses(&v1.ContainerStatus{
Name: "container2",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
},
},
}
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.
source.Add(test.initialPod)
// Changes holds the versions of the pod over time. Each of these states
// will be seen by the UpdateFunc handler.
for _, change := range test.changes {
time.Sleep(change.wait)
source.Modify(change.updated)
}
}()
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()
if test.sharedHooksContextTimeout > 0 {
ctx, _ = context.WithTimeout(ctx, test.sharedHooksContextTimeout)
}
errs := h.HandleHooks(ctx, velerotest.NewLogger(), test.initialPod, test.byContainer)
// for i, ee := range test.expectedErrors {
require.Len(t, errs, len(test.expectedErrors))
for i, ee := range test.expectedErrors {
assert.EqualError(t, errs[i], ee.Error())
}
})
}
}
func TestPodHasContainer(t *testing.T) {
tests := []struct {
name string
pod *v1.Pod
container string
expect bool
}{
{
name: "has container",
expect: true,
container: "container1",
pod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container1",
}).
Result(),
},
{
name: "does not have container",
expect: false,
container: "container1",
pod: builder.ForPod("default", "my-pod").
Containers(&v1.Container{
Name: "container2",
}).
Result(),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := podHasContainer(test.pod, test.container)
assert.Equal(t, actual, test.expect)
})
}
}
func TestIsContainerRunning(t *testing.T) {
tests := []struct {
name string
pod *v1.Pod
container string
expect bool
}{
{
name: "should return true when running",
container: "container1",
expect: true,
pod: builder.ForPod("default", "my-pod").
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
{
name: "should return false when no state is set",
container: "container1",
expect: false,
pod: builder.ForPod("default", "my-pod").
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{},
}).
Result(),
},
{
name: "should return false when waiting",
container: "container1",
expect: false,
pod: builder.ForPod("default", "my-pod").
ContainerStatuses(&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Waiting: &v1.ContainerStateWaiting{},
},
}).
Result(),
},
{
name: "should return true when running and first container is terminated",
container: "container1",
expect: true,
pod: builder.ForPod("default", "my-pod").
ContainerStatuses(&v1.ContainerStatus{
Name: "container0",
State: v1.ContainerState{
Terminated: &v1.ContainerStateTerminated{},
},
},
&v1.ContainerStatus{
Name: "container1",
State: v1.ContainerState{
Running: &v1.ContainerStateRunning{},
},
}).
Result(),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := isContainerRunning(test.pod, test.container)
assert.Equal(t, actual, test.expect)
})
}
}
func TestMaxHookWait(t *testing.T) {
tests := []struct {
name string
byContainer map[string][]PodExecRestoreHook
expect time.Duration
}{
{
name: "should return 0 for nil map",
byContainer: nil,
expect: 0,
},
{
name: "should return 0 if all hooks are 0 or negative",
expect: 0,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
Hook: velerov1api.ExecRestoreHook{
ExecTimeout: metav1.Duration{time.Second},
WaitTimeout: metav1.Duration{0},
},
},
{
Hook: velerov1api.ExecRestoreHook{
WaitTimeout: metav1.Duration{-1},
},
},
},
},
},
{
name: "should return biggest wait timeout from multiple hooks in multiple containers",
expect: time.Hour,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
Hook: velerov1api.ExecRestoreHook{
WaitTimeout: metav1.Duration{time.Second},
},
},
{
Hook: velerov1api.ExecRestoreHook{
WaitTimeout: metav1.Duration{time.Second},
},
},
},
"container2": {
{
Hook: velerov1api.ExecRestoreHook{
WaitTimeout: metav1.Duration{time.Hour},
},
},
{
Hook: velerov1api.ExecRestoreHook{
WaitTimeout: metav1.Duration{time.Minute},
},
},
},
},
},
{
name: "should return 0 if any hook does not have a wait timeout",
expect: 0,
byContainer: map[string][]PodExecRestoreHook{
"container1": {
{
Hook: velerov1api.ExecRestoreHook{
ExecTimeout: metav1.Duration{time.Second},
WaitTimeout: metav1.Duration{time.Second},
},
},
{
Hook: velerov1api.ExecRestoreHook{
WaitTimeout: metav1.Duration{0},
},
},
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := maxHookWait(test.byContainer)
assert.Equal(t, actual, test.expect)
})
}
}

View File

@@ -0,0 +1,92 @@
/*
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 storage
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
)
// DefaultBackupLocationInfo holds server default backup storage location information
type DefaultBackupLocationInfo struct {
// StorageLocation is the name of the backup storage location designated as the default
StorageLocation string
// StoreValidationFrequency is the default validation frequency for any backup storage location
StoreValidationFrequency time.Duration
}
// IsReadyToValidate calculates if a given backup storage location is ready to be validated.
//
// Rules:
// Users can choose a validation frequency per location. This will overrite the server's default value
// To skip/stop validation, set the frequency to zero
// This will always return "true" for the first attempt at validating a location, regardless of its validation frequency setting
// Otherwise, it returns "ready" only when NOW is equal to or after the next validation time
// (next validation time: last validation time + validation frequency)
func IsReadyToValidate(bslValidationFrequency *metav1.Duration, lastValidationTime *metav1.Time, defaultLocationInfo DefaultBackupLocationInfo, log logrus.FieldLogger) bool {
validationFrequency := defaultLocationInfo.StoreValidationFrequency
// If the bsl validation frequency is not specifically set, skip this block and continue, using the server's default
if bslValidationFrequency != nil {
validationFrequency = bslValidationFrequency.Duration
}
if validationFrequency == 0 {
log.Debug("Validation period for this backup location is set to 0, skipping validation")
return false
}
if validationFrequency < 0 {
log.Debugf("Validation period must be non-negative, changing from %d to %d", validationFrequency, defaultLocationInfo.StoreValidationFrequency)
validationFrequency = defaultLocationInfo.StoreValidationFrequency
}
lastValidation := lastValidationTime
if lastValidation != nil { // always ready to validate the first time around, so only even do this check if this has happened before
nextValidation := lastValidation.Add(validationFrequency) // next validation time: last validation time + validation frequency
if time.Now().UTC().Before(nextValidation) { // ready only when NOW is equal to or after the next validation time
return false
}
}
return true
}
// ListBackupStorageLocations verifies if there are any backup storage locations.
// For all purposes, if either there is an error while attempting to fetch items or
// if there are no items an error would be returned since the functioning of the system
// would be haulted.
func ListBackupStorageLocations(ctx context.Context, kbClient client.Client, namespace string) (velerov1api.BackupStorageLocationList, error) {
var locations velerov1api.BackupStorageLocationList
if err := kbClient.List(ctx, &locations, &client.ListOptions{
Namespace: namespace,
}); err != nil {
return velerov1api.BackupStorageLocationList{}, err
}
if len(locations.Items) == 0 {
return velerov1api.BackupStorageLocationList{}, errors.New("no backup storage locations found")
}
return locations, nil
}

View File

@@ -0,0 +1,168 @@
/*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 storage
import (
"context"
"testing"
"time"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/scheme"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
)
func TestIsReadyToValidate(t *testing.T) {
tests := []struct {
name string
bslValidationFrequency *metav1.Duration
lastValidationTime *metav1.Time
defaultLocationInfo DefaultBackupLocationInfo
// serverDefaultValidationFrequency time.Duration
// backupLocation *velerov1api.BackupStorageLocation
ready bool
}{
{
name: "don't validate, since frequency is set to zero",
bslValidationFrequency: &metav1.Duration{Duration: 0},
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 0,
},
ready: false,
},
{
name: "validate as per location setting, as that takes precedence, and always if it has never been validated before regardless of the frequency setting",
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Hour},
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 0,
},
ready: true,
},
{
name: "don't validate as per location setting, as it is set to zero and that takes precedence",
bslValidationFrequency: &metav1.Duration{Duration: 0},
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 1,
},
ready: false,
},
{
name: "validate as per default setting when location setting is not set",
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 1,
},
ready: true,
},
{
name: "don't validate when default setting is set to zero and the location setting is not set",
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 0,
},
ready: false,
},
{
name: "don't validate when now is before the NEXT validation time (validation frequency + last validation time)",
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Second},
lastValidationTime: &metav1.Time{Time: time.Now()},
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 0,
},
ready: false,
},
{
name: "validate when now is equal to the NEXT validation time (validation frequency + last validation time)",
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Second},
lastValidationTime: &metav1.Time{Time: time.Now().Add(-1 * time.Second)},
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 0,
},
ready: true,
},
{
name: "validate when now is after the NEXT validation time (validation frequency + last validation time)",
bslValidationFrequency: &metav1.Duration{Duration: 1 * time.Second},
lastValidationTime: &metav1.Time{Time: time.Now().Add(-2 * time.Second)},
defaultLocationInfo: DefaultBackupLocationInfo{
StoreValidationFrequency: 0,
},
ready: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
log := velerotest.NewLogger()
g.Expect(IsReadyToValidate(tt.bslValidationFrequency, tt.lastValidationTime, tt.defaultLocationInfo, log)).To(BeIdenticalTo(tt.ready))
})
}
}
func TestListBackupStorageLocations(t *testing.T) {
tests := []struct {
name string
backupLocations *velerov1api.BackupStorageLocationList
expectError bool
}{
{
name: "1 existing location does not return an error",
backupLocations: &velerov1api.BackupStorageLocationList{
Items: []velerov1api.BackupStorageLocation{
*builder.ForBackupStorageLocation("ns-1", "location-1").Result(),
},
},
expectError: false,
},
{
name: "multiple existing location does not return an error",
backupLocations: &velerov1api.BackupStorageLocationList{
Items: []velerov1api.BackupStorageLocation{
*builder.ForBackupStorageLocation("ns-1", "location-1").Result(),
*builder.ForBackupStorageLocation("ns-1", "location-2").Result(),
*builder.ForBackupStorageLocation("ns-1", "location-3").Result(),
},
},
expectError: false,
},
{
name: "no existing locations returns an error",
backupLocations: &velerov1api.BackupStorageLocationList{},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)
client := fake.NewFakeClientWithScheme(scheme.Scheme, tt.backupLocations)
if tt.expectError {
_, err := ListBackupStorageLocations(context.Background(), client, "ns-1")
g.Expect(err).NotTo(BeNil())
} else {
_, err := ListBackupStorageLocations(context.Background(), client, "ns-1")
g.Expect(err).To(BeNil())
}
})
}
}

View File

@@ -0,0 +1,73 @@
/*
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 velero
import (
"context"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/clock"
"sigs.k8s.io/controller-runtime/pkg/client"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/buildinfo"
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
)
// ServerStatus holds information for retrieving installed
// plugins and for updating the ServerStatusRequest timestamp.
type ServerStatus struct {
PluginRegistry PluginLister
Clock clock.Clock
}
// PatchStatusProcessed patches status fields, including loading the plugin info, and updates
// the ServerStatusRequest.Status.Phase to ServerStatusRequestPhaseProcessed.
func (s *ServerStatus) PatchStatusProcessed(kbClient client.Client, req *velerov1api.ServerStatusRequest, ctx context.Context) error {
statusPatch := client.MergeFrom(req.DeepCopyObject())
req.Status.ServerVersion = buildinfo.Version
req.Status.Phase = velerov1api.ServerStatusRequestPhaseProcessed
req.Status.ProcessedTimestamp = &metav1.Time{Time: s.Clock.Now()}
req.Status.Plugins = getInstalledPluginInfo(s.PluginRegistry)
if err := kbClient.Status().Patch(ctx, req, statusPatch); err != nil {
return errors.WithStack(err)
}
return nil
}
type PluginLister interface {
// List returns all PluginIdentifiers for kind.
List(kind framework.PluginKind) []framework.PluginIdentifier
}
func getInstalledPluginInfo(pluginLister PluginLister) []velerov1api.PluginInfo {
var plugins []velerov1api.PluginInfo
for _, v := range framework.AllPluginKinds() {
list := pluginLister.List(v)
for _, plugin := range list {
pluginInfo := velerov1api.PluginInfo{
Name: plugin.Name,
Kind: plugin.Kind.String(),
}
plugins = append(plugins, pluginInfo)
}
}
return plugins
}

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