mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-15 09:12:52 +00:00
Compare commits
82 Commits
dependabot
...
v1.9.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a617fe5af | ||
|
|
20af50692a | ||
|
|
2fa4a01d57 | ||
|
|
58f64e6a01 | ||
|
|
48856f2d9c | ||
|
|
d1ead7a443 | ||
|
|
4a57c6df77 | ||
|
|
bd646b14b9 | ||
|
|
3ca580b7d9 | ||
|
|
0993a44bab | ||
|
|
6750836d69 | ||
|
|
6358507796 | ||
|
|
9027e0b728 | ||
|
|
55cf05f369 | ||
|
|
904cdab920 | ||
|
|
f54db0e2cd | ||
|
|
36ac65696b | ||
|
|
95d4e34406 | ||
|
|
66edb1a0ea | ||
|
|
e22a5f97d0 | ||
|
|
337adaea18 | ||
|
|
6fc19445b3 | ||
|
|
59814d7378 | ||
|
|
c6274c7f00 | ||
|
|
82a100981c | ||
|
|
798310015b | ||
|
|
14a1be8416 | ||
|
|
beaaa3aca2 | ||
|
|
a3f32f942f | ||
|
|
11dbf8c974 | ||
|
|
efd8eb3e3c | ||
|
|
6f5d9b030a | ||
|
|
b7ee7e4e1c | ||
|
|
962f543470 | ||
|
|
6ad78a1d1e | ||
|
|
f911e13242 | ||
|
|
515eff5330 | ||
|
|
1aa5004606 | ||
|
|
0ae1f9c565 | ||
|
|
70a03ed27f | ||
|
|
5d84a27300 | ||
|
|
b0945d7740 | ||
|
|
727c633226 | ||
|
|
2b9a799e84 | ||
|
|
313f836d23 | ||
|
|
3de8be83f4 | ||
|
|
9937607e72 | ||
|
|
bfbefee0f5 | ||
|
|
61b247419c | ||
|
|
6fe8d4b65f | ||
|
|
e4c84b7b3d | ||
|
|
dc45cd141c | ||
|
|
af6912286b | ||
|
|
54eaa57ada | ||
|
|
2d88c9a436 | ||
|
|
7a749b8cf7 | ||
|
|
5f86cfae15 | ||
|
|
8487585732 | ||
|
|
5838e35e2e | ||
|
|
56eb492acb | ||
|
|
5ac7d52cac | ||
|
|
b7073fb2bf | ||
|
|
ac58c7508b | ||
|
|
18375cf1a9 | ||
|
|
b870847375 | ||
|
|
4d20c5a112 | ||
|
|
e76b697b45 | ||
|
|
b5c14d90bb | ||
|
|
a6fb4bb65a | ||
|
|
1996ee3be0 | ||
|
|
6021f148c4 | ||
|
|
1ed7481c90 | ||
|
|
ce9ac0d8b0 | ||
|
|
5dbc98e679 | ||
|
|
8c2a75eea5 | ||
|
|
e9e2b66b5f | ||
|
|
ef890f2a5e | ||
|
|
6418fda2e4 | ||
|
|
43c70b4691 | ||
|
|
2021e4fa58 | ||
|
|
162cf6e99b | ||
|
|
881e562ab1 |
2
.github/workflows/crds-verify-kind.yaml
vendored
2
.github/workflows/crds-verify-kind.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
go-version: 1.18
|
||||
id: go
|
||||
# Look for a CLI that's made for this PR
|
||||
- name: Fetch built CLI
|
||||
|
||||
4
.github/workflows/e2e-test-kind.yaml
vendored
4
.github/workflows/e2e-test-kind.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.18
|
||||
id: go
|
||||
# Look for a CLI that's made for this PR
|
||||
- name: Fetch built CLI
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.18
|
||||
id: go
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
2
.github/workflows/pr-ci-check.yml
vendored
2
.github/workflows/pr-ci-check.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.18
|
||||
id: go
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
4
.github/workflows/pr-codespell.yml
vendored
4
.github/workflows/pr-codespell.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
# ignore the config/.../crd.go file as it's generated binary data that is edited elswhere.
|
||||
skip: .git,*.png,*.jpg,*.woff,*.ttf,*.gif,*.ico,./config/crd/v1beta1/crds/crds.go,./config/crd/v1/crds/crds.go
|
||||
ignore_words_list: iam,aks,ist,bridget,ue
|
||||
skip: .git,*.png,*.jpg,*.woff,*.ttf,*.gif,*.ico,./config/crd/v1beta1/crds/crds.go,./config/crd/v1/crds/crds.go,./go.sum
|
||||
ignore_words_list: iam,aks,ist,bridget,ue,shouldnot
|
||||
check_filenames: true
|
||||
check_hidden: true
|
||||
|
||||
2
.github/workflows/push.yml
vendored
2
.github/workflows/push.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
go-version: 1.18
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
dist: _output
|
||||
builds:
|
||||
- main: ./cmd/velero/main.go
|
||||
- main: ./cmd/velero/velero.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# 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.17.11 as builder-env
|
||||
FROM --platform=$BUILDPLATFORM golang:1.18.8 as builder-env
|
||||
|
||||
ARG GOPROXY
|
||||
ARG PKG
|
||||
@@ -29,8 +29,6 @@ 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
|
||||
@@ -45,12 +43,12 @@ ENV GOOS=${TARGETOS} \
|
||||
GOARM=${TARGETVARIANT}
|
||||
|
||||
RUN mkdir -p /output/usr/bin && \
|
||||
bash ./hack/download-restic.sh && \
|
||||
export GOARM=$( echo "${GOARM}" | cut -c2-) && \
|
||||
bash ./hack/build-restic.sh && \
|
||||
go build -o /output/${BIN} \
|
||||
-ldflags "${LDFLAGS}" ${PKG}/cmd/${BIN}
|
||||
|
||||
FROM gcr.io/distroless/base-debian11@sha256:e672eb713e56feb13e349773973b81b1b9284f70b15cf18d1a09ad31a03abe59
|
||||
FROM gcr.io/distroless/base-debian11@sha256:99133cb0878bb1f84d1753957c6fd4b84f006f2798535de22ebf7ba170bbf434
|
||||
|
||||
LABEL maintainer="Nolan Brubaker <brubakern@vmware.com>"
|
||||
|
||||
|
||||
2
Tiltfile
2
Tiltfile
@@ -50,7 +50,7 @@ git_sha = str(local("git rev-parse HEAD", quiet = True, echo_off = True)).strip(
|
||||
|
||||
tilt_helper_dockerfile_header = """
|
||||
# Tilt image
|
||||
FROM golang:1.17 as tilt-helper
|
||||
FROM golang:1.18 as tilt-helper
|
||||
|
||||
# Support live reloading with Tilt
|
||||
RUN wget --output-document /restart.sh --quiet https://raw.githubusercontent.com/windmilleng/rerun-process-wrapper/master/restart.sh && \
|
||||
|
||||
@@ -1,3 +1,81 @@
|
||||
## v1.9.3
|
||||
### 2022-11-03
|
||||
|
||||
### Download
|
||||
https://github.com/vmware-tanzu/velero/releases/tag/v1.9.3
|
||||
|
||||
### Container Image
|
||||
`velero/velero:v1.9.3`
|
||||
|
||||
### Documentation
|
||||
https://velero.io/docs/v1.9/
|
||||
|
||||
### Upgrading
|
||||
https://velero.io/docs/v1.9/upgrade-to-1.9/
|
||||
|
||||
### All changes
|
||||
* Fix controller problematic log output (#5570, @qiuming-best)
|
||||
* Add compile restic binary for CVE fix (#5564, @qiuming-best)
|
||||
* Bump up golang version to 1.18.8 (#5558, @qiuming-best)
|
||||
* Enhance the restore priorities list to support specifying the low prioritized resources that need to be restored in the last (#5529, @ywk253100)
|
||||
* Fix v1.9.3 CSI VolumeSnapshot status duplicate issue. (#5518, @blackpiglet)
|
||||
* Bump up the distroless image to the latest version (#5500, @ywk253100)
|
||||
* Add some corner cases checking for CSI snapshot in backup controller. (#5482, @blackpiglet)
|
||||
* Skip the exclusion check for additional resources returned by BIA (#5406, @reasonerjt)
|
||||
* Exclude "csinodes.storage.k8s.io" and "volumeattachments.storage.k8s.io" from restore by default. (#5448, @jxun)
|
||||
* Update the k8s.io dependencies to 0.24.0 and Removed the `WithClusterName` method as it is a "legacy field that was always cleared by the system and never used" as per upstream k8s. (#5472, @kcboyle)
|
||||
|
||||
## v1.9.2
|
||||
### 2022-09-14
|
||||
|
||||
### Download
|
||||
https://github.com/vmware-tanzu/velero/releases/tag/v1.9.2
|
||||
|
||||
### Container Image
|
||||
`velero/velero:v1.9.2`
|
||||
|
||||
### Documentation
|
||||
https://velero.io/docs/v1.9/
|
||||
|
||||
### Upgrading
|
||||
https://velero.io/docs/v1.9/upgrade-to-1.9/
|
||||
|
||||
### All changes
|
||||
|
||||
* Fix CVE-2022-1962 by bumping up golang version to 1.17.13 (#5286, @qiuming-best)
|
||||
* Fix code spell check fail (#5300, @qiuming-best)
|
||||
* Fix nil pointer panic when restoring StatefulSets (#5301, @divolgin)
|
||||
* Check for empty ns list before checking nslist[0] (#5302, @sseago)
|
||||
* check vsc null pointer (#5303, @lilongfeng0902)
|
||||
* Fix edge cases for already exists resources (#5304, @shubham-pampattiwar)
|
||||
* Increase ensure restic repository timeout to 5m (#5336, @shubham-pampattiwar)
|
||||
* Added DownloadTargetKindCSIBackupVolumeSnapshots for retrieving the signed URL to download only the `<backup name>`-csi-volumesnapshots.json.gz and DownloadTargetKindCSIBackupVolumeSnapshotContents to download only `<backup name>`-csi-volumesnapshotcontents.json.gz in the DownloadRequest CR structure. These files are already present in the backup layout. (#5307, @anshulahuja98)
|
||||
## v1.9.1
|
||||
### 2022-08-03
|
||||
|
||||
### Download
|
||||
https://github.com/vmware-tanzu/velero/releases/tag/v1.9.1
|
||||
|
||||
### Container Image
|
||||
`velero/velero:v1.9.1`
|
||||
|
||||
### Documentation
|
||||
https://velero.io/docs/v1.9/
|
||||
|
||||
### Upgrading
|
||||
https://velero.io/docs/v1.9/upgrade-to-1.9/
|
||||
|
||||
### All changes
|
||||
|
||||
* Fix bsl validation bug: the BSL is validated continually and doesn't respect the validation period configured (#5112, @ywk253100)
|
||||
* Modify BackupStoreGetter to avoid BSL spec changes (#5134, @sseago)
|
||||
* Delay CA file deletion in PVB controller. (#5150, @jxun)
|
||||
* Skip registering "crd-remap-version" plugin when feature flag "EnableAPIGroupVersions" is set (#5173, @reasonerjt)
|
||||
* Fix restic backups to multiple backup storage locations bug (#5175, @qiuming-best)
|
||||
* Make CSI snapshot creation timeout configurable. (#5189, @jxun)
|
||||
* Add annotation "pv.kubernetes.io/migrated-to" for CSI checking. (#5186, @jxun)
|
||||
* Bump up base image and package version to fix CVEs. (#5202, @ywk253100)
|
||||
|
||||
## v1.9.0
|
||||
### 2022-06-13
|
||||
|
||||
@@ -102,3 +180,4 @@ With bumping up the API to v1 in CSI plugin, the v0.3.0 CSI plugin will only wor
|
||||
* Fix E2E test [Backups][Deletion][Restic] on GCP. (#4968, @jxun)
|
||||
* Disable status as sub resource in CRDs (#4972, @ywk253100)
|
||||
* Add more information for failing to get path or snapshot in restic backup and restore. (#4988, @jxun)
|
||||
* When spec.RestoreStatus is empty, don't restore status (#5015, @sseago)
|
||||
|
||||
@@ -37,6 +37,11 @@ spec:
|
||||
spec:
|
||||
description: BackupSpec defines the specification for a Velero backup.
|
||||
properties:
|
||||
csiSnapshotTimeout:
|
||||
description: CSISnapshotTimeout specifies the time used to wait for
|
||||
CSI VolumeSnapshot status turns to ReadyToUse during creation, before
|
||||
returning error as timeout. The default value is 10 minute.
|
||||
type: string
|
||||
defaultVolumesToRestic:
|
||||
description: DefaultVolumesToRestic specifies whether restic should
|
||||
be used to take a backup of all pod volumes by default.
|
||||
|
||||
@@ -50,6 +50,8 @@ spec:
|
||||
- BackupResourceList
|
||||
- RestoreLog
|
||||
- RestoreResults
|
||||
- CSIBackupVolumeSnapshots
|
||||
- CSIBackupVolumeSnapshotContents
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of the kubernetes resource with
|
||||
|
||||
@@ -205,14 +205,14 @@ spec:
|
||||
properties:
|
||||
args:
|
||||
description: 'Arguments to the entrypoint.
|
||||
The docker image''s CMD is used if this
|
||||
is not provided. Variable references $(VAR_NAME)
|
||||
are expanded using the container''s environment.
|
||||
If a variable cannot be resolved, the
|
||||
reference in the input string will be
|
||||
unchanged. Double $$ are reduced to a
|
||||
single $, which allows for escaping the
|
||||
$(VAR_NAME) syntax: i.e. "$$(VAR_NAME)"
|
||||
The container image''s CMD is used if
|
||||
this is not provided. Variable references
|
||||
$(VAR_NAME) are expanded using the container''s
|
||||
environment. If a variable cannot be resolved,
|
||||
the reference in the input string will
|
||||
be unchanged. Double $$ are reduced to
|
||||
a single $, which allows for escaping
|
||||
the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)"
|
||||
will produce the string literal "$(VAR_NAME)".
|
||||
Escaped references will never be expanded,
|
||||
regardless of whether the variable exists
|
||||
@@ -223,15 +223,15 @@ spec:
|
||||
type: array
|
||||
command:
|
||||
description: 'Entrypoint array. Not executed
|
||||
within a shell. The docker image''s ENTRYPOINT
|
||||
is used if this is not provided. Variable
|
||||
references $(VAR_NAME) are expanded using
|
||||
the container''s environment. If a variable
|
||||
cannot be resolved, the reference in the
|
||||
input string will be unchanged. Double
|
||||
$$ are reduced to a single $, which allows
|
||||
for escaping the $(VAR_NAME) syntax: i.e.
|
||||
"$$(VAR_NAME)" will produce the string
|
||||
within a shell. The container image''s
|
||||
ENTRYPOINT is used if this is not provided.
|
||||
Variable references $(VAR_NAME) are expanded
|
||||
using the container''s environment. If
|
||||
a variable cannot be resolved, the reference
|
||||
in the input string will be unchanged.
|
||||
Double $$ are reduced to a single $, which
|
||||
allows for escaping the $(VAR_NAME) syntax:
|
||||
i.e. "$$(VAR_NAME)" will produce the string
|
||||
literal "$(VAR_NAME)". Escaped references
|
||||
will never be expanded, regardless of
|
||||
whether the variable exists or not. Cannot
|
||||
@@ -427,8 +427,8 @@ spec:
|
||||
type: object
|
||||
type: array
|
||||
image:
|
||||
description: 'Docker image name. More info:
|
||||
https://kubernetes.io/docs/concepts/containers/images
|
||||
description: 'Container image name. More
|
||||
info: https://kubernetes.io/docs/concepts/containers/images
|
||||
This field is optional to allow higher
|
||||
level config management to default or
|
||||
override container images in workload
|
||||
@@ -456,9 +456,8 @@ spec:
|
||||
info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
|
||||
properties:
|
||||
exec:
|
||||
description: One and only one of
|
||||
the following should be specified.
|
||||
Exec specifies the action to take.
|
||||
description: Exec specifies the
|
||||
action to take.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the
|
||||
@@ -534,11 +533,13 @@ spec:
|
||||
- port
|
||||
type: object
|
||||
tcpSocket:
|
||||
description: 'TCPSocket specifies
|
||||
an action involving a TCP port.
|
||||
TCP hooks not yet supported TODO:
|
||||
implement a realistic TCP lifecycle
|
||||
hook'
|
||||
description: Deprecated. TCPSocket
|
||||
is NOT supported as a LifecycleHandler
|
||||
and kept for the backward compatibility.
|
||||
There are no validation of this
|
||||
field and lifecycle hooks will
|
||||
fail in runtime when tcp handler
|
||||
is specified.
|
||||
properties:
|
||||
host:
|
||||
description: 'Optional: Host
|
||||
@@ -566,23 +567,21 @@ spec:
|
||||
such as liveness/startup probe failure,
|
||||
preemption, resource contention, etc.
|
||||
The handler is not called if the container
|
||||
crashes or exits. The reason for termination
|
||||
is passed to the handler. The Pod''s
|
||||
termination grace period countdown
|
||||
begins before the PreStop hooked is
|
||||
executed. Regardless of the outcome
|
||||
of the handler, the container will
|
||||
eventually terminate within the Pod''s
|
||||
termination grace period. Other management
|
||||
of the container blocks until the
|
||||
hook completes or until the termination
|
||||
grace period is reached. More info:
|
||||
https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
|
||||
crashes or exits. The Pod''s termination
|
||||
grace period countdown begins before
|
||||
the PreStop hook is executed. Regardless
|
||||
of the outcome of the handler, the
|
||||
container will eventually terminate
|
||||
within the Pod''s termination grace
|
||||
period (unless delayed by finalizers).
|
||||
Other management of the container
|
||||
blocks until the hook completes or
|
||||
until the termination grace period
|
||||
is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks'
|
||||
properties:
|
||||
exec:
|
||||
description: One and only one of
|
||||
the following should be specified.
|
||||
Exec specifies the action to take.
|
||||
description: Exec specifies the
|
||||
action to take.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the
|
||||
@@ -658,11 +657,13 @@ spec:
|
||||
- port
|
||||
type: object
|
||||
tcpSocket:
|
||||
description: 'TCPSocket specifies
|
||||
an action involving a TCP port.
|
||||
TCP hooks not yet supported TODO:
|
||||
implement a realistic TCP lifecycle
|
||||
hook'
|
||||
description: Deprecated. TCPSocket
|
||||
is NOT supported as a LifecycleHandler
|
||||
and kept for the backward compatibility.
|
||||
There are no validation of this
|
||||
field and lifecycle hooks will
|
||||
fail in runtime when tcp handler
|
||||
is specified.
|
||||
properties:
|
||||
host:
|
||||
description: 'Optional: Host
|
||||
@@ -691,9 +692,8 @@ spec:
|
||||
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
|
||||
properties:
|
||||
exec:
|
||||
description: One and only one of the
|
||||
following should be specified. Exec
|
||||
specifies the action to take.
|
||||
description: Exec specifies the action
|
||||
to take.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command
|
||||
@@ -720,6 +720,29 @@ spec:
|
||||
3. Minimum value is 1.
|
||||
format: int32
|
||||
type: integer
|
||||
grpc:
|
||||
description: GRPC specifies an action
|
||||
involving a GRPC port. This is a beta
|
||||
field and requires enabling GRPCContainerProbe
|
||||
feature gate.
|
||||
properties:
|
||||
port:
|
||||
description: Port number of the
|
||||
gRPC service. Number must be in
|
||||
the range 1 to 65535.
|
||||
format: int32
|
||||
type: integer
|
||||
service:
|
||||
description: "Service is the name
|
||||
of the service to place in the
|
||||
gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
|
||||
\n If this is not specified, the
|
||||
default behavior is defined by
|
||||
gRPC."
|
||||
type: string
|
||||
required:
|
||||
- port
|
||||
type: object
|
||||
httpGet:
|
||||
description: HTTPGet specifies the http
|
||||
request to perform.
|
||||
@@ -793,10 +816,8 @@ spec:
|
||||
format: int32
|
||||
type: integer
|
||||
tcpSocket:
|
||||
description: 'TCPSocket specifies an
|
||||
action involving a TCP port. TCP hooks
|
||||
not yet supported TODO: implement
|
||||
a realistic TCP lifecycle hook'
|
||||
description: TCPSocket specifies an
|
||||
action involving a TCP port.
|
||||
properties:
|
||||
host:
|
||||
description: 'Optional: Host name
|
||||
@@ -918,9 +939,8 @@ spec:
|
||||
Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
|
||||
properties:
|
||||
exec:
|
||||
description: One and only one of the
|
||||
following should be specified. Exec
|
||||
specifies the action to take.
|
||||
description: Exec specifies the action
|
||||
to take.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command
|
||||
@@ -947,6 +967,29 @@ spec:
|
||||
3. Minimum value is 1.
|
||||
format: int32
|
||||
type: integer
|
||||
grpc:
|
||||
description: GRPC specifies an action
|
||||
involving a GRPC port. This is a beta
|
||||
field and requires enabling GRPCContainerProbe
|
||||
feature gate.
|
||||
properties:
|
||||
port:
|
||||
description: Port number of the
|
||||
gRPC service. Number must be in
|
||||
the range 1 to 65535.
|
||||
format: int32
|
||||
type: integer
|
||||
service:
|
||||
description: "Service is the name
|
||||
of the service to place in the
|
||||
gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
|
||||
\n If this is not specified, the
|
||||
default behavior is defined by
|
||||
gRPC."
|
||||
type: string
|
||||
required:
|
||||
- port
|
||||
type: object
|
||||
httpGet:
|
||||
description: HTTPGet specifies the http
|
||||
request to perform.
|
||||
@@ -1020,10 +1063,8 @@ spec:
|
||||
format: int32
|
||||
type: integer
|
||||
tcpSocket:
|
||||
description: 'TCPSocket specifies an
|
||||
action involving a TCP port. TCP hooks
|
||||
not yet supported TODO: implement
|
||||
a realistic TCP lifecycle hook'
|
||||
description: TCPSocket specifies an
|
||||
action involving a TCP port.
|
||||
properties:
|
||||
host:
|
||||
description: 'Optional: Host name
|
||||
@@ -1121,13 +1162,17 @@ spec:
|
||||
no_new_privs flag will be set on the
|
||||
container process. AllowPrivilegeEscalation
|
||||
is true always when the container
|
||||
is: 1) run as Privileged 2) has CAP_SYS_ADMIN'
|
||||
is: 1) run as Privileged 2) has CAP_SYS_ADMIN
|
||||
Note that this field cannot be set
|
||||
when spec.os.name is windows.'
|
||||
type: boolean
|
||||
capabilities:
|
||||
description: The capabilities to add/drop
|
||||
when running containers. Defaults
|
||||
to the default set of capabilities
|
||||
granted by the container runtime.
|
||||
Note that this field cannot be set
|
||||
when spec.os.name is windows.
|
||||
properties:
|
||||
add:
|
||||
description: Added capabilities
|
||||
@@ -1148,7 +1193,9 @@ spec:
|
||||
description: Run container in privileged
|
||||
mode. Processes in privileged containers
|
||||
are essentially equivalent to root
|
||||
on the host. Defaults to false.
|
||||
on the host. Defaults to false. Note
|
||||
that this field cannot be set when
|
||||
spec.os.name is windows.
|
||||
type: boolean
|
||||
procMount:
|
||||
description: procMount denotes the type
|
||||
@@ -1157,12 +1204,15 @@ spec:
|
||||
uses the container runtime defaults
|
||||
for readonly paths and masked paths.
|
||||
This requires the ProcMountType feature
|
||||
flag to be enabled.
|
||||
flag to be enabled. Note that this
|
||||
field cannot be set when spec.os.name
|
||||
is windows.
|
||||
type: string
|
||||
readOnlyRootFilesystem:
|
||||
description: Whether this container
|
||||
has a read-only root filesystem. Default
|
||||
is false.
|
||||
is false. Note that this field cannot
|
||||
be set when spec.os.name is windows.
|
||||
type: boolean
|
||||
runAsGroup:
|
||||
description: The GID to run the entrypoint
|
||||
@@ -1171,7 +1221,9 @@ spec:
|
||||
in PodSecurityContext. If set in
|
||||
both SecurityContext and PodSecurityContext,
|
||||
the value specified in SecurityContext
|
||||
takes precedence.
|
||||
takes precedence. Note that this field
|
||||
cannot be set when spec.os.name is
|
||||
windows.
|
||||
format: int64
|
||||
type: integer
|
||||
runAsNonRoot:
|
||||
@@ -1196,7 +1248,9 @@ spec:
|
||||
PodSecurityContext. If set in both
|
||||
SecurityContext and PodSecurityContext,
|
||||
the value specified in SecurityContext
|
||||
takes precedence.
|
||||
takes precedence. Note that this field
|
||||
cannot be set when spec.os.name is
|
||||
windows.
|
||||
format: int64
|
||||
type: integer
|
||||
seLinuxOptions:
|
||||
@@ -1207,7 +1261,9 @@ spec:
|
||||
container. May also be set in PodSecurityContext. If
|
||||
set in both SecurityContext and PodSecurityContext,
|
||||
the value specified in SecurityContext
|
||||
takes precedence.
|
||||
takes precedence. Note that this field
|
||||
cannot be set when spec.os.name is
|
||||
windows.
|
||||
properties:
|
||||
level:
|
||||
description: Level is SELinux level
|
||||
@@ -1231,7 +1287,9 @@ spec:
|
||||
use by this container. If seccomp
|
||||
options are provided at both the pod
|
||||
& container level, the container options
|
||||
override the pod options.
|
||||
override the pod options. Note that
|
||||
this field cannot be set when spec.os.name
|
||||
is windows.
|
||||
properties:
|
||||
localhostProfile:
|
||||
description: localhostProfile indicates
|
||||
@@ -1264,7 +1322,8 @@ spec:
|
||||
will be used. If set in both SecurityContext
|
||||
and PodSecurityContext, the value
|
||||
specified in SecurityContext takes
|
||||
precedence.
|
||||
precedence. Note that this field cannot
|
||||
be set when spec.os.name is linux.
|
||||
properties:
|
||||
gmsaCredentialSpec:
|
||||
description: GMSACredentialSpec
|
||||
@@ -1326,9 +1385,8 @@ spec:
|
||||
updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
|
||||
properties:
|
||||
exec:
|
||||
description: One and only one of the
|
||||
following should be specified. Exec
|
||||
specifies the action to take.
|
||||
description: Exec specifies the action
|
||||
to take.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command
|
||||
@@ -1355,6 +1413,29 @@ spec:
|
||||
3. Minimum value is 1.
|
||||
format: int32
|
||||
type: integer
|
||||
grpc:
|
||||
description: GRPC specifies an action
|
||||
involving a GRPC port. This is a beta
|
||||
field and requires enabling GRPCContainerProbe
|
||||
feature gate.
|
||||
properties:
|
||||
port:
|
||||
description: Port number of the
|
||||
gRPC service. Number must be in
|
||||
the range 1 to 65535.
|
||||
format: int32
|
||||
type: integer
|
||||
service:
|
||||
description: "Service is the name
|
||||
of the service to place in the
|
||||
gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
|
||||
\n If this is not specified, the
|
||||
default behavior is defined by
|
||||
gRPC."
|
||||
type: string
|
||||
required:
|
||||
- port
|
||||
type: object
|
||||
httpGet:
|
||||
description: HTTPGet specifies the http
|
||||
request to perform.
|
||||
@@ -1428,10 +1509,8 @@ spec:
|
||||
format: int32
|
||||
type: integer
|
||||
tcpSocket:
|
||||
description: 'TCPSocket specifies an
|
||||
action involving a TCP port. TCP hooks
|
||||
not yet supported TODO: implement
|
||||
a realistic TCP lifecycle hook'
|
||||
description: TCPSocket specifies an
|
||||
action involving a TCP port.
|
||||
properties:
|
||||
host:
|
||||
description: 'Optional: Host name
|
||||
|
||||
@@ -61,6 +61,11 @@ spec:
|
||||
description: Template is the definition of the Backup to be run on
|
||||
the provided schedule
|
||||
properties:
|
||||
csiSnapshotTimeout:
|
||||
description: CSISnapshotTimeout specifies the time used to wait
|
||||
for CSI VolumeSnapshot status turns to ReadyToUse during creation,
|
||||
before returning error as timeout. The default value is 10 minute.
|
||||
type: string
|
||||
defaultVolumesToRestic:
|
||||
description: DefaultVolumesToRestic specifies whether restic should
|
||||
be used to take a backup of all pod volumes by default.
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -505,6 +505,8 @@ spec:
|
||||
- BackupResourceList
|
||||
- RestoreLog
|
||||
- RestoreResults
|
||||
- CSIBackupVolumeSnapshots
|
||||
- CSIBackupVolumeSnapshotContents
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of the kubernetes resource with
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
This document proposes a solution that allows user to specify a backup order for resources of specific resource type.
|
||||
|
||||
## Background
|
||||
During backup process, user may need to back up resources of specific type in some specific order to ensure the resources were backup properly because these resources are related and ordering might be required to preserve the consistency for the apps to recover itself <EFBFBD>from the backup image
|
||||
During backup process, user may need to back up resources of specific type in some specific order to ensure the resources were backup properly because these resources are related and ordering might be required to preserve the consistency for the apps to recover itself from the backup image
|
||||
(Ex: primary-secondary database pods in a cluster).
|
||||
|
||||
## Goals
|
||||
@@ -12,7 +12,7 @@ During backup process, user may need to back up resources of specific type in so
|
||||
- Use a plugin to backup an resources and all the sub resources. For example use a plugin for StatefulSet and backup pods belong to the StatefulSet in specific order. This plugin solution is not generic and requires plugin for each resource type.
|
||||
|
||||
## High-Level Design
|
||||
User will specify a map of resource type to list resource names (separate by semicolons). Each name will be in the format "namespaceName/resourceName" to enable ordering accross namespaces. Based on this map, the resources of each resource type will be sorted by the order specified in the list of resources. If a resource instance belong to that specific type but its name is not in the order list, then it will be put behind other resources that are in the list.
|
||||
User will specify a map of resource type to list resource names (separate by semicolons). Each name will be in the format "namespaceName/resourceName" to enable ordering across namespaces. Based on this map, the resources of each resource type will be sorted by the order specified in the list of resources. If a resource instance belong to that specific type but its name is not in the order list, then it will be put behind other resources that are in the list.
|
||||
|
||||
### Changes to BackupSpec
|
||||
Add new field to BackupSpec
|
||||
@@ -36,5 +36,5 @@ Example:
|
||||
>velero backup create mybackup --ordered-resources "pod=ns1/pod1,ns1/pod2;persistentvolumeclaim=n2/slavepod,ns2/primarypod"
|
||||
|
||||
## Open Issues
|
||||
- In the CLI, the design proposes to use commas to separate items of a resource type and semicolon to separate key-value pairs. This follows the convention of using commas to separate items in a list (For example: --include-namespaces ns1,ns2). However, the syntax for map in labels and annotations use commas to seperate key-value pairs. So it introduces some inconsistency.
|
||||
- In the CLI, the design proposes to use commas to separate items of a resource type and semicolon to separate key-value pairs. This follows the convention of using commas to separate items in a list (For example: --include-namespaces ns1,ns2). However, the syntax for map in labels and annotations use commas to separate key-value pairs. So it introduces some inconsistency.
|
||||
- For pods that managed by Deployment or DaemonSet, this design may not work because the pods' name is randomly generated and if pods are restarted, they would have different names so the Backup operation may not consider the restarted pods in the sorting algorithm. This problem will be addressed when we enhance the design to use regular expression to specify the OrderResources instead of exact match.
|
||||
|
||||
@@ -28,7 +28,7 @@ This document proposes adding _controller-tools_ to the project to automatically
|
||||
_controller-tools_ works by reading the Go files that contain the API type definitions.
|
||||
It uses a combination of the struct fields, types, tags and comments to build the OpenAPIv3 schema for the CRDs. The tooling makes some assumptions based on conventions followed in upstream Kubernetes and the ecosystem, which involves some changes to the Velero API type definitions, especially around optional fields.
|
||||
|
||||
In order for _controller-tools_ to read the Go files containing Velero API type defintiions, the CRDs need to be generated at build time, as these files are not available at runtime (i.e. the Go files are not accessible by the compiled binary).
|
||||
In order for _controller-tools_ to read the Go files containing Velero API type definitions, the CRDs need to be generated at build time, as these files are not available at runtime (i.e. the Go files are not accessible by the compiled binary).
|
||||
These generated CRD manifests (YAML) will then need to be available to the `pkg/install` package for it to include when installing Velero resources.
|
||||
|
||||
## Detailed Design
|
||||
|
||||
@@ -429,7 +429,7 @@ Instead, a new method for 'Progress' will be added to interface. Velero server r
|
||||
|
||||
But, this involves good amount of changes and needs a way for backward compatibility.
|
||||
|
||||
As volume plugins are mostly K8s native, its fine to go ahead with current limiation.
|
||||
As volume plugins are mostly K8s native, its fine to go ahead with current limitation.
|
||||
|
||||
### Update Backup CR
|
||||
Instead of creating new CRs, plugins can directly update the status of Backup CR. But, this deviates from current approach of having separate CRs like PodVolumeBackup/PodVolumeRestore to know operations progress.
|
||||
|
||||
91
go.mod
91
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/vmware-tanzu/velero
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.10.0
|
||||
@@ -12,43 +12,43 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0
|
||||
github.com/apex/log v1.9.0
|
||||
github.com/aws/aws-sdk-go v1.28.2
|
||||
github.com/bombsimon/logrusr v1.1.0
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible
|
||||
github.com/bombsimon/logrusr/v3 v3.0.0
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gofrs/uuid v3.2.0+incompatible
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/google/go-cmp v0.5.6
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hashicorp/go-hclog v0.14.1
|
||||
github.com/hashicorp/go-plugin v1.4.3
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.16.0
|
||||
github.com/onsi/gomega v1.18.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/robfig/cron v1.1.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/afero v1.6.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/vmware-tanzu/crash-diagnostics v0.3.7
|
||||
golang.org/x/mod v0.4.2
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
|
||||
golang.org/x/net v0.0.0-20220615171555-694bf12d69de
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
google.golang.org/api v0.56.0
|
||||
google.golang.org/grpc v1.40.0
|
||||
k8s.io/api v0.22.2
|
||||
k8s.io/apiextensions-apiserver v0.22.2
|
||||
k8s.io/apimachinery v0.22.2
|
||||
k8s.io/cli-runtime v0.22.2
|
||||
k8s.io/client-go v0.22.2
|
||||
k8s.io/api v0.24.2
|
||||
k8s.io/apiextensions-apiserver v0.24.2
|
||||
k8s.io/apimachinery v0.24.2
|
||||
k8s.io/cli-runtime v0.24.0
|
||||
k8s.io/client-go v0.24.2
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/kube-aggregator v0.19.12
|
||||
sigs.k8s.io/controller-runtime v0.10.2
|
||||
sigs.k8s.io/controller-runtime v0.12.2
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
)
|
||||
|
||||
@@ -62,24 +62,30 @@ require (
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-logr/logr v0.4.0 // indirect
|
||||
github.com/go-logr/zapr v0.4.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/zapr v1.2.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.20.0 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/gnostic v0.6.9 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.1.0 // indirect
|
||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-ieproxy v0.0.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
@@ -88,39 +94,40 @@ require (
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/oklog/run v1.0.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/prometheus/common v0.34.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/vladimirvivien/gexe v0.1.1 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.starlark.net v0.0.0-20201006213952-227f4aabceb5 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.19.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
|
||||
go.uber.org/zap v1.19.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
||||
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
k8s.io/component-base v0.22.2 // indirect
|
||||
k8s.io/klog/v2 v2.9.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/component-base v0.24.2 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20220614142933-1062c7ade5f8 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
|
||||
|
||||
228
go.sum
228
go.sum
@@ -52,7 +52,6 @@ github.com/Azure/azure-sdk-for-go v61.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
|
||||
github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM=
|
||||
github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
@@ -108,6 +107,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||
github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
|
||||
github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
|
||||
github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
|
||||
@@ -117,6 +117,8 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.28.2 h1:j5IXG9CdyLfcVfICqo1PXVv+rua+QQHbkXuvuU/JF+8=
|
||||
@@ -133,16 +135,17 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bombsimon/logrusr v1.1.0 h1:Y03FI4Z/Shyrc9jF26vuaUbnPxC5NMJnTtJA/3Lihq8=
|
||||
github.com/bombsimon/logrusr v1.1.0/go.mod h1:Jq0nHtvxabKE5EMwAAdgTaz7dfWE8C4i11NOltxGQpc=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bombsimon/logrusr/v3 v3.0.0 h1:tcAoLfuAhKP9npBxWzSdpsvKPQt1XV02nSf2lZA82TQ=
|
||||
github.com/bombsimon/logrusr/v3 v3.0.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
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/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -167,6 +170,7 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
|
||||
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -186,6 +190,8 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7fo
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
@@ -196,19 +202,24 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
|
||||
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -219,29 +230,38 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
|
||||
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-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
|
||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
|
||||
github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk=
|
||||
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
|
||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
@@ -252,6 +272,7 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -290,6 +311,11 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w=
|
||||
github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
|
||||
github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
|
||||
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=
|
||||
@@ -301,8 +327,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
@@ -324,6 +351,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
@@ -332,17 +360,18 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@@ -385,8 +414,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
|
||||
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
@@ -398,14 +427,16 @@ 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/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
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.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
@@ -414,7 +445,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@@ -439,6 +469,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@@ -476,15 +508,17 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||
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=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
@@ -505,14 +539,16 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
|
||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
@@ -531,8 +567,10 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
|
||||
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.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
|
||||
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
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=
|
||||
@@ -542,14 +580,17 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
||||
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.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.34.0 h1:RBmGO9d/FVjqHT0yUGQwBJhkwKV+wPCn7KGpvfab0uE=
|
||||
github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE=
|
||||
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.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/robfig/cron v1.1.0 h1:jk4/Hud3TTdcrJgUOBgsqrZBarcxl6ADIjSC2iniwLY=
|
||||
github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
|
||||
@@ -558,6 +599,7 @@ github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
@@ -586,8 +628,9 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
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=
|
||||
@@ -608,8 +651,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
|
||||
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
|
||||
@@ -627,6 +671,9 @@ github.com/vladimirvivien/gexe v0.1.1 h1:2A0SBaOSKH+cwLVdt6H+KkHZotZWRNLlWygANGw
|
||||
github.com/vladimirvivien/gexe v0.1.1/go.mod h1:LHQL00w/7gDUKIak24n801ABp8C+ni6eBht9vGVst8w=
|
||||
github.com/vmware-tanzu/crash-diagnostics v0.3.7 h1:6gbv/3o1FzyRLS7Dz/+yVg1Lk1oRBQLyI3d1YTtlTT8=
|
||||
github.com/vmware-tanzu/crash-diagnostics v0.3.7/go.mod h1:gO8670rd+qdjnJVol674snT/A46GQ27u085kKhZznlM=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
@@ -635,15 +682,19 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
|
||||
go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
|
||||
go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
|
||||
@@ -674,15 +725,17 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -697,8 +750,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -722,7 +777,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
@@ -734,8 +788,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -785,8 +840,16 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220615171555-694bf12d69de h1:ogOG2+P6LjO2j55AkRScrkB2BFpd+Z8TY2wcM0Z3MGo=
|
||||
golang.org/x/net v0.0.0-20220615171555-694bf12d69de/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -802,8 +865,11 @@ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb h1:8tDJ3aechhddbdPAxpycgXHJRMLpk/Ab+aa4OgdN5/g=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
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=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -849,7 +915,6 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/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-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -866,7 +931,6 @@ golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -892,14 +956,21 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 h1:PgOr27OhUx2IRqGJ2RxAWI4dJQ7bi9cSrB82uzFzfUA=
|
||||
golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -916,8 +987,10 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -979,12 +1052,11 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
||||
@@ -1059,6 +1131,7 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
@@ -1079,8 +1152,10 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA=
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v1.8.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=
|
||||
@@ -1122,8 +1197,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -1156,8 +1232,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
@@ -1170,60 +1248,78 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
|
||||
k8s.io/api v0.19.12/go.mod h1:EK+KvSq2urA6+CjVdZyAHEphXoLq2K2eW6lxOzTKSaY=
|
||||
k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw=
|
||||
k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
|
||||
k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4=
|
||||
k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
|
||||
k8s.io/api v0.24.0/go.mod h1:5Jl90IUrJHUJYEMANRURMiVvJ0g7Ax7r3R1bqO8zx8I=
|
||||
k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI=
|
||||
k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg=
|
||||
k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k=
|
||||
k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ=
|
||||
k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
|
||||
k8s.io/apimachinery v0.19.12/go.mod h1:9eb44nUQSsz9QZiilFRuMj3ZbTmoWolU8S2gnXoRMjo=
|
||||
k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk=
|
||||
k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
|
||||
k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM=
|
||||
k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
|
||||
k8s.io/apiserver v0.19.12/go.mod h1:ldZAZTNIKfMMv/UUEhk6UyTXC0/34iRdNFHo+MJOPc4=
|
||||
k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
|
||||
k8s.io/cli-runtime v0.22.2 h1:fsd9rFk9FSaVq4SUq1fM27c8CFGsYZUJ/3BkgmjYWuY=
|
||||
k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI=
|
||||
k8s.io/cli-runtime v0.22.2/go.mod h1:tkm2YeORFpbgQHEK/igqttvPTRIHFRz5kATlw53zlMI=
|
||||
k8s.io/cli-runtime v0.24.0 h1:ot3Qf49T852uEyNApABO1UHHpFIckKK/NqpheZYN2gM=
|
||||
k8s.io/cli-runtime v0.24.0/go.mod h1:9XxoZDsEkRFUThnwqNviqzljtT/LdHtNWvcNFrAXl0A=
|
||||
k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
|
||||
k8s.io/client-go v0.19.12/go.mod h1:BAGKQraZ6fDmXhT46pGXWZQQqN7P4E0BJux0+9O6Gt0=
|
||||
k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc=
|
||||
k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
|
||||
k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw=
|
||||
k8s.io/client-go v0.24.2 h1:CoXFSf8if+bLEbinDqN9ePIDGzcLtqhfd6jpfnwGOFA=
|
||||
k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30=
|
||||
k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
|
||||
k8s.io/code-generator v0.19.12/go.mod h1:ADrDvaUQWGn4a8lX0ONtzb7uFmDRQOMSYIMk1qWIAx8=
|
||||
k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||
k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w=
|
||||
k8s.io/component-base v0.19.12/go.mod h1:tpwExE0sY3A7CwtlxGL7SnQOdQfUlnFybT6GmAD+z/s=
|
||||
k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M=
|
||||
k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
|
||||
k8s.io/component-base v0.24.2 h1:kwpQdoSfbcH+8MPN4tALtajLDfSfYxBDYlXobNWI6OU=
|
||||
k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM=
|
||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=
|
||||
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc=
|
||||
k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-aggregator v0.19.12 h1:OwyNUe/7/gxzEnaLd3sC9Yrpx0fZAERzvFslX5Qq5g8=
|
||||
k8s.io/kube-aggregator v0.19.12/go.mod h1:K76wPd03pSHEmS1FgJOcpryac5C3va4cbCvSu+4EmE0=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
|
||||
k8s.io/kube-openapi v0.0.0-20220614142933-1062c7ade5f8 h1:IyQ1DifCBk589JD4Cm2CT2poIdO3lfPzz3WwVh1Ugf8=
|
||||
k8s.io/kube-openapi v0.0.0-20220614142933-1062c7ade5f8/go.mod h1:guXtiQW/y/AWAfPSOaI/1eY0TGBAmL5OygiIyUOKDRc=
|
||||
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b h1:wxEMGetGMur3J1xuGLQY7GEQYg9bZxKn3tKo5k/eYcs=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
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.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/controller-runtime v0.10.2 h1:jW8qiY+yMnnPx6O9hu63tgcwaKzd1yLYui+mpvClOOc=
|
||||
sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw=
|
||||
sigs.k8s.io/controller-runtime v0.12.2 h1:nqV02cvhbAj7tbt21bpPpTByrXGn2INHRsi39lXy9sE=
|
||||
sigs.k8s.io/controller-runtime v0.12.2/go.mod h1:qKsk4WE6zW2Hfj0G4v10EnNB2jMG1C+NTb8h+DwCoU0=
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ=
|
||||
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||
sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g=
|
||||
sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI=
|
||||
sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM=
|
||||
sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
|
||||
@@ -25,8 +25,8 @@ run:
|
||||
# from this option's value (see skip-dirs-use-default).
|
||||
# "/" will be replaced by current OS file path separator to properly work
|
||||
# on Windows.
|
||||
#skip-dirs:
|
||||
# - src/external_libs
|
||||
skip-dirs:
|
||||
- test/e2e/*
|
||||
# - autogenerated_by_my_lib
|
||||
|
||||
# default is true. Enables skipping of directories:
|
||||
@@ -39,8 +39,8 @@ run:
|
||||
# autogenerated files. If it's not please let us know.
|
||||
# "/" will be replaced by current OS file path separator to properly work
|
||||
# on Windows.
|
||||
# skip-files:
|
||||
# - ".*\\.my\\.go$"
|
||||
skip-files:
|
||||
- ".*_test.go$"
|
||||
# - lib/bad.go
|
||||
|
||||
# by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules":
|
||||
@@ -117,7 +117,7 @@ linters-settings:
|
||||
# minimal length of string constant, 3 by default
|
||||
min-len: 3
|
||||
# minimal occurrences count to trigger, 3 by default
|
||||
min-occurrences: 3
|
||||
min-occurrences: 5
|
||||
gocritic:
|
||||
# Which checks should be enabled; can't be combined with 'disabled-checks';
|
||||
# See https://go-critic.github.io/overview#checks-overview
|
||||
@@ -320,7 +320,7 @@ linters:
|
||||
fast: false
|
||||
|
||||
|
||||
#issues:
|
||||
issues:
|
||||
# # List of regexps of issue texts to exclude, empty list by default.
|
||||
# # But independently from this option we use default exclude patterns,
|
||||
# # it can be disabled by `exclude-use-default: false`. To list all
|
||||
@@ -359,7 +359,7 @@ linters:
|
||||
# it can be disabled by this option. To list all
|
||||
# excluded by default patterns execute `golangci-lint run --help`.
|
||||
# Default value for this option is true.
|
||||
exclude-use-default: false
|
||||
exclude-use-default: true
|
||||
|
||||
# The default value is false. If set to true exclude and exclude-rules
|
||||
# regular expressions become case sensitive.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
FROM golang:1.17.11
|
||||
FROM golang:1.18.8
|
||||
|
||||
ARG GOPROXY
|
||||
|
||||
@@ -36,11 +36,11 @@ RUN wget --quiet https://github.com/kubernetes-sigs/kubebuilder/releases/downloa
|
||||
chmod +x /usr/local/kubebuilder/bin/kubebuilder
|
||||
|
||||
# get controller-tools
|
||||
RUN go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0
|
||||
RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0
|
||||
|
||||
# get goimports (the revision is pinned so we don't indiscriminately update, but the particular commit
|
||||
# is not important)
|
||||
RUN go get golang.org/x/tools/cmd/goimports@11e9d9cc0042e6bd10337d4d2c3e5d9295508e7d
|
||||
RUN go install golang.org/x/tools/cmd/goimports@11e9d9cc0042e6bd10337d4d2c3e5d9295508e7d
|
||||
|
||||
# get protoc compiler and golang plugin
|
||||
WORKDIR /root
|
||||
@@ -49,7 +49,7 @@ RUN wget --quiet https://github.com/protocolbuffers/protobuf/releases/download/v
|
||||
unzip protoc-3.9.1-linux-x86_64.zip && \
|
||||
mv bin/protoc /usr/bin/protoc && \
|
||||
chmod +x /usr/bin/protoc
|
||||
RUN go get github.com/golang/protobuf/protoc-gen-go@v1.0.0
|
||||
RUN go install github.com/golang/protobuf/protoc-gen-go@v1.0.0
|
||||
|
||||
# get goreleaser
|
||||
RUN wget --quiet https://github.com/goreleaser/goreleaser/releases/download/v0.120.8/goreleaser_Linux_x86_64.tar.gz && \
|
||||
@@ -58,7 +58,7 @@ 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.45.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
|
||||
|
||||
@@ -22,6 +22,7 @@ set -o pipefail
|
||||
# is the path expected by the Velero Dockerfile.
|
||||
output_dir=${OUTPUT_DIR:-/output/usr/bin}
|
||||
restic_bin=${output_dir}/restic
|
||||
build_path=$(dirname "$PWD")
|
||||
|
||||
if [[ -z "${BIN}" ]]; then
|
||||
echo "BIN must be set"
|
||||
@@ -46,8 +47,9 @@ if [[ -z "${RESTIC_VERSION}" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl -s -L https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_${GOOS}_${GOARCH}.bz2 -O
|
||||
bunzip2 restic_${RESTIC_VERSION}_${GOOS}_${GOARCH}.bz2
|
||||
mv restic_${RESTIC_VERSION}_${GOOS}_${GOARCH} ${restic_bin}
|
||||
|
||||
mkdir ${build_path}/restic
|
||||
git clone -b v${RESTIC_VERSION} https://github.com/restic/restic.git ${build_path}/restic
|
||||
pushd ${build_path}/restic
|
||||
go run build.go --goos "${GOOS}" --goarch "${GOARCH}" --goarm "${GOARM}" -o ${restic_bin}
|
||||
chmod +x ${restic_bin}
|
||||
popd
|
||||
@@ -95,7 +95,7 @@ eval $(go run $DIR/chk_version.go)
|
||||
printf "To clarify, you've provided a version string of $VELERO_VERSION.\n"
|
||||
printf "Based on this, the following assumptions have been made: \n"
|
||||
|
||||
# $VELERO_PATCH gets populated by the chk_version.go scrip that parses and verifies the given version format
|
||||
# $VELERO_PATCH gets populated by the chk_version.go script that parses and verifies the given version format
|
||||
# If we've got a patch release, we assume the tag is on release branch.
|
||||
if [[ "$VELERO_PATCH" != 0 ]]; then
|
||||
printf "*\t This is a patch release.\n"
|
||||
|
||||
@@ -110,6 +110,12 @@ type BackupSpec struct {
|
||||
// +optional
|
||||
// +nullable
|
||||
OrderedResources map[string]string `json:"orderedResources,omitempty"`
|
||||
|
||||
// CSISnapshotTimeout specifies the time used to wait for CSI VolumeSnapshot status turns to
|
||||
// ReadyToUse during creation, before returning error as timeout.
|
||||
// The default value is 10 minute.
|
||||
// +optional
|
||||
CSISnapshotTimeout metav1.Duration `json:"csiSnapshotTimeout,omitempty"`
|
||||
}
|
||||
|
||||
// BackupHooks contains custom behaviors that should be executed at different phases of the backup.
|
||||
|
||||
@@ -25,17 +25,19 @@ type DownloadRequestSpec struct {
|
||||
}
|
||||
|
||||
// DownloadTargetKind represents what type of file to download.
|
||||
// +kubebuilder:validation:Enum=BackupLog;BackupContents;BackupVolumeSnapshots;BackupItemSnapshots;BackupResourceList;RestoreLog;RestoreResults
|
||||
// +kubebuilder:validation:Enum=BackupLog;BackupContents;BackupVolumeSnapshots;BackupItemSnapshots;BackupResourceList;RestoreLog;RestoreResults;CSIBackupVolumeSnapshots;CSIBackupVolumeSnapshotContents
|
||||
type DownloadTargetKind string
|
||||
|
||||
const (
|
||||
DownloadTargetKindBackupLog DownloadTargetKind = "BackupLog"
|
||||
DownloadTargetKindBackupContents DownloadTargetKind = "BackupContents"
|
||||
DownloadTargetKindBackupVolumeSnapshots DownloadTargetKind = "BackupVolumeSnapshots"
|
||||
DownloadTargetKindBackupItemSnapshots DownloadTargetKind = "BackupItemSnapshots"
|
||||
DownloadTargetKindBackupResourceList DownloadTargetKind = "BackupResourceList"
|
||||
DownloadTargetKindRestoreLog DownloadTargetKind = "RestoreLog"
|
||||
DownloadTargetKindRestoreResults DownloadTargetKind = "RestoreResults"
|
||||
DownloadTargetKindBackupLog DownloadTargetKind = "BackupLog"
|
||||
DownloadTargetKindBackupContents DownloadTargetKind = "BackupContents"
|
||||
DownloadTargetKindBackupVolumeSnapshots DownloadTargetKind = "BackupVolumeSnapshots"
|
||||
DownloadTargetKindBackupItemSnapshots DownloadTargetKind = "BackupItemSnapshots"
|
||||
DownloadTargetKindBackupResourceList DownloadTargetKind = "BackupResourceList"
|
||||
DownloadTargetKindRestoreLog DownloadTargetKind = "RestoreLog"
|
||||
DownloadTargetKindRestoreResults DownloadTargetKind = "RestoreResults"
|
||||
DownloadTargetKindCSIBackupVolumeSnapshots DownloadTargetKind = "CSIBackupVolumeSnapshots"
|
||||
DownloadTargetKindCSIBackupVolumeSnapshotContents DownloadTargetKind = "CSIBackupVolumeSnapshotContents"
|
||||
)
|
||||
|
||||
// DownloadTarget is the specification for what kind of file to download, and the name of the
|
||||
|
||||
@@ -250,6 +250,7 @@ func (in *BackupSpec) DeepCopyInto(out *BackupSpec) {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
out.CSISnapshotTimeout = in.CSISnapshotTimeout
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSpec.
|
||||
|
||||
@@ -84,7 +84,7 @@ func (e *Extractor) readBackup(tarRdr *tar.Reader) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
target := filepath.Join(dir, header.Name)
|
||||
target := filepath.Join(dir, header.Name) //nolint:gosec
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
|
||||
@@ -408,7 +408,7 @@ func (kb *kubernetesBackupper) BackupWithResolvers(log logrus.FieldLogger,
|
||||
}
|
||||
|
||||
func (kb *kubernetesBackupper) backupItem(log logrus.FieldLogger, gr schema.GroupResource, itemBackupper *itemBackupper, unstructured *unstructured.Unstructured, preferredGVR schema.GroupVersionResource) bool {
|
||||
backedUpItem, err := itemBackupper.backupItem(log, unstructured, gr, preferredGVR)
|
||||
backedUpItem, err := itemBackupper.backupItem(log, unstructured, gr, preferredGVR, false)
|
||||
if aggregate, ok := err.(kubeerrs.Aggregate); ok {
|
||||
log.WithField("name", unstructured.GetName()).Infof("%d errors encountered backup up item", len(aggregate.Errors()))
|
||||
// log each error separately so we get error location info in the log, and an
|
||||
|
||||
@@ -24,6 +24,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
@@ -47,6 +49,11 @@ import (
|
||||
"github.com/vmware-tanzu/velero/pkg/volume"
|
||||
)
|
||||
|
||||
const (
|
||||
mustIncludeAdditionalItemAnnotation = "backup.velero.io/must-include-additional-items"
|
||||
excludeFromBackupLabel = "velero.io/exclude-from-backup"
|
||||
)
|
||||
|
||||
// itemBackupper can back up individual items to a tar writer.
|
||||
type itemBackupper struct {
|
||||
backupRequest *Request
|
||||
@@ -65,7 +72,7 @@ type itemBackupper struct {
|
||||
// namespaces IncludesExcludes list.
|
||||
// In addition to the error return, backupItem also returns a bool indicating whether the item
|
||||
// was actually backed up.
|
||||
func (ib *itemBackupper) backupItem(logger logrus.FieldLogger, obj runtime.Unstructured, groupResource schema.GroupResource, preferredGVR schema.GroupVersionResource) (bool, error) {
|
||||
func (ib *itemBackupper) backupItem(logger logrus.FieldLogger, obj runtime.Unstructured, groupResource schema.GroupResource, preferredGVR schema.GroupVersionResource, mustInclude bool) (bool, error) {
|
||||
metadata, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -78,28 +85,31 @@ func (ib *itemBackupper) backupItem(logger logrus.FieldLogger, obj runtime.Unstr
|
||||
log = log.WithField("resource", groupResource.String())
|
||||
log = log.WithField("namespace", namespace)
|
||||
|
||||
if metadata.GetLabels()["velero.io/exclude-from-backup"] == "true" {
|
||||
log.Info("Excluding item because it has label velero.io/exclude-from-backup=true")
|
||||
return false, nil
|
||||
}
|
||||
if mustInclude {
|
||||
log.Infof("Skipping the exclusion checks for this resource")
|
||||
} else {
|
||||
if metadata.GetLabels()[excludeFromBackupLabel] == "true" {
|
||||
log.Infof("Excluding item because it has label %s=true", excludeFromBackupLabel)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// NOTE: we have to re-check namespace & resource includes/excludes because it's possible that
|
||||
// backupItem can be invoked by a custom action.
|
||||
if namespace != "" && !ib.backupRequest.NamespaceIncludesExcludes.ShouldInclude(namespace) {
|
||||
log.Info("Excluding item because namespace is excluded")
|
||||
return false, nil
|
||||
}
|
||||
// NOTE: we have to re-check namespace & resource includes/excludes because it's possible that
|
||||
// backupItem can be invoked by a custom action.
|
||||
if namespace != "" && !ib.backupRequest.NamespaceIncludesExcludes.ShouldInclude(namespace) {
|
||||
log.Info("Excluding item because namespace is excluded")
|
||||
return false, nil
|
||||
}
|
||||
// NOTE: we specifically allow namespaces to be backed up even if IncludeClusterResources is
|
||||
// false.
|
||||
if namespace == "" && groupResource != kuberesource.Namespaces && ib.backupRequest.Spec.IncludeClusterResources != nil && !*ib.backupRequest.Spec.IncludeClusterResources {
|
||||
log.Info("Excluding item because resource is cluster-scoped and backup.spec.includeClusterResources is false")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// NOTE: we specifically allow namespaces to be backed up even if IncludeClusterResources is
|
||||
// false.
|
||||
if namespace == "" && groupResource != kuberesource.Namespaces && ib.backupRequest.Spec.IncludeClusterResources != nil && !*ib.backupRequest.Spec.IncludeClusterResources {
|
||||
log.Info("Excluding item because resource is cluster-scoped and backup.spec.includeClusterResources is false")
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if !ib.backupRequest.ResourceIncludesExcludes.ShouldInclude(groupResource.String()) {
|
||||
log.Info("Excluding item because resource is excluded")
|
||||
return false, nil
|
||||
if !ib.backupRequest.ResourceIncludesExcludes.ShouldInclude(groupResource.String()) {
|
||||
log.Info("Excluding item because resource is excluded")
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
if metadata.GetDeletionTimestamp() != nil {
|
||||
@@ -315,7 +325,8 @@ func (ib *itemBackupper) executeActions(
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error executing custom action (groupResource=%s, namespace=%s, name=%s)", groupResource.String(), namespace, name)
|
||||
}
|
||||
obj = updatedItem
|
||||
u := &unstructured.Unstructured{Object: updatedItem.UnstructuredContent()}
|
||||
mustInclude := u.GetAnnotations()[mustIncludeAdditionalItemAnnotation] == "true"
|
||||
|
||||
for _, additionalItem := range additionalItemIdentifiers {
|
||||
gvr, resource, err := ib.discoveryHelper.ResourceFor(additionalItem.GroupResource.WithVersion(""))
|
||||
@@ -329,6 +340,7 @@ func (ib *itemBackupper) executeActions(
|
||||
}
|
||||
|
||||
item, err := client.Get(additionalItem.Name, metav1.GetOptions{})
|
||||
|
||||
if apierrors.IsNotFound(err) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"groupResource": additionalItem.GroupResource,
|
||||
@@ -341,12 +353,17 @@ func (ib *itemBackupper) executeActions(
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
if _, err = ib.backupItem(log, item, gvr.GroupResource(), gvr); err != nil {
|
||||
if _, err = ib.backupItem(log, item, gvr.GroupResource(), gvr, mustInclude); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// remove the annotation as it's for communication between BIA and velero server,
|
||||
// we don't want the resource be restored with this annotation.
|
||||
if _, ok := u.GetAnnotations()[mustIncludeAdditionalItemAnnotation]; ok {
|
||||
delete(u.GetAnnotations(), mustIncludeAdditionalItemAnnotation)
|
||||
}
|
||||
obj = u
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ func sortResourcesByOrder(log logrus.FieldLogger, items []*kubernetesResource, o
|
||||
}
|
||||
|
||||
// getOrderedResourcesForType gets order of resourceType from orderResources.
|
||||
func getOrderedResourcesForType(log logrus.FieldLogger, orderedResources map[string]string, resourceType string) []string {
|
||||
func getOrderedResourcesForType(orderedResources map[string]string, resourceType string) []string {
|
||||
if orderedResources == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func (r *itemCollector) getResourceItems(log logrus.FieldLogger, gv schema.Group
|
||||
clusterScoped = !resource.Namespaced
|
||||
)
|
||||
|
||||
orders := getOrderedResourcesForType(log, r.backupRequest.Backup.Spec.OrderedResources, resource.Name)
|
||||
orders := getOrderedResourcesForType(r.backupRequest.Backup.Spec.OrderedResources, resource.Name)
|
||||
// Getting the preferred group version of this resource
|
||||
preferredGVR, _, err := r.discoveryHelper.ResourceFor(gr.WithVersion(""))
|
||||
if err != nil {
|
||||
@@ -225,8 +225,11 @@ func (r *itemCollector) getResourceItems(log logrus.FieldLogger, gv schema.Group
|
||||
|
||||
namespacesToList := getNamespacesToList(r.backupRequest.NamespaceIncludesExcludes)
|
||||
|
||||
// Check if we're backing up namespaces, and only certain ones
|
||||
if gr == kuberesource.Namespaces && namespacesToList[0] != "" {
|
||||
// Check if we're backing up namespaces for a less-than-full backup.
|
||||
// We enter this block if resource is Namespaces and the namespae list is either empty or contains
|
||||
// an explicit namespace list. (We skip this block if the list contains "" since that indicates
|
||||
// a full-cluster backup
|
||||
if gr == kuberesource.Namespaces && (len(namespacesToList) == 0 || namespacesToList[0] != "") {
|
||||
resourceClient, err := r.dynamicFactory.ClientForGroupVersionResource(gv, resource, "")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error getting dynamic client")
|
||||
|
||||
@@ -50,7 +50,7 @@ type Request struct {
|
||||
VolumeSnapshots []*volume.Snapshot
|
||||
PodVolumeBackups []*velerov1api.PodVolumeBackup
|
||||
BackedUpItems map[itemKey]struct{}
|
||||
CSISnapshots []*snapshotv1api.VolumeSnapshot
|
||||
CSISnapshots []snapshotv1api.VolumeSnapshot
|
||||
}
|
||||
|
||||
// BackupResourceList returns the list of backed up resources grouped by the API
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -233,3 +233,9 @@ func (b *BackupBuilder) OrderedResources(orders map[string]string) *BackupBuilde
|
||||
b.object.Spec.OrderedResources = orders
|
||||
return b
|
||||
}
|
||||
|
||||
// CSISnapshotTimeout sets the Backup's CSISnapshotTimeout
|
||||
func (b *BackupBuilder) CSISnapshotTimeout(timeout time.Duration) *BackupBuilder {
|
||||
b.object.Spec.CSISnapshotTimeout.Duration = timeout
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -117,14 +117,6 @@ func setMapEntries(m map[string]string, vals ...string) map[string]string {
|
||||
return m
|
||||
}
|
||||
|
||||
// WithClusterName is a functional option that applies the specified
|
||||
// cluster name to an object.
|
||||
func WithClusterName(val string) func(obj metav1.Object) {
|
||||
return func(obj metav1.Object) {
|
||||
obj.SetClusterName(val)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFinalizers is a functional option that applies the specified
|
||||
// finalizers to an object.
|
||||
func WithFinalizers(vals ...string) func(obj metav1.Object) {
|
||||
|
||||
66
pkg/builder/volume_snapshot_builder.go
Normal file
66
pkg/builder/volume_snapshot_builder.go
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// VolumeSnapshotBuilder builds VolumeSnapshot objects.
|
||||
type VolumeSnapshotBuilder struct {
|
||||
object *snapshotv1api.VolumeSnapshot
|
||||
}
|
||||
|
||||
// ForVolumeSnapshot is the constructor for VolumeSnapshotBuilder.
|
||||
func ForVolumeSnapshot(ns, name string) *VolumeSnapshotBuilder {
|
||||
return &VolumeSnapshotBuilder{
|
||||
object: &snapshotv1api.VolumeSnapshot{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: snapshotv1api.SchemeGroupVersion.String(),
|
||||
Kind: "VolumeSnapshot",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: ns,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the VolumeSnapshot's ObjectMeta.
|
||||
func (v *VolumeSnapshotBuilder) ObjectMeta(opts ...ObjectMetaOpt) *VolumeSnapshotBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(v.object)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Result return the built VolumeSnapshot.
|
||||
func (v *VolumeSnapshotBuilder) Result() *snapshotv1api.VolumeSnapshot {
|
||||
return v.object
|
||||
}
|
||||
|
||||
// Status init the built VolumeSnapshot's status.
|
||||
func (v *VolumeSnapshotBuilder) Status() *VolumeSnapshotBuilder {
|
||||
v.object.Status = &snapshotv1api.VolumeSnapshotStatus{}
|
||||
return v
|
||||
}
|
||||
|
||||
// BoundVolumeSnapshotContentName set built VolumeSnapshot's status BoundVolumeSnapshotContentName field.
|
||||
func (v *VolumeSnapshotBuilder) BoundVolumeSnapshotContentName(vscName string) *VolumeSnapshotBuilder {
|
||||
v.object.Status.BoundVolumeSnapshotContentName = &vscName
|
||||
return v
|
||||
}
|
||||
67
pkg/builder/volume_snapshot_content_builder.go
Normal file
67
pkg/builder/volume_snapshot_content_builder.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// VolumeSnapshotContentBuilder builds VolumeSnapshotContent object.
|
||||
type VolumeSnapshotContentBuilder struct {
|
||||
object *snapshotv1api.VolumeSnapshotContent
|
||||
}
|
||||
|
||||
// ForVolumeSnapshotContent is the constructor of VolumeSnapshotContentBuilder.
|
||||
func ForVolumeSnapshotContent(name string) *VolumeSnapshotContentBuilder {
|
||||
return &VolumeSnapshotContentBuilder{
|
||||
object: &snapshotv1api.VolumeSnapshotContent{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: snapshotv1api.SchemeGroupVersion.String(),
|
||||
Kind: "VolumeSnapshotContent",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Result returns the built VolumeSnapshotContent.
|
||||
func (v *VolumeSnapshotContentBuilder) Result() *snapshotv1api.VolumeSnapshotContent {
|
||||
return v.object
|
||||
}
|
||||
|
||||
// Status initiates VolumeSnapshotContent's status.
|
||||
func (v *VolumeSnapshotContentBuilder) Status() *VolumeSnapshotContentBuilder {
|
||||
v.object.Status = &snapshotv1api.VolumeSnapshotContentStatus{}
|
||||
return v
|
||||
}
|
||||
|
||||
// DeletionPolicy sets built VolumeSnapshotContent's spec.DeletionPolicy value.
|
||||
func (v *VolumeSnapshotContentBuilder) DeletionPolicy(policy snapshotv1api.DeletionPolicy) *VolumeSnapshotContentBuilder {
|
||||
v.object.Spec.DeletionPolicy = policy
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *VolumeSnapshotContentBuilder) VolumeSnapshotRef(namespace, name string) *VolumeSnapshotContentBuilder {
|
||||
v.object.Spec.VolumeSnapshotRef = v1.ObjectReference{
|
||||
APIVersion: "snapshot.storage.k8s.io/v1",
|
||||
Kind: "VolumeSnapshot",
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
return v
|
||||
}
|
||||
@@ -98,6 +98,7 @@ type CreateOptions struct {
|
||||
SnapshotLocations []string
|
||||
FromSchedule string
|
||||
OrderedResources string
|
||||
CSISnapshotTimeout time.Duration
|
||||
|
||||
client veleroclient.Interface
|
||||
}
|
||||
@@ -122,6 +123,7 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
flags.StringSliceVar(&o.SnapshotLocations, "volume-snapshot-locations", o.SnapshotLocations, "List of locations (at most one per provider) where volume snapshots should be stored.")
|
||||
flags.VarP(&o.Selector, "selector", "l", "Only back up resources matching this label selector.")
|
||||
flags.StringVar(&o.OrderedResources, "ordered-resources", "", "Mapping Kinds to an ordered list of specific resources of that Kind. Resource names are separated by commas and their names are in format 'namespace/resourcename'. For cluster scope resource, simply use resource name. Key-value pairs in the mapping are separated by semi-colon. Example: 'pods=ns1/pod1,ns1/pod2;persistentvolumeclaims=ns1/pvc4,ns1/pvc8'. Optional.")
|
||||
flags.DurationVar(&o.CSISnapshotTimeout, "csi-snapshot-timeout", o.CSISnapshotTimeout, "How long to wait for CSI snapshot creation before timeout.")
|
||||
f := flags.VarPF(&o.SnapshotVolumes, "snapshot-volumes", "", "Take snapshots of PersistentVolumes as part of the backup.")
|
||||
// this allows the user to just specify "--snapshot-volumes" as shorthand for "--snapshot-volumes=true"
|
||||
// like a normal bool flag
|
||||
@@ -332,7 +334,8 @@ func (o *CreateOptions) BuildBackup(namespace string) (*velerov1api.Backup, erro
|
||||
LabelSelector(o.Selector.LabelSelector).
|
||||
TTL(o.TTL).
|
||||
StorageLocation(o.StorageLocation).
|
||||
VolumeSnapshotLocations(o.SnapshotLocations...)
|
||||
VolumeSnapshotLocations(o.SnapshotLocations...).
|
||||
CSISnapshotTimeout(o.CSISnapshotTimeout)
|
||||
if len(o.OrderedResources) > 0 {
|
||||
orders, err := ParseOrderedResources(o.OrderedResources)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ package backup
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -35,6 +36,7 @@ func TestCreateOptions_BuildBackup(t *testing.T) {
|
||||
o.Labels.Set("velero.io/test=true")
|
||||
o.OrderedResources = "pods=p1,p2;persistentvolumeclaims=pvc1,pvc2"
|
||||
orders, err := ParseOrderedResources(o.OrderedResources)
|
||||
o.CSISnapshotTimeout = 20 * time.Minute
|
||||
assert.NoError(t, err)
|
||||
|
||||
backup, err := o.BuildBackup(testNamespace)
|
||||
@@ -46,6 +48,7 @@ func TestCreateOptions_BuildBackup(t *testing.T) {
|
||||
SnapshotVolumes: o.SnapshotVolumes.Value,
|
||||
IncludeClusterResources: o.IncludeClusterResources.Value,
|
||||
OrderedResources: orders,
|
||||
CSISnapshotTimeout: metav1.Duration{Duration: o.CSISnapshotTimeout},
|
||||
}, backup.Spec)
|
||||
|
||||
assert.Equal(t, map[string]string{
|
||||
|
||||
@@ -73,7 +73,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
}
|
||||
|
||||
first := true
|
||||
for _, backup := range backups.Items {
|
||||
for i, backup := range backups.Items {
|
||||
deleteRequestListOptions := pkgbackup.NewDeleteBackupRequestListOptions(backup.Name, string(backup.UID))
|
||||
deleteRequestList, err := veleroClient.VeleroV1().DeleteBackupRequests(f.Namespace()).List(context.TODO(), deleteRequestListOptions)
|
||||
if err != nil {
|
||||
@@ -102,7 +102,7 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
}
|
||||
}
|
||||
|
||||
s := output.DescribeBackup(context.Background(), kbClient, &backup, deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
s := output.DescribeBackup(context.Background(), kbClient, &backups.Items[i], deleteRequestList.Items, podVolumeBackupList.Items, vscList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
|
||||
@@ -209,10 +209,10 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
if err := kbClient.List(context.Background(), locations, &kbclient.ListOptions{Namespace: f.Namespace()}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
for _, location := range locations.Items {
|
||||
for i, location := range locations.Items {
|
||||
if location.Spec.Default {
|
||||
location.Spec.Default = false
|
||||
if err := kbClient.Update(context.Background(), &location, &kbclient.UpdateOptions{}); err != nil {
|
||||
if err := kbClient.Update(context.Background(), &locations.Items[i], &kbclient.UpdateOptions{}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
break
|
||||
|
||||
@@ -115,8 +115,8 @@ func Run(f client.Factory, o *cli.DeleteOptions) error {
|
||||
}
|
||||
|
||||
// Create a backup-location deletion request for each
|
||||
for _, location := range locations.Items {
|
||||
if err := kbClient.Delete(context.Background(), &location, &kbclient.DeleteOptions{}); err != nil {
|
||||
for i, location := range locations.Items {
|
||||
if err := kbClient.Delete(context.Background(), &locations.Items[i], &kbclient.DeleteOptions{}); err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
}
|
||||
@@ -162,8 +162,8 @@ func findAssociatedResticRepos(client kbclient.Client, bslName, ns string) (vele
|
||||
|
||||
func deleteBackups(client kbclient.Client, backups velerov1api.BackupList) []error {
|
||||
var errs []error
|
||||
for _, backup := range backups.Items {
|
||||
if err := client.Delete(context.Background(), &backup, &kbclient.DeleteOptions{}); err != nil {
|
||||
for i, backup := range backups.Items {
|
||||
if err := client.Delete(context.Background(), &backups.Items[i], &kbclient.DeleteOptions{}); err != nil {
|
||||
errs = append(errs, errors.WithStack(fmt.Errorf("delete backup %q associated with deleted BSL: %w", backup.Name, err)))
|
||||
continue
|
||||
}
|
||||
@@ -174,8 +174,8 @@ func deleteBackups(client kbclient.Client, backups velerov1api.BackupList) []err
|
||||
|
||||
func deleteResticRepos(client kbclient.Client, repos velerov1api.ResticRepositoryList) []error {
|
||||
var errs []error
|
||||
for _, repo := range repos.Items {
|
||||
if err := client.Delete(context.Background(), &repo, &kbclient.DeleteOptions{}); err != nil {
|
||||
for i, repo := range repos.Items {
|
||||
if err := client.Delete(context.Background(), &repos.Items[i], &kbclient.DeleteOptions{}); err != nil {
|
||||
errs = append(errs, errors.WithStack(fmt.Errorf("delete Restic repository %q associated with deleted BSL: %w", repo.Name, err)))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func (o *SetOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
if err := kbClient.List(context.Background(), locations, &kbclient.ListOptions{Namespace: f.Namespace()}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
for _, location := range locations.Items {
|
||||
for i, location := range locations.Items {
|
||||
if !location.Spec.Default {
|
||||
continue
|
||||
}
|
||||
@@ -129,7 +129,7 @@ func (o *SetOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
break
|
||||
}
|
||||
location.Spec.Default = false
|
||||
if err := kbClient.Update(context.Background(), &location, &kbclient.UpdateOptions{}); err != nil {
|
||||
if err := kbClient.Update(context.Background(), &locations.Items[i], &kbclient.UpdateOptions{}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
break
|
||||
|
||||
@@ -175,7 +175,7 @@ func (s *resticServer) run() {
|
||||
metricsMux := http.NewServeMux()
|
||||
metricsMux.Handle("/metrics", promhttp.Handler())
|
||||
s.logger.Infof("Starting metric server for restic at address [%s]", s.metricsAddress)
|
||||
if err := http.ListenAndServe(s.metricsAddress, metricsMux); err != nil {
|
||||
if err := http.ListenAndServe(s.metricsAddress, metricsMux); err != nil { //nolint:gosec
|
||||
s.logger.Fatalf("Failed to start metric server for restic at [%s]: %v", s.metricsAddress, err)
|
||||
}
|
||||
}()
|
||||
@@ -291,7 +291,7 @@ func (s *resticServer) markInProgressPVBsFailed(client ctrlclient.Client) {
|
||||
log.WithError(errors.WithStack(err)).Error("failed to list podvolumebackups")
|
||||
return
|
||||
}
|
||||
for _, pvb := range pvbs.Items {
|
||||
for i, pvb := range pvbs.Items {
|
||||
if pvb.Status.Phase != velerov1api.PodVolumeBackupPhaseInProgress {
|
||||
log.Debugf("the status of podvolumebackup %q is %q, skip", pvb.GetName(), pvb.Status.Phase)
|
||||
continue
|
||||
@@ -304,7 +304,7 @@ func (s *resticServer) markInProgressPVBsFailed(client ctrlclient.Client) {
|
||||
pvb.Status.Phase = velerov1api.PodVolumeBackupPhaseFailed
|
||||
pvb.Status.Message = fmt.Sprintf("get a podvolumebackup with status %q during the server starting, mark it as %q", velerov1api.PodVolumeBackupPhaseInProgress, pvb.Status.Phase)
|
||||
pvb.Status.CompletionTimestamp = &metav1.Time{Time: time.Now()}
|
||||
if err := client.Patch(s.ctx, &pvb, ctrlclient.MergeFrom(original)); err != nil {
|
||||
if err := client.Patch(s.ctx, &pvbs.Items[i], ctrlclient.MergeFrom(original)); err != nil {
|
||||
log.WithError(errors.WithStack(err)).Errorf("failed to patch podvolumebackup %q", pvb.GetName())
|
||||
continue
|
||||
}
|
||||
@@ -318,7 +318,7 @@ func (s *resticServer) markInProgressPVRsFailed(client ctrlclient.Client) {
|
||||
log.WithError(errors.WithStack(err)).Error("failed to list podvolumerestores")
|
||||
return
|
||||
}
|
||||
for _, pvr := range pvrs.Items {
|
||||
for i, pvr := range pvrs.Items {
|
||||
if pvr.Status.Phase != velerov1api.PodVolumeRestorePhaseInProgress {
|
||||
log.Debugf("the status of podvolumerestore %q is %q, skip", pvr.GetName(), pvr.Status.Phase)
|
||||
continue
|
||||
@@ -342,7 +342,7 @@ func (s *resticServer) markInProgressPVRsFailed(client ctrlclient.Client) {
|
||||
pvr.Status.Phase = velerov1api.PodVolumeRestorePhaseFailed
|
||||
pvr.Status.Message = fmt.Sprintf("get a podvolumerestore with status %q during the server starting, mark it as %q", velerov1api.PodVolumeRestorePhaseInProgress, pvr.Status.Phase)
|
||||
pvr.Status.CompletionTimestamp = &metav1.Time{Time: time.Now()}
|
||||
if err := client.Patch(s.ctx, &pvr, ctrlclient.MergeFrom(original)); err != nil {
|
||||
if err := client.Patch(s.ctx, &pvrs.Items[i], ctrlclient.MergeFrom(original)); err != nil {
|
||||
log.WithError(errors.WithStack(err)).Errorf("failed to patch podvolumerestore %q", pvr.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -68,14 +68,14 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
}
|
||||
|
||||
first := true
|
||||
for _, restore := range restores.Items {
|
||||
for i, restore := range restores.Items {
|
||||
opts := restic.NewPodVolumeRestoreListOptions(restore.Name)
|
||||
podvolumeRestoreList, err := veleroClient.VeleroV1().PodVolumeRestores(f.Namespace()).List(context.TODO(), opts)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error getting PodVolumeRestores for restore %s: %v\n", restore.Name, err)
|
||||
}
|
||||
|
||||
s := output.DescribeRestore(context.Background(), kbClient, &restore, podvolumeRestoreList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
s := output.DescribeRestore(context.Background(), kbClient, &restores.Items[i], podvolumeRestoreList.Items, details, veleroClient, insecureSkipTLSVerify, caCertFile)
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
|
||||
@@ -145,6 +145,7 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
VolumeSnapshotLocations: o.BackupOptions.SnapshotLocations,
|
||||
DefaultVolumesToRestic: o.BackupOptions.DefaultVolumesToRestic.Value,
|
||||
OrderedResources: orders,
|
||||
CSISnapshotTimeout: metav1.Duration{Duration: o.BackupOptions.CSISnapshotTimeout},
|
||||
},
|
||||
Schedule: o.Schedule,
|
||||
UseOwnerReferencesInBackup: &o.UseOwnerReferencesInBackup,
|
||||
|
||||
@@ -53,8 +53,8 @@ func NewDescribeCommand(f client.Factory, use string) *cobra.Command {
|
||||
}
|
||||
|
||||
first := true
|
||||
for _, schedule := range schedules.Items {
|
||||
s := output.DescribeSchedule(&schedule)
|
||||
for i := range schedules.Items {
|
||||
s := output.DescribeSchedule(&schedules.Items[i])
|
||||
if first {
|
||||
first = false
|
||||
fmt.Print(s)
|
||||
|
||||
@@ -19,9 +19,11 @@ package plugin
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/features"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/backup"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
velerodiscovery "github.com/vmware-tanzu/velero/pkg/discovery"
|
||||
@@ -36,11 +38,10 @@ func NewCommand(f client.Factory) *cobra.Command {
|
||||
Hidden: true,
|
||||
Short: "INTERNAL COMMAND ONLY - not intended to be run directly by users",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
pluginServer.
|
||||
pluginServer = pluginServer.
|
||||
RegisterBackupItemAction("velero.io/pv", newPVBackupItemAction).
|
||||
RegisterBackupItemAction("velero.io/pod", newPodBackupItemAction).
|
||||
RegisterBackupItemAction("velero.io/service-account", newServiceAccountBackupItemAction(f)).
|
||||
RegisterBackupItemAction("velero.io/crd-remap-version", newRemapCRDVersionAction(f)).
|
||||
RegisterRestoreItemAction("velero.io/job", newJobRestoreItemAction).
|
||||
RegisterRestoreItemAction("velero.io/pod", newPodRestoreItemAction).
|
||||
RegisterRestoreItemAction("velero.io/restic", newResticRestoreItemAction(f)).
|
||||
@@ -55,13 +56,15 @@ func NewCommand(f client.Factory) *cobra.Command {
|
||||
RegisterRestoreItemAction("velero.io/crd-preserve-fields", newCRDV1PreserveUnknownFieldsItemAction).
|
||||
RegisterRestoreItemAction("velero.io/change-pvc-node-selector", newChangePVCNodeSelectorItemAction(f)).
|
||||
RegisterRestoreItemAction("velero.io/apiservice", newAPIServiceRestoreItemAction).
|
||||
RegisterRestoreItemAction("velero.io/admission-webhook-configuration", newAdmissionWebhookConfigurationAction).
|
||||
Serve()
|
||||
RegisterRestoreItemAction("velero.io/admission-webhook-configuration", newAdmissionWebhookConfigurationAction)
|
||||
if !features.IsEnabled(velerov1api.APIGroupVersionsFeatureFlag) {
|
||||
// Do not register crd-remap-version BIA if the API Group feature flag is enabled, so that the v1 CRD can be backed up
|
||||
pluginServer = pluginServer.RegisterBackupItemAction("velero.io/crd-remap-version", newRemapCRDVersionAction(f))
|
||||
}
|
||||
pluginServer.Serve()
|
||||
},
|
||||
}
|
||||
|
||||
pluginServer.BindFlags(c.Flags())
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bombsimon/logrusr"
|
||||
logrusr "github.com/bombsimon/logrusr/v3"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -102,6 +102,8 @@ const (
|
||||
// the default TTL for a backup
|
||||
defaultBackupTTL = 30 * 24 * time.Hour
|
||||
|
||||
defaultCSISnapshotTimeout = 10 * time.Minute
|
||||
|
||||
// defaultCredentialsDirectory is the path on disk where credential
|
||||
// files will be written to
|
||||
defaultCredentialsDirectory = "/tmp/credentials"
|
||||
@@ -111,8 +113,8 @@ type serverConfig struct {
|
||||
// TODO(2.0) Deprecate defaultBackupLocation
|
||||
pluginDir, metricsAddress, defaultBackupLocation string
|
||||
backupSyncPeriod, podVolumeOperationTimeout, resourceTerminatingTimeout time.Duration
|
||||
defaultBackupTTL, storeValidationFrequency time.Duration
|
||||
restoreResourcePriorities []string
|
||||
defaultBackupTTL, storeValidationFrequency, defaultCSISnapshotTimeout time.Duration
|
||||
restoreResourcePriorities restore.Priorities
|
||||
defaultVolumeSnapshotLocations map[string]string
|
||||
restoreOnly bool
|
||||
disabledControllers []string
|
||||
@@ -142,6 +144,7 @@ func NewCommand(f client.Factory) *cobra.Command {
|
||||
defaultVolumeSnapshotLocations: make(map[string]string),
|
||||
backupSyncPeriod: defaultBackupSyncPeriod,
|
||||
defaultBackupTTL: defaultBackupTTL,
|
||||
defaultCSISnapshotTimeout: defaultCSISnapshotTimeout,
|
||||
storeValidationFrequency: defaultStoreValidationFrequency,
|
||||
podVolumeOperationTimeout: defaultPodVolumeOperationTimeout,
|
||||
restoreResourcePriorities: defaultRestorePriorities,
|
||||
@@ -205,7 +208,7 @@ func NewCommand(f client.Factory) *cobra.Command {
|
||||
command.Flags().DurationVar(&config.podVolumeOperationTimeout, "restic-timeout", config.podVolumeOperationTimeout, "How long backups/restores of pod volumes should be allowed to run before timing out.")
|
||||
command.Flags().BoolVar(&config.restoreOnly, "restore-only", config.restoreOnly, "Run in a mode where only restores are allowed; backups, schedules, and garbage-collection are all disabled. DEPRECATED: this flag will be removed in v2.0. Use read-only backup storage locations instead.")
|
||||
command.Flags().StringSliceVar(&config.disabledControllers, "disable-controllers", config.disabledControllers, fmt.Sprintf("List of controllers to disable on startup. Valid values are %s", strings.Join(controller.DisableableControllers, ",")))
|
||||
command.Flags().StringSliceVar(&config.restoreResourcePriorities, "restore-resource-priorities", config.restoreResourcePriorities, "Desired order of resource restores; any resource not in the list will be restored alphabetically after the prioritized resources.")
|
||||
command.Flags().Var(&config.restoreResourcePriorities, "restore-resource-priorities", "Desired order of resource restores, the priority list contains two parts which are split by \"-\" element. The resources before \"-\" element are restored first as high priorities, the resources after \"-\" element are restored last as low priorities, and any resource not in the list will be restored alphabetically between the high and low priorities.")
|
||||
command.Flags().StringVar(&config.defaultBackupLocation, "default-backup-storage-location", config.defaultBackupLocation, "Name of the default backup storage location. DEPRECATED: this flag will be removed in v2.0. Use \"velero backup-location set --default\" instead.")
|
||||
command.Flags().DurationVar(&config.storeValidationFrequency, "store-validation-frequency", config.storeValidationFrequency, "How often to verify if the storage is valid. Optional. Set this to `0s` to disable sync. Default 1 minute.")
|
||||
command.Flags().Var(&volumeSnapshotLocations, "default-volume-snapshot-locations", "List of unique volume providers and default volume snapshot location (provider1:location-01,provider2:location-02,...)")
|
||||
@@ -307,7 +310,7 @@ func newServer(f client.Factory, config serverConfig, logger *logrus.Logger) (*s
|
||||
corev1api.AddToScheme(scheme)
|
||||
snapshotv1api.AddToScheme(scheme)
|
||||
|
||||
ctrl.SetLogger(logrusr.NewLogger(logger))
|
||||
ctrl.SetLogger(logrusr.New(logger))
|
||||
|
||||
mgr, err := ctrl.NewManager(clientConfig, ctrl.Options{
|
||||
Scheme: scheme,
|
||||
@@ -464,6 +467,7 @@ func (s *server) veleroResourcesExist() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// High priorities:
|
||||
// - Custom Resource Definitions come before Custom Resource so that they can be
|
||||
// restored with their corresponding CRD.
|
||||
// - Namespaces go second because all namespaced resources depend on them.
|
||||
@@ -486,28 +490,36 @@ func (s *server) veleroResourcesExist() error {
|
||||
// - CAPI Clusters come before ClusterResourceSets because failing to do so means the CAPI controller-manager will panic.
|
||||
// Both Clusters and ClusterResourceSets need to come before ClusterResourceSetBinding in order to properly restore workload clusters.
|
||||
// See https://github.com/kubernetes-sigs/cluster-api/issues/4105
|
||||
var defaultRestorePriorities = []string{
|
||||
"customresourcedefinitions",
|
||||
"namespaces",
|
||||
"storageclasses",
|
||||
"volumesnapshotclass.snapshot.storage.k8s.io",
|
||||
"volumesnapshotcontents.snapshot.storage.k8s.io",
|
||||
"volumesnapshots.snapshot.storage.k8s.io",
|
||||
"persistentvolumes",
|
||||
"persistentvolumeclaims",
|
||||
"secrets",
|
||||
"configmaps",
|
||||
"serviceaccounts",
|
||||
"limitranges",
|
||||
"pods",
|
||||
// we fully qualify replicasets.apps because prior to Kubernetes 1.16, replicasets also
|
||||
// existed in the extensions API group, but we back up replicasets from "apps" so we want
|
||||
// to ensure that we prioritize restoring from "apps" too, since this is how they're stored
|
||||
// in the backup.
|
||||
"replicasets.apps",
|
||||
"clusterclasses.cluster.x-k8s.io",
|
||||
"clusters.cluster.x-k8s.io",
|
||||
"clusterresourcesets.addons.cluster.x-k8s.io",
|
||||
//
|
||||
// Low priorities:
|
||||
// - Tanzu ClusterBootstrap go last as it can reference any other kind of resources
|
||||
var defaultRestorePriorities = restore.Priorities{
|
||||
HighPriorities: []string{
|
||||
"customresourcedefinitions",
|
||||
"namespaces",
|
||||
"storageclasses",
|
||||
"volumesnapshotclass.snapshot.storage.k8s.io",
|
||||
"volumesnapshotcontents.snapshot.storage.k8s.io",
|
||||
"volumesnapshots.snapshot.storage.k8s.io",
|
||||
"persistentvolumes",
|
||||
"persistentvolumeclaims",
|
||||
"secrets",
|
||||
"configmaps",
|
||||
"serviceaccounts",
|
||||
"limitranges",
|
||||
"pods",
|
||||
// we fully qualify replicasets.apps because prior to Kubernetes 1.16, replicasets also
|
||||
// existed in the extensions API group, but we back up replicasets from "apps" so we want
|
||||
// to ensure that we prioritize restoring from "apps" too, since this is how they're stored
|
||||
// in the backup.
|
||||
"replicasets.apps",
|
||||
"clusterclasses.cluster.x-k8s.io",
|
||||
"clusters.cluster.x-k8s.io",
|
||||
"clusterresourcesets.addons.cluster.x-k8s.io",
|
||||
},
|
||||
LowPriorities: []string{
|
||||
"clusterbootstraps.run.tanzu.vmware.com",
|
||||
},
|
||||
}
|
||||
|
||||
func (s *server) initRestic() error {
|
||||
@@ -582,7 +594,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
metricsMux := http.NewServeMux()
|
||||
metricsMux.Handle("/metrics", promhttp.Handler())
|
||||
s.logger.Infof("Starting metric server at address [%s]", s.metricsAddress)
|
||||
if err := http.ListenAndServe(s.metricsAddress, metricsMux); err != nil {
|
||||
if err := http.ListenAndServe(s.metricsAddress, metricsMux); err != nil { //nolint:gosec
|
||||
s.logger.Fatalf("Failed to start metric server at [%s]: %v", s.metricsAddress, err)
|
||||
}
|
||||
}()
|
||||
@@ -599,7 +611,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
|
||||
csiVSLister, csiVSCLister, csiVSClassLister := s.getCSISnapshotListers()
|
||||
|
||||
backupSyncControllerRunInfo := func() controllerRunInfo {
|
||||
backupSyncControllerRunInfo := func() controllerRunInfo { //nolint:typecheck
|
||||
backupSyncContoller := controller.NewBackupSyncController(
|
||||
s.veleroClient.VeleroV1(),
|
||||
s.mgr.GetClient(),
|
||||
@@ -624,7 +636,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
|
||||
backupTracker := controller.NewBackupTracker()
|
||||
|
||||
backupControllerRunInfo := func() controllerRunInfo {
|
||||
backupControllerRunInfo := func() controllerRunInfo { //nolint:typecheck
|
||||
backupper, err := backup.NewKubernetesBackupper(
|
||||
s.veleroClient.VeleroV1(),
|
||||
s.discoveryHelper,
|
||||
@@ -650,6 +662,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
s.config.defaultBackupLocation,
|
||||
s.config.defaultVolumesToRestic,
|
||||
s.config.defaultBackupTTL,
|
||||
s.config.defaultCSISnapshotTimeout,
|
||||
s.sharedInformerFactory.Velero().V1().VolumeSnapshotLocations().Lister(),
|
||||
defaultVolumeSnapshotLocations,
|
||||
s.metrics,
|
||||
@@ -667,7 +680,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
}
|
||||
}
|
||||
|
||||
gcControllerRunInfo := func() controllerRunInfo {
|
||||
gcControllerRunInfo := func() controllerRunInfo { //nolint:typecheck
|
||||
gcController := controller.NewGCController(
|
||||
s.logger,
|
||||
s.sharedInformerFactory.Velero().V1().Backups(),
|
||||
@@ -683,7 +696,7 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string
|
||||
}
|
||||
}
|
||||
|
||||
restoreControllerRunInfo := func() controllerRunInfo {
|
||||
restoreControllerRunInfo := func() controllerRunInfo { //nolint:typecheck
|
||||
restorer, err := restore.NewKubernetesRestorer(
|
||||
s.veleroClient.VeleroV1(),
|
||||
s.discoveryHelper,
|
||||
@@ -893,7 +906,7 @@ func (s *server) runProfiler() {
|
||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
if err := http.ListenAndServe(s.config.profilerAddress, mux); err != nil {
|
||||
if err := http.ListenAndServe(s.config.profilerAddress, mux); err != nil { //nolint:gosec
|
||||
s.logger.WithError(errors.WithStack(err)).Error("error running profiler http server")
|
||||
}
|
||||
}
|
||||
@@ -951,7 +964,7 @@ func markInProgressBackupsFailed(ctx context.Context, client ctrlclient.Client,
|
||||
return
|
||||
}
|
||||
|
||||
for _, backup := range backups.Items {
|
||||
for i, backup := range backups.Items {
|
||||
if backup.Status.Phase != velerov1api.BackupPhaseInProgress {
|
||||
log.Debugf("the status of backup %q is %q, skip", backup.GetName(), backup.Status.Phase)
|
||||
continue
|
||||
@@ -960,7 +973,7 @@ func markInProgressBackupsFailed(ctx context.Context, client ctrlclient.Client,
|
||||
updated.Status.Phase = velerov1api.BackupPhaseFailed
|
||||
updated.Status.FailureReason = fmt.Sprintf("get a backup with status %q during the server starting, mark it as %q", velerov1api.BackupPhaseInProgress, updated.Status.Phase)
|
||||
updated.Status.CompletionTimestamp = &metav1.Time{Time: time.Now()}
|
||||
if err := client.Patch(ctx, updated, ctrlclient.MergeFrom(&backup)); err != nil {
|
||||
if err := client.Patch(ctx, updated, ctrlclient.MergeFrom(&backups.Items[i])); err != nil {
|
||||
log.WithError(errors.WithStack(err)).Errorf("failed to patch backup %q", backup.GetName())
|
||||
continue
|
||||
}
|
||||
@@ -974,7 +987,7 @@ func markInProgressRestoresFailed(ctx context.Context, client ctrlclient.Client,
|
||||
log.WithError(errors.WithStack(err)).Error("failed to list restores")
|
||||
return
|
||||
}
|
||||
for _, restore := range restores.Items {
|
||||
for i, restore := range restores.Items {
|
||||
if restore.Status.Phase != velerov1api.RestorePhaseInProgress {
|
||||
log.Debugf("the status of restore %q is %q, skip", restore.GetName(), restore.Status.Phase)
|
||||
continue
|
||||
@@ -983,7 +996,7 @@ func markInProgressRestoresFailed(ctx context.Context, client ctrlclient.Client,
|
||||
updated.Status.Phase = velerov1api.RestorePhaseFailed
|
||||
updated.Status.FailureReason = fmt.Sprintf("get a restore with status %q during the server starting, mark it as %q", velerov1api.RestorePhaseInProgress, updated.Status.Phase)
|
||||
updated.Status.CompletionTimestamp = &metav1.Time{Time: time.Now()}
|
||||
if err := client.Patch(ctx, updated, ctrlclient.MergeFrom(&restore)); err != nil {
|
||||
if err := client.Patch(ctx, updated, ctrlclient.MergeFrom(&restores.Items[i])); err != nil {
|
||||
log.WithError(errors.WithStack(err)).Errorf("failed to patch restore %q", restore.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func Stream(ctx context.Context, kbClient kbclient.Client, namespace, name strin
|
||||
httpClient := new(http.Client)
|
||||
httpClient.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: insecureSkipTLSVerify,
|
||||
InsecureSkipVerify: insecureSkipTLSVerify, //nolint:gosec
|
||||
RootCAs: caPool,
|
||||
},
|
||||
IdleConnTimeout: timeout,
|
||||
|
||||
@@ -126,7 +126,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
||||
}
|
||||
d.Printf("\tIncluded:\t%s\n", s)
|
||||
if len(spec.ExcludedNamespaces) == 0 {
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
} else {
|
||||
s = strings.Join(spec.ExcludedNamespaces, ", ")
|
||||
}
|
||||
@@ -141,7 +141,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
||||
}
|
||||
d.Printf("\tIncluded:\t%s\n", s)
|
||||
if len(spec.ExcludedResources) == 0 {
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
} else {
|
||||
s = strings.Join(spec.ExcludedResources, ", ")
|
||||
}
|
||||
@@ -150,7 +150,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
||||
d.Printf("\tCluster-scoped:\t%s\n", BoolPointerString(spec.IncludeClusterResources, "excluded", "included", "auto"))
|
||||
|
||||
d.Println()
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
if spec.LabelSelector != nil {
|
||||
s = metav1.FormatLabelSelector(spec.LabelSelector)
|
||||
}
|
||||
@@ -167,7 +167,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
||||
|
||||
d.Println()
|
||||
if len(spec.Hooks.Resources) == 0 {
|
||||
d.Printf("Hooks:\t<none>\n")
|
||||
d.Printf("Hooks:\t" + emptyDisplay + "\n")
|
||||
} else {
|
||||
d.Printf("Hooks:\n")
|
||||
d.Printf("\tResources:\n")
|
||||
@@ -182,7 +182,7 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
||||
}
|
||||
d.Printf("\t\t\t\tIncluded:\t%s\n", s)
|
||||
if len(spec.ExcludedNamespaces) == 0 {
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
} else {
|
||||
s = strings.Join(spec.ExcludedNamespaces, ", ")
|
||||
}
|
||||
@@ -197,14 +197,14 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
|
||||
}
|
||||
d.Printf("\t\t\t\tIncluded:\t%s\n", s)
|
||||
if len(spec.ExcludedResources) == 0 {
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
} else {
|
||||
s = strings.Join(spec.ExcludedResources, ", ")
|
||||
}
|
||||
d.Printf("\t\t\t\tExcluded:\t%s\n", s)
|
||||
|
||||
d.Println()
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
if backupResourceHookSpec.LabelSelector != nil {
|
||||
s = metav1.FormatLabelSelector(backupResourceHookSpec.LabelSelector)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,10 @@ import (
|
||||
"github.com/vmware-tanzu/velero/pkg/util/encode"
|
||||
)
|
||||
|
||||
const downloadRequestTimeout = 30 * time.Second
|
||||
const (
|
||||
downloadRequestTimeout = 30 * time.Second
|
||||
emptyDisplay = "<none>"
|
||||
)
|
||||
|
||||
// BindFlags defines a set of output-specific flags within the provided
|
||||
// FlagSet.
|
||||
|
||||
@@ -107,7 +107,7 @@ func DescribeRestore(ctx context.Context, kbClient kbclient.Client, restore *vel
|
||||
}
|
||||
d.Printf("\tIncluded:\t%s\n", s)
|
||||
if len(restore.Spec.ExcludedNamespaces) == 0 {
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
} else {
|
||||
s = strings.Join(restore.Spec.ExcludedNamespaces, ", ")
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func DescribeRestore(ctx context.Context, kbClient kbclient.Client, restore *vel
|
||||
}
|
||||
d.Printf("\tIncluded:\t%s\n", s)
|
||||
if len(restore.Spec.ExcludedResources) == 0 {
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
} else {
|
||||
s = strings.Join(restore.Spec.ExcludedResources, ", ")
|
||||
}
|
||||
@@ -134,7 +134,7 @@ func DescribeRestore(ctx context.Context, kbClient kbclient.Client, restore *vel
|
||||
d.DescribeMap("Namespace mappings", restore.Spec.NamespaceMapping)
|
||||
|
||||
d.Println()
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
if restore.Spec.LabelSelector != nil {
|
||||
s = metav1.FormatLabelSelector(restore.Spec.LabelSelector)
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func DescribeRestore(ctx context.Context, kbClient kbclient.Client, restore *vel
|
||||
}
|
||||
|
||||
d.Println()
|
||||
s = "<none>"
|
||||
s = emptyDisplay
|
||||
if restore.Spec.ExistingResourcePolicy != "" {
|
||||
s = string(restore.Spec.ExistingResourcePolicy)
|
||||
}
|
||||
@@ -194,7 +194,7 @@ func describeRestoreResult(d *Describer, name string, result pkgrestore.Result)
|
||||
d.DescribeSlice(1, "Velero", result.Velero)
|
||||
d.DescribeSlice(1, "Cluster", result.Cluster)
|
||||
if len(result.Namespaces) == 0 {
|
||||
d.Printf("\tNamespaces: <none>\n")
|
||||
d.Printf("\tNamespaces:" + emptyDisplay + "\n")
|
||||
} else {
|
||||
d.Printf("\tNamespaces:\n")
|
||||
for ns, warnings := range result.Namespaces {
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -87,13 +86,14 @@ type backupController struct {
|
||||
defaultBackupLocation string
|
||||
defaultVolumesToRestic bool
|
||||
defaultBackupTTL time.Duration
|
||||
defaultCSISnapshotTimeout time.Duration
|
||||
snapshotLocationLister velerov1listers.VolumeSnapshotLocationLister
|
||||
defaultSnapshotLocations map[string]string
|
||||
metrics *metrics.ServerMetrics
|
||||
backupStoreGetter persistence.ObjectBackupStoreGetter
|
||||
formatFlag logging.Format
|
||||
volumeSnapshotLister snapshotv1listers.VolumeSnapshotLister
|
||||
volumeSnapshotClient *snapshotterClientSet.Clientset
|
||||
volumeSnapshotClient snapshotterClientSet.Interface
|
||||
volumeSnapshotContentLister snapshotv1listers.VolumeSnapshotContentLister
|
||||
volumeSnapshotClassLister snapshotv1listers.VolumeSnapshotClassLister
|
||||
}
|
||||
@@ -111,12 +111,13 @@ func NewBackupController(
|
||||
defaultBackupLocation string,
|
||||
defaultVolumesToRestic bool,
|
||||
defaultBackupTTL time.Duration,
|
||||
defaultCSISnapshotTimeout time.Duration,
|
||||
volumeSnapshotLocationLister velerov1listers.VolumeSnapshotLocationLister,
|
||||
defaultSnapshotLocations map[string]string,
|
||||
metrics *metrics.ServerMetrics,
|
||||
formatFlag logging.Format,
|
||||
volumeSnapshotLister snapshotv1listers.VolumeSnapshotLister,
|
||||
volumeSnapshotClient *snapshotterClientSet.Clientset,
|
||||
volumeSnapshotClient snapshotterClientSet.Interface,
|
||||
volumeSnapshotContentLister snapshotv1listers.VolumeSnapshotContentLister,
|
||||
volumesnapshotClassLister snapshotv1listers.VolumeSnapshotClassLister,
|
||||
backupStoreGetter persistence.ObjectBackupStoreGetter,
|
||||
@@ -135,6 +136,7 @@ func NewBackupController(
|
||||
defaultBackupLocation: defaultBackupLocation,
|
||||
defaultVolumesToRestic: defaultVolumesToRestic,
|
||||
defaultBackupTTL: defaultBackupTTL,
|
||||
defaultCSISnapshotTimeout: defaultCSISnapshotTimeout,
|
||||
snapshotLocationLister: volumeSnapshotLocationLister,
|
||||
defaultSnapshotLocations: defaultSnapshotLocations,
|
||||
metrics: metrics,
|
||||
@@ -359,6 +361,11 @@ func (c *backupController) prepareBackupRequest(backup *velerov1api.Backup) *pkg
|
||||
request.Spec.TTL.Duration = c.defaultBackupTTL
|
||||
}
|
||||
|
||||
if request.Spec.CSISnapshotTimeout.Duration == 0 {
|
||||
// set default CSI VolumeSnapshot timeout
|
||||
request.Spec.CSISnapshotTimeout.Duration = c.defaultCSISnapshotTimeout
|
||||
}
|
||||
|
||||
// calculate expiration
|
||||
request.Status.Expiration = &metav1.Time{Time: c.clock.Now().Add(request.Spec.TTL.Duration)}
|
||||
|
||||
@@ -624,28 +631,18 @@ func (c *backupController) runBackup(backup *pkgbackup.Request) error {
|
||||
|
||||
// Empty slices here so that they can be passed in to the persistBackup call later, regardless of whether or not CSI's enabled.
|
||||
// This way, we only make the Lister call if the feature flag's on.
|
||||
var volumeSnapshots []*snapshotv1api.VolumeSnapshot
|
||||
var volumeSnapshots []snapshotv1api.VolumeSnapshot
|
||||
var volumeSnapshotContents []*snapshotv1api.VolumeSnapshotContent
|
||||
var volumeSnapshotClasses []*snapshotv1api.VolumeSnapshotClass
|
||||
if features.IsEnabled(velerov1api.CSIFeatureFlag) {
|
||||
selector := label.NewSelectorForBackup(backup.Name)
|
||||
// Listers are wrapped in a nil check out of caution, since they may not be populated based on the
|
||||
// EnableCSI feature flag. This is more to guard against programmer error, as they shouldn't be nil
|
||||
// when EnableCSI is on.
|
||||
if c.volumeSnapshotLister != nil {
|
||||
volumeSnapshots, err = c.volumeSnapshotLister.List(selector)
|
||||
if err != nil {
|
||||
backupLog.Error(err)
|
||||
}
|
||||
|
||||
err = c.checkVolumeSnapshotReadyToUse(context.Background(), volumeSnapshots)
|
||||
if err != nil {
|
||||
backupLog.Errorf("fail to wait VolumeSnapshot change to Ready: %s", err.Error())
|
||||
}
|
||||
|
||||
backup.CSISnapshots = volumeSnapshots
|
||||
volumeSnapshots, err := c.waitVolumeSnapshotReadyToUse(context.Background(), backup.Spec.CSISnapshotTimeout.Duration, backup.Name)
|
||||
if err != nil {
|
||||
backupLog.Errorf("fail to wait VolumeSnapshot change to Ready: %s", err.Error())
|
||||
}
|
||||
|
||||
backup.CSISnapshots = volumeSnapshots
|
||||
|
||||
selector := label.NewSelectorForBackup(backup.Name)
|
||||
if c.volumeSnapshotContentLister != nil {
|
||||
volumeSnapshotContents, err = c.volumeSnapshotContentLister.List(selector)
|
||||
if err != nil {
|
||||
@@ -671,7 +668,7 @@ func (c *backupController) runBackup(backup *pkgbackup.Request) error {
|
||||
}
|
||||
|
||||
// Delete the VolumeSnapshots created in the backup, when CSI feature is enabled.
|
||||
c.deleteVolumeSnapshot(volumeSnapshots, volumeSnapshotContents, *backup, backupLog)
|
||||
c.deleteVolumeSnapshot(volumeSnapshots, volumeSnapshotContents, backupLog)
|
||||
|
||||
}
|
||||
|
||||
@@ -723,7 +720,7 @@ func (c *backupController) runBackup(backup *pkgbackup.Request) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if errs := persistBackup(backup, backupFile, logFile, backupStore, c.logger.WithField(Backup, kubeutil.NamespaceAndName(backup)), volumeSnapshots, volumeSnapshotContents, volumeSnapshotClasses); len(errs) > 0 {
|
||||
if errs := persistBackup(backup, backupFile, logFile, backupStore, volumeSnapshots, volumeSnapshotContents, volumeSnapshotClasses); len(errs) > 0 {
|
||||
fatalErrs = append(fatalErrs, errs...)
|
||||
}
|
||||
|
||||
@@ -767,8 +764,7 @@ func recordBackupMetrics(log logrus.FieldLogger, backup *velerov1api.Backup, bac
|
||||
func persistBackup(backup *pkgbackup.Request,
|
||||
backupContents, backupLog *os.File,
|
||||
backupStore persistence.BackupStore,
|
||||
log logrus.FieldLogger,
|
||||
csiVolumeSnapshots []*snapshotv1api.VolumeSnapshot,
|
||||
csiVolumeSnapshots []snapshotv1api.VolumeSnapshot,
|
||||
csiVolumeSnapshotContents []*snapshotv1api.VolumeSnapshotContent,
|
||||
csiVolumesnapshotClasses []*snapshotv1api.VolumeSnapshotClass,
|
||||
) []error {
|
||||
@@ -875,17 +871,35 @@ func encodeToJSONGzip(data interface{}, desc string) (*bytes.Buffer, []error) {
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Waiting for VolumeSnapshot ReadyTosue to true is time consuming. Try to make the process parallel by
|
||||
// waitVolumeSnapshotReadyToUse is used to wait VolumeSnapshot turned to ReadyToUse.
|
||||
// Waiting for VolumeSnapshot ReadyToUse to true is time consuming. Try to make the process parallel by
|
||||
// using goroutine here instead of waiting in CSI plugin, because it's not easy to make BackupItemAction
|
||||
// parallel by now. After BackupItemAction parallel is implemented, this logic should be moved to CSI plugin
|
||||
// as https://github.com/vmware-tanzu/velero-plugin-for-csi/pull/100
|
||||
func (c *backupController) checkVolumeSnapshotReadyToUse(ctx context.Context, volumesnapshots []*snapshotv1api.VolumeSnapshot) error {
|
||||
func (c *backupController) waitVolumeSnapshotReadyToUse(ctx context.Context,
|
||||
csiSnapshotTimeout time.Duration, backupName string) ([]snapshotv1api.VolumeSnapshot, error) {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
timeout := 10 * time.Minute
|
||||
timeout := csiSnapshotTimeout
|
||||
interval := 5 * time.Second
|
||||
volumeSnapshots := make([]snapshotv1api.VolumeSnapshot, 0)
|
||||
|
||||
for _, vs := range volumesnapshots {
|
||||
volumeSnapshot := vs
|
||||
if c.volumeSnapshotLister != nil {
|
||||
tmpVSs, err := c.volumeSnapshotLister.List(label.NewSelectorForBackup(backupName))
|
||||
if err != nil {
|
||||
c.logger.Error(err)
|
||||
return volumeSnapshots, err
|
||||
}
|
||||
|
||||
for _, vs := range tmpVSs {
|
||||
volumeSnapshots = append(volumeSnapshots, *vs)
|
||||
}
|
||||
}
|
||||
|
||||
vsChannel := make(chan snapshotv1api.VolumeSnapshot, len(volumeSnapshots))
|
||||
defer close(vsChannel)
|
||||
|
||||
for index := range volumeSnapshots {
|
||||
volumeSnapshot := volumeSnapshots[index]
|
||||
eg.Go(func() error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
tmpVS, err := c.volumeSnapshotClient.SnapshotV1().VolumeSnapshots(volumeSnapshot.Namespace).Get(ctx, volumeSnapshot.Name, metav1.GetOptions{})
|
||||
@@ -893,19 +907,31 @@ func (c *backupController) checkVolumeSnapshotReadyToUse(ctx context.Context, vo
|
||||
return false, errors.Wrapf(err, fmt.Sprintf("failed to get volumesnapshot %s/%s", volumeSnapshot.Namespace, volumeSnapshot.Name))
|
||||
}
|
||||
if tmpVS.Status == nil || tmpVS.Status.BoundVolumeSnapshotContentName == nil || !boolptr.IsSetToTrue(tmpVS.Status.ReadyToUse) {
|
||||
log.Infof("Waiting for CSI driver to reconcile volumesnapshot %s/%s. Retrying in %ds", volumeSnapshot.Namespace, volumeSnapshot.Name, interval/time.Second)
|
||||
c.logger.Infof("Waiting for CSI driver to reconcile volumesnapshot %s/%s. Retrying in %ds", volumeSnapshot.Namespace, volumeSnapshot.Name, interval/time.Second)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
c.logger.Debugf("VolumeSnapshot %s/%s turned into ReadyToUse.", volumeSnapshot.Namespace, volumeSnapshot.Name)
|
||||
// Put the ReadyToUse VolumeSnapshot element in the result channel.
|
||||
vsChannel <- *tmpVS
|
||||
return true, nil
|
||||
})
|
||||
if err == wait.ErrWaitTimeout {
|
||||
log.Errorf("Timed out awaiting reconciliation of volumesnapshot %s/%s", volumeSnapshot.Namespace, volumeSnapshot.Name)
|
||||
c.logger.Errorf("Timed out awaiting reconciliation of volumesnapshot %s/%s", volumeSnapshot.Namespace, volumeSnapshot.Name)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
return eg.Wait()
|
||||
|
||||
err := eg.Wait()
|
||||
|
||||
result := make([]snapshotv1api.VolumeSnapshot, 0)
|
||||
length := len(vsChannel)
|
||||
for index := 0; index < length; index++ {
|
||||
result = append(result, <-vsChannel)
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// deleteVolumeSnapshot delete VolumeSnapshot created during backup.
|
||||
@@ -913,9 +939,9 @@ func (c *backupController) checkVolumeSnapshotReadyToUse(ctx context.Context, vo
|
||||
// which will cause snapshot deletion on cloud provider, then backup cannot restore the PV.
|
||||
// If DeletionPolicy is Retain, just delete it. If DeletionPolicy is Delete, need to
|
||||
// change DeletionPolicy to Retain before deleting VS, then change DeletionPolicy back to Delete.
|
||||
func (c *backupController) deleteVolumeSnapshot(volumeSnapshots []*snapshotv1api.VolumeSnapshot,
|
||||
func (c *backupController) deleteVolumeSnapshot(volumeSnapshots []snapshotv1api.VolumeSnapshot,
|
||||
volumeSnapshotContents []*snapshotv1api.VolumeSnapshotContent,
|
||||
backup pkgbackup.Request, logger logrus.FieldLogger) {
|
||||
logger logrus.FieldLogger) {
|
||||
var wg sync.WaitGroup
|
||||
vscMap := make(map[string]*snapshotv1api.VolumeSnapshotContent)
|
||||
for _, vsc := range volumeSnapshotContents {
|
||||
@@ -924,16 +950,23 @@ func (c *backupController) deleteVolumeSnapshot(volumeSnapshots []*snapshotv1api
|
||||
|
||||
for _, vs := range volumeSnapshots {
|
||||
wg.Add(1)
|
||||
go func(vs *snapshotv1api.VolumeSnapshot) {
|
||||
go func(vs snapshotv1api.VolumeSnapshot) {
|
||||
defer wg.Done()
|
||||
var vsc *snapshotv1api.VolumeSnapshotContent
|
||||
modifyVSCFlag := false
|
||||
if vs.Status.BoundVolumeSnapshotContentName != nil &&
|
||||
if vs.Status != nil &&
|
||||
vs.Status.BoundVolumeSnapshotContentName != nil &&
|
||||
len(*vs.Status.BoundVolumeSnapshotContentName) > 0 {
|
||||
vsc = vscMap[*vs.Status.BoundVolumeSnapshotContentName]
|
||||
if nil == vsc {
|
||||
logger.Errorf("Not find %s from the vscMap", vs.Status.BoundVolumeSnapshotContentName)
|
||||
return
|
||||
}
|
||||
if vsc.Spec.DeletionPolicy == snapshotv1api.VolumeSnapshotContentDelete {
|
||||
modifyVSCFlag = true
|
||||
}
|
||||
} else {
|
||||
logger.Errorf("VolumeSnapshot %s/%s is not ready. This is not expected.", vs.Namespace, vs.Name)
|
||||
}
|
||||
|
||||
// Change VolumeSnapshotContent's DeletionPolicy to Retain before deleting VolumeSnapshot,
|
||||
@@ -959,7 +992,7 @@ func (c *backupController) deleteVolumeSnapshot(volumeSnapshots []*snapshotv1api
|
||||
}
|
||||
|
||||
// Delete VolumeSnapshot from cluster
|
||||
logger.Debugf("Deleting VolumeSnapshotContent %s", vsc.Name)
|
||||
logger.Debugf("Deleting VolumeSnapshot %s/%s", vs.Namespace, vs.Name)
|
||||
err := c.volumeSnapshotClient.SnapshotV1().VolumeSnapshots(vs.Namespace).Delete(context.TODO(), vs.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
logger.Errorf("fail to delete VolumeSnapshot %s/%s: %s", vs.Namespace, vs.Name, err.Error())
|
||||
|
||||
@@ -27,6 +27,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
snapshotfake "github.com/kubernetes-csi/external-snapshotter/client/v4/clientset/versioned/fake"
|
||||
snapshotinformers "github.com/kubernetes-csi/external-snapshotter/client/v4/informers/externalversions"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -1163,3 +1166,101 @@ func Test_getLastSuccessBySchedule(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteVolumeSnapshot(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
vsArray []snapshotv1api.VolumeSnapshot
|
||||
vscArray []*snapshotv1api.VolumeSnapshotContent
|
||||
expectedVSArray []snapshotv1api.VolumeSnapshot
|
||||
expectedVSCArray []snapshotv1api.VolumeSnapshotContent
|
||||
}{
|
||||
{
|
||||
name: "VS is ReadyToUse, and VS has corresponding VSC. VS should be deleted.",
|
||||
vsArray: []snapshotv1api.VolumeSnapshot{
|
||||
*builder.ForVolumeSnapshot("velero", "vs1").ObjectMeta(builder.WithLabels("testing-vs", "vs1")).Status().BoundVolumeSnapshotContentName("vsc1").Result(),
|
||||
},
|
||||
vscArray: []*snapshotv1api.VolumeSnapshotContent{
|
||||
builder.ForVolumeSnapshotContent("vsc1").DeletionPolicy(snapshotv1api.VolumeSnapshotContentDelete).Status().Result(),
|
||||
},
|
||||
expectedVSArray: []snapshotv1api.VolumeSnapshot{},
|
||||
expectedVSCArray: []snapshotv1api.VolumeSnapshotContent{
|
||||
*builder.ForVolumeSnapshotContent("vsc1").DeletionPolicy(snapshotv1api.VolumeSnapshotContentRetain).VolumeSnapshotRef("ns-", "name-").Status().Result(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Corresponding VSC not found for VS. VS is not deleted.",
|
||||
vsArray: []snapshotv1api.VolumeSnapshot{
|
||||
*builder.ForVolumeSnapshot("velero", "vs1").ObjectMeta(builder.WithLabels("testing-vs", "vs1")).Status().BoundVolumeSnapshotContentName("vsc1").Result(),
|
||||
},
|
||||
vscArray: []*snapshotv1api.VolumeSnapshotContent{},
|
||||
expectedVSArray: []snapshotv1api.VolumeSnapshot{
|
||||
*builder.ForVolumeSnapshot("velero", "vs1").Status().BoundVolumeSnapshotContentName("vsc1").Result(),
|
||||
},
|
||||
expectedVSCArray: []snapshotv1api.VolumeSnapshotContent{},
|
||||
},
|
||||
{
|
||||
name: "VS status is nil. VSC should not be modified.",
|
||||
vsArray: []snapshotv1api.VolumeSnapshot{
|
||||
*builder.ForVolumeSnapshot("velero", "vs1").ObjectMeta(builder.WithLabels("testing-vs", "vs1")).Result(),
|
||||
},
|
||||
vscArray: []*snapshotv1api.VolumeSnapshotContent{
|
||||
builder.ForVolumeSnapshotContent("vsc1").DeletionPolicy(snapshotv1api.VolumeSnapshotContentDelete).Status().Result(),
|
||||
},
|
||||
expectedVSArray: []snapshotv1api.VolumeSnapshot{},
|
||||
expectedVSCArray: []snapshotv1api.VolumeSnapshotContent{
|
||||
*builder.ForVolumeSnapshotContent("vsc1").DeletionPolicy(snapshotv1api.VolumeSnapshotContentDelete).Status().Result(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fakeClient := velerotest.NewFakeControllerRuntimeClientBuilder(t).WithLists().Build()
|
||||
|
||||
vsClient := snapshotfake.NewSimpleClientset()
|
||||
for _, vsc := range tc.vscArray {
|
||||
_, err := vsClient.SnapshotV1().VolumeSnapshotContents().Create(context.TODO(), vsc, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
err = fakeClient.Create(context.TODO(), vsc, &kbclient.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
for _, vs := range tc.vsArray {
|
||||
_, err := vsClient.SnapshotV1().VolumeSnapshots("velero").Create(context.TODO(), &vs, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
err = fakeClient.Create(context.TODO(), &vs, &kbclient.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
sharedInformers := snapshotinformers.NewSharedInformerFactory(vsClient, 0)
|
||||
|
||||
for _, vs := range tc.vsArray {
|
||||
sharedInformers.Snapshot().V1().VolumeSnapshots().Informer().GetStore().Add(vs)
|
||||
}
|
||||
|
||||
logger := logging.DefaultLogger(logrus.DebugLevel, logging.FormatText)
|
||||
c := &backupController{
|
||||
kbClient: fakeClient,
|
||||
volumeSnapshotClient: vsClient,
|
||||
volumeSnapshotLister: sharedInformers.Snapshot().V1().VolumeSnapshots().Lister(),
|
||||
}
|
||||
|
||||
c.deleteVolumeSnapshot(tc.vsArray, tc.vscArray, logger)
|
||||
|
||||
vsList, err := c.volumeSnapshotClient.SnapshotV1().VolumeSnapshots("velero").List(context.TODO(), metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(tc.expectedVSArray), len(vsList.Items))
|
||||
for index := range tc.expectedVSArray {
|
||||
assert.Equal(t, tc.expectedVSArray[index].Status, vsList.Items[index].Status)
|
||||
assert.Equal(t, tc.expectedVSArray[index].Spec, vsList.Items[index].Spec)
|
||||
}
|
||||
|
||||
vscList, err := c.volumeSnapshotClient.SnapshotV1().VolumeSnapshotContents().List(context.TODO(), metav1.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(tc.expectedVSCArray), len(vscList.Items))
|
||||
for index := range tc.expectedVSCArray {
|
||||
assert.Equal(t, tc.expectedVSCArray[index].Spec, vscList.Items[index].Spec)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,11 +323,11 @@ func (r *backupDeletionReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
}); err != nil {
|
||||
log.WithError(errors.WithStack(err)).Error("Error listing restore API objects")
|
||||
} else {
|
||||
for _, restore := range restoreList.Items {
|
||||
for i, restore := range restoreList.Items {
|
||||
if restore.Spec.BackupName != backup.Name {
|
||||
continue
|
||||
}
|
||||
restoreLog := log.WithField("restore", kube.NamespaceAndName(&restore))
|
||||
restoreLog := log.WithField("restore", kube.NamespaceAndName(&restoreList.Items[i]))
|
||||
|
||||
restoreLog.Info("Deleting restore log/results from backup storage")
|
||||
if err := backupStore.DeleteRestore(restore.Name); err != nil {
|
||||
@@ -337,8 +337,8 @@ func (r *backupDeletionReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
||||
}
|
||||
|
||||
restoreLog.Info("Deleting restore referencing backup")
|
||||
if err := r.Delete(ctx, &restore); err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "error deleting restore %s", kube.NamespaceAndName(&restore)).Error())
|
||||
if err := r.Delete(ctx, &restoreList.Items[i]); err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "error deleting restore %s", kube.NamespaceAndName(&restoreList.Items[i])).Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -421,11 +421,11 @@ func (r *backupDeletionReconciler) deleteExistingDeletionRequests(ctx context.Co
|
||||
return []error{errors.Wrap(err, "error listing existing DeleteBackupRequests for backup")}
|
||||
}
|
||||
var errs []error
|
||||
for _, dbr := range dbrList.Items {
|
||||
for i, dbr := range dbrList.Items {
|
||||
if dbr.Name == req.Name {
|
||||
continue
|
||||
}
|
||||
if err := r.Delete(ctx, &dbr); err != nil {
|
||||
if err := r.Delete(ctx, &dbrList.Items[i]); err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
} else {
|
||||
log.Infof("deletion request '%s' removed.", dbr.Name)
|
||||
|
||||
@@ -24,12 +24,10 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/storage"
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
@@ -39,7 +37,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
backupStorageLocationSyncPeriod = 1 * time.Minute
|
||||
// keep the enqueue period a smaller value to make sure the BSL can be validated as expected.
|
||||
// The BSL validation frequency is 1 minute by default, if we set the enqueue period as 1 minute,
|
||||
// this will cause the actual validation interval for each BSL to be 2 minutes
|
||||
bslValidationEnqueuePeriod = 10 * time.Second
|
||||
)
|
||||
|
||||
// BackupStorageLocationReconciler reconciles a BackupStorageLocation object
|
||||
@@ -185,7 +186,7 @@ func (r *BackupStorageLocationReconciler) SetupWithManager(mgr ctrl.Manager) err
|
||||
r.Log,
|
||||
mgr.GetClient(),
|
||||
&velerov1api.BackupStorageLocationList{},
|
||||
backupStorageLocationSyncPeriod,
|
||||
bslValidationEnqueuePeriod,
|
||||
// Add filter function to enqueue BSL per ValidationFrequency setting.
|
||||
func(object client.Object) bool {
|
||||
location := object.(*velerov1api.BackupStorageLocation)
|
||||
@@ -193,22 +194,8 @@ func (r *BackupStorageLocationReconciler) SetupWithManager(mgr ctrl.Manager) err
|
||||
},
|
||||
)
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&velerov1api.BackupStorageLocation{}).
|
||||
// Handle BSL's creation event and spec update event to let changed BSL got validation immediately.
|
||||
WithEventFilter(predicate.Funcs{
|
||||
CreateFunc: func(ce event.CreateEvent) bool {
|
||||
return true
|
||||
},
|
||||
UpdateFunc: func(ue event.UpdateEvent) bool {
|
||||
return ue.ObjectNew.GetGeneration() != ue.ObjectOld.GetGeneration()
|
||||
},
|
||||
DeleteFunc: func(de event.DeleteEvent) bool {
|
||||
return false
|
||||
},
|
||||
GenericFunc: func(ge event.GenericEvent) bool {
|
||||
return false
|
||||
},
|
||||
}).
|
||||
// As the "status.LastValidationTime" field is always updated, this triggers new reconciling process, skip the update event that include no spec change to avoid the reconcile loop
|
||||
For(&velerov1api.BackupStorageLocation{}, builder.WithPredicates(kube.SpecChangePredicate{})).
|
||||
Watches(g, nil).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ func (c *backupSyncController) run() {
|
||||
pluginManager := c.newPluginManager(c.logger)
|
||||
defer pluginManager.CleanupClients()
|
||||
|
||||
for _, location := range locations {
|
||||
for i, location := range locations {
|
||||
log := c.logger.WithField("backupLocation", location.Name)
|
||||
|
||||
syncPeriod := c.defaultBackupSyncPeriod
|
||||
@@ -177,7 +177,7 @@ func (c *backupSyncController) run() {
|
||||
|
||||
log.Debug("Checking backup location for backups to sync into cluster")
|
||||
|
||||
backupStore, err := c.backupStoreGetter.Get(&location, pluginManager, log)
|
||||
backupStore, err := c.backupStoreGetter.Get(&locations[i], pluginManager, log)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Error getting backup store for this location")
|
||||
continue
|
||||
@@ -337,7 +337,7 @@ func (c *backupSyncController) run() {
|
||||
// update the location's last-synced time field
|
||||
statusPatch := client.MergeFrom(location.DeepCopy())
|
||||
location.Status.LastSyncedTime = &metav1.Time{Time: time.Now().UTC()}
|
||||
if err := c.kbClient.Patch(context.Background(), &location, statusPatch); err != nil {
|
||||
if err := c.kbClient.Patch(context.Background(), &locations[i], statusPatch); err != nil {
|
||||
log.WithError(errors.WithStack(err)).Error("Error patching backup location's last-synced time")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -124,7 +124,11 @@ func (r *PodVolumeBackupReconciler) Reconcile(ctx context.Context, req ctrl.Requ
|
||||
if err != nil {
|
||||
return r.updateStatusToFailed(ctx, &pvb, err, "building Restic command", log)
|
||||
}
|
||||
defer os.Remove(resticDetails.credsFile)
|
||||
|
||||
defer func() {
|
||||
os.Remove(resticDetails.credsFile)
|
||||
os.Remove(resticDetails.caCertFile)
|
||||
}()
|
||||
|
||||
backupLocation := &velerov1api.BackupStorageLocation{}
|
||||
if err := r.Client.Get(context.Background(), client.ObjectKey{
|
||||
@@ -204,19 +208,6 @@ func (r *PodVolumeBackupReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
func (r *PodVolumeBackupReconciler) singlePathMatch(path string) (string, error) {
|
||||
matches, err := r.FileSystem.Glob(path)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
if len(matches) != 1 {
|
||||
return "", errors.Errorf("expected one matching path: %s, got %d", path, len(matches))
|
||||
}
|
||||
|
||||
return matches[0], nil
|
||||
}
|
||||
|
||||
// getParentSnapshot finds the most recent completed PodVolumeBackup for the
|
||||
// specified PVC and returns its Restic snapshot ID. Any errors encountered are
|
||||
// logged but not returned since they do not prevent a backup from proceeding.
|
||||
@@ -237,7 +228,7 @@ func (r *PodVolumeBackupReconciler) getParentSnapshot(ctx context.Context, log l
|
||||
|
||||
// Go through all the podvolumebackups for the PVC and look for the most
|
||||
// recent completed one to use as the parent.
|
||||
var mostRecentPVB *velerov1api.PodVolumeBackup
|
||||
var mostRecentPVB velerov1api.PodVolumeBackup
|
||||
for _, pvb := range pvbList.Items {
|
||||
if pvb.Status.Phase != velerov1api.PodVolumeBackupPhaseCompleted {
|
||||
continue
|
||||
@@ -254,12 +245,12 @@ func (r *PodVolumeBackupReconciler) getParentSnapshot(ctx context.Context, log l
|
||||
continue
|
||||
}
|
||||
|
||||
if mostRecentPVB == nil || pvb.Status.StartTimestamp.After(mostRecentPVB.Status.StartTimestamp.Time) {
|
||||
mostRecentPVB = &pvb
|
||||
if mostRecentPVB.Status == (velerov1api.PodVolumeBackupStatus{}) || pvb.Status.StartTimestamp.After(mostRecentPVB.Status.StartTimestamp.Time) {
|
||||
mostRecentPVB = pvb
|
||||
}
|
||||
}
|
||||
|
||||
if mostRecentPVB == nil {
|
||||
if mostRecentPVB.Status == (velerov1api.PodVolumeBackupStatus{}) {
|
||||
log.Info("No completed PodVolumeBackup found for PVC")
|
||||
return ""
|
||||
}
|
||||
@@ -313,7 +304,7 @@ func (r *PodVolumeBackupReconciler) buildResticCommand(ctx context.Context, log
|
||||
pathGlob := fmt.Sprintf("/host_pods/%s/volumes/*/%s", string(pvb.Spec.Pod.UID), volDir)
|
||||
log.WithField("pathGlob", pathGlob).Debug("Looking for path matching glob")
|
||||
|
||||
path, err := r.singlePathMatch(pathGlob)
|
||||
path, err := kube.SinglePathMatch(pathGlob, r.FileSystem, log)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "identifying unique volume path on host")
|
||||
}
|
||||
@@ -344,8 +335,6 @@ func (r *PodVolumeBackupReconciler) buildResticCommand(ctx context.Context, log
|
||||
if err != nil {
|
||||
log.WithError(err).Error("creating temporary caCert file")
|
||||
}
|
||||
defer os.Remove(details.caCertFile)
|
||||
|
||||
}
|
||||
cmd.CACertFile = details.caCertFile
|
||||
|
||||
|
||||
@@ -215,19 +215,6 @@ func getResticInitContainerIndex(pod *corev1api.Pod) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func singlePathMatch(path string) (string, error) {
|
||||
matches, err := filepath.Glob(path)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
if len(matches) != 1 {
|
||||
return "", errors.Errorf("expected one matching path: %s, got %d", path, len(matches))
|
||||
}
|
||||
|
||||
return matches[0], nil
|
||||
}
|
||||
|
||||
func (c *PodVolumeRestoreReconciler) processRestore(ctx context.Context, req *velerov1api.PodVolumeRestore, pod *corev1api.Pod, log logrus.FieldLogger) error {
|
||||
volumeDir, err := kube.GetVolumeDirectory(ctx, log, pod, req.Spec.Volume, c.Client)
|
||||
if err != nil {
|
||||
@@ -236,7 +223,9 @@ func (c *PodVolumeRestoreReconciler) processRestore(ctx context.Context, req *ve
|
||||
|
||||
// Get the full path of the new volume's directory as mounted in the daemonset pod, which
|
||||
// will look like: /host_pods/<new-pod-uid>/volumes/<volume-plugin-name>/<volume-dir>
|
||||
volumePath, err := singlePathMatch(fmt.Sprintf("/host_pods/%s/volumes/*/%s", string(req.Spec.Pod.UID), volumeDir))
|
||||
volumePath, err := kube.SinglePathMatch(
|
||||
fmt.Sprintf("/host_pods/%s/volumes/*/%s", string(req.Spec.Pod.UID), volumeDir),
|
||||
c.fileSystem, log)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error identifying path of volume")
|
||||
}
|
||||
@@ -321,7 +310,7 @@ func (c *PodVolumeRestoreReconciler) processRestore(ctx context.Context, req *ve
|
||||
// Write a done file with name=<restore-uid> into the just-created .velero dir
|
||||
// within the volume. The velero restic init container on the pod is waiting
|
||||
// for this file to exist in each restored volume before completing.
|
||||
if err := ioutil.WriteFile(filepath.Join(volumePath, ".velero", string(restoreUID)), nil, 0644); err != nil {
|
||||
if err := ioutil.WriteFile(filepath.Join(volumePath, ".velero", string(restoreUID)), nil, 0644); err != nil { //nolint:gosec
|
||||
return errors.Wrap(err, "error writing done file")
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,12 @@ var nonRestorableResources = []string{
|
||||
// created as needed if they don't exist.
|
||||
// https://github.com/vmware-tanzu/velero/issues/1113
|
||||
"resticrepositories.velero.io",
|
||||
|
||||
// CSINode delegates cluster node for CSI operation.
|
||||
// VolumeAttachement records PV mounts to which node.
|
||||
// https://github.com/vmware-tanzu/velero/issues/4823
|
||||
"csinodes.storage.k8s.io",
|
||||
"volumeattachments.storage.k8s.io",
|
||||
}
|
||||
|
||||
type restoreController struct {
|
||||
@@ -436,7 +442,7 @@ func (c *restoreController) fetchBackupInfo(backupName string, pluginManager cli
|
||||
func (c *restoreController) runValidatedRestore(restore *api.Restore, info backupInfo) error {
|
||||
// instantiate the per-restore logger that will output both to a temp file
|
||||
// (for upload to object storage) and to stdout.
|
||||
restoreLog, err := newRestoreLogger(restore, c.logger, c.restoreLogLevel, c.logFormat)
|
||||
restoreLog, err := newRestoreLogger(restore, c.restoreLogLevel, c.logFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -550,14 +556,14 @@ func (c *restoreController) runValidatedRestore(restore *api.Restore, info backu
|
||||
"errors": restoreErrors,
|
||||
}
|
||||
|
||||
if err := putResults(restore, m, info.backupStore, c.logger); err != nil {
|
||||
if err := putResults(restore, m, info.backupStore); err != nil {
|
||||
c.logger.WithError(err).Error("Error uploading restore results to backup storage")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func putResults(restore *api.Restore, results map[string]pkgrestore.Result, backupStore persistence.BackupStore, log logrus.FieldLogger) error {
|
||||
func putResults(restore *api.Restore, results map[string]pkgrestore.Result, backupStore persistence.BackupStore) error {
|
||||
buf := new(bytes.Buffer)
|
||||
gzw := gzip.NewWriter(buf)
|
||||
defer gzw.Close()
|
||||
@@ -642,7 +648,7 @@ type restoreLogger struct {
|
||||
w *gzip.Writer
|
||||
}
|
||||
|
||||
func newRestoreLogger(restore *api.Restore, baseLogger logrus.FieldLogger, logLevel logrus.Level, logFormat logging.Format) (*restoreLogger, error) {
|
||||
func newRestoreLogger(restore *api.Restore, logLevel logrus.Level, logFormat logging.Format) (*restoreLogger, error) {
|
||||
file, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating temp file")
|
||||
|
||||
@@ -131,19 +131,25 @@ func (b *objectBackupStoreGetter) Get(location *velerov1api.BackupStorageLocatio
|
||||
return nil, errors.Errorf("backup storage location's bucket name %q must not contain a '/' (if using a prefix, put it in the 'Prefix' field instead)", location.Spec.ObjectStorage.Bucket)
|
||||
}
|
||||
|
||||
// Pass a new map into the object store rather than modifying the passed-in
|
||||
// location. This prevents Velero controllers from accidentally modifying
|
||||
// the in-cluster BSL with data which doesn't belong in Spec.Config
|
||||
objectStoreConfig := make(map[string]string)
|
||||
if location.Spec.Config != nil {
|
||||
for key, val := range location.Spec.Config {
|
||||
objectStoreConfig[key] = val
|
||||
}
|
||||
}
|
||||
|
||||
// add the bucket name and prefix to the config map so that object stores
|
||||
// can use them when initializing. The AWS object store uses the bucket
|
||||
// name to determine the bucket's region when setting up its client.
|
||||
if location.Spec.Config == nil {
|
||||
location.Spec.Config = make(map[string]string)
|
||||
}
|
||||
|
||||
location.Spec.Config["bucket"] = bucket
|
||||
location.Spec.Config["prefix"] = prefix
|
||||
objectStoreConfig["bucket"] = bucket
|
||||
objectStoreConfig["prefix"] = prefix
|
||||
|
||||
// Only include a CACert if it's specified in order to maintain compatibility with plugins that don't expect it.
|
||||
if location.Spec.ObjectStorage.CACert != nil {
|
||||
location.Spec.Config["caCert"] = string(location.Spec.ObjectStorage.CACert)
|
||||
objectStoreConfig["caCert"] = string(location.Spec.ObjectStorage.CACert)
|
||||
}
|
||||
|
||||
// If the BSL specifies a credential, fetch its path on disk and pass to
|
||||
@@ -154,7 +160,7 @@ func (b *objectBackupStoreGetter) Get(location *velerov1api.BackupStorageLocatio
|
||||
return nil, errors.Wrap(err, "unable to get credentials")
|
||||
}
|
||||
|
||||
location.Spec.Config["credentialsFile"] = credsFile
|
||||
objectStoreConfig["credentialsFile"] = credsFile
|
||||
}
|
||||
|
||||
objectStore, err := objectStoreGetter.GetObjectStore(location.Spec.Provider)
|
||||
@@ -162,7 +168,7 @@ func (b *objectBackupStoreGetter) Get(location *velerov1api.BackupStorageLocatio
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := objectStore.Init(location.Spec.Config); err != nil {
|
||||
if err := objectStore.Init(objectStoreConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -520,6 +526,10 @@ func (s *objectBackupStore) GetDownloadURL(target velerov1api.DownloadTarget) (s
|
||||
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getRestoreLogKey(target.Name), DownloadURLTTL)
|
||||
case velerov1api.DownloadTargetKindRestoreResults:
|
||||
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getRestoreResultsKey(target.Name), DownloadURLTTL)
|
||||
case velerov1api.DownloadTargetKindCSIBackupVolumeSnapshots:
|
||||
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getCSIVolumeSnapshotKey(target.Name), DownloadURLTTL)
|
||||
case velerov1api.DownloadTargetKindCSIBackupVolumeSnapshotContents:
|
||||
return s.objectStore.CreateSignedURL(s.bucket, s.layout.getCSIVolumeSnapshotContentsKey(target.Name), DownloadURLTTL)
|
||||
default:
|
||||
return "", errors.Errorf("unsupported download target kind %q", target.Kind)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func (b *clientBuilder) clientConfig() *hcplugin.ClientConfig {
|
||||
string(framework.PluginKindItemSnapshotter): framework.NewItemSnapshotterPlugin(framework.ClientLogger(b.clientLogger)),
|
||||
},
|
||||
Logger: b.pluginLogger,
|
||||
Cmd: exec.Command(b.commandName, b.commandArgs...),
|
||||
Cmd: exec.Command(b.commandName, b.commandArgs...), //nolint
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
veleroflag "github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/logging"
|
||||
)
|
||||
|
||||
@@ -78,6 +77,7 @@ type Server interface {
|
||||
|
||||
// RegisterItemSnapshotters registers multiple Item Snapshotters
|
||||
RegisterItemSnapshotters(map[string]HandlerInitializer) Server
|
||||
|
||||
// Server runs the plugin server.
|
||||
Serve()
|
||||
}
|
||||
@@ -87,7 +87,6 @@ type server struct {
|
||||
log *logrus.Logger
|
||||
logLevelFlag *logging.LevelFlag
|
||||
flagSet *pflag.FlagSet
|
||||
featureSet *veleroflag.StringArray
|
||||
backupItemAction *BackupItemActionPlugin
|
||||
volumeSnapshotter *VolumeSnapshotterPlugin
|
||||
objectStore *ObjectStorePlugin
|
||||
@@ -99,12 +98,10 @@ type server struct {
|
||||
// NewServer returns a new Server
|
||||
func NewServer() Server {
|
||||
log := newLogger()
|
||||
features := veleroflag.NewStringArray()
|
||||
|
||||
return &server{
|
||||
log: log,
|
||||
logLevelFlag: logging.LogLevelFlag(log.Level),
|
||||
featureSet: &features,
|
||||
backupItemAction: NewBackupItemActionPlugin(serverLogger(log)),
|
||||
volumeSnapshotter: NewVolumeSnapshotterPlugin(serverLogger(log)),
|
||||
objectStore: NewObjectStorePlugin(serverLogger(log)),
|
||||
@@ -116,7 +113,6 @@ func NewServer() Server {
|
||||
|
||||
func (s *server) BindFlags(flags *pflag.FlagSet) Server {
|
||||
flags.Var(s.logLevelFlag, "log-level", fmt.Sprintf("The level at which to log. Valid values are %s.", strings.Join(s.logLevelFlag.AllowedValues(), ", ")))
|
||||
flags.Var(s.featureSet, "features", "List of feature flags for this plugin")
|
||||
s.flagSet = flags
|
||||
s.flagSet.ParseErrorsWhitelist.UnknownFlags = true
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ func newGRPCErrorWithCode(err error, code codes.Code, details ...goproto.Message
|
||||
|
||||
// newGRPCError is a convenience function for creating a new gRPC error
|
||||
// with code = codes.Unknown
|
||||
func newGRPCError(err error, details ...goproto.Message) error {
|
||||
func newGRPCError(err error, details ...goproto.Message) error { //nolint:unparam
|
||||
return newGRPCErrorWithCode(err, codes.Unknown, details...)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,14 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
//nolint:unparam
|
||||
package restic
|
||||
|
||||
const (
|
||||
// AWS specific environment variable
|
||||
awsProfileEnvVar = "AWS_PROFILE"
|
||||
awsProfileKey = "profile"
|
||||
awsCredentialsFileEnvVar = "AWS_SHARED_CREDENTIALS_FILE"
|
||||
awsCredentialsFileEnvVar = "AWS_SHARED_CREDENTIALS_FILE" //nolint:gosec
|
||||
)
|
||||
|
||||
// getS3ResticEnvVars gets the environment variables that restic
|
||||
|
||||
@@ -81,7 +81,7 @@ func getStorageAccountKey(config map[string]string) (string, *azure.Environment,
|
||||
}
|
||||
|
||||
// we need config["resourceGroup"], config["storageAccount"]
|
||||
if _, err := getRequiredValues(mapLookup(config), resourceGroupConfigKey, storageAccountConfigKey); err != nil {
|
||||
if err := getRequiredValues(mapLookup(config), resourceGroupConfigKey, storageAccountConfigKey); err != nil {
|
||||
return "", env, errors.Wrap(err, "unable to get all required config values")
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ func getAzureResticEnvVars(config map[string]string) (map[string]string, error)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := getRequiredValues(mapLookup(config), storageAccountConfigKey); err != nil {
|
||||
if err := getRequiredValues(mapLookup(config), storageAccountConfigKey); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get all required config values")
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ func parseAzureEnvironment(cloudName string) (*azure.Environment, error) {
|
||||
return &env, errors.WithStack(err)
|
||||
}
|
||||
|
||||
func getRequiredValues(getValue func(string) string, keys ...string) (map[string]string, error) {
|
||||
func getRequiredValues(getValue func(string) string, keys ...string) error {
|
||||
missing := []string{}
|
||||
results := map[string]string{}
|
||||
|
||||
@@ -203,8 +203,8 @@ func getRequiredValues(getValue func(string) string, keys ...string) (map[string
|
||||
}
|
||||
|
||||
if len(missing) > 0 {
|
||||
return nil, errors.Errorf("the following keys do not have values: %s", strings.Join(missing, ", "))
|
||||
return errors.Errorf("the following keys do not have values: %s", strings.Join(missing, ", "))
|
||||
}
|
||||
|
||||
return results, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func (c *Command) String() string {
|
||||
// Cmd returns an exec.Cmd for the command.
|
||||
func (c *Command) Cmd() *exec.Cmd {
|
||||
parts := c.StringSlice()
|
||||
cmd := exec.Command(parts[0], parts[1:]...)
|
||||
cmd := exec.Command(parts[0], parts[1:]...) //nolint:gosec
|
||||
cmd.Dir = c.Dir
|
||||
|
||||
if len(c.Env) > 0 {
|
||||
|
||||
@@ -18,12 +18,12 @@ package restic
|
||||
|
||||
const (
|
||||
// GCP specific environment variable
|
||||
gcpCredentialsFileEnvVar = "GOOGLE_APPLICATION_CREDENTIALS"
|
||||
gcpCredentialsFileEnvVar = "GOOGLE_APPLICATION_CREDENTIALS" //nolint:gosec
|
||||
)
|
||||
|
||||
// getGCPResticEnvVars gets the environment variables that restic relies
|
||||
// on based on info in the provided object storage location config map.
|
||||
func getGCPResticEnvVars(config map[string]string) (map[string]string, error) {
|
||||
func getGCPResticEnvVars(config map[string]string) (map[string]string, error) { //nolint:unparam
|
||||
result := make(map[string]string)
|
||||
|
||||
if credentialsFile, ok := config[credentialsFileKey]; ok {
|
||||
|
||||
@@ -34,4 +34,4 @@ func (exec FakeResticBackupExec) RunBackup(cmd *restic.Command, log logrus.Field
|
||||
// GetSnapshotID gets the Restic snapshot ID.
|
||||
func (exec FakeResticBackupExec) GetSnapshotID(cmd *restic.Command) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ func (r *repositoryEnsurer) EnsureRepo(ctx context.Context, namespace, volumeNam
|
||||
select {
|
||||
// repositories should become either ready or not ready quickly if they're
|
||||
// newly created.
|
||||
case <-time.After(time.Minute):
|
||||
case <-time.After(time.Minute * 5):
|
||||
return nil, errors.New("timed out waiting for restic repository to become ready")
|
||||
case <-ctx.Done():
|
||||
return nil, errors.New("timed out waiting for restic repository to become ready")
|
||||
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
//nolint:gosec
|
||||
package restic
|
||||
|
||||
import (
|
||||
|
||||
@@ -70,9 +70,9 @@ func (a *AdmissionWebhookConfigurationAction) Execute(input *velero.RestoreItemA
|
||||
return velero.NewRestoreItemActionExecuteOutput(input.Item), nil
|
||||
}
|
||||
newWebhooks := make([]interface{}, 0)
|
||||
for i, entry := range webhooks {
|
||||
for i := range webhooks {
|
||||
logger2 := logger.WithField("index", i)
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&entry)
|
||||
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&webhooks[i])
|
||||
if err != nil {
|
||||
logger2.Errorf("failed to convert the webhook entry, error: %v, it will be dropped", err)
|
||||
continue
|
||||
|
||||
@@ -99,7 +99,7 @@ func (a *ChangeStorageClassAction) Execute(input *velero.RestoreItemActionExecut
|
||||
|
||||
if len(sts.Spec.VolumeClaimTemplates) > 0 {
|
||||
for index, pvc := range sts.Spec.VolumeClaimTemplates {
|
||||
exists, newStorageClass, err := a.isStorageClassExist(log, *pvc.Spec.StorageClassName, config)
|
||||
exists, newStorageClass, err := a.isStorageClassExist(log, pvc.Spec.StorageClassName, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !exists {
|
||||
@@ -124,7 +124,7 @@ func (a *ChangeStorageClassAction) Execute(input *velero.RestoreItemActionExecut
|
||||
return nil, errors.Wrap(err, "error getting item's spec.storageClassName")
|
||||
}
|
||||
|
||||
exists, newStorageClass, err := a.isStorageClassExist(log, storageClass, config)
|
||||
exists, newStorageClass, err := a.isStorageClassExist(log, &storageClass, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !exists {
|
||||
@@ -140,15 +140,15 @@ func (a *ChangeStorageClassAction) Execute(input *velero.RestoreItemActionExecut
|
||||
return velero.NewRestoreItemActionExecuteOutput(obj), nil
|
||||
}
|
||||
|
||||
func (a *ChangeStorageClassAction) isStorageClassExist(log *logrus.Entry, storageClass string, cm *corev1.ConfigMap) (exists bool, newStorageClass string, err error) {
|
||||
if storageClass == "" {
|
||||
func (a *ChangeStorageClassAction) isStorageClassExist(log *logrus.Entry, storageClass *string, cm *corev1.ConfigMap) (exists bool, newStorageClass string, err error) {
|
||||
if storageClass == nil || *storageClass == "" {
|
||||
log.Debug("Item has no storage class specified")
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
newStorageClass, ok := cm.Data[storageClass]
|
||||
newStorageClass, ok := cm.Data[*storageClass]
|
||||
if !ok {
|
||||
log.Debugf("No mapping found for storage class %s", storageClass)
|
||||
log.Debugf("No mapping found for storage class %s", *storageClass)
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
|
||||
92
pkg/restore/priority.go
Normal file
92
pkg/restore/priority.go
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright The Velero Contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package restore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
prioritySeparator = "-"
|
||||
)
|
||||
|
||||
// Priorities defines the desired order of resource operations:
|
||||
// Resources in the HighPriorities list will be handled first
|
||||
// Resources in the LowPriorities list will be handled last
|
||||
// Other resources will be handled alphabetically after the high prioritized resources and before the low prioritized resources
|
||||
type Priorities struct {
|
||||
HighPriorities []string
|
||||
LowPriorities []string
|
||||
}
|
||||
|
||||
// String returns a string representation of Priority.
|
||||
func (p *Priorities) String() string {
|
||||
priorities := p.HighPriorities
|
||||
if len(p.LowPriorities) > 0 {
|
||||
priorities = append(priorities, prioritySeparator)
|
||||
priorities = append(priorities, p.LowPriorities...)
|
||||
}
|
||||
return strings.Join(priorities, ",")
|
||||
}
|
||||
|
||||
// Set parses the provided string to the priority object
|
||||
func (p *Priorities) Set(s string) error {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
strs := strings.Split(s, ",")
|
||||
separatorIndex := -1
|
||||
for i, str := range strs {
|
||||
if str == prioritySeparator {
|
||||
if separatorIndex > -1 {
|
||||
return fmt.Errorf("multiple priority separator %q found", prioritySeparator)
|
||||
}
|
||||
separatorIndex = i
|
||||
}
|
||||
}
|
||||
// has no separator
|
||||
if separatorIndex == -1 {
|
||||
p.HighPriorities = strs
|
||||
return nil
|
||||
}
|
||||
// start with separator
|
||||
if separatorIndex == 0 {
|
||||
// contain only separator
|
||||
if len(strs) == 1 {
|
||||
return nil
|
||||
}
|
||||
p.LowPriorities = strs[1:]
|
||||
return nil
|
||||
}
|
||||
// end with separator
|
||||
if separatorIndex == len(strs)-1 {
|
||||
p.HighPriorities = strs[:len(strs)-1]
|
||||
return nil
|
||||
}
|
||||
|
||||
// separator in the middle
|
||||
p.HighPriorities = strs[:separatorIndex]
|
||||
p.LowPriorities = strs[separatorIndex+1:]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Type specifies the flag type
|
||||
func (p *Priorities) Type() string {
|
||||
return "stringArray"
|
||||
}
|
||||
110
pkg/restore/priority_test.go
Normal file
110
pkg/restore/priority_test.go
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright The Velero Contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package restore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestStringOfPriorities(t *testing.T) {
|
||||
priority := Priorities{
|
||||
HighPriorities: []string{"high"},
|
||||
}
|
||||
assert.Equal(t, "high", priority.String())
|
||||
|
||||
priority = Priorities{
|
||||
HighPriorities: []string{"high"},
|
||||
LowPriorities: []string{"low"},
|
||||
}
|
||||
assert.Equal(t, "high,-,low", priority.String())
|
||||
}
|
||||
|
||||
func TestSetOfPriority(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input string
|
||||
priorities Priorities
|
||||
hasErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty input",
|
||||
input: "",
|
||||
priorities: Priorities{},
|
||||
hasErr: false,
|
||||
},
|
||||
{
|
||||
name: "only high priorities",
|
||||
input: "p0",
|
||||
priorities: Priorities{
|
||||
HighPriorities: []string{"p0"},
|
||||
},
|
||||
hasErr: false,
|
||||
},
|
||||
{
|
||||
name: "only low priorities",
|
||||
input: "-,p9",
|
||||
priorities: Priorities{
|
||||
LowPriorities: []string{"p9"},
|
||||
},
|
||||
hasErr: false,
|
||||
},
|
||||
{
|
||||
name: "only separator",
|
||||
input: "-",
|
||||
priorities: Priorities{},
|
||||
hasErr: false,
|
||||
},
|
||||
{
|
||||
name: "multiple separators",
|
||||
input: "-,-",
|
||||
priorities: Priorities{},
|
||||
hasErr: true,
|
||||
},
|
||||
{
|
||||
name: "contain both high and low priorities",
|
||||
input: "p0,p1,p2,-,p9",
|
||||
priorities: Priorities{
|
||||
HighPriorities: []string{"p0", "p1", "p2"},
|
||||
LowPriorities: []string{"p9"},
|
||||
},
|
||||
hasErr: false,
|
||||
},
|
||||
{
|
||||
name: "end with separator",
|
||||
input: "p0,-",
|
||||
priorities: Priorities{
|
||||
HighPriorities: []string{"p0"},
|
||||
},
|
||||
hasErr: false,
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
p := Priorities{}
|
||||
err := p.Set(c.input)
|
||||
if c.hasErr {
|
||||
require.NotNil(t, err)
|
||||
} else {
|
||||
require.Nil(t, err)
|
||||
}
|
||||
assert.Equal(t, c.priorities, p)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ type kubernetesRestorer struct {
|
||||
resticRestorerFactory restic.RestorerFactory
|
||||
resticTimeout time.Duration
|
||||
resourceTerminatingTimeout time.Duration
|
||||
resourcePriorities []string
|
||||
resourcePriorities Priorities
|
||||
fileSystem filesystem.Interface
|
||||
pvRenamer func(string) (string, error)
|
||||
logger logrus.FieldLogger
|
||||
@@ -120,7 +120,7 @@ func NewKubernetesRestorer(
|
||||
restoreClient velerov1client.RestoresGetter,
|
||||
discoveryHelper discovery.Helper,
|
||||
dynamicFactory client.DynamicFactory,
|
||||
resourcePriorities []string,
|
||||
resourcePriorities Priorities,
|
||||
namespaceClient corev1.NamespaceInterface,
|
||||
resticRestorerFactory restic.RestorerFactory,
|
||||
resticTimeout time.Duration,
|
||||
@@ -207,11 +207,8 @@ func (kr *kubernetesRestorer) RestoreWithResolvers(
|
||||
)
|
||||
|
||||
// Get resource status includes-excludes. Defaults to excluding all resources
|
||||
restoreStatusIncludesExcludes := collections.GetResourceIncludesExcludes(
|
||||
kr.discoveryHelper,
|
||||
[]string{},
|
||||
[]string{"*"},
|
||||
)
|
||||
var restoreStatusIncludesExcludes *collections.IncludesExcludes
|
||||
|
||||
if req.Restore.Spec.RestoreStatus != nil {
|
||||
restoreStatusIncludesExcludes = collections.GetResourceIncludesExcludes(
|
||||
kr.discoveryHelper,
|
||||
@@ -354,7 +351,7 @@ type restoreContext struct {
|
||||
renamedPVs map[string]string
|
||||
pvRenamer func(string) (string, error)
|
||||
discoveryHelper discovery.Helper
|
||||
resourcePriorities []string
|
||||
resourcePriorities Priorities
|
||||
hooksWaitGroup sync.WaitGroup
|
||||
hooksErrs chan error
|
||||
resourceRestoreHooks []hook.ResourceRestoreHook
|
||||
@@ -370,19 +367,31 @@ type resourceClientKey struct {
|
||||
|
||||
// getOrderedResources returns an ordered list of resource identifiers to restore,
|
||||
// based on the provided resource priorities and backup contents. The returned list
|
||||
// begins with all of the prioritized resources (in order), and appends to that
|
||||
// an alphabetized list of all resources in the backup.
|
||||
func getOrderedResources(resourcePriorities []string, backupResources map[string]*archive.ResourceItems) []string {
|
||||
// alphabetize resources in the backup
|
||||
orderedBackupResources := make([]string, 0, len(backupResources))
|
||||
// begins with all of the high prioritized resources (in order), ends with all of
|
||||
// the low prioritized resources(in order), and an alphabetized list of resources
|
||||
// in the backup(pick out the prioritized resources) is put in the middle.
|
||||
func getOrderedResources(resourcePriorities Priorities, backupResources map[string]*archive.ResourceItems) []string {
|
||||
priorities := map[string]struct{}{}
|
||||
for _, priority := range resourcePriorities.HighPriorities {
|
||||
priorities[priority] = struct{}{}
|
||||
}
|
||||
for _, priority := range resourcePriorities.LowPriorities {
|
||||
priorities[priority] = struct{}{}
|
||||
}
|
||||
|
||||
// pick the prioritized resources out
|
||||
var orderedBackupResources []string
|
||||
for resource := range backupResources {
|
||||
if _, exist := priorities[resource]; exist {
|
||||
continue
|
||||
}
|
||||
orderedBackupResources = append(orderedBackupResources, resource)
|
||||
}
|
||||
// alphabetize resources in the backup
|
||||
sort.Strings(orderedBackupResources)
|
||||
|
||||
// Main list: everything in resource priorities, followed by what's in the
|
||||
// backup (alphabetized).
|
||||
return append(resourcePriorities, orderedBackupResources...)
|
||||
list := append(resourcePriorities.HighPriorities, orderedBackupResources...)
|
||||
return append(list, resourcePriorities.LowPriorities...)
|
||||
}
|
||||
|
||||
type progressUpdate struct {
|
||||
@@ -469,7 +478,7 @@ func (ctx *restoreContext) execute() (Result, Result) {
|
||||
backupResources,
|
||||
make([]restoreableResource, 0),
|
||||
sets.NewString(),
|
||||
[]string{"customresourcedefinitions"},
|
||||
Priorities{HighPriorities: []string{"customresourcedefinitions"}},
|
||||
false,
|
||||
)
|
||||
warnings.Merge(&w)
|
||||
@@ -1020,7 +1029,7 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
|
||||
// Check to see if the claimRef.namespace field needs to be remapped,
|
||||
// and do so if necessary.
|
||||
_, err = remapClaimRefNS(ctx, obj)
|
||||
err = remapClaimRefNS(ctx, obj)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs
|
||||
@@ -1110,7 +1119,7 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
ctx.log.Infof("Restoring persistent volume as-is because it doesn't have a snapshot and its reclaim policy is not Delete.")
|
||||
|
||||
// Check to see if the claimRef.namespace field needs to be remapped, and do so if necessary.
|
||||
_, err = remapClaimRefNS(ctx, obj)
|
||||
err = remapClaimRefNS(ctx, obj)
|
||||
if err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs
|
||||
@@ -1252,12 +1261,31 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs
|
||||
}
|
||||
if isAlreadyExistsError {
|
||||
fromCluster, err := resourceClient.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
ctx.log.Infof("Error retrieving cluster version of %s: %v", kube.NamespaceAndName(obj), err)
|
||||
warnings.Add(namespace, err)
|
||||
return warnings, errs
|
||||
|
||||
// check if we want to treat the error as a warning, in some cases the creation call might not get executed due to object API validations
|
||||
// and Velero might not get the already exists error type but in reality the object already exists
|
||||
objectExists := false
|
||||
var fromCluster *unstructured.Unstructured
|
||||
|
||||
if restoreErr != nil && !isAlreadyExistsError {
|
||||
// check for the existence of the object in cluster, if no error then it implies that object exists
|
||||
// and if err then we want to fallthrough and do another get call later
|
||||
fromCluster, err = resourceClient.Get(name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
objectExists = true
|
||||
}
|
||||
}
|
||||
|
||||
if isAlreadyExistsError || objectExists {
|
||||
// do a get call if we did not run this previously i.e.
|
||||
// we've only run this for errors other than isAlreadyExistError
|
||||
if fromCluster == nil {
|
||||
fromCluster, err = resourceClient.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
ctx.log.Errorf("Error retrieving cluster version of %s: %v", kube.NamespaceAndName(obj), err)
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs
|
||||
}
|
||||
}
|
||||
// Remove insubstantial metadata.
|
||||
fromCluster, err = resetMetadataAndStatus(fromCluster)
|
||||
@@ -1362,13 +1390,14 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
shouldRestoreStatus := ctx.resourceStatusIncludesExcludes.ShouldInclude(groupResource.String())
|
||||
shouldRestoreStatus := ctx.resourceStatusIncludesExcludes != nil && ctx.resourceStatusIncludesExcludes.ShouldInclude(groupResource.String())
|
||||
if shouldRestoreStatus && statusFieldErr != nil {
|
||||
err := fmt.Errorf("could not get status to be restored %s: %v", kube.NamespaceAndName(obj), statusFieldErr)
|
||||
ctx.log.Errorf(err.Error())
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs
|
||||
}
|
||||
ctx.log.Debugf("status field for %s: exists: %v, should restore: %v", groupResource, statusFieldExists, shouldRestoreStatus)
|
||||
// if it should restore status, run a UpdateStatus
|
||||
if statusFieldExists && shouldRestoreStatus {
|
||||
if err := unstructured.SetNestedField(obj.Object, objStatus, "status"); err != nil {
|
||||
@@ -1379,6 +1408,7 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
obj.SetResourceVersion(createdObj.GetResourceVersion())
|
||||
updated, err := resourceClient.UpdateStatus(obj, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
ctx.log.Infof("status field update failed %s: %v", kube.NamespaceAndName(obj), err)
|
||||
warnings.Add(namespace, err)
|
||||
} else {
|
||||
createdObj = updated
|
||||
@@ -1499,37 +1529,37 @@ func shouldRenamePV(ctx *restoreContext, obj *unstructured.Unstructured, client
|
||||
// remapClaimRefNS remaps a PersistentVolume's claimRef.Namespace based on a
|
||||
// restore's NamespaceMappings, if necessary. Returns true if the namespace was
|
||||
// remapped, false if it was not required.
|
||||
func remapClaimRefNS(ctx *restoreContext, obj *unstructured.Unstructured) (bool, error) {
|
||||
func remapClaimRefNS(ctx *restoreContext, obj *unstructured.Unstructured) error {
|
||||
if len(ctx.restore.Spec.NamespaceMapping) == 0 {
|
||||
ctx.log.Debug("Persistent volume does not need to have the claimRef.namespace remapped because restore is not remapping any namespaces")
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Conversion to the real type here is more readable than all the error checking
|
||||
// involved with reading each field individually.
|
||||
pv := new(v1.PersistentVolume)
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, pv); err != nil {
|
||||
return false, errors.Wrapf(err, "error converting persistent volume to structured")
|
||||
return errors.Wrapf(err, "error converting persistent volume to structured")
|
||||
}
|
||||
|
||||
if pv.Spec.ClaimRef == nil {
|
||||
ctx.log.Debugf("Persistent volume does not need to have the claimRef.namespace remapped because it's not claimed")
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
targetNS, ok := ctx.restore.Spec.NamespaceMapping[pv.Spec.ClaimRef.Namespace]
|
||||
|
||||
if !ok {
|
||||
ctx.log.Debugf("Persistent volume does not need to have the claimRef.namespace remapped because it's not claimed by a PVC in a namespace that's being remapped")
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
err := unstructured.SetNestedField(obj.Object, targetNS, "spec", "claimRef", "namespace")
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
ctx.log.Debug("Persistent volume's namespace was updated")
|
||||
return true, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// restorePodVolumeBackups restores the PodVolumeBackups for the given restored pod
|
||||
@@ -1772,7 +1802,7 @@ func (ctx *restoreContext) getOrderedResourceCollection(
|
||||
backupResources map[string]*archive.ResourceItems,
|
||||
restoreResourceCollection []restoreableResource,
|
||||
processedResources sets.String,
|
||||
resourcePriorities []string,
|
||||
resourcePriorities Priorities,
|
||||
includeAllResources bool,
|
||||
) ([]restoreableResource, sets.String, Result, Result) {
|
||||
var warnings, errs Result
|
||||
@@ -1794,7 +1824,7 @@ func (ctx *restoreContext) getOrderedResourceCollection(
|
||||
if includeAllResources {
|
||||
resourceList = getOrderedResources(resourcePriorities, backupResources)
|
||||
} else {
|
||||
resourceList = resourcePriorities
|
||||
resourceList = resourcePriorities.HighPriorities
|
||||
}
|
||||
for _, resource := range resourceList {
|
||||
// try to resolve the resource via discovery to a complete group/version/resource
|
||||
@@ -2025,7 +2055,7 @@ func (ctx *restoreContext) processUpdateResourcePolicy(fromCluster, fromClusterW
|
||||
// try patching the in-cluster resource (resource diff plus latest backup/restore labels)
|
||||
_, err = resourceClient.Patch(obj.GetName(), patchBytes)
|
||||
if err != nil {
|
||||
ctx.log.Errorf("patch attempt failed for %s %s: %v", fromCluster.GroupVersionKind(), kube.NamespaceAndName(fromCluster), err)
|
||||
ctx.log.Warnf("patch attempt failed for %s %s: %v", fromCluster.GroupVersionKind(), kube.NamespaceAndName(fromCluster), err)
|
||||
warnings.Add(namespace, err)
|
||||
// try just patching the labels
|
||||
warningsFromUpdate, errsFromUpdate := ctx.updateBackupRestoreLabels(fromCluster, fromClusterWithLabels, namespace, resourceClient)
|
||||
|
||||
@@ -679,7 +679,7 @@ func TestRestoreResourcePriorities(t *testing.T) {
|
||||
backup *velerov1api.Backup
|
||||
apiResources []*test.APIResource
|
||||
tarball io.Reader
|
||||
resourcePriorities []string
|
||||
resourcePriorities Priorities
|
||||
}{
|
||||
{
|
||||
name: "resources are restored according to the specified resource priorities",
|
||||
@@ -713,7 +713,10 @@ func TestRestoreResourcePriorities(t *testing.T) {
|
||||
test.Deployments(),
|
||||
test.ServiceAccounts(),
|
||||
},
|
||||
resourcePriorities: []string{"persistentvolumes", "serviceaccounts", "pods", "deployments.apps"},
|
||||
resourcePriorities: Priorities{
|
||||
HighPriorities: []string{"persistentvolumes", "persistentvolumeclaims", "serviceaccounts"},
|
||||
LowPriorities: []string{"deployments.apps"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -745,7 +748,7 @@ func TestRestoreResourcePriorities(t *testing.T) {
|
||||
)
|
||||
|
||||
assertEmptyResults(t, warnings, errs)
|
||||
assertResourceCreationOrder(t, tc.resourcePriorities, recorder.resources)
|
||||
assertResourceCreationOrder(t, []string{"persistentvolumes", "persistentvolumeclaims", "serviceaccounts", "pods", "deployments.apps"}, recorder.resources)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -871,7 +874,6 @@ func TestRestoreItems(t *testing.T) {
|
||||
ObjectMeta(
|
||||
builder.WithLabels("key-1", "val-1"),
|
||||
builder.WithAnnotations("key-1", "val-1"),
|
||||
builder.WithClusterName("cluster-1"),
|
||||
builder.WithFinalizers("finalizer-1"),
|
||||
).
|
||||
Result(),
|
||||
@@ -2623,7 +2625,7 @@ func TestRestorePersistentVolumes(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
h := newHarness(t)
|
||||
h.restorer.resourcePriorities = []string{"persistentvolumes", "persistentvolumeclaims"}
|
||||
h.restorer.resourcePriorities = Priorities{HighPriorities: []string{"persistentvolumes", "persistentvolumeclaims"}}
|
||||
h.restorer.pvRenamer = func(oldName string) (string, error) {
|
||||
renamed := "renamed-" + oldName
|
||||
return renamed, nil
|
||||
@@ -2941,19 +2943,19 @@ func TestIsCompleted(t *testing.T) {
|
||||
func Test_getOrderedResources(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
resourcePriorities []string
|
||||
resourcePriorities Priorities
|
||||
backupResources map[string]*archive.ResourceItems
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
name: "when only priorities are specified, they're returned in order",
|
||||
resourcePriorities: []string{"prio-3", "prio-2", "prio-1"},
|
||||
resourcePriorities: Priorities{HighPriorities: []string{"prio-3", "prio-2", "prio-1"}},
|
||||
backupResources: nil,
|
||||
want: []string{"prio-3", "prio-2", "prio-1"},
|
||||
},
|
||||
{
|
||||
name: "when only backup resources are specified, they're returned in alphabetical order",
|
||||
resourcePriorities: nil,
|
||||
resourcePriorities: Priorities{},
|
||||
backupResources: map[string]*archive.ResourceItems{
|
||||
"backup-resource-3": nil,
|
||||
"backup-resource-2": nil,
|
||||
@@ -2963,14 +2965,26 @@ func Test_getOrderedResources(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "when priorities and backup resources are specified, they're returned in the correct order",
|
||||
resourcePriorities: []string{"prio-3", "prio-2", "prio-1"},
|
||||
resourcePriorities: Priorities{HighPriorities: []string{"prio-3", "prio-2", "prio-1"}},
|
||||
backupResources: map[string]*archive.ResourceItems{
|
||||
"prio-3": nil,
|
||||
"backup-resource-3": nil,
|
||||
"backup-resource-2": nil,
|
||||
"backup-resource-1": nil,
|
||||
},
|
||||
want: []string{"prio-3", "prio-2", "prio-1", "backup-resource-1", "backup-resource-2", "backup-resource-3", "prio-3"},
|
||||
want: []string{"prio-3", "prio-2", "prio-1", "backup-resource-1", "backup-resource-2", "backup-resource-3"},
|
||||
},
|
||||
{
|
||||
name: "when priorities and backup resources are specified, they're returned in the correct order",
|
||||
resourcePriorities: Priorities{HighPriorities: []string{"prio-3", "prio-2", "prio-1"}, LowPriorities: []string{"prio-0"}},
|
||||
backupResources: map[string]*archive.ResourceItems{
|
||||
"prio-3": nil,
|
||||
"prio-0": nil,
|
||||
"backup-resource-3": nil,
|
||||
"backup-resource-2": nil,
|
||||
"backup-resource-1": nil,
|
||||
},
|
||||
want: []string{"prio-3", "prio-2", "prio-1", "backup-resource-1", "backup-resource-2", "backup-resource-3", "prio-0"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v4/apis/volumesnapshot/v1"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -34,6 +35,8 @@ func NewFakeControllerRuntimeClientBuilder(t *testing.T) *k8sfake.ClientBuilder
|
||||
require.NoError(t, err)
|
||||
err = corev1api.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
err = snapshotv1api.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
return k8sfake.NewClientBuilder().WithScheme(scheme)
|
||||
}
|
||||
|
||||
@@ -43,5 +46,7 @@ func NewFakeControllerRuntimeClient(t *testing.T, initObjs ...runtime.Object) cl
|
||||
require.NoError(t, err)
|
||||
err = corev1api.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
err = snapshotv1api.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
return k8sfake.NewFakeClientWithScheme(scheme, initObjs...)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package kube
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
@@ -96,3 +97,10 @@ func (p *PeriodicalEnqueueSource) Start(ctx context.Context, h handler.EventHand
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PeriodicalEnqueueSource) String() string {
|
||||
if p.objList != nil {
|
||||
return fmt.Sprintf("kind source: %T", p.objList)
|
||||
}
|
||||
return "kind source: unknown type"
|
||||
}
|
||||
|
||||
47
pkg/util/kube/predicate.go
Normal file
47
pkg/util/kube/predicate.go
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
)
|
||||
|
||||
// SpecChangePredicate implements a default update predicate function on Spec change
|
||||
// As Velero doesn't enable subresource in CRDs, we cannot use the object's metadata.generation field to check the spec change
|
||||
// More details about the generation field refer to https://github.com/kubernetes-sigs/controller-runtime/blob/v0.12.2/pkg/predicate/predicate.go#L156
|
||||
type SpecChangePredicate struct {
|
||||
predicate.Funcs
|
||||
}
|
||||
|
||||
func (SpecChangePredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectOld == nil {
|
||||
return false
|
||||
}
|
||||
if e.ObjectNew == nil {
|
||||
return false
|
||||
}
|
||||
oldSpec := reflect.ValueOf(e.ObjectOld).Elem().FieldByName("Spec")
|
||||
// contains no field named "Spec", return false directly
|
||||
if oldSpec.IsZero() {
|
||||
return false
|
||||
}
|
||||
newSpec := reflect.ValueOf(e.ObjectNew).Elem().FieldByName("Spec")
|
||||
return !reflect.DeepEqual(oldSpec.Interface(), newSpec.Interface())
|
||||
}
|
||||
180
pkg/util/kube/predicate_test.go
Normal file
180
pkg/util/kube/predicate_test.go
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
|
||||
velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
func TestSpecChangePredicate(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
oldObj client.Object
|
||||
newObj client.Object
|
||||
changed bool
|
||||
}{
|
||||
{
|
||||
name: "Contains no spec field",
|
||||
oldObj: &velerov1.BackupStorageLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bsl01",
|
||||
},
|
||||
},
|
||||
newObj: &velerov1.BackupStorageLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bsl01",
|
||||
},
|
||||
},
|
||||
changed: false,
|
||||
},
|
||||
{
|
||||
name: "ObjectMetas are different, Specs are same",
|
||||
oldObj: &velerov1.BackupStorageLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bsl01",
|
||||
Annotations: map[string]string{"key1": "value1"},
|
||||
},
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
},
|
||||
},
|
||||
newObj: &velerov1.BackupStorageLocation{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bsl01",
|
||||
Annotations: map[string]string{"key2": "value2"},
|
||||
},
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
},
|
||||
},
|
||||
changed: false,
|
||||
},
|
||||
{
|
||||
name: "Statuses are different, Specs are same",
|
||||
oldObj: &velerov1.BackupStorageLocation{
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
},
|
||||
Status: velerov1.BackupStorageLocationStatus{
|
||||
Phase: velerov1.BackupStorageLocationPhaseAvailable,
|
||||
},
|
||||
},
|
||||
newObj: &velerov1.BackupStorageLocation{
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
},
|
||||
Status: velerov1.BackupStorageLocationStatus{
|
||||
Phase: velerov1.BackupStorageLocationPhaseUnavailable,
|
||||
},
|
||||
},
|
||||
changed: false,
|
||||
},
|
||||
{
|
||||
name: "Specs are different",
|
||||
oldObj: &velerov1.BackupStorageLocation{
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
},
|
||||
},
|
||||
newObj: &velerov1.BackupStorageLocation{
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "aws",
|
||||
},
|
||||
},
|
||||
changed: true,
|
||||
},
|
||||
{
|
||||
name: "Specs are same",
|
||||
oldObj: &velerov1.BackupStorageLocation{
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
Config: map[string]string{"key": "value"},
|
||||
Credential: &corev1api.SecretKeySelector{
|
||||
LocalObjectReference: corev1api.LocalObjectReference{
|
||||
Name: "secret",
|
||||
},
|
||||
Key: "credential",
|
||||
},
|
||||
StorageType: velerov1.StorageType{
|
||||
ObjectStorage: &velerov1.ObjectStorageLocation{
|
||||
Bucket: "bucket1",
|
||||
Prefix: "prefix",
|
||||
CACert: []byte{'a'},
|
||||
},
|
||||
},
|
||||
Default: true,
|
||||
AccessMode: velerov1.BackupStorageLocationAccessModeReadWrite,
|
||||
BackupSyncPeriod: &metav1.Duration{
|
||||
Duration: 1 * time.Minute,
|
||||
},
|
||||
ValidationFrequency: &metav1.Duration{
|
||||
Duration: 1 * time.Minute,
|
||||
},
|
||||
},
|
||||
},
|
||||
newObj: &velerov1.BackupStorageLocation{
|
||||
Spec: velerov1.BackupStorageLocationSpec{
|
||||
Provider: "azure",
|
||||
Config: map[string]string{"key": "value"},
|
||||
Credential: &corev1api.SecretKeySelector{
|
||||
LocalObjectReference: corev1api.LocalObjectReference{
|
||||
Name: "secret",
|
||||
},
|
||||
Key: "credential",
|
||||
},
|
||||
StorageType: velerov1.StorageType{
|
||||
ObjectStorage: &velerov1.ObjectStorageLocation{
|
||||
Bucket: "bucket1",
|
||||
Prefix: "prefix",
|
||||
CACert: []byte{'a'},
|
||||
},
|
||||
},
|
||||
Default: true,
|
||||
AccessMode: velerov1.BackupStorageLocationAccessModeReadWrite,
|
||||
BackupSyncPeriod: &metav1.Duration{
|
||||
Duration: 1 * time.Minute,
|
||||
},
|
||||
ValidationFrequency: &metav1.Duration{
|
||||
Duration: 1 * time.Minute,
|
||||
},
|
||||
},
|
||||
},
|
||||
changed: false,
|
||||
},
|
||||
}
|
||||
|
||||
predicate := SpecChangePredicate{}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
changed := predicate.Update(event.UpdateEvent{
|
||||
ObjectOld: c.oldObj,
|
||||
ObjectNew: c.newObj,
|
||||
})
|
||||
assert.Equal(t, c.changed, changed)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -34,15 +34,20 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/util/filesystem"
|
||||
)
|
||||
|
||||
// These annotations are taken from the Kubernetes persistent volume/persistent volume claim controller.
|
||||
// They cannot be directly importing because they are part of the kubernetes/kubernetes package, and importing that package is unsupported.
|
||||
// Their values are well-known and slow changing. They're duplicated here as constants to provide compile-time checking.
|
||||
// Originals can be found in kubernetes/kubernetes/pkg/controller/volume/persistentvolume/util/util.go.
|
||||
const KubeAnnBindCompleted = "pv.kubernetes.io/bind-completed"
|
||||
const KubeAnnBoundByController = "pv.kubernetes.io/bound-by-controller"
|
||||
const KubeAnnDynamicallyProvisioned = "pv.kubernetes.io/provisioned-by"
|
||||
const (
|
||||
KubeAnnBindCompleted = "pv.kubernetes.io/bind-completed"
|
||||
KubeAnnBoundByController = "pv.kubernetes.io/bound-by-controller"
|
||||
KubeAnnDynamicallyProvisioned = "pv.kubernetes.io/provisioned-by"
|
||||
KubeAnnMigratedTo = "pv.kubernetes.io/migrated-to"
|
||||
)
|
||||
|
||||
// NamespaceAndName returns a string in the format <namespace>/<name>
|
||||
func NamespaceAndName(objMeta metav1.Object) string {
|
||||
@@ -118,9 +123,9 @@ func EnsureNamespaceExistsAndIsReady(namespace *corev1api.Namespace, client core
|
||||
func GetVolumeDirectory(ctx context.Context, log logrus.FieldLogger, pod *corev1api.Pod, volumeName string, cli client.Client) (string, error) {
|
||||
var volume *corev1api.Volume
|
||||
|
||||
for _, item := range pod.Spec.Volumes {
|
||||
for i, item := range pod.Spec.Volumes {
|
||||
if item.Name == volumeName {
|
||||
volume = &item
|
||||
volume = &pod.Spec.Volumes[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -163,6 +168,9 @@ func GetVolumeDirectory(ctx context.Context, log logrus.FieldLogger, pod *corev1
|
||||
return pvc.Spec.VolumeName, nil
|
||||
}
|
||||
|
||||
// isProvisionedByCSI function checks whether this is a CSI PV by annotation.
|
||||
// Either "pv.kubernetes.io/provisioned-by" or "pv.kubernetes.io/migrated-to" indicates
|
||||
// PV is provisioned by CSI.
|
||||
func isProvisionedByCSI(log logrus.FieldLogger, pv *corev1api.PersistentVolume, kbClient client.Client) (bool, error) {
|
||||
if pv.Spec.CSI != nil {
|
||||
return true, nil
|
||||
@@ -171,14 +179,15 @@ func isProvisionedByCSI(log logrus.FieldLogger, pv *corev1api.PersistentVolume,
|
||||
// Refer to https://github.com/vmware-tanzu/velero/issues/4496 for more details
|
||||
if pv.Annotations != nil {
|
||||
driverName := pv.Annotations[KubeAnnDynamicallyProvisioned]
|
||||
if len(driverName) > 0 {
|
||||
migratedDriver := pv.Annotations[KubeAnnMigratedTo]
|
||||
if len(driverName) > 0 || len(migratedDriver) > 0 {
|
||||
list := &storagev1api.CSIDriverList{}
|
||||
if err := kbClient.List(context.TODO(), list); err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, driver := range list.Items {
|
||||
if driverName == driver.Name {
|
||||
log.Debugf("the annotation %s=%s indicates the volume is provisioned by a CSI driver", KubeAnnDynamicallyProvisioned, driverName)
|
||||
if driverName == driver.Name || migratedDriver == driver.Name {
|
||||
log.Debugf("the annotation %s or %s equals to %s indicates the volume is provisioned by a CSI driver", KubeAnnDynamicallyProvisioned, KubeAnnMigratedTo, driverName)
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
@@ -187,6 +196,21 @@ func isProvisionedByCSI(log logrus.FieldLogger, pv *corev1api.PersistentVolume,
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// SinglePathMatch function will be called by PVB and PVR controller to check whether pass-in volume path is valid.
|
||||
// Check whether there is only one match by the path's pattern (/host_pods/%s/volumes/*/volume_name/[mount|]).
|
||||
func SinglePathMatch(path string, fs filesystem.Interface, log logrus.FieldLogger) (string, error) {
|
||||
matches, err := fs.Glob(path)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
if len(matches) != 1 {
|
||||
return "", errors.Errorf("expected one matching path: %s, got %d", path, len(matches))
|
||||
}
|
||||
|
||||
log.Debugf("This is a valid volume path: %s.", matches[0])
|
||||
return matches[0], nil
|
||||
}
|
||||
|
||||
// IsV1CRDReady checks a v1 CRD to see if it's ready, with both the Established and NamesAccepted conditions.
|
||||
func IsV1CRDReady(crd *apiextv1.CustomResourceDefinition) bool {
|
||||
var isEstablished, namesAccepted bool
|
||||
|
||||
@@ -197,6 +197,13 @@ func TestGetVolumeDirectorySuccess(t *testing.T) {
|
||||
pv: builder.ForPersistentVolume("a-pv").ObjectMeta(builder.WithAnnotations(KubeAnnDynamicallyProvisioned, "csi.test.com")).Result(),
|
||||
want: "a-pv/mount",
|
||||
},
|
||||
{
|
||||
name: "Volume with CSI annotation 'pv.kubernetes.io/migrated-to' appends '/mount' to the volume name",
|
||||
pod: builder.ForPod("ns-1", "my-pod").Volumes(builder.ForVolume("my-vol").PersistentVolumeClaimSource("my-pvc").Result()).Result(),
|
||||
pvc: builder.ForPersistentVolumeClaim("ns-1", "my-pvc").VolumeName("a-pv").Result(),
|
||||
pv: builder.ForPersistentVolume("a-pv").ObjectMeta(builder.WithAnnotations(KubeAnnMigratedTo, "csi.test.com")).Result(),
|
||||
want: "a-pv/mount",
|
||||
},
|
||||
}
|
||||
|
||||
csiDriver := storagev1api.CSIDriver{
|
||||
@@ -425,3 +432,13 @@ func TestIsCRDReady(t *testing.T) {
|
||||
_, err = IsCRDReady(obj)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestSinglePathMatch(t *testing.T) {
|
||||
fakeFS := velerotest.NewFakeFileSystem()
|
||||
fakeFS.MkdirAll("testDir1/subpath", 0755)
|
||||
fakeFS.MkdirAll("testDir2/subpath", 0755)
|
||||
|
||||
_, err := SinglePathMatch("./*/subpath", fakeFS, logrus.StandardLogger())
|
||||
assert.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), "expected one matching path")
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ metadata:
|
||||
namespace: velero
|
||||
# Parameters about the backup. Required.
|
||||
spec:
|
||||
# CSISnapshotTimeout specifies the time used to wait for
|
||||
# CSI VolumeSnapshot status turns to ReadyToUse during creation, before
|
||||
# returning error as timeout. The default value is 10 minute.
|
||||
csiSnapshotTimeout: 10m
|
||||
# Array of namespaces to include in the backup. If unspecified, all namespaces are included.
|
||||
# Optional.
|
||||
includedNamespaces:
|
||||
|
||||
@@ -34,6 +34,10 @@ spec:
|
||||
schedule: 0 7 * * *
|
||||
# Template is the spec that should be used for each backup triggered by this schedule.
|
||||
template:
|
||||
# CSISnapshotTimeout specifies the time used to wait for
|
||||
# CSI VolumeSnapshot status turns to ReadyToUse during creation, before
|
||||
# returning error as timeout. The default value is 10 minute.
|
||||
csiSnapshotTimeout: 10m
|
||||
# Array of namespaces to include in the scheduled backup. If unspecified, all namespaces are included.
|
||||
# Optional.
|
||||
includedNamespaces:
|
||||
|
||||
@@ -47,10 +47,10 @@ cd velero
|
||||
kubectl apply -f examples/nginx-app/with-pv.yaml
|
||||
```
|
||||
|
||||
1. Create a backup with PV snapshotting:
|
||||
1. Create a backup with PV snapshotting. `--csi-snapshot-timeout` is used to setup time to wait before CSI snapshot creation timeout. The default value is 10 minutes:
|
||||
|
||||
```bash
|
||||
velero backup create nginx-backup --include-namespaces nginx-example
|
||||
velero backup create nginx-backup --include-namespaces nginx-example --csi-snapshot-timeout=20m
|
||||
```
|
||||
|
||||
1. Simulate a disaster:
|
||||
|
||||
@@ -29,6 +29,11 @@ metadata:
|
||||
namespace: velero
|
||||
# Parameters about the backup. Required.
|
||||
spec:
|
||||
# Available since v1.9.1.
|
||||
# CSISnapshotTimeout specifies the time used to wait for
|
||||
# CSI VolumeSnapshot status turns to ReadyToUse during creation, before
|
||||
# returning error as timeout. The default value is 10 minute.
|
||||
csiSnapshotTimeout: 10m
|
||||
# Array of namespaces to include in the backup. If unspecified, all namespaces are included.
|
||||
# Optional.
|
||||
includedNamespaces:
|
||||
|
||||
@@ -34,6 +34,11 @@ spec:
|
||||
schedule: 0 7 * * *
|
||||
# Template is the spec that should be used for each backup triggered by this schedule.
|
||||
template:
|
||||
# Available since v1.9.1.
|
||||
# CSISnapshotTimeout specifies the time used to wait for
|
||||
# CSI VolumeSnapshot status turns to ReadyToUse during creation, before
|
||||
# returning error as timeout. The default value is 10 minute.
|
||||
csiSnapshotTimeout: 10m
|
||||
# Array of namespaces to include in the scheduled backup. If unspecified, all namespaces are included.
|
||||
# Optional.
|
||||
includedNamespaces:
|
||||
|
||||
@@ -88,7 +88,7 @@ DEBUG_E2E_TEST ?= false
|
||||
|
||||
.PHONY:ginkgo
|
||||
ginkgo: # Make sure ginkgo is in $GOPATH/bin
|
||||
go get github.com/onsi/ginkgo/ginkgo
|
||||
go install github.com/onsi/ginkgo/ginkgo@v1.16.5
|
||||
|
||||
.PHONY: run
|
||||
run: ginkgo
|
||||
|
||||
@@ -221,7 +221,7 @@ func BslDeletionTest(useVolumeSnapshots bool) {
|
||||
snapshotCheckPoint, err = GetSnapshotCheckPoint(client, VeleroCfg, 1, bslDeletionTestNs, backupName_1, []string{podName_1})
|
||||
Expect(err).NotTo(HaveOccurred(), "Fail to get Azure CSI snapshot checkpoint")
|
||||
Expect(SnapshotsShouldBeCreatedInCloud(VeleroCfg.CloudProvider,
|
||||
VeleroCfg.CloudCredentialsFile, VeleroCfg.AdditionalBSLBucket,
|
||||
VeleroCfg.CloudCredentialsFile, VeleroCfg.BSLBucket,
|
||||
VeleroCfg.BSLConfig, backupName_1, snapshotCheckPoint)).To(Succeed())
|
||||
})
|
||||
By(fmt.Sprintf("Snapshot of bsl %s should be created in cloud object store", backupLocation_2), func() {
|
||||
@@ -232,6 +232,8 @@ func BslDeletionTest(useVolumeSnapshots bool) {
|
||||
BSLCredentials = VeleroCfg.AdditionalBSLCredentials
|
||||
BSLConfig = VeleroCfg.AdditionalBSLConfig
|
||||
} else {
|
||||
// Snapshotting by non-vSphere provider using credentials
|
||||
// and config in default BSL
|
||||
BSLCredentials = VeleroCfg.CloudCredentialsFile
|
||||
BSLConfig = VeleroCfg.BSLConfig
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ var _ = Describe("[Schedule][OrederedResources] Backup resources should follow t
|
||||
func TestE2e(t *testing.T) {
|
||||
// Skip running E2E tests when running only "short" tests because:
|
||||
// 1. E2E tests are long running tests involving installation of Velero and performing backup and restore operations.
|
||||
// 2. E2E tests require a kubernetes cluster to install and run velero which further requires ore configuration. See above referenced command line flags.
|
||||
// 2. E2E tests require a kubernetes cluster to install and run velero which further requires more configuration. See above referenced command line flags.
|
||||
if testing.Short() {
|
||||
t.Skip("Skipping E2E tests")
|
||||
}
|
||||
|
||||
@@ -36,9 +36,9 @@ type ObjectsInStorage interface {
|
||||
|
||||
func ObjectsShouldBeInBucket(cloudProvider, cloudCredentialsFile, bslBucket, bslPrefix, bslConfig, backupName, subPrefix string) error {
|
||||
fmt.Printf("|| VERIFICATION || - %s %s should exist in storage [%s]\n", subPrefix, backupName, bslPrefix)
|
||||
exist, _ := IsObjectsInBucket(cloudProvider, cloudCredentialsFile, bslBucket, bslPrefix, bslConfig, backupName, subPrefix)
|
||||
exist, err := IsObjectsInBucket(cloudProvider, cloudCredentialsFile, bslBucket, bslPrefix, bslConfig, backupName, subPrefix)
|
||||
if !exist {
|
||||
return errors.New(fmt.Sprintf("|| UNEXPECTED ||Backup object %s is not exist in object store after backup as expected\n", backupName))
|
||||
return errors.Wrap(err, fmt.Sprintf("|| UNEXPECTED ||Backup object %s is not exist in object store after backup as expected\n", backupName))
|
||||
}
|
||||
fmt.Printf("|| EXPECTED || - Backup %s exist in object storage bucket %s\n", backupName, bslBucket)
|
||||
return nil
|
||||
|
||||
@@ -87,6 +87,13 @@ var pluginsMatrix = map[string]map[string][]string{
|
||||
"gcp": {"velero/velero-plugin-for-gcp:v1.4.0"},
|
||||
"azure-csi": {"velero/velero-plugin-for-microsoft-azure:v1.4.0", "velero/velero-plugin-for-csi:v0.2.0"},
|
||||
},
|
||||
"v1.9": {
|
||||
"aws": {"velero/velero-plugin-for-aws:v1.5.0"},
|
||||
"azure": {"velero/velero-plugin-for-microsoft-azure:v1.5.0"},
|
||||
"vsphere": {"velero/velero-plugin-for-aws:v1.5.0", "vsphereveleroplugin/velero-plugin-for-vsphere:v1.4.0"},
|
||||
"gcp": {"velero/velero-plugin-for-gcp:v1.5.0"},
|
||||
"azure-csi": {"velero/velero-plugin-for-microsoft-azure:v1.5.0", "velero/velero-plugin-for-csi:v0.3.0"},
|
||||
},
|
||||
"main": {
|
||||
"aws": {"velero/velero-plugin-for-aws:main"},
|
||||
"azure": {"velero/velero-plugin-for-microsoft-azure:main"},
|
||||
|
||||
Reference in New Issue
Block a user