mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-11 23:32:53 +00:00
Compare commits
22 Commits
dependabot
...
v1.6.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fe3a50bfd | ||
|
|
3743ca4d53 | ||
|
|
6feb84a1cc | ||
|
|
b090b27275 | ||
|
|
499631ba8e | ||
|
|
aa274e8c65 | ||
|
|
9e7daf7e37 | ||
|
|
e2581866bc | ||
|
|
037e475227 | ||
|
|
8c9cdb9603 | ||
|
|
a77702c885 | ||
|
|
1d882c6509 | ||
|
|
07060d7fea | ||
|
|
ef34b9b654 | ||
|
|
e22d6591e4 | ||
|
|
38493995ad | ||
|
|
74a0b39e3e | ||
|
|
a378d3a9d4 | ||
|
|
0f576fb748 | ||
|
|
119529c9a2 | ||
|
|
2c26119b10 | ||
|
|
cbccdbd05a |
3
.github/workflows/crds-verify-kind.yaml
vendored
3
.github/workflows/crds-verify-kind.yaml
vendored
@@ -58,6 +58,8 @@ jobs:
|
||||
- 1.18.15
|
||||
- 1.19.7
|
||||
- 1.20.2
|
||||
- 1.21.1
|
||||
- 1.22.0
|
||||
# All steps run in parallel unless otherwise specified.
|
||||
# See https://docs.github.com/en/actions/learn-github-actions/managing-complex-workflows#creating-dependent-jobs
|
||||
steps:
|
||||
@@ -75,6 +77,7 @@ jobs:
|
||||
velero-${{ github.event.pull_request.number }}-
|
||||
- uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
version: "v0.11.1"
|
||||
image: "kindest/node:v${{ matrix.k8s }}"
|
||||
- name: Install CRDs
|
||||
run: |
|
||||
|
||||
114
.github/workflows/e2e-test-kind.yaml
vendored
Normal file
114
.github/workflows/e2e-test-kind.yaml
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
name: "Run the E2E test on kind"
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
# Do not run when the change only includes these directories.
|
||||
paths-ignore:
|
||||
- "site/**"
|
||||
- "design/**"
|
||||
jobs:
|
||||
# Build the Velero CLI and image once for all Kubernetes versions, and cache it so the fan-out workers can get it.
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Look for a CLI that's made for this PR
|
||||
- name: Fetch built CLI
|
||||
id: cli-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ./_output/bin/linux/amd64/velero
|
||||
# The cache key a combination of the current PR number and the commit SHA
|
||||
key: velero-cli-${{ github.event.pull_request.number }}-${{ github.sha }}
|
||||
- name: Fetch built image
|
||||
id: image-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ./velero.tar
|
||||
# The cache key a combination of the current PR number and the commit SHA
|
||||
key: velero-image-${{ github.event.pull_request.number }}-${{ github.sha }}
|
||||
- name: Fetch cached go modules
|
||||
uses: actions/cache@v2
|
||||
if: steps.cli-cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v2
|
||||
if: steps.cli-cache.outputs.cache-hit != 'true' || steps.image-cache.outputs.cache-hit != 'true'
|
||||
# If no binaries were built for this PR, build it now.
|
||||
- name: Build Velero CLI
|
||||
if: steps.cli-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
make local
|
||||
# If no image were built for this PR, build it now.
|
||||
- name: Build Velero Image
|
||||
if: steps.image-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
IMAGE=velero VERSION=pr-test make container
|
||||
docker save velero:pr-test -o ./velero.tar
|
||||
# Run E2E test against all kubernetes versions on kind
|
||||
run-e2e-test:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
k8s:
|
||||
# doesn't cover 1.15 as 1.15 doesn't support "apiextensions.k8s.io/v1" that is needed for the case
|
||||
#- 1.15.12
|
||||
- 1.16.15
|
||||
- 1.17.17
|
||||
- 1.18.15
|
||||
- 1.19.7
|
||||
- 1.20.2
|
||||
- 1.21.1
|
||||
- 1.22.0
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install MinIO
|
||||
run:
|
||||
docker run -d --rm -p 9000:9000 -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -e "MINIO_DEFAULT_BUCKETS=bucket,additional-bucket" bitnami/minio:2021.6.17-debian-10-r7
|
||||
- uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
version: "v0.11.1"
|
||||
image: "kindest/node:v${{ matrix.k8s }}"
|
||||
- name: Fetch built CLI
|
||||
id: cli-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ./_output/bin/linux/amd64/velero
|
||||
key: velero-cli-${{ github.event.pull_request.number }}-${{ github.sha }}
|
||||
- name: Fetch built Image
|
||||
id: image-cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ./velero.tar
|
||||
key: velero-image-${{ github.event.pull_request.number }}-${{ github.sha }}
|
||||
- name: Load Velero Image
|
||||
run:
|
||||
kind load image-archive velero.tar
|
||||
# always try to fetch the cached go modules as the e2e test needs it either
|
||||
- name: Fetch cached go modules
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
- name: Run E2E test
|
||||
run: |
|
||||
cat << EOF > /tmp/credential
|
||||
[default]
|
||||
aws_access_key_id=minio
|
||||
aws_secret_access_key=minio123
|
||||
EOF
|
||||
GOPATH=~/go CLOUD_PROVIDER=kind \
|
||||
OBJECT_STORE_PROVIDER=aws BSL_CONFIG=region=minio,s3ForcePathStyle="true",s3Url=http://$(hostname -i):9000 \
|
||||
CREDS_FILE=/tmp/credential BSL_BUCKET=bucket \
|
||||
ADDITIONAL_OBJECT_STORE_PROVIDER=aws ADDITIONAL_BSL_CONFIG=region=minio,s3ForcePathStyle="true",s3Url=http://$(hostname -i):9000 \
|
||||
ADDITIONAL_CREDS_FILE=/tmp/credential ADDITIONAL_BSL_BUCKET=additional-bucket \
|
||||
GINKGO_FOCUS=Basic VELERO_IMAGE=velero:pr-test \
|
||||
make -C test/e2e run
|
||||
2
.github/workflows/pr-codespell.yml
vendored
2
.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/crds/crds.go
|
||||
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
|
||||
check_filenames: true
|
||||
check_hidden: true
|
||||
|
||||
@@ -41,7 +41,7 @@ builds:
|
||||
- goos: windows
|
||||
goarch: ppc64le
|
||||
ldflags:
|
||||
- -X "github.com/vmware-tanzu/velero/pkg/buildinfo.Version={{ .Tag }}" -X "github.com/vmware-tanzu/velero/pkg/buildinfo.GitSHA={{ .FullCommit }}" -X "github.com/vmware-tanzu/velero/pkg/buildinfo.GitTreeState={{ .Env.GIT_TREE_STATE }}"
|
||||
- -X "github.com/vmware-tanzu/velero/pkg/buildinfo.Version={{ .Tag }}" -X "github.com/vmware-tanzu/velero/pkg/buildinfo.GitSHA={{ .FullCommit }}" -X "github.com/vmware-tanzu/velero/pkg/buildinfo.GitTreeState={{ .Env.GIT_TREE_STATE }}" -X "github.com/vmware-tanzu/velero/pkg/buildinfo.ImageRegistry={{ .Env.REGISTRY }}"
|
||||
archives:
|
||||
- name_template: "{{ .ProjectName }}-{{ .Tag }}-{{ .Os }}-{{ .Arch }}"
|
||||
wrap_in_directory: true
|
||||
|
||||
@@ -18,11 +18,12 @@ ARG PKG
|
||||
ARG VERSION
|
||||
ARG GIT_SHA
|
||||
ARG GIT_TREE_STATE
|
||||
ARG REGISTRY
|
||||
|
||||
ENV CGO_ENABLED=0 \
|
||||
GO111MODULE=on \
|
||||
GOPROXY=${GOPROXY} \
|
||||
LDFLAGS="-X ${PKG}/pkg/buildinfo.Version=${VERSION} -X ${PKG}/pkg/buildinfo.GitSHA=${GIT_SHA} -X ${PKG}/pkg/buildinfo.GitTreeState=${GIT_TREE_STATE}"
|
||||
LDFLAGS="-X ${PKG}/pkg/buildinfo.Version=${VERSION} -X ${PKG}/pkg/buildinfo.GitSHA=${GIT_SHA} -X ${PKG}/pkg/buildinfo.GitTreeState=${GIT_TREE_STATE} -X ${PKG}/pkg/buildinfo.ImageRegistry=${REGISTRY}"
|
||||
|
||||
WORKDIR /go/src/github.com/vmware-tanzu/velero
|
||||
|
||||
|
||||
6
Makefile
6
Makefile
@@ -110,7 +110,6 @@ GOPROXY ?= https://proxy.golang.org
|
||||
|
||||
# If you want to build all binaries, see the 'all-build' rule.
|
||||
# If you want to build all containers, see the 'all-containers' rule.
|
||||
# If you want to build AND push all containers, see the 'all-push' rule.
|
||||
all:
|
||||
@$(MAKE) build
|
||||
@$(MAKE) build BIN=velero-restic-restore-helper
|
||||
@@ -129,6 +128,7 @@ local: build-dirs
|
||||
GOOS=$(GOOS) \
|
||||
GOARCH=$(GOARCH) \
|
||||
VERSION=$(VERSION) \
|
||||
REGISTRY=$(REGISTRY) \
|
||||
PKG=$(PKG) \
|
||||
BIN=$(BIN) \
|
||||
GIT_SHA=$(GIT_SHA) \
|
||||
@@ -144,6 +144,7 @@ _output/bin/$(GOOS)/$(GOARCH)/$(BIN): build-dirs
|
||||
GOOS=$(GOOS) \
|
||||
GOARCH=$(GOARCH) \
|
||||
VERSION=$(VERSION) \
|
||||
REGISTRY=$(REGISTRY) \
|
||||
PKG=$(PKG) \
|
||||
BIN=$(BIN) \
|
||||
GIT_SHA=$(GIT_SHA) \
|
||||
@@ -186,6 +187,7 @@ endif
|
||||
--build-arg=VERSION=$(VERSION) \
|
||||
--build-arg=GIT_SHA=$(GIT_SHA) \
|
||||
--build-arg=GIT_TREE_STATE=$(GIT_TREE_STATE) \
|
||||
--build-arg=REGISTRY=$(REGISTRY) \
|
||||
-f $(VELERO_DOCKERFILE) .
|
||||
|
||||
container:
|
||||
@@ -201,6 +203,7 @@ endif
|
||||
--build-arg=VERSION=$(VERSION) \
|
||||
--build-arg=GIT_SHA=$(GIT_SHA) \
|
||||
--build-arg=GIT_TREE_STATE=$(GIT_TREE_STATE) \
|
||||
--build-arg=REGISTRY=$(REGISTRY) \
|
||||
--build-arg=RESTIC_VERSION=$(RESTIC_VERSION) \
|
||||
-f $(VELERO_DOCKERFILE) .
|
||||
@echo "container: $(IMAGE):$(VERSION)"
|
||||
@@ -346,6 +349,7 @@ release:
|
||||
GITHUB_TOKEN=$(GITHUB_TOKEN) \
|
||||
RELEASE_NOTES_FILE=$(RELEASE_NOTES_FILE) \
|
||||
PUBLISH=$(PUBLISH) \
|
||||
REGISTRY=$(REGISTRY) \
|
||||
./hack/release-tools/goreleaser.sh'"
|
||||
|
||||
serve-docs: build-image-hugo
|
||||
|
||||
22
Tiltfile
22
Tiltfile
@@ -1,17 +1,17 @@
|
||||
# -*- mode: Python -*-
|
||||
|
||||
k8s_yaml([
|
||||
'config/crd/bases/velero.io_backups.yaml',
|
||||
'config/crd/bases/velero.io_backupstoragelocations.yaml',
|
||||
'config/crd/bases/velero.io_deletebackuprequests.yaml',
|
||||
'config/crd/bases/velero.io_downloadrequests.yaml',
|
||||
'config/crd/bases/velero.io_podvolumebackups.yaml',
|
||||
'config/crd/bases/velero.io_podvolumerestores.yaml',
|
||||
'config/crd/bases/velero.io_resticrepositories.yaml',
|
||||
'config/crd/bases/velero.io_restores.yaml',
|
||||
'config/crd/bases/velero.io_schedules.yaml',
|
||||
'config/crd/bases/velero.io_serverstatusrequests.yaml',
|
||||
'config/crd/bases/velero.io_volumesnapshotlocations.yaml',
|
||||
'config/crd/v1/bases/velero.io_backups.yaml',
|
||||
'config/crd/v1/bases/velero.io_backupstoragelocations.yaml',
|
||||
'config/crd/v1/bases/velero.io_deletebackuprequests.yaml',
|
||||
'config/crd/v1/bases/velero.io_downloadrequests.yaml',
|
||||
'config/crd/v1/bases/velero.io_podvolumebackups.yaml',
|
||||
'config/crd/v1/bases/velero.io_podvolumerestores.yaml',
|
||||
'config/crd/v1/bases/velero.io_resticrepositories.yaml',
|
||||
'config/crd/v1/bases/velero.io_restores.yaml',
|
||||
'config/crd/v1/bases/velero.io_schedules.yaml',
|
||||
'config/crd/v1/bases/velero.io_serverstatusrequests.yaml',
|
||||
'config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml',
|
||||
])
|
||||
|
||||
# default values
|
||||
|
||||
@@ -1,3 +1,80 @@
|
||||
## v1.6.3
|
||||
### 2021-07-30
|
||||
|
||||
### Download
|
||||
https://github.com/vmware-tanzu/velero/releases/tag/v1.6.3
|
||||
|
||||
### Container Image
|
||||
`velero/velero:v1.6.3`
|
||||
|
||||
### Documentation
|
||||
https://velero.io/docs/v1.6/
|
||||
|
||||
### Upgrading
|
||||
https://velero.io/docs/v1.6/upgrade-to-1.6/
|
||||
|
||||
### Highlights
|
||||
|
||||
This release introduces changes to provide compatibility with Kubernetes v1.22.
|
||||
|
||||
The `apiextensions.k8s.io/v1beta1` API version of `CustomResourceDefinition` will no longer be served in Kubernetes v1.22.
|
||||
Velero will now use the cluster preferred API version for the `CustomResourceDefinition`s that it creates.
|
||||
|
||||
If you are using Kubernetes v1.15 or earlier, the `apiextensions.k8s.io/v1beta1` API version will be used.
|
||||
If you are using Kubernetes v1.22 or later, the `apiextensions.k8s.io/v1` API version will be used.
|
||||
For clusters between these versions, the cluster preferred API version will be used.
|
||||
|
||||
The `rbac.authorization.k8s.io/v1beta1` API version of `ClusterRoleBinding` will no longer be served in Kubernetes v1.22.
|
||||
Velero will now use the `rbac.authorization.k8s.io/v1` API version for the `ClusterRoleBinding`s that it creates.
|
||||
This API version was introduced in Kubernetes v1.8.
|
||||
|
||||
### All Changes
|
||||
|
||||
* enable e2e tests to choose crd apiVersion (#3941, @sseago)
|
||||
* Upgrade Velero ClusterRoleBinding to use v1 API (#3995, @jenting)
|
||||
* Install Kubernetes preferred CRDs API version (v1beta1/v1). (#3999, @jenting)
|
||||
* Use the cluster preferred CRD API version when polling for Velero CRD readiness. (#4015, @zubron)
|
||||
* Add a RestoreItemAction plugin (`velero.io/apiservice`) which skips the restore of any `APIService` which is managed by Kubernetes. These are identified using the `kube-aggregator.kubernetes.io/automanaged` label. (#4028, @zubron)
|
||||
|
||||
## v1.6.2
|
||||
### 2021-07-16
|
||||
|
||||
### Download
|
||||
https://github.com/vmware-tanzu/velero/releases/tag/v1.6.2
|
||||
|
||||
### Container Image
|
||||
`velero/velero:v1.6.2`
|
||||
|
||||
### Documentation
|
||||
https://velero.io/docs/v1.6/
|
||||
|
||||
### Upgrading
|
||||
https://velero.io/docs/v1.6/upgrade-to-1.6/
|
||||
|
||||
This release contains no user facing changes but includes fixes for CVE-2021-3121 and CVE-2021-3580.
|
||||
|
||||
## v1.6.1
|
||||
### 2021-06-21
|
||||
|
||||
### Download
|
||||
https://github.com/vmware-tanzu/velero/releases/tag/v1.6.1
|
||||
|
||||
### Container Image
|
||||
`velero/velero:v1.6.1`
|
||||
|
||||
### Documentation
|
||||
https://velero.io/docs/v1.6/
|
||||
|
||||
### Upgrading
|
||||
https://velero.io/docs/v1.6/upgrade-to-1.6/
|
||||
|
||||
### All Changes
|
||||
|
||||
* Fix CR restore regression introduced in 1.6 restore progress. (#3845, @sseago)
|
||||
* Skip the restore of volumes that originally came from a projected volume when using restic. (#3877, @zubron)
|
||||
* skip backuping projected volume when using restic (#3866, @alaypatel07)
|
||||
* 🐛 Fix plugin name derivation from image name (#3711, @ashish-amarnath)
|
||||
|
||||
## v1.6.0
|
||||
### 2021-04-12
|
||||
|
||||
|
||||
433
config/crd/v1/bases/velero.io_backups.yaml
Normal file
433
config/crd/v1/bases/velero.io_backups.yaml
Normal file
@@ -0,0 +1,433 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: backups.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: Backup
|
||||
listKind: BackupList
|
||||
plural: backups
|
||||
singular: backup
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Backup is a Velero resource that represents the capture of Kubernetes
|
||||
cluster state at a point in time (API objects and associated volume state).
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: BackupSpec defines the specification for a Velero backup.
|
||||
properties:
|
||||
defaultVolumesToRestic:
|
||||
description: DefaultVolumesToRestic specifies whether restic should
|
||||
be used to take a backup of all pod volumes by default.
|
||||
type: boolean
|
||||
excludedNamespaces:
|
||||
description: ExcludedNamespaces contains a list of namespaces that
|
||||
are not included in the backup.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
excludedResources:
|
||||
description: ExcludedResources is a slice of resource names that are
|
||||
not included in the backup.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
hooks:
|
||||
description: Hooks represent custom behaviors that should be executed
|
||||
at different phases of the backup.
|
||||
properties:
|
||||
resources:
|
||||
description: Resources are hooks that should be executed when
|
||||
backing up individual instances of a resource.
|
||||
items:
|
||||
description: BackupResourceHookSpec defines one or more BackupResourceHooks
|
||||
that should be executed based on the rules defined for namespaces,
|
||||
resources, and label selector.
|
||||
properties:
|
||||
excludedNamespaces:
|
||||
description: ExcludedNamespaces specifies the namespaces
|
||||
to which this hook spec does not apply.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
excludedResources:
|
||||
description: ExcludedResources specifies the resources to
|
||||
which this hook spec does not apply.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
includedNamespaces:
|
||||
description: IncludedNamespaces specifies the namespaces
|
||||
to which this hook spec applies. If empty, it applies
|
||||
to all namespaces.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
includedResources:
|
||||
description: IncludedResources specifies the resources to
|
||||
which this hook spec applies. If empty, it applies to
|
||||
all resources.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
labelSelector:
|
||||
description: LabelSelector, if specified, filters the resources
|
||||
to which this hook spec applies.
|
||||
nullable: true
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector
|
||||
requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a selector
|
||||
that contains values, a key, and an operator that
|
||||
relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector
|
||||
applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are In,
|
||||
NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values.
|
||||
If the operator is In or NotIn, the values array
|
||||
must be non-empty. If the operator is Exists
|
||||
or DoesNotExist, the values array must be empty.
|
||||
This array is replaced during a strategic merge
|
||||
patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value} pairs.
|
||||
A single {key,value} in the matchLabels map is equivalent
|
||||
to an element of matchExpressions, whose key field
|
||||
is "key", the operator is "In", and the values array
|
||||
contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
name:
|
||||
description: Name is the name of this hook.
|
||||
type: string
|
||||
post:
|
||||
description: PostHooks is a list of BackupResourceHooks
|
||||
to execute after storing the item in the backup. These
|
||||
are executed after all "additional items" from item actions
|
||||
are processed.
|
||||
items:
|
||||
description: BackupResourceHook defines a hook for a resource.
|
||||
properties:
|
||||
exec:
|
||||
description: Exec defines an exec hook.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command and arguments
|
||||
to execute.
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
container:
|
||||
description: Container is the container in the
|
||||
pod where the command should be executed. If
|
||||
not specified, the pod's first container is
|
||||
used.
|
||||
type: string
|
||||
onError:
|
||||
description: OnError specifies how Velero should
|
||||
behave if it encounters an error executing this
|
||||
hook.
|
||||
enum:
|
||||
- Continue
|
||||
- Fail
|
||||
type: string
|
||||
timeout:
|
||||
description: Timeout defines the maximum amount
|
||||
of time Velero should wait for the hook to complete
|
||||
before considering the execution a failure.
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
required:
|
||||
- exec
|
||||
type: object
|
||||
type: array
|
||||
pre:
|
||||
description: PreHooks is a list of BackupResourceHooks to
|
||||
execute prior to storing the item in the backup. These
|
||||
are executed before any "additional items" from item actions
|
||||
are processed.
|
||||
items:
|
||||
description: BackupResourceHook defines a hook for a resource.
|
||||
properties:
|
||||
exec:
|
||||
description: Exec defines an exec hook.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command and arguments
|
||||
to execute.
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
container:
|
||||
description: Container is the container in the
|
||||
pod where the command should be executed. If
|
||||
not specified, the pod's first container is
|
||||
used.
|
||||
type: string
|
||||
onError:
|
||||
description: OnError specifies how Velero should
|
||||
behave if it encounters an error executing this
|
||||
hook.
|
||||
enum:
|
||||
- Continue
|
||||
- Fail
|
||||
type: string
|
||||
timeout:
|
||||
description: Timeout defines the maximum amount
|
||||
of time Velero should wait for the hook to complete
|
||||
before considering the execution a failure.
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
required:
|
||||
- exec
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
includeClusterResources:
|
||||
description: IncludeClusterResources specifies whether cluster-scoped
|
||||
resources should be included for consideration in the backup.
|
||||
nullable: true
|
||||
type: boolean
|
||||
includedNamespaces:
|
||||
description: IncludedNamespaces is a slice of namespace names to include
|
||||
objects from. If empty, all namespaces are included.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
includedResources:
|
||||
description: IncludedResources is a slice of resource names to include
|
||||
in the backup. If empty, all resources are included.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
labelSelector:
|
||||
description: LabelSelector is a metav1.LabelSelector to filter with
|
||||
when adding individual objects to the backup. If empty or nil, all
|
||||
objects are included. Optional.
|
||||
nullable: true
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector requirements.
|
||||
The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a selector that
|
||||
contains values, a key, and an operator that relates the key
|
||||
and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector applies
|
||||
to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship to
|
||||
a set of values. Valid operators are In, NotIn, Exists
|
||||
and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values. If the
|
||||
operator is In or NotIn, the values array must be non-empty.
|
||||
If the operator is Exists or DoesNotExist, the values
|
||||
array must be empty. This array is replaced during a strategic
|
||||
merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value} pairs. A single
|
||||
{key,value} in the matchLabels map is equivalent to an element
|
||||
of matchExpressions, whose key field is "key", the operator
|
||||
is "In", and the values array contains only "value". The requirements
|
||||
are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
orderedResources:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: OrderedResources specifies the backup order of resources
|
||||
of specific Kind. The map key is the Kind name and value is a list
|
||||
of resource names separated by commas. Each resource name has format
|
||||
"namespace/resourcename". For cluster resources, simply use "resourcename".
|
||||
nullable: true
|
||||
type: object
|
||||
snapshotVolumes:
|
||||
description: SnapshotVolumes specifies whether to take cloud snapshots
|
||||
of any PV's referenced in the set of objects included in the Backup.
|
||||
nullable: true
|
||||
type: boolean
|
||||
storageLocation:
|
||||
description: StorageLocation is a string containing the name of a
|
||||
BackupStorageLocation where the backup should be stored.
|
||||
type: string
|
||||
ttl:
|
||||
description: TTL is a time.Duration-parseable string describing how
|
||||
long the Backup should be retained for.
|
||||
type: string
|
||||
volumeSnapshotLocations:
|
||||
description: VolumeSnapshotLocations is a list containing names of
|
||||
VolumeSnapshotLocations associated with this backup.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
status:
|
||||
description: BackupStatus captures the current status of a Velero backup.
|
||||
properties:
|
||||
completionTimestamp:
|
||||
description: CompletionTimestamp records the time a backup was completed.
|
||||
Completion time is recorded even on failed backups. Completion time
|
||||
is recorded before uploading the backup object. The server's time
|
||||
is used for CompletionTimestamps
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
errors:
|
||||
description: Errors is a count of all error messages that were generated
|
||||
during execution of the backup. The actual errors are in the backup's
|
||||
log file in object storage.
|
||||
type: integer
|
||||
expiration:
|
||||
description: Expiration is when this Backup is eligible for garbage-collection.
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
formatVersion:
|
||||
description: FormatVersion is the backup format version, including
|
||||
major, minor, and patch version.
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current state of the Backup.
|
||||
enum:
|
||||
- New
|
||||
- FailedValidation
|
||||
- InProgress
|
||||
- Completed
|
||||
- PartiallyFailed
|
||||
- Failed
|
||||
- Deleting
|
||||
type: string
|
||||
progress:
|
||||
description: Progress contains information about the backup's execution
|
||||
progress. Note that this information is best-effort only -- if Velero
|
||||
fails to update it during a backup for any reason, it may be inaccurate/stale.
|
||||
nullable: true
|
||||
properties:
|
||||
itemsBackedUp:
|
||||
description: ItemsBackedUp is the number of items that have actually
|
||||
been written to the backup tarball so far.
|
||||
type: integer
|
||||
totalItems:
|
||||
description: TotalItems is the total number of items to be backed
|
||||
up. This number may change throughout the execution of the backup
|
||||
due to plugins that return additional related items to back
|
||||
up, the velero.io/exclude-from-backup label, and various other
|
||||
filters that happen as items are processed.
|
||||
type: integer
|
||||
type: object
|
||||
startTimestamp:
|
||||
description: StartTimestamp records the time a backup was started.
|
||||
Separate from CreationTimestamp, since that value changes on restores.
|
||||
The server's time is used for StartTimestamps
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
validationErrors:
|
||||
description: ValidationErrors is a slice of all validation errors
|
||||
(if applicable).
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
version:
|
||||
description: 'Version is the backup format major version. Deprecated:
|
||||
Please see FormatVersion'
|
||||
type: integer
|
||||
volumeSnapshotsAttempted:
|
||||
description: VolumeSnapshotsAttempted is the total number of attempted
|
||||
volume snapshots for this backup.
|
||||
type: integer
|
||||
volumeSnapshotsCompleted:
|
||||
description: VolumeSnapshotsCompleted is the total number of successfully
|
||||
completed volume snapshots for this backup.
|
||||
type: integer
|
||||
warnings:
|
||||
description: Warnings is a count of all warning messages that were
|
||||
generated during execution of the backup. The actual warnings are
|
||||
in the backup's log file in object storage.
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
178
config/crd/v1/bases/velero.io_backupstoragelocations.yaml
Normal file
178
config/crd/v1/bases/velero.io_backupstoragelocations.yaml
Normal file
@@ -0,0 +1,178 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: backupstoragelocations.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: BackupStorageLocation
|
||||
listKind: BackupStorageLocationList
|
||||
plural: backupstoragelocations
|
||||
shortNames:
|
||||
- bsl
|
||||
singular: backupstoragelocation
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- description: Backup Storage Location status such as Available/Unavailable
|
||||
jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
- description: LastValidationTime is the last time the backup store location was
|
||||
validated
|
||||
jsonPath: .status.lastValidationTime
|
||||
name: Last Validated
|
||||
type: date
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
- description: Default backup storage location
|
||||
jsonPath: .spec.default
|
||||
name: Default
|
||||
type: boolean
|
||||
name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: BackupStorageLocation is a location where Velero stores backup
|
||||
objects
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: BackupStorageLocationSpec defines the desired state of a
|
||||
Velero BackupStorageLocation
|
||||
properties:
|
||||
accessMode:
|
||||
description: AccessMode defines the permissions for the backup storage
|
||||
location.
|
||||
enum:
|
||||
- ReadOnly
|
||||
- ReadWrite
|
||||
type: string
|
||||
backupSyncPeriod:
|
||||
description: BackupSyncPeriod defines how frequently to sync backup
|
||||
API objects from object storage. A value of 0 disables sync.
|
||||
nullable: true
|
||||
type: string
|
||||
config:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Config is for provider-specific configuration fields.
|
||||
type: object
|
||||
credential:
|
||||
description: Credential contains the credential information intended
|
||||
to be used with this location
|
||||
properties:
|
||||
key:
|
||||
description: The key of the secret to select from. Must be a
|
||||
valid secret key.
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
TODO: Add other useful fields. apiVersion, kind, uid?'
|
||||
type: string
|
||||
optional:
|
||||
description: Specify whether the Secret or its key must be defined
|
||||
type: boolean
|
||||
required:
|
||||
- key
|
||||
type: object
|
||||
default:
|
||||
description: Default indicates this location is the default backup
|
||||
storage location.
|
||||
type: boolean
|
||||
objectStorage:
|
||||
description: ObjectStorageLocation specifies the settings necessary
|
||||
to connect to a provider's object storage.
|
||||
properties:
|
||||
bucket:
|
||||
description: Bucket is the bucket to use for object storage.
|
||||
type: string
|
||||
caCert:
|
||||
description: CACert defines a CA bundle to use when verifying
|
||||
TLS connections to the provider.
|
||||
format: byte
|
||||
type: string
|
||||
prefix:
|
||||
description: Prefix is the path inside a bucket to use for Velero
|
||||
storage. Optional.
|
||||
type: string
|
||||
required:
|
||||
- bucket
|
||||
type: object
|
||||
provider:
|
||||
description: Provider is the provider of the backup storage.
|
||||
type: string
|
||||
validationFrequency:
|
||||
description: ValidationFrequency defines how frequently to validate
|
||||
the corresponding object storage. A value of 0 disables validation.
|
||||
nullable: true
|
||||
type: string
|
||||
required:
|
||||
- objectStorage
|
||||
- provider
|
||||
type: object
|
||||
status:
|
||||
description: BackupStorageLocationStatus defines the observed state of
|
||||
BackupStorageLocation
|
||||
properties:
|
||||
accessMode:
|
||||
description: "AccessMode is an unused field. \n Deprecated: there
|
||||
is now an AccessMode field on the Spec and this field will be removed
|
||||
entirely as of v2.0."
|
||||
enum:
|
||||
- ReadOnly
|
||||
- ReadWrite
|
||||
type: string
|
||||
lastSyncedRevision:
|
||||
description: "LastSyncedRevision is the value of the `metadata/revision`
|
||||
file in the backup storage location the last time the BSL's contents
|
||||
were synced into the cluster. \n Deprecated: this field is no longer
|
||||
updated or used for detecting changes to the location's contents
|
||||
and will be removed entirely in v2.0."
|
||||
type: string
|
||||
lastSyncedTime:
|
||||
description: LastSyncedTime is the last time the contents of the location
|
||||
were synced into the cluster.
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
lastValidationTime:
|
||||
description: LastValidationTime is the last time the backup store
|
||||
location was validated the cluster.
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current state of the BackupStorageLocation.
|
||||
enum:
|
||||
- Available
|
||||
- Unavailable
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
71
config/crd/v1/bases/velero.io_deletebackuprequests.yaml
Normal file
71
config/crd/v1/bases/velero.io_deletebackuprequests.yaml
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: deletebackuprequests.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: DeleteBackupRequest
|
||||
listKind: DeleteBackupRequestList
|
||||
plural: deletebackuprequests
|
||||
singular: deletebackuprequest
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: DeleteBackupRequest is a request to delete one or more backups.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: DeleteBackupRequestSpec is the specification for which backups
|
||||
to delete.
|
||||
properties:
|
||||
backupName:
|
||||
type: string
|
||||
required:
|
||||
- backupName
|
||||
type: object
|
||||
status:
|
||||
description: DeleteBackupRequestStatus is the current status of a DeleteBackupRequest.
|
||||
properties:
|
||||
errors:
|
||||
description: Errors contains any errors that were encountered during
|
||||
the deletion process.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
phase:
|
||||
description: Phase is the current state of the DeleteBackupRequest.
|
||||
enum:
|
||||
- New
|
||||
- InProgress
|
||||
- Processed
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
94
config/crd/v1/bases/velero.io_downloadrequests.yaml
Normal file
94
config/crd/v1/bases/velero.io_downloadrequests.yaml
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: downloadrequests.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: DownloadRequest
|
||||
listKind: DownloadRequestList
|
||||
plural: downloadrequests
|
||||
singular: downloadrequest
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: DownloadRequest is a request to download an artifact from backup
|
||||
object storage, such as a backup log file.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: DownloadRequestSpec is the specification for a download request.
|
||||
properties:
|
||||
target:
|
||||
description: Target is what to download (e.g. logs for a backup).
|
||||
properties:
|
||||
kind:
|
||||
description: Kind is the type of file to download.
|
||||
enum:
|
||||
- BackupLog
|
||||
- BackupContents
|
||||
- BackupVolumeSnapshots
|
||||
- BackupResourceList
|
||||
- RestoreLog
|
||||
- RestoreResults
|
||||
type: string
|
||||
name:
|
||||
description: Name is the name of the kubernetes resource with
|
||||
which the file is associated.
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
required:
|
||||
- target
|
||||
type: object
|
||||
status:
|
||||
description: DownloadRequestStatus is the current status of a DownloadRequest.
|
||||
properties:
|
||||
downloadURL:
|
||||
description: DownloadURL contains the pre-signed URL for the target
|
||||
file.
|
||||
type: string
|
||||
expiration:
|
||||
description: Expiration is when this DownloadRequest expires and can
|
||||
be deleted by the system.
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current state of the DownloadRequest.
|
||||
enum:
|
||||
- New
|
||||
- Processed
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
161
config/crd/v1/bases/velero.io_podvolumebackups.yaml
Normal file
161
config/crd/v1/bases/velero.io_podvolumebackups.yaml
Normal file
@@ -0,0 +1,161 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: podvolumebackups.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: PodVolumeBackup
|
||||
listKind: PodVolumeBackupList
|
||||
plural: podvolumebackups
|
||||
singular: podvolumebackup
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: PodVolumeBackupSpec is the specification for a PodVolumeBackup.
|
||||
properties:
|
||||
backupStorageLocation:
|
||||
description: BackupStorageLocation is the name of the backup storage
|
||||
location where the restic repository is stored.
|
||||
type: string
|
||||
node:
|
||||
description: Node is the name of the node that the Pod is running
|
||||
on.
|
||||
type: string
|
||||
pod:
|
||||
description: Pod is a reference to the pod containing the volume to
|
||||
be backed up.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
type: string
|
||||
fieldPath:
|
||||
description: 'If referring to a piece of an object instead of
|
||||
an entire object, this string should contain a valid JSON/Go
|
||||
field access statement, such as desiredState.manifest.containers[2].
|
||||
For example, if the object reference is to a container within
|
||||
a pod, this would take on a value like: "spec.containers{name}"
|
||||
(where "name" refers to the name of the container that triggered
|
||||
the event) or if no container name is specified "spec.containers[2]"
|
||||
(container with index 2 in this pod). This syntax is chosen
|
||||
only to have some well-defined way of referencing a part of
|
||||
an object. TODO: this design is not final and this field is
|
||||
subject to change in the future.'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
|
||||
type: string
|
||||
namespace:
|
||||
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
|
||||
type: string
|
||||
resourceVersion:
|
||||
description: 'Specific resourceVersion to which this reference
|
||||
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
||||
type: string
|
||||
uid:
|
||||
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
|
||||
type: string
|
||||
type: object
|
||||
repoIdentifier:
|
||||
description: RepoIdentifier is the restic repository identifier.
|
||||
type: string
|
||||
tags:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Tags are a map of key-value pairs that should be applied
|
||||
to the volume backup as tags.
|
||||
type: object
|
||||
volume:
|
||||
description: Volume is the name of the volume within the Pod to be
|
||||
backed up.
|
||||
type: string
|
||||
required:
|
||||
- backupStorageLocation
|
||||
- node
|
||||
- pod
|
||||
- repoIdentifier
|
||||
- volume
|
||||
type: object
|
||||
status:
|
||||
description: PodVolumeBackupStatus is the current status of a PodVolumeBackup.
|
||||
properties:
|
||||
completionTimestamp:
|
||||
description: CompletionTimestamp records the time a backup was completed.
|
||||
Completion time is recorded even on failed backups. Completion time
|
||||
is recorded before uploading the backup object. The server's time
|
||||
is used for CompletionTimestamps
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
message:
|
||||
description: Message is a message about the pod volume backup's status.
|
||||
type: string
|
||||
path:
|
||||
description: Path is the full path within the controller pod being
|
||||
backed up.
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current state of the PodVolumeBackup.
|
||||
enum:
|
||||
- New
|
||||
- InProgress
|
||||
- Completed
|
||||
- Failed
|
||||
type: string
|
||||
progress:
|
||||
description: Progress holds the total number of bytes of the volume
|
||||
and the current number of backed up bytes. This can be used to display
|
||||
progress information about the backup operation.
|
||||
properties:
|
||||
bytesDone:
|
||||
format: int64
|
||||
type: integer
|
||||
totalBytes:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
snapshotID:
|
||||
description: SnapshotID is the identifier for the snapshot of the
|
||||
pod volume.
|
||||
type: string
|
||||
startTimestamp:
|
||||
description: StartTimestamp records the time a backup was started.
|
||||
Separate from CreationTimestamp, since that value changes on restores.
|
||||
The server's time is used for StartTimestamps
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
144
config/crd/v1/bases/velero.io_podvolumerestores.yaml
Normal file
144
config/crd/v1/bases/velero.io_podvolumerestores.yaml
Normal file
@@ -0,0 +1,144 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: podvolumerestores.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: PodVolumeRestore
|
||||
listKind: PodVolumeRestoreList
|
||||
plural: podvolumerestores
|
||||
singular: podvolumerestore
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: PodVolumeRestoreSpec is the specification for a PodVolumeRestore.
|
||||
properties:
|
||||
backupStorageLocation:
|
||||
description: BackupStorageLocation is the name of the backup storage
|
||||
location where the restic repository is stored.
|
||||
type: string
|
||||
pod:
|
||||
description: Pod is a reference to the pod containing the volume to
|
||||
be restored.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
type: string
|
||||
fieldPath:
|
||||
description: 'If referring to a piece of an object instead of
|
||||
an entire object, this string should contain a valid JSON/Go
|
||||
field access statement, such as desiredState.manifest.containers[2].
|
||||
For example, if the object reference is to a container within
|
||||
a pod, this would take on a value like: "spec.containers{name}"
|
||||
(where "name" refers to the name of the container that triggered
|
||||
the event) or if no container name is specified "spec.containers[2]"
|
||||
(container with index 2 in this pod). This syntax is chosen
|
||||
only to have some well-defined way of referencing a part of
|
||||
an object. TODO: this design is not final and this field is
|
||||
subject to change in the future.'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
|
||||
type: string
|
||||
namespace:
|
||||
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
|
||||
type: string
|
||||
resourceVersion:
|
||||
description: 'Specific resourceVersion to which this reference
|
||||
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
||||
type: string
|
||||
uid:
|
||||
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
|
||||
type: string
|
||||
type: object
|
||||
repoIdentifier:
|
||||
description: RepoIdentifier is the restic repository identifier.
|
||||
type: string
|
||||
snapshotID:
|
||||
description: SnapshotID is the ID of the volume snapshot to be restored.
|
||||
type: string
|
||||
volume:
|
||||
description: Volume is the name of the volume within the Pod to be
|
||||
restored.
|
||||
type: string
|
||||
required:
|
||||
- backupStorageLocation
|
||||
- pod
|
||||
- repoIdentifier
|
||||
- snapshotID
|
||||
- volume
|
||||
type: object
|
||||
status:
|
||||
description: PodVolumeRestoreStatus is the current status of a PodVolumeRestore.
|
||||
properties:
|
||||
completionTimestamp:
|
||||
description: CompletionTimestamp records the time a restore was completed.
|
||||
Completion time is recorded even on failed restores. The server's
|
||||
time is used for CompletionTimestamps
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
message:
|
||||
description: Message is a message about the pod volume restore's status.
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current state of the PodVolumeRestore.
|
||||
enum:
|
||||
- New
|
||||
- InProgress
|
||||
- Completed
|
||||
- Failed
|
||||
type: string
|
||||
progress:
|
||||
description: Progress holds the total number of bytes of the snapshot
|
||||
and the current number of restored bytes. This can be used to display
|
||||
progress information about the restore operation.
|
||||
properties:
|
||||
bytesDone:
|
||||
format: int64
|
||||
type: integer
|
||||
totalBytes:
|
||||
format: int64
|
||||
type: integer
|
||||
type: object
|
||||
startTimestamp:
|
||||
description: StartTimestamp records the time a restore was started.
|
||||
The server's time is used for StartTimestamps
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
89
config/crd/v1/bases/velero.io_resticrepositories.yaml
Normal file
89
config/crd/v1/bases/velero.io_resticrepositories.yaml
Normal file
@@ -0,0 +1,89 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: resticrepositories.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: ResticRepository
|
||||
listKind: ResticRepositoryList
|
||||
plural: resticrepositories
|
||||
singular: resticrepository
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ResticRepositorySpec is the specification for a ResticRepository.
|
||||
properties:
|
||||
backupStorageLocation:
|
||||
description: BackupStorageLocation is the name of the BackupStorageLocation
|
||||
that should contain this repository.
|
||||
type: string
|
||||
maintenanceFrequency:
|
||||
description: MaintenanceFrequency is how often maintenance should
|
||||
be run.
|
||||
type: string
|
||||
resticIdentifier:
|
||||
description: ResticIdentifier is the full restic-compatible string
|
||||
for identifying this repository.
|
||||
type: string
|
||||
volumeNamespace:
|
||||
description: VolumeNamespace is the namespace this restic repository
|
||||
contains pod volume backups for.
|
||||
type: string
|
||||
required:
|
||||
- backupStorageLocation
|
||||
- maintenanceFrequency
|
||||
- resticIdentifier
|
||||
- volumeNamespace
|
||||
type: object
|
||||
status:
|
||||
description: ResticRepositoryStatus is the current status of a ResticRepository.
|
||||
properties:
|
||||
lastMaintenanceTime:
|
||||
description: LastMaintenanceTime is the last time maintenance was
|
||||
run.
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
message:
|
||||
description: Message is a message about the current status of the
|
||||
ResticRepository.
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current state of the ResticRepository.
|
||||
enum:
|
||||
- New
|
||||
- Ready
|
||||
- NotReady
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
1699
config/crd/v1/bases/velero.io_restores.yaml
Normal file
1699
config/crd/v1/bases/velero.io_restores.yaml
Normal file
File diff suppressed because it is too large
Load Diff
394
config/crd/v1/bases/velero.io_schedules.yaml
Normal file
394
config/crd/v1/bases/velero.io_schedules.yaml
Normal file
@@ -0,0 +1,394 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: schedules.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: Schedule
|
||||
listKind: ScheduleList
|
||||
plural: schedules
|
||||
singular: schedule
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: Schedule is a Velero resource that represents a pre-scheduled
|
||||
or periodic Backup that should be run.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ScheduleSpec defines the specification for a Velero schedule
|
||||
properties:
|
||||
schedule:
|
||||
description: Schedule is a Cron expression defining when to run the
|
||||
Backup.
|
||||
type: string
|
||||
template:
|
||||
description: Template is the definition of the Backup to be run on
|
||||
the provided schedule
|
||||
properties:
|
||||
defaultVolumesToRestic:
|
||||
description: DefaultVolumesToRestic specifies whether restic should
|
||||
be used to take a backup of all pod volumes by default.
|
||||
type: boolean
|
||||
excludedNamespaces:
|
||||
description: ExcludedNamespaces contains a list of namespaces
|
||||
that are not included in the backup.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
excludedResources:
|
||||
description: ExcludedResources is a slice of resource names that
|
||||
are not included in the backup.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
hooks:
|
||||
description: Hooks represent custom behaviors that should be executed
|
||||
at different phases of the backup.
|
||||
properties:
|
||||
resources:
|
||||
description: Resources are hooks that should be executed when
|
||||
backing up individual instances of a resource.
|
||||
items:
|
||||
description: BackupResourceHookSpec defines one or more
|
||||
BackupResourceHooks that should be executed based on the
|
||||
rules defined for namespaces, resources, and label selector.
|
||||
properties:
|
||||
excludedNamespaces:
|
||||
description: ExcludedNamespaces specifies the namespaces
|
||||
to which this hook spec does not apply.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
excludedResources:
|
||||
description: ExcludedResources specifies the resources
|
||||
to which this hook spec does not apply.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
includedNamespaces:
|
||||
description: IncludedNamespaces specifies the namespaces
|
||||
to which this hook spec applies. If empty, it applies
|
||||
to all namespaces.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
includedResources:
|
||||
description: IncludedResources specifies the resources
|
||||
to which this hook spec applies. If empty, it applies
|
||||
to all resources.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
labelSelector:
|
||||
description: LabelSelector, if specified, filters the
|
||||
resources to which this hook spec applies.
|
||||
nullable: true
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
name:
|
||||
description: Name is the name of this hook.
|
||||
type: string
|
||||
post:
|
||||
description: PostHooks is a list of BackupResourceHooks
|
||||
to execute after storing the item in the backup. These
|
||||
are executed after all "additional items" from item
|
||||
actions are processed.
|
||||
items:
|
||||
description: BackupResourceHook defines a hook for
|
||||
a resource.
|
||||
properties:
|
||||
exec:
|
||||
description: Exec defines an exec hook.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command and arguments
|
||||
to execute.
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
container:
|
||||
description: Container is the container in
|
||||
the pod where the command should be executed.
|
||||
If not specified, the pod's first container
|
||||
is used.
|
||||
type: string
|
||||
onError:
|
||||
description: OnError specifies how Velero
|
||||
should behave if it encounters an error
|
||||
executing this hook.
|
||||
enum:
|
||||
- Continue
|
||||
- Fail
|
||||
type: string
|
||||
timeout:
|
||||
description: Timeout defines the maximum amount
|
||||
of time Velero should wait for the hook
|
||||
to complete before considering the execution
|
||||
a failure.
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
required:
|
||||
- exec
|
||||
type: object
|
||||
type: array
|
||||
pre:
|
||||
description: PreHooks is a list of BackupResourceHooks
|
||||
to execute prior to storing the item in the backup.
|
||||
These are executed before any "additional items" from
|
||||
item actions are processed.
|
||||
items:
|
||||
description: BackupResourceHook defines a hook for
|
||||
a resource.
|
||||
properties:
|
||||
exec:
|
||||
description: Exec defines an exec hook.
|
||||
properties:
|
||||
command:
|
||||
description: Command is the command and arguments
|
||||
to execute.
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
container:
|
||||
description: Container is the container in
|
||||
the pod where the command should be executed.
|
||||
If not specified, the pod's first container
|
||||
is used.
|
||||
type: string
|
||||
onError:
|
||||
description: OnError specifies how Velero
|
||||
should behave if it encounters an error
|
||||
executing this hook.
|
||||
enum:
|
||||
- Continue
|
||||
- Fail
|
||||
type: string
|
||||
timeout:
|
||||
description: Timeout defines the maximum amount
|
||||
of time Velero should wait for the hook
|
||||
to complete before considering the execution
|
||||
a failure.
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
required:
|
||||
- exec
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
includeClusterResources:
|
||||
description: IncludeClusterResources specifies whether cluster-scoped
|
||||
resources should be included for consideration in the backup.
|
||||
nullable: true
|
||||
type: boolean
|
||||
includedNamespaces:
|
||||
description: IncludedNamespaces is a slice of namespace names
|
||||
to include objects from. If empty, all namespaces are included.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
includedResources:
|
||||
description: IncludedResources is a slice of resource names to
|
||||
include in the backup. If empty, all resources are included.
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
labelSelector:
|
||||
description: LabelSelector is a metav1.LabelSelector to filter
|
||||
with when adding individual objects to the backup. If empty
|
||||
or nil, all objects are included. Optional.
|
||||
nullable: true
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label selector
|
||||
requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a selector
|
||||
that contains values, a key, and an operator that relates
|
||||
the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the selector
|
||||
applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are In, NotIn,
|
||||
Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string values. If
|
||||
the operator is In or NotIn, the values array must
|
||||
be non-empty. If the operator is Exists or DoesNotExist,
|
||||
the values array must be empty. This array is replaced
|
||||
during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value} pairs. A
|
||||
single {key,value} in the matchLabels map is equivalent
|
||||
to an element of matchExpressions, whose key field is "key",
|
||||
the operator is "In", and the values array contains only
|
||||
"value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
orderedResources:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: OrderedResources specifies the backup order of resources
|
||||
of specific Kind. The map key is the Kind name and value is
|
||||
a list of resource names separated by commas. Each resource
|
||||
name has format "namespace/resourcename". For cluster resources,
|
||||
simply use "resourcename".
|
||||
nullable: true
|
||||
type: object
|
||||
snapshotVolumes:
|
||||
description: SnapshotVolumes specifies whether to take cloud snapshots
|
||||
of any PV's referenced in the set of objects included in the
|
||||
Backup.
|
||||
nullable: true
|
||||
type: boolean
|
||||
storageLocation:
|
||||
description: StorageLocation is a string containing the name of
|
||||
a BackupStorageLocation where the backup should be stored.
|
||||
type: string
|
||||
ttl:
|
||||
description: TTL is a time.Duration-parseable string describing
|
||||
how long the Backup should be retained for.
|
||||
type: string
|
||||
volumeSnapshotLocations:
|
||||
description: VolumeSnapshotLocations is a list containing names
|
||||
of VolumeSnapshotLocations associated with this backup.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
useOwnerReferencesInBackup:
|
||||
description: UseOwnerReferencesBackup specifies whether to use OwnerReferences
|
||||
on backups created by this Schedule.
|
||||
nullable: true
|
||||
type: boolean
|
||||
required:
|
||||
- schedule
|
||||
- template
|
||||
type: object
|
||||
status:
|
||||
description: ScheduleStatus captures the current state of a Velero schedule
|
||||
properties:
|
||||
lastBackup:
|
||||
description: LastBackup is the last time a Backup was run for this
|
||||
Schedule schedule
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
phase:
|
||||
description: Phase is the current phase of the Schedule
|
||||
enum:
|
||||
- New
|
||||
- Enabled
|
||||
- FailedValidation
|
||||
type: string
|
||||
validationErrors:
|
||||
description: ValidationErrors is a slice of all validation errors
|
||||
(if applicable)
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
87
config/crd/v1/bases/velero.io_serverstatusrequests.yaml
Normal file
87
config/crd/v1/bases/velero.io_serverstatusrequests.yaml
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: serverstatusrequests.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: ServerStatusRequest
|
||||
listKind: ServerStatusRequestList
|
||||
plural: serverstatusrequests
|
||||
shortNames:
|
||||
- ssr
|
||||
singular: serverstatusrequest
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: ServerStatusRequest is a request to access current status information
|
||||
about the Velero server.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ServerStatusRequestSpec is the specification for a ServerStatusRequest.
|
||||
type: object
|
||||
status:
|
||||
description: ServerStatusRequestStatus is the current status of a ServerStatusRequest.
|
||||
properties:
|
||||
phase:
|
||||
description: Phase is the current lifecycle phase of the ServerStatusRequest.
|
||||
enum:
|
||||
- New
|
||||
- Processed
|
||||
type: string
|
||||
plugins:
|
||||
description: Plugins list information about the plugins running on
|
||||
the Velero server
|
||||
items:
|
||||
description: PluginInfo contains attributes of a Velero plugin
|
||||
properties:
|
||||
kind:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
- name
|
||||
type: object
|
||||
nullable: true
|
||||
type: array
|
||||
processedTimestamp:
|
||||
description: ProcessedTimestamp is when the ServerStatusRequest was
|
||||
processed by the ServerStatusRequestController.
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
serverVersion:
|
||||
description: ServerVersion is the Velero server version.
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
72
config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml
Normal file
72
config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.3.0
|
||||
creationTimestamp: null
|
||||
name: volumesnapshotlocations.velero.io
|
||||
spec:
|
||||
group: velero.io
|
||||
names:
|
||||
kind: VolumeSnapshotLocation
|
||||
listKind: VolumeSnapshotLocationList
|
||||
plural: volumesnapshotlocations
|
||||
singular: volumesnapshotlocation
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: VolumeSnapshotLocation is a location where Velero stores volume
|
||||
snapshots.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: VolumeSnapshotLocationSpec defines the specification for
|
||||
a Velero VolumeSnapshotLocation.
|
||||
properties:
|
||||
config:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Config is for provider-specific configuration fields.
|
||||
type: object
|
||||
provider:
|
||||
description: Provider is the provider of the volume storage.
|
||||
type: string
|
||||
required:
|
||||
- provider
|
||||
type: object
|
||||
status:
|
||||
description: VolumeSnapshotLocationStatus describes the current status
|
||||
of a Velero VolumeSnapshotLocation.
|
||||
properties:
|
||||
phase:
|
||||
description: VolumeSnapshotLocationPhase is the lifecycle phase of
|
||||
a Velero VolumeSnapshotLocation.
|
||||
enum:
|
||||
- Available
|
||||
- Unavailable
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
69
config/crd/v1/crds/crds.go
Normal file
69
config/crd/v1/crds/crds.go
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
// Package crds embeds the controller-tools generated CRD manifests
|
||||
package crds
|
||||
|
||||
//go:generate go run ../../../hack/crd-gen/main.go
|
||||
//go:generate go run ../../../../hack/crd-gen/v1/main.go
|
||||
4
config/crd/v1beta1/crds/doc.go
Normal file
4
config/crd/v1beta1/crds/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package crds embeds the controller-tools generated CRD manifests
|
||||
package crds
|
||||
|
||||
//go:generate go run ../../../../hack/crd-gen/v1beta1/main.go
|
||||
17
go.mod
17
go.mod
@@ -20,7 +20,7 @@ require (
|
||||
github.com/hashicorp/go-plugin v0.0.0-20190610192547-a1bc61569a26
|
||||
github.com/joho/godotenv v1.3.0
|
||||
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.0.0
|
||||
github.com/onsi/ginkgo v1.15.2
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.10.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.7.1
|
||||
@@ -35,12 +35,17 @@ require (
|
||||
google.golang.org/genproto v0.0.0-20200731012542-8145dea6a485 // indirect
|
||||
google.golang.org/grpc v1.31.0
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
k8s.io/api v0.19.7
|
||||
k8s.io/apiextensions-apiserver v0.19.7
|
||||
k8s.io/apimachinery v0.19.7
|
||||
k8s.io/cli-runtime v0.19.7
|
||||
k8s.io/client-go v0.19.7
|
||||
k8s.io/api v0.19.12
|
||||
k8s.io/apiextensions-apiserver v0.19.12
|
||||
k8s.io/apimachinery v0.19.12
|
||||
k8s.io/cli-runtime v0.19.12
|
||||
k8s.io/client-go v0.19.12
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/klog/v2 v2.3.0 // indirect
|
||||
k8s.io/kube-aggregator v0.19.12
|
||||
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7 // indirect
|
||||
sigs.k8s.io/cluster-api v0.3.11-0.20210106212952-b6c1b5b3db3d
|
||||
sigs.k8s.io/controller-runtime v0.7.1-0.20201215171748-096b2e07c091
|
||||
)
|
||||
|
||||
replace github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2
|
||||
|
||||
67
go.sum
67
go.sum
@@ -214,16 +214,15 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+
|
||||
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
|
||||
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
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/gobuffalo/flect v0.2.2 h1:PAVD7sp0KOdfswjAw9BpLCU9hXo7wFSzgpQ+zNeks/A=
|
||||
github.com/gobuffalo/flect v0.2.2/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
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/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=
|
||||
@@ -344,8 +343,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||
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=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
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/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -417,7 +415,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
@@ -431,8 +428,8 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.15.2 h1:l77YT15o814C2qVL47NOyjV/6RbaP7kKdrvZnxQ3Org=
|
||||
github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
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=
|
||||
@@ -628,7 +625,6 @@ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
||||
@@ -685,7 +681,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
|
||||
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -702,10 +697,8 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
|
||||
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -732,13 +725,13 @@ golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
|
||||
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
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=
|
||||
@@ -819,7 +812,6 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -830,34 +822,34 @@ honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXe
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
|
||||
k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI=
|
||||
k8s.io/api v0.19.7 h1:MpHhls03C2pyzoYcpbe4QqYiiZjdvW+tuWq6TbjV14Y=
|
||||
k8s.io/api v0.19.7/go.mod h1:KTryDUT3l6Mtv7K2J2486PNL9DBns3wOYTkGR+iz63Y=
|
||||
k8s.io/api v0.19.12 h1:412/DHd7Vofk2RMb0+RHWYYZwmEOG5Kh54+T/kyi4Zg=
|
||||
k8s.io/api v0.19.12/go.mod h1:EK+KvSq2urA6+CjVdZyAHEphXoLq2K2eW6lxOzTKSaY=
|
||||
k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg=
|
||||
k8s.io/apiextensions-apiserver v0.19.7 h1:aV9DANMSCCYBEMbtoT/5oesrtcciQrjy9yqWVtZZL5A=
|
||||
k8s.io/apiextensions-apiserver v0.19.7/go.mod h1:XJNNtjISNNePDEUClHt/igzMpQcmjVVh88QH+PKztPU=
|
||||
k8s.io/apiextensions-apiserver v0.19.12 h1:wY1liMH0Q2XozYj/qFQp+MJR0BbuMBn/L8/IMDvDByo=
|
||||
k8s.io/apiextensions-apiserver v0.19.12/go.mod h1:LXHRkG+7v33P+IzTKYVuqffGlB7Xg7K0VgfObTacbQg=
|
||||
k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig=
|
||||
k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
|
||||
k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
|
||||
k8s.io/apimachinery v0.19.7 h1:nTaEnYVH+i//aPgMA0zTEV2lfVLCV9LextqVd67mulc=
|
||||
k8s.io/apimachinery v0.19.7/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q=
|
||||
k8s.io/apimachinery v0.19.12 h1:XWmRhVo9vJOem6bLAyNnA31e5k1V06302wrIy35OA04=
|
||||
k8s.io/apimachinery v0.19.12/go.mod h1:9eb44nUQSsz9QZiilFRuMj3ZbTmoWolU8S2gnXoRMjo=
|
||||
k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA=
|
||||
k8s.io/apiserver v0.19.7 h1:fOOELJ9TNC6DgKL3GUkQLE/EBMLjwBseTstx2eRP61o=
|
||||
k8s.io/apiserver v0.19.7/go.mod h1:DmWVQggNePspa+vSsVytVbS3iBSDTXdJVt0akfHacKk=
|
||||
k8s.io/apiserver v0.19.12 h1:xQjt/jLqdYszJTRTDDnHUnA0S+a1TZ/8rgWr0/xoa6I=
|
||||
k8s.io/apiserver v0.19.12/go.mod h1:ldZAZTNIKfMMv/UUEhk6UyTXC0/34iRdNFHo+MJOPc4=
|
||||
k8s.io/cli-runtime v0.19.2/go.mod h1:CMynmJM4Yf02TlkbhKxoSzi4Zf518PukJ5xep/NaNeY=
|
||||
k8s.io/cli-runtime v0.19.7 h1:VkHsqrQYCD6+yBm2k9lOxLJtfo1tmb/TdYIHQ2RSCsY=
|
||||
k8s.io/cli-runtime v0.19.7/go.mod h1:UTtbWaGV/USZSrnvuW/lRZGM5OsemAT/q/Du/Ac+wKU=
|
||||
k8s.io/cli-runtime v0.19.12 h1:17snU0NcEnpU6TT5wcnBdBW/ydUQQ/qn82rKuAU5VkY=
|
||||
k8s.io/cli-runtime v0.19.12/go.mod h1:KopjJ53HaHZjG+WhJmH8WxZzxnXVNkxP7GO1QiQJ2uI=
|
||||
k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
|
||||
k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA=
|
||||
k8s.io/client-go v0.19.7 h1:SoJ4mzZ9LyXBGDe8MmpMznw0CwQ1ITWgsmG7GixvhUU=
|
||||
k8s.io/client-go v0.19.7/go.mod h1:iytGI7S3kmv6bWnn+bSQUE4VlrEi4YFssvVB7J7Hvqg=
|
||||
k8s.io/client-go v0.19.12 h1:bA6fG7J2cgY0pRKLQD6W15QSSZoPp9lHhg950BKQXjk=
|
||||
k8s.io/client-go v0.19.12/go.mod h1:BAGKQraZ6fDmXhT46pGXWZQQqN7P4E0BJux0+9O6Gt0=
|
||||
k8s.io/cluster-bootstrap v0.19.2 h1:6/LI5EnKCcB0QiDKIsTxoCOdKZtsSwr8Xm/tEhiMv78=
|
||||
k8s.io/cluster-bootstrap v0.19.2/go.mod h1:bzngsppPfdt9vAHUnDIEoMNsxD2b6XArVVH/W9PDDFk=
|
||||
k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
|
||||
k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk=
|
||||
k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0=
|
||||
k8s.io/code-generator v0.19.12/go.mod h1:ADrDvaUQWGn4a8lX0ONtzb7uFmDRQOMSYIMk1qWIAx8=
|
||||
k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo=
|
||||
k8s.io/component-base v0.19.7 h1:ZXS2VRWOWBOc2fTd1zjzhi/b/mkqFT9FDqiNsn1cH30=
|
||||
k8s.io/component-base v0.19.7/go.mod h1:YX8spPBgwl3I6UGcSdQiEMAqRMSUsGQOW7SEr4+Qa3U=
|
||||
k8s.io/component-base v0.19.12 h1:pEsTceFc3Hs9qJX4h2XYXQDzRMCNzTO8MX34bhjq0Io=
|
||||
k8s.io/component-base v0.19.12/go.mod h1:tpwExE0sY3A7CwtlxGL7SnQOdQfUlnFybT6GmAD+z/s=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
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=
|
||||
@@ -867,16 +859,22 @@ 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 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.3.0 h1:WmkrnW7fdrm0/DMClc+HIxtftvxVIPAhlVwMQo5yLco=
|
||||
k8s.io/klog/v2 v2.3.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
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-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ=
|
||||
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
|
||||
k8s.io/kubectl v0.19.2/go.mod h1:4ib3oj5ma6gF95QukTvC7ZBMxp60+UEAhDPjLuBIrV4=
|
||||
k8s.io/metrics v0.19.2/go.mod h1:IlLaAGXN0q7yrtB+SV0q3JIraf6VtlDr+iuTcX21fCU=
|
||||
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20200912215256-4140de9c8800 h1:9ZNvfPvVIEsp/T1ez4GQuzCcCTEQWhovSofhqR73A6g=
|
||||
k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7 h1:XQ0OMFdRDkDIu0b1zqEKSZdWUD7I4bZ4d4nqr8CLKbQ=
|
||||
k8s.io/utils v0.0.0-20201005171033-6301aaf42dc7/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
|
||||
sigs.k8s.io/cluster-api v0.3.11-0.20210106212952-b6c1b5b3db3d h1:OwD6b5QiyY4JXWRu7bK0gxKv/x51akqGLPmD1kRJmmI=
|
||||
sigs.k8s.io/cluster-api v0.3.11-0.20210106212952-b6c1b5b3db3d/go.mod h1:HwDMTKYusSK0SnTAr/P3htrxdiykBADqffkamkiUXhk=
|
||||
sigs.k8s.io/controller-runtime v0.7.1-0.20201215171748-096b2e07c091 h1:tqrTDj7mJmM6TdpoM1rN2PzBRH9yzCReqKGMy4sp+f0=
|
||||
@@ -885,8 +883,9 @@ sigs.k8s.io/kind v0.9.0/go.mod h1:cxKQWwmbtRDzQ+RNKnR6gZG6fjbeTtItp5cGf+ww+1Y=
|
||||
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3 h1:4oyYo8NREp49LBBhKxEqCulFjg26rawYKrnCmg+Sr6c=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
@@ -41,6 +41,11 @@ if [[ -z "${VERSION}" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${REGISTRY}" ]]; then
|
||||
echo "REGISTRY must be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${GIT_SHA}" ]]; then
|
||||
echo "GIT_SHA must be set"
|
||||
exit 1
|
||||
@@ -59,6 +64,7 @@ fi
|
||||
export CGO_ENABLED=0
|
||||
|
||||
LDFLAGS="-X ${PKG}/pkg/buildinfo.Version=${VERSION}"
|
||||
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.ImageRegistry=${REGISTRY}"
|
||||
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.GitSHA=${GIT_SHA}"
|
||||
LDFLAGS="${LDFLAGS} -X ${PKG}/pkg/buildinfo.GitTreeState=${GIT_TREE_STATE}"
|
||||
|
||||
|
||||
136
hack/crd-gen/v1/main.go
Normal file
136
hack/crd-gen/v1/main.go
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// This code embeds the CRD manifests in config/crd/v1/bases in
|
||||
// config/crd/v1/crds/crds.go.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// This is relative to config/crd/crds
|
||||
const goHeaderFile = "../../../../hack/boilerplate.go.txt"
|
||||
|
||||
const tpl = `{{.GoHeader}}
|
||||
// Code generated by crds_generate.go; DO NOT EDIT.
|
||||
|
||||
package crds
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io/ioutil"
|
||||
|
||||
apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
)
|
||||
|
||||
var rawCRDs = [][]byte{
|
||||
{{- range .RawCRDs }}
|
||||
[]byte({{ . }}),
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
var CRDs = crds()
|
||||
|
||||
func crds() []*apiextv1.CustomResourceDefinition {
|
||||
apiextinstall.Install(scheme.Scheme)
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
var objs []*apiextv1.CustomResourceDefinition
|
||||
for _, crd := range rawCRDs {
|
||||
gzr, err := gzip.NewReader(bytes.NewReader(crd))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bytes, err := ioutil.ReadAll(gzr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gzr.Close()
|
||||
|
||||
obj, _, err := decode(bytes, nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
objs = append(objs, obj.(*apiextv1.CustomResourceDefinition))
|
||||
}
|
||||
return objs
|
||||
}
|
||||
`
|
||||
|
||||
type templateData struct {
|
||||
GoHeader string
|
||||
RawCRDs []string
|
||||
}
|
||||
|
||||
func main() {
|
||||
headerBytes, err := ioutil.ReadFile(goHeaderFile)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
data := templateData{
|
||||
GoHeader: string(headerBytes),
|
||||
}
|
||||
|
||||
// This is relative to config/crd/crds
|
||||
manifests, err := ioutil.ReadDir("../bases")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
for _, crd := range manifests {
|
||||
file, err := os.Open("../bases/" + crd.Name())
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// gzip compress manifest
|
||||
var buf bytes.Buffer
|
||||
gzw := gzip.NewWriter(&buf)
|
||||
if _, err := io.Copy(gzw, file); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
file.Close()
|
||||
gzw.Close()
|
||||
|
||||
data.RawCRDs = append(data.RawCRDs, fmt.Sprintf("%q", buf.Bytes()))
|
||||
}
|
||||
|
||||
t, err := template.New("crd").Parse(tpl)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
out, err := os.Create("crds.go")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if err := t.Execute(out, data); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
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.
|
||||
@@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This code embeds the CRD manifests in config/crd/bases in
|
||||
// config/crd/crds/crds.go.
|
||||
// This code embeds the CRD manifests in config/crd/v1beta1/bases in
|
||||
// config/crd/v1beta1/crds/crds.go.
|
||||
|
||||
package main
|
||||
|
||||
@@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
// This is relative to config/crd/crds
|
||||
const goHeaderFile = "../../../hack/boilerplate.go.txt"
|
||||
const goHeaderFile = "../../../../hack/boilerplate.go.txt"
|
||||
|
||||
const tpl = `{{.GoHeader}}
|
||||
// Code generated by crds_generate.go; DO NOT EDIT.
|
||||
@@ -91,6 +91,9 @@ echo "BUILDX_PLATFORMS: $BUILDX_PLATFORMS"
|
||||
|
||||
echo "Building and pushing container images."
|
||||
|
||||
# The use of "registry" as the buildx output type below instructs
|
||||
# Docker to push the image
|
||||
|
||||
VERSION="$VERSION" \
|
||||
TAG_LATEST="$TAG_LATEST" \
|
||||
BUILDX_PLATFORMS="$BUILDX_PLATFORMS" \
|
||||
|
||||
@@ -29,6 +29,11 @@ if [ -z "${RELEASE_NOTES_FILE}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${REGISTRY}" ]; then
|
||||
echo "REGISTRY must be set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GIT_DIRTY=$(git status --porcelain 2> /dev/null)
|
||||
if [[ -z "${GIT_DIRTY}" ]]; then
|
||||
export GIT_TREE_STATE=clean
|
||||
|
||||
3
hack/restore-crd-patch-v1.json
Normal file
3
hack/restore-crd-patch-v1.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
{ "op": "replace", "path": "/spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/hooks/properties/resources/items/properties/postHooks/items/properties/init/properties/initContainers/items/properties/ports/items/required", "value": [ "containerPort", "protocol"] }
|
||||
]
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2017 the Velero contributors.
|
||||
# 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.
|
||||
@@ -44,20 +44,24 @@ ${GOPATH}/src/k8s.io/code-generator/generate-groups.sh \
|
||||
--output-base ../../.. \
|
||||
$@
|
||||
|
||||
# Generate manifests e.g. CRD, RBAC etc.
|
||||
controller-gen \
|
||||
crd:crdVersions=v1beta1,preserveUnknownFields=false,trivialVersions=true \
|
||||
paths=./pkg/apis/velero/v1/... \
|
||||
paths=./pkg/controller/... \
|
||||
output:crd:artifacts:config=config/crd/bases
|
||||
# Generate both apiextensions.k8s.io/v1beta1 and apiextensions.k8s.io/v1
|
||||
for version in v1beta1 v1
|
||||
do
|
||||
# Generate manifests e.g. CRD, RBAC etc.
|
||||
controller-gen \
|
||||
crd:crdVersions=$version,preserveUnknownFields=false,trivialVersions=true \
|
||||
paths=./pkg/apis/velero/v1/... \
|
||||
paths=./pkg/controller/... \
|
||||
output:crd:artifacts:config=config/crd/$version/bases
|
||||
|
||||
# this is a super hacky workaround for https://github.com/kubernetes/kubernetes/issues/91395
|
||||
# which a result of fixing the validation on CRD objects. The validation ensures the fields that are list map keys, are either marked
|
||||
# as required or have default values to ensure merging of list map items work as expected.
|
||||
# With "containerPort" and "protocol" being considered as x-kubernetes-list-map-keys in the container ports, and "protocol" was not
|
||||
# a required field, the CRD would fail validation with errors similar to the one reported in https://github.com/kubernetes/kubernetes/issues/91395.
|
||||
# once controller-gen (above) is able to generate CRDs with `protocol` as a required field, this hack can be removed.
|
||||
kubectl patch -f config/crd/bases/velero.io_restores.yaml -p "$(cat hack/restore-crd-patch.json)" --type=json --local=true -o yaml > /tmp/velero.io_restores-yaml.patched
|
||||
mv /tmp/velero.io_restores-yaml.patched config/crd/bases/velero.io_restores.yaml
|
||||
# this is a super hacky workaround for https://github.com/kubernetes/kubernetes/issues/91395
|
||||
# which a result of fixing the validation on CRD objects. The validation ensures the fields that are list map keys, are either marked
|
||||
# as required or have default values to ensure merging of list map items work as expected.
|
||||
# With "containerPort" and "protocol" being considered as x-kubernetes-list-map-keys in the container ports, and "protocol" was not
|
||||
# a required field, the CRD would fail validation with errors similar to the one reported in https://github.com/kubernetes/kubernetes/issues/91395.
|
||||
# once controller-gen (above) is able to generate CRDs with `protocol` as a required field, this hack can be removed.
|
||||
kubectl patch -f config/crd/$version/bases/velero.io_restores.yaml -p "$(cat hack/restore-crd-patch-$version.json)" --type=json --local=true -o yaml > /tmp/velero.io_restores-yaml.patched
|
||||
mv /tmp/velero.io_restores-yaml.patched config/crd/$version/bases/velero.io_restores.yaml
|
||||
|
||||
go generate ./config/crd/crds
|
||||
go generate ./config/crd/$version/crds
|
||||
done
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Copyright 2017 the Velero contributors.
|
||||
# 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.
|
||||
@@ -19,11 +19,14 @@ HACK_DIR=$(dirname "${BASH_SOURCE}")
|
||||
${HACK_DIR}/update-generated-crd-code.sh --verify-only
|
||||
|
||||
# ensure no changes to generated CRDs
|
||||
if ! git diff --exit-code config/crd/crds/crds.go >/dev/null; then
|
||||
# revert changes to state before running CRD generation to stay consistent
|
||||
# with code-generator `--verify-only` option which discards generated changes
|
||||
git checkout config/crd
|
||||
for version in v1beta1 v1
|
||||
do
|
||||
if ! git diff --exit-code config/crd/$version/crds/crds.go >/dev/null; then
|
||||
# revert changes to state before running CRD generation to stay consistent
|
||||
# with code-generator `--verify-only` option which discards generated changes
|
||||
git checkout config/crd
|
||||
|
||||
echo "CRD verification - failed! Generated CRDs are out-of-date, please run 'make update' and 'git add' the generated file(s)."
|
||||
exit 1
|
||||
fi
|
||||
echo "CRD verification - failed! Generated CRDs are out-of-date, please run 'make update' and 'git add' the generated file(s)."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
51
internal/velero/images.go
Normal file
51
internal/velero/images.go
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 velero
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
)
|
||||
|
||||
// Use Dockerhub as the default registry if the build process didn't supply a registry
|
||||
func imageRegistry() string {
|
||||
if buildinfo.ImageRegistry == "" {
|
||||
return "velero"
|
||||
}
|
||||
return buildinfo.ImageRegistry
|
||||
}
|
||||
|
||||
// ImageTag returns the image tag that should be used by Velero images.
|
||||
// It uses the Version from the buildinfo or "latest" if the build process didn't supply a version.
|
||||
func ImageTag() string {
|
||||
if buildinfo.Version == "" {
|
||||
return "latest"
|
||||
}
|
||||
return buildinfo.Version
|
||||
}
|
||||
|
||||
// DefaultVeleroImage returns the default container image to use for this version of Velero.
|
||||
func DefaultVeleroImage() string {
|
||||
return fmt.Sprintf("%s/%s:%s", imageRegistry(), "velero", ImageTag())
|
||||
}
|
||||
|
||||
// DefaultResticRestoreHelperImage returns the default container image to use for the restic restore helper
|
||||
// for this version of Velero.
|
||||
func DefaultResticRestoreHelperImage() string {
|
||||
return fmt.Sprintf("%s/%s:%s", imageRegistry(), "velero-restic-restore-helper", ImageTag())
|
||||
}
|
||||
140
internal/velero/images_test.go
Normal file
140
internal/velero/images_test.go
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
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 velero
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
)
|
||||
|
||||
func TestImageTag(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
buildInfoVersion string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "tag is latest when buildinfo.Version is empty",
|
||||
want: "latest",
|
||||
},
|
||||
{
|
||||
name: "tag is buildinfo.Version when not empty",
|
||||
buildInfoVersion: "custom-build-version",
|
||||
want: "custom-build-version",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
originalVersion := buildinfo.Version
|
||||
buildinfo.Version = tc.buildInfoVersion
|
||||
defer func() {
|
||||
buildinfo.Version = originalVersion
|
||||
}()
|
||||
|
||||
assert.Equal(t, tc.want, ImageTag())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageRegistry(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
buildInfoRegistry string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "registry is velero when buildinfo.ImageRegistry is empty",
|
||||
want: "velero",
|
||||
},
|
||||
{
|
||||
name: "registry is buildinfo.ImageRegistry when not empty",
|
||||
buildInfoRegistry: "custom-build-image-registry",
|
||||
want: "custom-build-image-registry",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
originalImageRegistry := buildinfo.ImageRegistry
|
||||
buildinfo.ImageRegistry = tc.buildInfoRegistry
|
||||
defer func() {
|
||||
buildinfo.ImageRegistry = originalImageRegistry
|
||||
}()
|
||||
|
||||
assert.Equal(t, tc.want, imageRegistry())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testDefaultImage(t *testing.T, defaultImageFn func() string, imageName string) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
buildInfoVersion string
|
||||
buildInfoRegistry string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "image uses velero as registry and latest as tag when buildinfo.ImageRegistry and buildinfo.Version are empty",
|
||||
want: fmt.Sprintf("velero/%s:latest", imageName),
|
||||
},
|
||||
{
|
||||
name: "image uses buildinfo.ImageRegistry as registry when not empty",
|
||||
buildInfoRegistry: "custom-build-image-registry",
|
||||
want: fmt.Sprintf("custom-build-image-registry/%s:latest", imageName),
|
||||
},
|
||||
{
|
||||
name: "image uses buildinfo.Version as tag when not empty",
|
||||
buildInfoVersion: "custom-build-version",
|
||||
want: fmt.Sprintf("velero/%s:custom-build-version", imageName),
|
||||
},
|
||||
{
|
||||
name: "image uses both buildinfo.ImageRegistry and buildinfo.Version when not empty",
|
||||
buildInfoRegistry: "custom-build-image-registry",
|
||||
buildInfoVersion: "custom-build-version",
|
||||
want: fmt.Sprintf("custom-build-image-registry/%s:custom-build-version", imageName),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
originalImageRegistry := buildinfo.ImageRegistry
|
||||
originalVersion := buildinfo.Version
|
||||
buildinfo.ImageRegistry = tc.buildInfoRegistry
|
||||
buildinfo.Version = tc.buildInfoVersion
|
||||
defer func() {
|
||||
buildinfo.ImageRegistry = originalImageRegistry
|
||||
buildinfo.Version = originalVersion
|
||||
}()
|
||||
|
||||
assert.Equal(t, tc.want, defaultImageFn())
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDefaultVeleroImage(t *testing.T) {
|
||||
testDefaultImage(t, DefaultVeleroImage, "velero")
|
||||
}
|
||||
|
||||
func TestDefaultResticRestoreHelperImage(t *testing.T) {
|
||||
testDefaultImage(t, DefaultResticRestoreHelperImage, "velero-restic-restore-helper")
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -767,9 +767,9 @@ func TestCRDInclusion(t *testing.T) {
|
||||
Result(),
|
||||
apiResources: []*test.APIResource{
|
||||
test.CRDs(
|
||||
builder.ForCustomResourceDefinition("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("test.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
||||
),
|
||||
test.VSLs(
|
||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
||||
@@ -793,9 +793,9 @@ func TestCRDInclusion(t *testing.T) {
|
||||
Result(),
|
||||
apiResources: []*test.APIResource{
|
||||
test.CRDs(
|
||||
builder.ForCustomResourceDefinition("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("test.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
||||
),
|
||||
test.VSLs(
|
||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
||||
@@ -813,9 +813,9 @@ func TestCRDInclusion(t *testing.T) {
|
||||
Result(),
|
||||
apiResources: []*test.APIResource{
|
||||
test.CRDs(
|
||||
builder.ForCustomResourceDefinition("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("test.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
||||
),
|
||||
test.VSLs(
|
||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
||||
@@ -839,9 +839,9 @@ func TestCRDInclusion(t *testing.T) {
|
||||
Result(),
|
||||
apiResources: []*test.APIResource{
|
||||
test.CRDs(
|
||||
builder.ForCustomResourceDefinition("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("test.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
||||
),
|
||||
test.VSLs(
|
||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
||||
@@ -862,9 +862,9 @@ func TestCRDInclusion(t *testing.T) {
|
||||
Result(),
|
||||
apiResources: []*test.APIResource{
|
||||
test.CRDs(
|
||||
builder.ForCustomResourceDefinition("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("test.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
||||
),
|
||||
test.VSLs(
|
||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
||||
@@ -883,9 +883,9 @@ func TestCRDInclusion(t *testing.T) {
|
||||
Result(),
|
||||
apiResources: []*test.APIResource{
|
||||
test.CRDs(
|
||||
builder.ForCustomResourceDefinition("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinition("test.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("backups.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("volumesnapshotlocations.velero.io").Result(),
|
||||
builder.ForCustomResourceDefinitionV1Beta1("test.velero.io").Result(),
|
||||
),
|
||||
test.VSLs(
|
||||
builder.ForVolumeSnapshotLocation("foo", "vsl-1").Result(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -44,7 +44,7 @@ func TestRemapCRDVersionAction(t *testing.T) {
|
||||
|
||||
// build a v1beta1 CRD with the same name and add it to the fake client that the plugin is going to call.
|
||||
// keep the same one for all 3 tests, since there's little value in recreating it
|
||||
b := builder.ForCustomResourceDefinition("test.velero.io")
|
||||
b := builder.ForCustomResourceDefinitionV1Beta1("test.velero.io")
|
||||
c := b.Result()
|
||||
_, err := betaClient.Create(context.TODO(), c, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -45,7 +45,7 @@ func ForPluginContainer(image string, pullPolicy corev1api.PullPolicy) *Containe
|
||||
|
||||
// getName returns the 'name' component of a docker
|
||||
// image that includes the entire string except the registry name, and transforms the combined
|
||||
// string into a DNS-1123 compatible name.
|
||||
// string into a RFC-1123 compatible name.
|
||||
func getName(image string) string {
|
||||
slashIndex := strings.Index(image, "/")
|
||||
slashCount := 0
|
||||
@@ -67,7 +67,14 @@ func getName(image string) string {
|
||||
end = colonIndex
|
||||
}
|
||||
|
||||
return strings.Replace(image[start:end], "/", "-", -1) // this makes it DNS-1123 compatible
|
||||
// https://github.com/distribution/distribution/blob/main/docs/spec/api.md#overview
|
||||
// valid repository names match the regex [a-z0-9]+(?:[._-][a-z0-9]+)*
|
||||
// image repository names can container [._] but [._] are not allowed in RFC-1123 labels.
|
||||
// replace '/', '_' and '.' with '-'
|
||||
re := strings.NewReplacer("/", "-",
|
||||
"_", "-",
|
||||
".", "-")
|
||||
return re.Replace(image[start:end])
|
||||
}
|
||||
|
||||
// Result returns the built Container.
|
||||
|
||||
@@ -75,7 +75,17 @@ func TestGetName(t *testing.T) {
|
||||
{
|
||||
name: "image name with registry hostname starting with a / will include the registry name ¯\\_(ツ)_/¯",
|
||||
image: "/gcr.io/my-repo/mystery/another/my-image",
|
||||
expected: "gcr.io-my-repo-mystery-another-my-image",
|
||||
expected: "gcr-io-my-repo-mystery-another-my-image",
|
||||
},
|
||||
{
|
||||
name: "image repository names containing _ ",
|
||||
image: "projects.registry.vmware.com/tanzu_migrator/route-2-httpproxy:myTag",
|
||||
expected: "tanzu-migrator-route-2-httpproxy",
|
||||
},
|
||||
{
|
||||
name: "image repository names containing . ",
|
||||
image: "projects.registry.vmware.com/tanzu.migrator/route-2-httpproxy:myTag",
|
||||
expected: "tanzu-migrator-route-2-httpproxy",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package builder
|
||||
|
||||
import (
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// CustomResourceDefinitionBuilder builds CustomResourceDefinition objects.
|
||||
type CustomResourceDefinitionBuilder struct {
|
||||
object *apiextv1beta1.CustomResourceDefinition
|
||||
}
|
||||
|
||||
// ForCustomResourceDefinition is the constructor for a CustomResourceDefinitionBuilder.
|
||||
func ForCustomResourceDefinition(name string) *CustomResourceDefinitionBuilder {
|
||||
return &CustomResourceDefinitionBuilder{
|
||||
object: &apiextv1beta1.CustomResourceDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: apiextv1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "CustomResourceDefinition",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Condition adds a CustomResourceDefinitionCondition objects to a CustomResourceDefinitionBuilder.
|
||||
func (c *CustomResourceDefinitionBuilder) Condition(cond apiextv1beta1.CustomResourceDefinitionCondition) *CustomResourceDefinitionBuilder {
|
||||
c.object.Status.Conditions = append(c.object.Status.Conditions, cond)
|
||||
return c
|
||||
}
|
||||
|
||||
// Result returns the built CustomResourceDefinition.
|
||||
func (b *CustomResourceDefinitionBuilder) Result() *apiextv1beta1.CustomResourceDefinition {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the CustomResourceDefinition's ObjectMeta.
|
||||
func (b *CustomResourceDefinitionBuilder) ObjectMeta(opts ...ObjectMetaOpt) *CustomResourceDefinitionBuilder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionConditionBuilder builds CustomResourceDefinitionCondition objects.
|
||||
type CustomResourceDefinitionConditionBuilder struct {
|
||||
object apiextv1beta1.CustomResourceDefinitionCondition
|
||||
}
|
||||
|
||||
// ForCustomResourceDefinitionConditionBuilder is the construction for a CustomResourceDefinitionConditionBuilder.
|
||||
func ForCustomResourceDefinitionCondition() *CustomResourceDefinitionConditionBuilder {
|
||||
return &CustomResourceDefinitionConditionBuilder{
|
||||
object: apiextv1beta1.CustomResourceDefinitionCondition{},
|
||||
}
|
||||
}
|
||||
|
||||
// Type sets the Condition's type.
|
||||
func (c *CustomResourceDefinitionConditionBuilder) Type(t apiextv1beta1.CustomResourceDefinitionConditionType) *CustomResourceDefinitionConditionBuilder {
|
||||
c.object.Type = t
|
||||
return c
|
||||
}
|
||||
|
||||
// Status sets the Condition's status.
|
||||
func (c *CustomResourceDefinitionConditionBuilder) Status(cs apiextv1beta1.ConditionStatus) *CustomResourceDefinitionConditionBuilder {
|
||||
c.object.Status = cs
|
||||
return c
|
||||
}
|
||||
|
||||
// Results returns the built CustomResourceDefinitionCondition.
|
||||
func (b *CustomResourceDefinitionConditionBuilder) Result() apiextv1beta1.CustomResourceDefinitionCondition {
|
||||
return b.object
|
||||
}
|
||||
91
pkg/builder/customresourcedefinition_v1beta1_builder.go
Normal file
91
pkg/builder/customresourcedefinition_v1beta1_builder.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
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 (
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// CustomResourceDefinitionV1Beta1Builder builds v1beta1 CustomResourceDefinition objects.
|
||||
type CustomResourceDefinitionV1Beta1Builder struct {
|
||||
object *apiextv1beta1.CustomResourceDefinition
|
||||
}
|
||||
|
||||
// ForCustomResourceDefinitionV1Beta1 is the constructor for a CustomResourceDefinitionV1Beta1Builder.
|
||||
func ForCustomResourceDefinitionV1Beta1(name string) *CustomResourceDefinitionV1Beta1Builder {
|
||||
return &CustomResourceDefinitionV1Beta1Builder{
|
||||
object: &apiextv1beta1.CustomResourceDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: apiextv1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "CustomResourceDefinition",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Condition adds a CustomResourceDefinitionCondition objects to a CustomResourceDefinitionV1Beta1Builder.
|
||||
func (c *CustomResourceDefinitionV1Beta1Builder) Condition(cond apiextv1beta1.CustomResourceDefinitionCondition) *CustomResourceDefinitionV1Beta1Builder {
|
||||
c.object.Status.Conditions = append(c.object.Status.Conditions, cond)
|
||||
return c
|
||||
}
|
||||
|
||||
// Result returns the built CustomResourceDefinition.
|
||||
func (b *CustomResourceDefinitionV1Beta1Builder) Result() *apiextv1beta1.CustomResourceDefinition {
|
||||
return b.object
|
||||
}
|
||||
|
||||
// ObjectMeta applies functional options to the CustomResourceDefinition's ObjectMeta.
|
||||
func (b *CustomResourceDefinitionV1Beta1Builder) ObjectMeta(opts ...ObjectMetaOpt) *CustomResourceDefinitionV1Beta1Builder {
|
||||
for _, opt := range opts {
|
||||
opt(b.object)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionV1Beta1ConditionBuilder builds CustomResourceDefinitionV1Beta1Condition objects.
|
||||
type CustomResourceDefinitionV1Beta1ConditionBuilder struct {
|
||||
object apiextv1beta1.CustomResourceDefinitionCondition
|
||||
}
|
||||
|
||||
// ForCustomResourceDefinitionV1Beta1Condition is the construction for a CustomResourceDefinitionV1Beta1ConditionBuilder.
|
||||
func ForCustomResourceDefinitionV1Beta1Condition() *CustomResourceDefinitionV1Beta1ConditionBuilder {
|
||||
return &CustomResourceDefinitionV1Beta1ConditionBuilder{
|
||||
object: apiextv1beta1.CustomResourceDefinitionCondition{},
|
||||
}
|
||||
}
|
||||
|
||||
// Type sets the Condition's type.
|
||||
func (c *CustomResourceDefinitionV1Beta1ConditionBuilder) Type(t apiextv1beta1.CustomResourceDefinitionConditionType) *CustomResourceDefinitionV1Beta1ConditionBuilder {
|
||||
c.object.Type = t
|
||||
return c
|
||||
}
|
||||
|
||||
// Status sets the Condition's status.
|
||||
func (c *CustomResourceDefinitionV1Beta1ConditionBuilder) Status(cs apiextv1beta1.ConditionStatus) *CustomResourceDefinitionV1Beta1ConditionBuilder {
|
||||
c.object.Status = cs
|
||||
return c
|
||||
}
|
||||
|
||||
// Result returns the built v1beta1 CustomResourceDefinitionCondition.
|
||||
func (c *CustomResourceDefinitionV1Beta1ConditionBuilder) Result() apiextv1beta1.CustomResourceDefinitionCondition {
|
||||
return c.object
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2017 the Velero contributors.
|
||||
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.
|
||||
@@ -31,6 +31,10 @@ var (
|
||||
// GitTreeState indicates if the git tree is clean or dirty, set by the go linker's -X flag at build
|
||||
// time.
|
||||
GitTreeState string
|
||||
|
||||
// ImageRegistry is the image registry that this build of Velero should use by default to pull the
|
||||
// Velero and Restic Restore Helper images from.
|
||||
ImageRegistry string
|
||||
)
|
||||
|
||||
// FormattedGitSHA renders the Git SHA with an indicator of the tree state.
|
||||
@@ -19,6 +19,9 @@ package client
|
||||
import (
|
||||
"os"
|
||||
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
k8scheme "k8s.io/client-go/kubernetes/scheme"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -45,7 +48,8 @@ type Factory interface {
|
||||
// DynamicClient returns a Kubernetes dynamic client. It uses the following priority to specify the cluster
|
||||
// configuration: --kubeconfig flag, KUBECONFIG environment variable, in-cluster configuration.
|
||||
DynamicClient() (dynamic.Interface, error)
|
||||
// KubebuilderClient returns a Kubernetes dynamic client. It uses the following priority to specify the cluster
|
||||
// KubebuilderClient returns a client for the controller runtime framework. It adds Kubernetes and Velero
|
||||
// types to its scheme. It uses the following priority to specify the cluster
|
||||
// configuration: --kubeconfig flag, KUBECONFIG environment variable, in-cluster configuration.
|
||||
KubebuilderClient() (kbclient.Client, error)
|
||||
// SetBasename changes the basename for an already-constructed client.
|
||||
@@ -151,6 +155,9 @@ func (f *factory) KubebuilderClient() (kbclient.Client, error) {
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
velerov1api.AddToScheme(scheme)
|
||||
k8scheme.AddToScheme(scheme)
|
||||
apiextv1beta1.AddToScheme(scheme)
|
||||
apiextv1.AddToScheme(scheme)
|
||||
kubebuilderClient, err := kbclient.New(clientConfig, kbclient.Options{
|
||||
Scheme: scheme,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -25,15 +25,19 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/velero"
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/output"
|
||||
velerodiscovery "github.com/vmware-tanzu/velero/pkg/discovery"
|
||||
"github.com/vmware-tanzu/velero/pkg/install"
|
||||
kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
@@ -68,6 +72,7 @@ type InstallOptions struct {
|
||||
Plugins flag.StringArray
|
||||
NoDefaultBackupLocation bool
|
||||
CRDsOnly bool
|
||||
CRDsVersion string
|
||||
CACertFile string
|
||||
Features string
|
||||
DefaultVolumesToRestic bool
|
||||
@@ -102,6 +107,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
flags.DurationVar(&o.DefaultResticMaintenanceFrequency, "default-restic-prune-frequency", o.DefaultResticMaintenanceFrequency, "How often 'restic prune' is run for restic repositories by default. Optional.")
|
||||
flags.Var(&o.Plugins, "plugins", "Plugin container images to install into the Velero Deployment")
|
||||
flags.BoolVar(&o.CRDsOnly, "crds-only", o.CRDsOnly, "Only generate CustomResourceDefinition resources. Useful for updating CRDs for an existing Velero install.")
|
||||
flags.StringVar(&o.CRDsVersion, "crds-version", o.CRDsVersion, "The version to generate CustomResourceDefinition resources if Velero can't discover the Kubernetes preferred CRD API version. Optional.")
|
||||
flags.StringVar(&o.CACertFile, "cacert", o.CACertFile, "File containing a certificate bundle to use when verifying TLS connections to the object store. Optional.")
|
||||
flags.StringVar(&o.Features, "features", o.Features, "Comma separated list of Velero feature flags to be set on the Velero deployment and the restic daemonset, if restic is enabled")
|
||||
flags.BoolVar(&o.DefaultVolumesToRestic, "default-volumes-to-restic", o.DefaultVolumesToRestic, "Bool flag to configure Velero server to use restic by default to backup all pod volumes on all backups. Optional.")
|
||||
@@ -111,7 +117,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) {
|
||||
func NewInstallOptions() *InstallOptions {
|
||||
return &InstallOptions{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Image: install.DefaultImage,
|
||||
Image: velero.DefaultVeleroImage(),
|
||||
BackupStorageConfig: flag.NewMap(),
|
||||
VolumeSnapshotConfig: flag.NewMap(),
|
||||
PodAnnotations: flag.NewMap(),
|
||||
@@ -128,6 +134,7 @@ func NewInstallOptions() *InstallOptions {
|
||||
UseVolumeSnapshots: true,
|
||||
NoDefaultBackupLocation: false,
|
||||
CRDsOnly: false,
|
||||
CRDsVersion: "v1",
|
||||
DefaultVolumesToRestic: false,
|
||||
}
|
||||
}
|
||||
@@ -186,6 +193,7 @@ func (o *InstallOptions) AsVeleroOptions() (*install.VeleroOptions, error) {
|
||||
NoDefaultBackupLocation: o.NoDefaultBackupLocation,
|
||||
CACertData: caCertData,
|
||||
Features: strings.Split(o.Features, ","),
|
||||
CRDsVersion: o.CRDsVersion,
|
||||
DefaultVolumesToRestic: o.DefaultVolumesToRestic,
|
||||
}, nil
|
||||
}
|
||||
@@ -246,19 +254,37 @@ This is useful as a starting point for more customized installations.
|
||||
|
||||
// Run executes a command in the context of the provided arguments.
|
||||
func (o *InstallOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
// Find the kube-apiserver group apiextensions.k8s.io preferred API version
|
||||
clientset, err := f.KubeClient()
|
||||
if err == nil {
|
||||
// kubeconfig available
|
||||
discoveryHelper, err := velerodiscovery.NewHelper(clientset.Discovery(), &logrus.Logger{})
|
||||
if err == nil {
|
||||
// kubernetes apiserver available
|
||||
gvr, _, err := discoveryHelper.ResourceFor(
|
||||
schema.GroupVersionResource{
|
||||
Group: "apiextensions.k8s.io",
|
||||
Resource: "customresourcedefinitions",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the group apiextensions.k8s.io preferred API version
|
||||
o.CRDsVersion = gvr.Version
|
||||
}
|
||||
}
|
||||
|
||||
var resources *unstructured.UnstructuredList
|
||||
if o.CRDsOnly {
|
||||
resources = install.AllCRDs()
|
||||
resources = install.AllCRDs(o.CRDsVersion)
|
||||
} else {
|
||||
vo, err := o.AsVeleroOptions()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resources, err = install.AllResources(vo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resources = install.AllResources(vo)
|
||||
}
|
||||
|
||||
if _, err := output.PrintWithFormat(c, resources); err != nil {
|
||||
@@ -272,24 +298,28 @@ func (o *InstallOptions) Run(c *cobra.Command, f client.Factory) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
factory := client.NewDynamicFactory(dynamicClient)
|
||||
dynamicFactory := client.NewDynamicFactory(dynamicClient)
|
||||
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errorMsg := fmt.Sprintf("\n\nError installing Velero. Use `kubectl logs deploy/velero -n %s` to check the deploy logs", o.Namespace)
|
||||
|
||||
err = install.Install(factory, resources, os.Stdout)
|
||||
err = install.Install(dynamicFactory, kbClient, resources, os.Stdout)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
|
||||
if o.Wait {
|
||||
fmt.Println("Waiting for Velero deployment to be ready.")
|
||||
if _, err = install.DeploymentIsReady(factory, o.Namespace); err != nil {
|
||||
if _, err = install.DeploymentIsReady(dynamicFactory, o.Namespace); err != nil {
|
||||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
|
||||
if o.UseRestic {
|
||||
fmt.Println("Waiting for Velero restic daemonset to be ready.")
|
||||
if _, err = install.DaemonSetIsReady(factory, o.Namespace); err != nil {
|
||||
if _, err = install.DaemonSetIsReady(dynamicFactory, o.Namespace); err != nil {
|
||||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
}
|
||||
@@ -318,6 +348,11 @@ func (o *InstallOptions) Validate(c *cobra.Command, args []string, f client.Fact
|
||||
return err
|
||||
}
|
||||
|
||||
// Check the CRD version is valid.
|
||||
if o.CRDsVersion != "v1beta1" && o.CRDsVersion != "v1" {
|
||||
return errors.Errorf("CRD version must be v1beta1 or v1")
|
||||
}
|
||||
|
||||
// If we're only installing CRDs, we can skip the rest of the validation.
|
||||
if o.CRDsOnly {
|
||||
return nil
|
||||
|
||||
@@ -26,20 +26,19 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
kubeerrs "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli"
|
||||
"github.com/vmware-tanzu/velero/pkg/install"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
|
||||
// uninstallOptions collects all the options for uninstalling Velero from a Kubernetes cluster.
|
||||
@@ -78,9 +77,9 @@ Use '--force' to skip the prompt confirming if you want to uninstall Velero.
|
||||
}
|
||||
}
|
||||
|
||||
client, extCl, err := kube.GetClusterClient()
|
||||
kbClient, err := f.KubebuilderClient()
|
||||
cmd.CheckError(err)
|
||||
cmd.CheckError(Run(context.Background(), client, extCl, f.Namespace(), o.wait))
|
||||
cmd.CheckError(Run(context.Background(), kbClient, f.Namespace(), o.wait))
|
||||
},
|
||||
}
|
||||
|
||||
@@ -89,54 +88,74 @@ Use '--force' to skip the prompt confirming if you want to uninstall Velero.
|
||||
}
|
||||
|
||||
// Run removes all components that were deployed using the Velero install command
|
||||
func Run(ctx context.Context, client *kubernetes.Clientset, extensionsClient *apiextensionsclientset.Clientset, namespace string, waitToTerminate bool) error {
|
||||
func Run(ctx context.Context, kbClient kbclient.Client, namespace string, waitToTerminate bool) error {
|
||||
var errs []error
|
||||
|
||||
// namespace
|
||||
ns, err := client.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
ns := &corev1.Namespace{}
|
||||
key := kbclient.ObjectKey{Name: namespace}
|
||||
if err := kbClient.Get(ctx, key, ns); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
fmt.Printf("Velero installation namespace %q does not exist, skipping.\n", namespace)
|
||||
fmt.Printf("Velero namespace %q does not exist, skipping.\n", namespace)
|
||||
} else {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
} else {
|
||||
if ns.Status.Phase == corev1.NamespaceTerminating {
|
||||
fmt.Printf("Velero installation namespace %q is terminating.\n", namespace)
|
||||
fmt.Printf("Velero namespace %q is terminating.\n", namespace)
|
||||
} else {
|
||||
err = client.CoreV1().Namespaces().Delete(ctx, ns.Name, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
if err := kbClient.Delete(ctx, ns); err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rolebinding
|
||||
// ClusterRoleBinding
|
||||
crb := install.ClusterRoleBinding(namespace)
|
||||
if err := client.RbacV1().ClusterRoleBindings().Delete(ctx, crb.Name, metav1.DeleteOptions{}); err != nil {
|
||||
key = kbclient.ObjectKey{Name: crb.Name}
|
||||
if err := kbClient.Get(ctx, key, crb); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
fmt.Printf("Velero installation clusterrolebinding %q does not exist, skipping.\n", crb.Name)
|
||||
fmt.Printf("Velero ClusterRoleBinding %q does not exist, skipping.\n", crb.Name)
|
||||
} else {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
} else {
|
||||
if err := kbClient.Delete(ctx, crb); err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
||||
// CRDs
|
||||
veleroLabels := labels.FormatLabels(install.Labels())
|
||||
crds, err := extensionsClient.ApiextensionsV1().CustomResourceDefinitions().List(ctx, metav1.ListOptions{
|
||||
LabelSelector: veleroLabels,
|
||||
})
|
||||
if err != nil {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
|
||||
veleroLabelSelector := labels.SelectorFromSet(install.Labels())
|
||||
opts := []kbclient.DeleteAllOfOption{
|
||||
kbclient.InNamespace(namespace),
|
||||
kbclient.MatchingLabelsSelector{
|
||||
Selector: veleroLabelSelector,
|
||||
},
|
||||
}
|
||||
if len(crds.Items) == 0 {
|
||||
fmt.Print("Velero CRDs do not exist, skipping.\n")
|
||||
v1CRDsRemoved := false
|
||||
v1crd := &apiextv1.CustomResourceDefinition{}
|
||||
if err := kbClient.DeleteAllOf(ctx, v1crd, opts...); err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
fmt.Println("V1 Velero CRDs not found, skipping...")
|
||||
} else {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
} else {
|
||||
for _, removeCRD := range crds.Items {
|
||||
if err = extensionsClient.ApiextensionsV1().CustomResourceDefinitions().Delete(ctx, removeCRD.ObjectMeta.Name, metav1.DeleteOptions{}); err != nil {
|
||||
err2 := errors.WithMessagef(err, "Uninstall failed removing CRD %s", removeCRD.ObjectMeta.Name)
|
||||
errs = append(errs, errors.WithStack(err2))
|
||||
v1CRDsRemoved = true
|
||||
}
|
||||
|
||||
// Remove any old Velero v1beta1 CRDs hanging around.
|
||||
v1beta1crd := &apiextv1beta1.CustomResourceDefinition{}
|
||||
if err := kbClient.DeleteAllOf(ctx, v1beta1crd, opts...); err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
if !v1CRDsRemoved {
|
||||
// Only mention this if there were no V1 CRDs removed
|
||||
fmt.Println("V1Beta1 Velero CRDs not found, skipping...")
|
||||
}
|
||||
} else {
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +166,7 @@ func Run(ctx context.Context, client *kubernetes.Clientset, extensionsClient *ap
|
||||
defer cancel()
|
||||
|
||||
checkFunc := func() {
|
||||
_, err := client.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{})
|
||||
err := kbClient.Get(ctx, key, ns)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
fmt.Print("\n")
|
||||
|
||||
@@ -54,6 +54,7 @@ func NewCommand(f client.Factory) *cobra.Command {
|
||||
RegisterRestoreItemAction("velero.io/cluster-role-bindings", newClusterRoleBindingItemAction).
|
||||
RegisterRestoreItemAction("velero.io/crd-preserve-fields", newCRDV1PreserveUnknownFieldsItemAction).
|
||||
RegisterRestoreItemAction("velero.io/change-pvc-node-selector", newChangePVCNodeSelectorItemAction(f)).
|
||||
RegisterRestoreItemAction("velero.io/apiservice", newAPIServiceRestoreItemAction).
|
||||
Serve()
|
||||
},
|
||||
}
|
||||
@@ -197,3 +198,7 @@ func newChangePVCNodeSelectorItemAction(f client.Factory) veleroplugin.HandlerIn
|
||||
), nil
|
||||
}
|
||||
}
|
||||
|
||||
func newAPIServiceRestoreItemAction(logger logrus.FieldLogger) (interface{}, error) {
|
||||
return restore.NewAPIServiceAction(logger), nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2018, 2019, 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -23,11 +23,13 @@ import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/velero"
|
||||
)
|
||||
|
||||
func DaemonSet(namespace string, opts ...podTemplateOption) *appsv1.DaemonSet {
|
||||
c := &podTemplateConfig{
|
||||
image: DefaultImage,
|
||||
image: velero.DefaultVeleroImage(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/vmware-tanzu/velero/internal/velero"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
)
|
||||
|
||||
@@ -117,7 +118,7 @@ func WithDefaultVolumesToRestic() podTemplateOption {
|
||||
func Deployment(namespace string, opts ...podTemplateOption) *appsv1.Deployment {
|
||||
// TODO: Add support for server args
|
||||
c := &podTemplateConfig{
|
||||
image: DefaultImage,
|
||||
image: velero.DefaultVeleroImage(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
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.
|
||||
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package install
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -32,6 +34,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
@@ -57,53 +60,95 @@ type ResourceGroup struct {
|
||||
OtherResources []*unstructured.Unstructured
|
||||
}
|
||||
|
||||
// crdsAreReady polls the API server to see if the BackupStorageLocation and VolumeSnapshotLocation CRDs are ready to create objects.
|
||||
func crdsAreReady(factory client.DynamicFactory, crdKinds []string) (bool, error) {
|
||||
gvk := schema.FromAPIVersionAndKind(apiextv1beta1.SchemeGroupVersion.String(), "CustomResourceDefinition")
|
||||
apiResource := metav1.APIResource{
|
||||
Name: kindToResource["CustomResourceDefinition"],
|
||||
Namespaced: false,
|
||||
}
|
||||
c, err := factory.ClientForGroupVersionResource(gvk.GroupVersion(), apiResource, "")
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "Error creating client for CustomResourceDefinition polling")
|
||||
}
|
||||
// Track all the CRDs that have been found and successfully marshalled.
|
||||
// len should be equal to len(crdKinds) in the happy path.
|
||||
foundCRDs := make([]*apiextv1beta1.CustomResourceDefinition, 0)
|
||||
var areReady bool
|
||||
err = wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
|
||||
for _, k := range crdKinds {
|
||||
unstruct, err := c.Get(k, metav1.GetOptions{})
|
||||
// crdV1Beta1ReadinessFn returns a function that can be used for polling to check
|
||||
// if the provided unstructured v1beta1 CRDs are ready for use in the cluster.
|
||||
func crdV1Beta1ReadinessFn(kbClient kbclient.Client, unstructuredCrds []*unstructured.Unstructured) func() (bool, error) {
|
||||
// Track all the CRDs that have been found and in ready state.
|
||||
// len should be equal to len(unstructuredCrds) in the happy path.
|
||||
return func() (bool, error) {
|
||||
foundCRDs := make([]*apiextv1beta1.CustomResourceDefinition, 0)
|
||||
for _, unstructuredCrd := range unstructuredCrds {
|
||||
crd := &apiextv1beta1.CustomResourceDefinition{}
|
||||
key := kbclient.ObjectKey{Name: unstructuredCrd.GetName()}
|
||||
err := kbClient.Get(context.Background(), key, crd)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, errors.Wrapf(err, "error waiting for %s to be ready", k)
|
||||
return false, errors.Wrapf(err, "error waiting for %s to be ready", crd.GetName())
|
||||
}
|
||||
|
||||
crd := new(apiextv1beta1.CustomResourceDefinition)
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstruct.Object, crd); err != nil {
|
||||
return false, errors.Wrapf(err, "error converting %s from unstructured", k)
|
||||
}
|
||||
|
||||
foundCRDs = append(foundCRDs, crd)
|
||||
}
|
||||
|
||||
if len(foundCRDs) != len(crdKinds) {
|
||||
if len(foundCRDs) != len(unstructuredCrds) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, crd := range foundCRDs {
|
||||
if !kube.IsCRDReady(crd) {
|
||||
ready := kube.IsV1Beta1CRDReady(crd)
|
||||
if !ready {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
}
|
||||
areReady = true
|
||||
|
||||
return true, nil
|
||||
})
|
||||
return areReady, nil
|
||||
}
|
||||
}
|
||||
|
||||
// crdV1ReadinessFn returns a function that can be used for polling to check
|
||||
// if the provided unstructured v1 CRDs are ready for use in the cluster.
|
||||
func crdV1ReadinessFn(kbClient kbclient.Client, unstructuredCrds []*unstructured.Unstructured) func() (bool, error) {
|
||||
return func() (bool, error) {
|
||||
foundCRDs := make([]*apiextv1.CustomResourceDefinition, 0)
|
||||
for _, unstructuredCrd := range unstructuredCrds {
|
||||
crd := &apiextv1.CustomResourceDefinition{}
|
||||
key := kbclient.ObjectKey{Name: unstructuredCrd.GetName()}
|
||||
err := kbClient.Get(context.Background(), key, crd)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return false, nil
|
||||
} else if err != nil {
|
||||
return false, errors.Wrapf(err, "error waiting for %s to be ready", crd.GetName())
|
||||
}
|
||||
foundCRDs = append(foundCRDs, crd)
|
||||
}
|
||||
|
||||
if len(foundCRDs) != len(unstructuredCrds) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, crd := range foundCRDs {
|
||||
ready := kube.IsV1CRDReady(crd)
|
||||
if !ready {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// crdsAreReady polls the API server to see if the Velero CRDs are ready to create objects.
|
||||
func crdsAreReady(kbClient kbclient.Client, crds []*unstructured.Unstructured) (bool, error) {
|
||||
if len(crds) == 0 {
|
||||
// no CRDs to check so return
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// We assume that all Velero CRDs have the same GVK so we can use the GVK of the
|
||||
// first CRD to determine whether to use the v1beta1 or v1 API during polling.
|
||||
gvk := crds[0].GroupVersionKind()
|
||||
|
||||
var crdReadinessFn func() (bool, error)
|
||||
if gvk.Version == "v1beta1" {
|
||||
crdReadinessFn = crdV1Beta1ReadinessFn(kbClient, crds)
|
||||
} else if gvk.Version == "v1" {
|
||||
crdReadinessFn = crdV1ReadinessFn(kbClient, crds)
|
||||
} else {
|
||||
return false, fmt.Errorf("unsupported CRD version %q", gvk.Version)
|
||||
}
|
||||
|
||||
err := wait.PollImmediate(time.Second, time.Minute, crdReadinessFn)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "Error polling for CRDs")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func isAvailable(c appsv1.DeploymentCondition) bool {
|
||||
@@ -282,19 +327,19 @@ func CreateClient(r *unstructured.Unstructured, factory client.DynamicFactory, w
|
||||
// Resources will be sorted into CustomResourceDefinitions and any other resource type, and the function will wait up to 1 minute
|
||||
// for CRDs to be ready before proceeding.
|
||||
// An io.Writer can be used to output to a log or the console.
|
||||
func Install(factory client.DynamicFactory, resources *unstructured.UnstructuredList, w io.Writer) error {
|
||||
func Install(dynamicFactory client.DynamicFactory, kbClient kbclient.Client, resources *unstructured.UnstructuredList, w io.Writer) error {
|
||||
rg := GroupResources(resources)
|
||||
|
||||
//Install CRDs first
|
||||
for _, r := range rg.CRDResources {
|
||||
if err := createResource(r, factory, w); err != nil {
|
||||
if err := createResource(r, dynamicFactory, w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for CRDs to be ready before proceeding
|
||||
fmt.Fprint(w, "Waiting for resources to be ready in cluster...\n")
|
||||
_, err := crdsAreReady(factory, []string{"backupstoragelocations.velero.io", "volumesnapshotlocations.velero.io"})
|
||||
_, err := crdsAreReady(kbClient, rg.CRDResources)
|
||||
if err == wait.ErrWaitTimeout {
|
||||
return errors.Errorf("timeout reached, CRDs not ready")
|
||||
} else if err != nil {
|
||||
@@ -303,7 +348,7 @@ func Install(factory client.DynamicFactory, resources *unstructured.Unstructured
|
||||
|
||||
// Install all other resources
|
||||
for _, r := range rg.OtherResources {
|
||||
if err = createResource(r, factory, w); err != nil {
|
||||
if err = createResource(r, dynamicFactory, w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -19,30 +19,19 @@ package install
|
||||
import (
|
||||
"time"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1beta1 "k8s.io/api/rbac/v1beta1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/vmware-tanzu/velero/config/crd/crds"
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
v1crds "github.com/vmware-tanzu/velero/config/crd/v1/crds"
|
||||
v1beta1crds "github.com/vmware-tanzu/velero/config/crd/v1beta1/crds"
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
)
|
||||
|
||||
// Use "latest" if the build process didn't supply a version
|
||||
func imageVersion() string {
|
||||
if buildinfo.Version == "" {
|
||||
return "latest"
|
||||
}
|
||||
return buildinfo.Version
|
||||
}
|
||||
|
||||
// DefaultImage is the default image to use for the Velero deployment and restic daemonset containers.
|
||||
var (
|
||||
DefaultImage = "velero/velero:" + imageVersion()
|
||||
DefaultVeleroPodCPURequest = "500m"
|
||||
DefaultVeleroPodMemRequest = "128Mi"
|
||||
DefaultVeleroPodCPULimit = "1000m"
|
||||
@@ -105,25 +94,25 @@ func ServiceAccount(namespace string, annotations map[string]string) *corev1.Ser
|
||||
}
|
||||
}
|
||||
|
||||
func ClusterRoleBinding(namespace string) *rbacv1beta1.ClusterRoleBinding {
|
||||
func ClusterRoleBinding(namespace string) *rbacv1.ClusterRoleBinding {
|
||||
crbName := "velero"
|
||||
if namespace != DefaultVeleroNamespace {
|
||||
crbName = "velero-" + namespace
|
||||
}
|
||||
crb := &rbacv1beta1.ClusterRoleBinding{
|
||||
crb := &rbacv1.ClusterRoleBinding{
|
||||
ObjectMeta: objectMeta("", crbName),
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ClusterRoleBinding",
|
||||
APIVersion: rbacv1beta1.SchemeGroupVersion.String(),
|
||||
APIVersion: rbacv1.SchemeGroupVersion.String(),
|
||||
},
|
||||
Subjects: []rbacv1beta1.Subject{
|
||||
Subjects: []rbacv1.Subject{
|
||||
{
|
||||
Kind: "ServiceAccount",
|
||||
Namespace: namespace,
|
||||
Name: "velero",
|
||||
},
|
||||
},
|
||||
RoleRef: rbacv1beta1.RoleRef{
|
||||
RoleRef: rbacv1.RoleRef{
|
||||
Kind: "ClusterRole",
|
||||
Name: "cluster-admin",
|
||||
APIGroup: "rbac.authorization.k8s.io",
|
||||
@@ -227,17 +216,26 @@ type VeleroOptions struct {
|
||||
NoDefaultBackupLocation bool
|
||||
CACertData []byte
|
||||
Features []string
|
||||
CRDsVersion string
|
||||
DefaultVolumesToRestic bool
|
||||
}
|
||||
|
||||
func AllCRDs() *unstructured.UnstructuredList {
|
||||
func AllCRDs(perferredAPIVersion string) *unstructured.UnstructuredList {
|
||||
resources := new(unstructured.UnstructuredList)
|
||||
// Set the GVK so that the serialization framework outputs the list properly
|
||||
resources.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "List"})
|
||||
|
||||
for _, crd := range crds.CRDs {
|
||||
crd.SetLabels(Labels())
|
||||
appendUnstructured(resources, crd)
|
||||
switch perferredAPIVersion {
|
||||
case "v1beta1":
|
||||
for _, crd := range v1beta1crds.CRDs {
|
||||
crd.SetLabels(Labels())
|
||||
appendUnstructured(resources, crd)
|
||||
}
|
||||
case "v1":
|
||||
for _, crd := range v1crds.CRDs {
|
||||
crd.SetLabels(Labels())
|
||||
appendUnstructured(resources, crd)
|
||||
}
|
||||
}
|
||||
|
||||
return resources
|
||||
@@ -245,8 +243,8 @@ func AllCRDs() *unstructured.UnstructuredList {
|
||||
|
||||
// AllResources returns a list of all resources necessary to install Velero, in the appropriate order, into a Kubernetes cluster.
|
||||
// Items are unstructured, since there are different data types returned.
|
||||
func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) {
|
||||
resources := AllCRDs()
|
||||
func AllResources(o *VeleroOptions) *unstructured.UnstructuredList {
|
||||
resources := AllCRDs(o.CRDsVersion)
|
||||
|
||||
ns := Namespace(o.Namespace)
|
||||
appendUnstructured(resources, ns)
|
||||
@@ -317,5 +315,5 @@ func AllResources(o *VeleroOptions) (*unstructured.UnstructuredList, error) {
|
||||
appendUnstructured(resources, ds)
|
||||
}
|
||||
|
||||
return resources, nil
|
||||
return resources
|
||||
}
|
||||
|
||||
@@ -100,9 +100,20 @@ func isPVBMatchPod(pvb *velerov1api.PodVolumeBackup, podName string, namespace s
|
||||
return podName == pvb.Spec.Pod.Name && namespace == pvb.Spec.Pod.Namespace
|
||||
}
|
||||
|
||||
// volumeIsProjected checks if the given volume exists in the list of podVolumes
|
||||
// and returns true if the volume has a projected source
|
||||
func volumeIsProjected(volumeName string, podVolumes []corev1api.Volume) bool {
|
||||
for _, volume := range podVolumes {
|
||||
if volume.Name == volumeName && volume.Projected != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetVolumeBackupsForPod returns a map, of volume name -> snapshot id,
|
||||
// of the PodVolumeBackups that exist for the provided pod.
|
||||
func GetVolumeBackupsForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, pod metav1.Object, sourcePodNs string) map[string]string {
|
||||
func GetVolumeBackupsForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, pod *corev1api.Pod, sourcePodNs string) map[string]string {
|
||||
volumes := make(map[string]string)
|
||||
|
||||
for _, pvb := range podVolumeBackups {
|
||||
@@ -116,6 +127,13 @@ func GetVolumeBackupsForPod(podVolumeBackups []*velerov1api.PodVolumeBackup, pod
|
||||
continue
|
||||
}
|
||||
|
||||
// If the volume came from a projected source, skip its restore.
|
||||
// This allows backups affected by https://github.com/vmware-tanzu/velero/issues/3863
|
||||
// to be restored successfully.
|
||||
if volumeIsProjected(pvb.Spec.Volume, pod.Spec.Volumes) {
|
||||
continue
|
||||
}
|
||||
|
||||
volumes[pvb.Spec.Volume] = pvb.Status.SnapshotID
|
||||
}
|
||||
|
||||
@@ -183,6 +201,10 @@ func GetPodVolumesUsingRestic(pod *corev1api.Pod, defaultVolumesToRestic bool) [
|
||||
if pv.ConfigMap != nil {
|
||||
continue
|
||||
}
|
||||
// don't backup volumes mounted as projected volumes, all data in those come from kube state.
|
||||
if pv.Projected != nil {
|
||||
continue
|
||||
}
|
||||
// don't backup volumes that are included in the exclude list.
|
||||
if contains(volsToExclude, pv.Name) {
|
||||
continue
|
||||
|
||||
@@ -37,6 +37,7 @@ func TestGetVolumeBackupsForPod(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
podVolumeBackups []*velerov1api.PodVolumeBackup
|
||||
podVolumes []corev1api.Volume
|
||||
podAnnotations map[string]string
|
||||
podName string
|
||||
sourcePodNs string
|
||||
@@ -127,6 +128,30 @@ func TestGetVolumeBackupsForPod(t *testing.T) {
|
||||
sourcePodNs: "TestNS",
|
||||
expected: map[string]string{"pvbtest1-foo": "snapshot1"},
|
||||
},
|
||||
{
|
||||
name: "volumes from PVBs that correspond to a pod volume from a projected source are not returned",
|
||||
podVolumeBackups: []*velerov1api.PodVolumeBackup{
|
||||
builder.ForPodVolumeBackup("velero", "pvb-1").PodName("TestPod").PodNamespace("TestNS").SnapshotID("snapshot1").Volume("pvb-non-projected").Result(),
|
||||
builder.ForPodVolumeBackup("velero", "pvb-1").PodName("TestPod").PodNamespace("TestNS").SnapshotID("snapshot2").Volume("pvb-projected").Result(),
|
||||
},
|
||||
podVolumes: []corev1api.Volume{
|
||||
{
|
||||
Name: "pvb-non-projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "pvb-projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
Projected: &corev1api.ProjectedVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
podName: "TestPod",
|
||||
sourcePodNs: "TestNS",
|
||||
expected: map[string]string{"pvb-non-projected": "snapshot1"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -134,6 +159,7 @@ func TestGetVolumeBackupsForPod(t *testing.T) {
|
||||
pod := &corev1api.Pod{}
|
||||
pod.Annotations = test.podAnnotations
|
||||
pod.Name = test.podName
|
||||
pod.Spec.Volumes = test.podVolumes
|
||||
|
||||
res := GetVolumeBackupsForPod(test.podVolumeBackups, pod, test.sourcePodNs)
|
||||
assert.Equal(t, test.expected, res)
|
||||
@@ -507,6 +533,41 @@ func TestGetPodVolumesUsingRestic(t *testing.T) {
|
||||
},
|
||||
expected: []string{"resticPV1", "resticPV2", "resticPV3"},
|
||||
},
|
||||
{
|
||||
name: "should exclude projected volumes",
|
||||
defaultVolumesToRestic: true,
|
||||
pod: &corev1api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
VolumesToExcludeAnnotation: "nonResticPV1,nonResticPV2,nonResticPV3",
|
||||
},
|
||||
},
|
||||
Spec: corev1api.PodSpec{
|
||||
Volumes: []corev1api.Volume{
|
||||
{Name: "resticPV1"}, {Name: "resticPV2"}, {Name: "resticPV3"},
|
||||
{
|
||||
Name: "projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
Projected: &corev1api.ProjectedVolumeSource{
|
||||
Sources: []corev1api.VolumeProjection{{
|
||||
Secret: &corev1api.SecretProjection{
|
||||
LocalObjectReference: corev1api.LocalObjectReference{},
|
||||
Items: nil,
|
||||
Optional: nil,
|
||||
},
|
||||
DownwardAPI: nil,
|
||||
ConfigMap: nil,
|
||||
ServiceAccountToken: nil,
|
||||
}},
|
||||
DefaultMode: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"resticPV1", "resticPV2", "resticPV3"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -594,3 +655,78 @@ func TestIsPVBMatchPod(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestVolumeIsProjected(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
volumeName string
|
||||
podVolumes []corev1api.Volume
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "volume name not in list of volumes",
|
||||
volumeName: "missing-volume",
|
||||
podVolumes: []corev1api.Volume{
|
||||
{
|
||||
Name: "non-projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
Projected: &corev1api.ProjectedVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "volume name in list of volumes but not projected",
|
||||
volumeName: "non-projected",
|
||||
podVolumes: []corev1api.Volume{
|
||||
{
|
||||
Name: "non-projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
Projected: &corev1api.ProjectedVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "volume name in list of volumes and projected",
|
||||
volumeName: "projected",
|
||||
podVolumes: []corev1api.Volume{
|
||||
{
|
||||
Name: "non-projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "projected",
|
||||
VolumeSource: corev1api.VolumeSource{
|
||||
Projected: &corev1api.ProjectedVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual := volumeIsProjected(tc.volumeName, tc.podVolumes)
|
||||
assert.Equal(t, tc.expected, actual)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
51
pkg/restore/apiservice_action.go
Normal file
51
pkg/restore/apiservice_action.go
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 (
|
||||
"github.com/sirupsen/logrus"
|
||||
"k8s.io/kube-aggregator/pkg/controllers/autoregister"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
)
|
||||
|
||||
type APIServiceAction struct {
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// NewAPIServiceAction returns an APIServiceAction which is a RestoreItemAction plugin
|
||||
// that will skip the restore of any APIServices which are managed by Kubernetes. This
|
||||
// is determined by looking for the "kube-aggregator.kubernetes.io/automanaged" label on
|
||||
// the APIService.
|
||||
func NewAPIServiceAction(logger logrus.FieldLogger) *APIServiceAction {
|
||||
return &APIServiceAction{logger: logger}
|
||||
}
|
||||
|
||||
func (a *APIServiceAction) AppliesTo() (velero.ResourceSelector, error) {
|
||||
return velero.ResourceSelector{
|
||||
IncludedResources: []string{"apiservices"},
|
||||
LabelSelector: autoregister.AutoRegisterManagedLabel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *APIServiceAction) Execute(input *velero.RestoreItemActionExecuteInput) (*velero.RestoreItemActionExecuteOutput, error) {
|
||||
a.logger.Info("Executing APIServiceAction")
|
||||
defer a.logger.Info("Done executing APIServiceAction")
|
||||
|
||||
a.logger.Infof("Skipping restore of APIService as it is managed by Kubernetes")
|
||||
return velero.NewRestoreItemActionExecuteOutput(input.Item).WithoutRestore(), nil
|
||||
}
|
||||
53
pkg/restore/apiservice_action_test.go
Normal file
53
pkg/restore/apiservice_action_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
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/require"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
func TestAPIServiceActionExecuteSkipsRestore(t *testing.T) {
|
||||
obj := apiregistrationv1.APIService{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "v1.test.velero.io",
|
||||
},
|
||||
}
|
||||
|
||||
unstructuredAPIService, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&obj)
|
||||
require.NoError(t, err)
|
||||
|
||||
action := NewAPIServiceAction(velerotest.NewLogger())
|
||||
res, err := action.Execute(&velero.RestoreItemActionExecuteInput{
|
||||
Item: &unstructured.Unstructured{Object: unstructuredAPIService},
|
||||
ItemFromBackup: &unstructured.Unstructured{Object: unstructuredAPIService},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
var apiService apiregistrationv1.APIService
|
||||
require.NoError(t, runtime.DefaultUnstructuredConverter.FromUnstructured(res.UpdatedItem.UnstructuredContent(), &apiService))
|
||||
require.Equal(t, obj, apiService)
|
||||
require.Equal(t, true, res.SkipRestore)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2018, 2019, 2020 the Velero contributors.
|
||||
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.
|
||||
@@ -29,9 +29,9 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
veleroimage "github.com/vmware-tanzu/velero/internal/velero"
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/label"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/framework"
|
||||
@@ -41,7 +41,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultImageBase = "velero/velero-restic-restore-helper"
|
||||
defaultCPURequestLimit = "100m"
|
||||
defaultMemRequestLimit = "128Mi"
|
||||
defaultCommand = "/velero-restic-restore-helper"
|
||||
@@ -193,13 +192,13 @@ func getCommand(log logrus.FieldLogger, config *corev1.ConfigMap) []string {
|
||||
func getImage(log logrus.FieldLogger, config *corev1.ConfigMap) string {
|
||||
if config == nil {
|
||||
log.Debug("No config found for plugin")
|
||||
return initContainerImage(defaultImageBase)
|
||||
return veleroimage.DefaultResticRestoreHelperImage()
|
||||
}
|
||||
|
||||
image := config.Data["image"]
|
||||
if image == "" {
|
||||
log.Debugf("No custom image configured")
|
||||
return initContainerImage(defaultImageBase)
|
||||
return veleroimage.DefaultResticRestoreHelperImage()
|
||||
}
|
||||
|
||||
log = log.WithField("image", image)
|
||||
@@ -207,15 +206,17 @@ func getImage(log logrus.FieldLogger, config *corev1.ConfigMap) string {
|
||||
parts := strings.Split(image, "/")
|
||||
|
||||
if len(parts) == 1 {
|
||||
defaultImage := veleroimage.DefaultResticRestoreHelperImage()
|
||||
// Image supplied without registry part
|
||||
log.Debugf("Plugin config contains image name without registry name. Return defaultImageBase")
|
||||
return initContainerImage(defaultImageBase)
|
||||
log.Infof("Plugin config contains image name without registry name. Using default init container image: %q", defaultImage)
|
||||
return defaultImage
|
||||
}
|
||||
|
||||
if !(strings.Contains(parts[len(parts)-1], ":")) {
|
||||
// tag-less image name: add tag
|
||||
log.Debugf("Plugin config contains image name without tag. Adding tag.")
|
||||
return initContainerImage(image)
|
||||
tag := veleroimage.ImageTag()
|
||||
// tag-less image name: add default image tag for this version of Velero
|
||||
log.Infof("Plugin config contains image name without tag. Adding tag: %q", tag)
|
||||
return fmt.Sprintf("%s:%s", image, tag)
|
||||
} else {
|
||||
// tagged image name
|
||||
log.Debugf("Plugin config contains image name with tag")
|
||||
@@ -306,12 +307,3 @@ func newResticInitContainerBuilder(image, restoreUID string) *builder.ContainerB
|
||||
},
|
||||
}...)
|
||||
}
|
||||
|
||||
func initContainerImage(imageBase string) string {
|
||||
tag := buildinfo.Version
|
||||
if tag == "" {
|
||||
tag = "latest"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s:%s", imageBase, tag)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
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.
|
||||
@@ -18,7 +18,6 @@ package restore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
@@ -31,6 +30,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
veleroimage "github.com/vmware-tanzu/velero/internal/velero"
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
"github.com/vmware-tanzu/velero/pkg/buildinfo"
|
||||
@@ -49,41 +49,40 @@ func TestGetImage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
originalVersion := buildinfo.Version
|
||||
buildinfo.Version = "buildinfo-version"
|
||||
defer func() {
|
||||
buildinfo.Version = originalVersion
|
||||
}()
|
||||
defaultImage := veleroimage.DefaultResticRestoreHelperImage()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
configMap *corev1api.ConfigMap
|
||||
want string
|
||||
name string
|
||||
configMap *corev1api.ConfigMap
|
||||
buildInfoVersion string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "nil config map returns default image with buildinfo.Version as tag",
|
||||
name: "nil config map returns default image",
|
||||
configMap: nil,
|
||||
want: fmt.Sprintf("%s:%s", defaultImageBase, buildinfo.Version),
|
||||
want: defaultImage,
|
||||
},
|
||||
{
|
||||
name: "config map without 'image' key returns default image with buildinfo.Version as tag",
|
||||
name: "config map without 'image' key returns default image",
|
||||
configMap: configMapWithData("non-matching-key", "val"),
|
||||
want: fmt.Sprintf("%s:%s", defaultImageBase, buildinfo.Version),
|
||||
want: defaultImage,
|
||||
},
|
||||
{
|
||||
name: "config map without '/' in image name returns default image with buildinfo.Version as tag",
|
||||
name: "config map without '/' in image name returns default image",
|
||||
configMap: configMapWithData("image", "my-image"),
|
||||
want: fmt.Sprintf("%s:%s", defaultImageBase, buildinfo.Version),
|
||||
want: defaultImage,
|
||||
},
|
||||
{
|
||||
name: "config map with untagged image returns image with buildinfo.Version as tag",
|
||||
configMap: configMapWithData("image", "myregistry.io/my-image"),
|
||||
want: fmt.Sprintf("%s:%s", "myregistry.io/my-image", buildinfo.Version),
|
||||
name: "config map with untagged image returns image with buildinfo.Version as tag",
|
||||
configMap: configMapWithData("image", "myregistry.io/my-image"),
|
||||
buildInfoVersion: "buildinfo-version",
|
||||
want: "myregistry.io/my-image:buildinfo-version",
|
||||
},
|
||||
{
|
||||
name: "config map with untagged image and custom registry port with ':' returns image with buildinfo.Version as tag",
|
||||
configMap: configMapWithData("image", "myregistry.io:34567/my-image"),
|
||||
want: fmt.Sprintf("%s:%s", "myregistry.io:34567/my-image", buildinfo.Version),
|
||||
name: "config map with untagged image and custom registry port with ':' returns image with buildinfo.Version as tag",
|
||||
configMap: configMapWithData("image", "myregistry.io:34567/my-image"),
|
||||
buildInfoVersion: "buildinfo-version",
|
||||
want: "myregistry.io:34567/my-image:buildinfo-version",
|
||||
},
|
||||
{
|
||||
name: "config map with tagged image returns tagged image",
|
||||
@@ -99,6 +98,13 @@ func TestGetImage(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.buildInfoVersion != "" {
|
||||
originalVersion := buildinfo.Version
|
||||
buildinfo.Version = test.buildInfoVersion
|
||||
defer func() {
|
||||
buildinfo.Version = originalVersion
|
||||
}()
|
||||
}
|
||||
assert.Equal(t, test.want, getImage(velerotest.NewLogger(), test.configMap))
|
||||
})
|
||||
}
|
||||
@@ -119,6 +125,8 @@ func TestResticRestoreActionExecute(t *testing.T) {
|
||||
veleroNs = "velero"
|
||||
)
|
||||
|
||||
defaultResticRestoreHelperImage := veleroimage.DefaultResticRestoreHelperImage()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pod *corev1api.Pod
|
||||
@@ -135,7 +143,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
|
||||
ObjectMeta(
|
||||
builder.WithAnnotations("snapshot.velero.io/myvol", "")).
|
||||
InitContainers(
|
||||
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
|
||||
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
|
||||
Resources(&resourceReqs).
|
||||
SecurityContext(&securityContext).
|
||||
VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()).
|
||||
@@ -152,7 +160,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
|
||||
ObjectMeta(
|
||||
builder.WithAnnotations("snapshot.velero.io/myvol", "")).
|
||||
InitContainers(
|
||||
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
|
||||
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
|
||||
Resources(&resourceReqs).
|
||||
SecurityContext(&securityContext).
|
||||
VolumeMounts(builder.ForVolumeMount("myvol", "/restores/myvol").Result()).
|
||||
@@ -195,7 +203,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
|
||||
ObjectMeta(
|
||||
builder.WithAnnotations("snapshot.velero.io/not-used", "")).
|
||||
InitContainers(
|
||||
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
|
||||
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
|
||||
Resources(&resourceReqs).
|
||||
SecurityContext(&securityContext).
|
||||
VolumeMounts(builder.ForVolumeMount("vol-1", "/restores/vol-1").Result(), builder.ForVolumeMount("vol-2", "/restores/vol-2").Result()).
|
||||
@@ -239,7 +247,7 @@ func TestResticRestoreActionExecute(t *testing.T) {
|
||||
builder.ForVolume("vol-2").PersistentVolumeClaimSource("pvc-2").Result(),
|
||||
).
|
||||
InitContainers(
|
||||
newResticInitContainerBuilder(initContainerImage(defaultImageBase), "").
|
||||
newResticInitContainerBuilder(defaultResticRestoreHelperImage, "").
|
||||
Resources(&resourceReqs).
|
||||
SecurityContext(&securityContext).
|
||||
VolumeMounts(builder.ForVolumeMount("vol-1", "/restores/vol-1").Result(), builder.ForVolumeMount("vol-2", "/restores/vol-2").Result()).
|
||||
|
||||
@@ -377,6 +377,10 @@ func getOrderedResources(resourcePriorities []string, backupResources map[string
|
||||
return append(resourcePriorities, orderedBackupResources...)
|
||||
}
|
||||
|
||||
type progressUpdate struct {
|
||||
totalItems, itemsRestored int
|
||||
}
|
||||
|
||||
func (ctx *restoreContext) execute() (Result, Result) {
|
||||
warnings, errs := Result{}, Result{}
|
||||
|
||||
@@ -409,14 +413,6 @@ func (ctx *restoreContext) execute() (Result, Result) {
|
||||
}
|
||||
}
|
||||
|
||||
selectedResourceCollection, w, e := ctx.getOrderedResourceCollection(backupResources)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
|
||||
type progressUpdate struct {
|
||||
totalItems, itemsRestored int
|
||||
}
|
||||
|
||||
update := make(chan progressUpdate)
|
||||
|
||||
quit := make(chan struct{})
|
||||
@@ -456,94 +452,69 @@ func (ctx *restoreContext) execute() (Result, Result) {
|
||||
}()
|
||||
|
||||
// totalItems: previously discovered items, i: iteration counter.
|
||||
totalItems, i, existingNamespaces := 0, 0, sets.NewString()
|
||||
totalItems, processedItems, existingNamespaces := 0, 0, sets.NewString()
|
||||
|
||||
// First restore CRDs. This is needed so that they are available in the cluster
|
||||
// when getOrderedResourceCollection is called again on the whole backup and
|
||||
// needs to validate all resources listed.
|
||||
crdResourceCollection, processedResources, w, e := ctx.getOrderedResourceCollection(
|
||||
backupResources,
|
||||
make([]restoreableResource, 0),
|
||||
sets.NewString(),
|
||||
[]string{"customresourcedefinitions"},
|
||||
false,
|
||||
)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
|
||||
for _, selectedResource := range crdResourceCollection {
|
||||
totalItems += selectedResource.totalItems
|
||||
}
|
||||
|
||||
for _, selectedResource := range crdResourceCollection {
|
||||
var w, e Result
|
||||
// Restore this resource
|
||||
processedItems, w, e = ctx.processSelectedResource(
|
||||
selectedResource,
|
||||
totalItems,
|
||||
processedItems,
|
||||
existingNamespaces,
|
||||
update,
|
||||
)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
}
|
||||
|
||||
// Restore everything else
|
||||
selectedResourceCollection, _, w, e := ctx.getOrderedResourceCollection(
|
||||
backupResources,
|
||||
crdResourceCollection,
|
||||
processedResources,
|
||||
ctx.resourcePriorities,
|
||||
true,
|
||||
)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
|
||||
// reset processedItems and totalItems before processing full resource list
|
||||
processedItems = 0
|
||||
totalItems = 0
|
||||
for _, selectedResource := range selectedResourceCollection {
|
||||
totalItems += selectedResource.totalItems
|
||||
}
|
||||
|
||||
for _, selectedResource := range selectedResourceCollection {
|
||||
groupResource := schema.ParseGroupResource(selectedResource.resource)
|
||||
|
||||
for namespace, selectedItems := range selectedResource.selectedItemsByNamespace {
|
||||
for _, selectedItem := range selectedItems {
|
||||
// If we don't know whether this namespace exists yet, attempt to create
|
||||
// it in order to ensure it exists. Try to get it from the backup tarball
|
||||
// (in order to get any backed-up metadata), but if we don't find it there,
|
||||
// create a blank one.
|
||||
if namespace != "" && !existingNamespaces.Has(selectedItem.targetNamespace) {
|
||||
logger := ctx.log.WithField("namespace", namespace)
|
||||
|
||||
ns := getNamespace(
|
||||
logger,
|
||||
archive.GetItemFilePath(ctx.restoreDir, "namespaces", "", namespace),
|
||||
selectedItem.targetNamespace,
|
||||
)
|
||||
_, nsCreated, err := kube.EnsureNamespaceExistsAndIsReady(
|
||||
ns,
|
||||
ctx.namespaceClient,
|
||||
ctx.resourceTerminatingTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
errs.AddVeleroError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Add the newly created namespace to the list of restored items.
|
||||
if nsCreated {
|
||||
itemKey := velero.ResourceIdentifier{
|
||||
GroupResource: kuberesource.Namespaces,
|
||||
Namespace: ns.Namespace,
|
||||
Name: ns.Name,
|
||||
}
|
||||
ctx.restoredItems[itemKey] = struct{}{}
|
||||
}
|
||||
|
||||
// Keep track of namespaces that we know exist so we don't
|
||||
// have to try to create them multiple times.
|
||||
existingNamespaces.Insert(selectedItem.targetNamespace)
|
||||
}
|
||||
|
||||
obj, err := archive.Unmarshal(ctx.fileSystem, selectedItem.path)
|
||||
if err != nil {
|
||||
errs.Add(
|
||||
selectedItem.targetNamespace,
|
||||
fmt.Errorf(
|
||||
"error decoding %q: %v",
|
||||
strings.Replace(selectedItem.path, ctx.restoreDir+"/", "", -1),
|
||||
err,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
w, e := ctx.restoreItem(obj, groupResource, selectedItem.targetNamespace)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
i++
|
||||
|
||||
// totalItems keeps the count of items previously known. There
|
||||
// may be additional items restored by plugins. We want to include
|
||||
// the additional items by looking at restoredItems at the same
|
||||
// time, we don't want previously known items counted twice as
|
||||
// they are present in both restoredItems and totalItems.
|
||||
actualTotalItems := len(ctx.restoredItems) + (totalItems - i)
|
||||
update <- progressUpdate{
|
||||
totalItems: actualTotalItems,
|
||||
itemsRestored: len(ctx.restoredItems),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we just restored custom resource definitions (CRDs), refresh
|
||||
// discovery because the restored CRDs may have created new APIs that
|
||||
// didn't previously exist in the cluster, and we want to be able to
|
||||
// resolve & restore instances of them in subsequent loop iterations.
|
||||
if groupResource == kuberesource.CustomResourceDefinitions {
|
||||
if err := ctx.discoveryHelper.Refresh(); err != nil {
|
||||
warnings.Add("", errors.Wrap(err, "refresh discovery after restoring CRDs"))
|
||||
}
|
||||
}
|
||||
var w, e Result
|
||||
// Restore this resource
|
||||
processedItems, w, e = ctx.processSelectedResource(
|
||||
selectedResource,
|
||||
totalItems,
|
||||
processedItems,
|
||||
existingNamespaces,
|
||||
update,
|
||||
)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
}
|
||||
|
||||
// Close the progress update channel.
|
||||
@@ -605,6 +576,107 @@ func (ctx *restoreContext) execute() (Result, Result) {
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
// Process and restore one restoreableResource from the backup and update restore progress
|
||||
// metadata. At this point, the resource has already been validated and counted for inclusion
|
||||
// in the expected total restore count.
|
||||
func (ctx *restoreContext) processSelectedResource(
|
||||
selectedResource restoreableResource,
|
||||
totalItems int,
|
||||
processedItems int,
|
||||
existingNamespaces sets.String,
|
||||
update chan progressUpdate,
|
||||
) (int, Result, Result) {
|
||||
warnings, errs := Result{}, Result{}
|
||||
groupResource := schema.ParseGroupResource(selectedResource.resource)
|
||||
|
||||
for namespace, selectedItems := range selectedResource.selectedItemsByNamespace {
|
||||
for _, selectedItem := range selectedItems {
|
||||
// If we don't know whether this namespace exists yet, attempt to create
|
||||
// it in order to ensure it exists. Try to get it from the backup tarball
|
||||
// (in order to get any backed-up metadata), but if we don't find it there,
|
||||
// create a blank one.
|
||||
if namespace != "" && !existingNamespaces.Has(selectedItem.targetNamespace) {
|
||||
logger := ctx.log.WithField("namespace", namespace)
|
||||
|
||||
ns := getNamespace(
|
||||
logger,
|
||||
archive.GetItemFilePath(ctx.restoreDir, "namespaces", "", namespace),
|
||||
selectedItem.targetNamespace,
|
||||
)
|
||||
_, nsCreated, err := kube.EnsureNamespaceExistsAndIsReady(
|
||||
ns,
|
||||
ctx.namespaceClient,
|
||||
ctx.resourceTerminatingTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
errs.AddVeleroError(err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Add the newly created namespace to the list of restored items.
|
||||
if nsCreated {
|
||||
itemKey := velero.ResourceIdentifier{
|
||||
GroupResource: kuberesource.Namespaces,
|
||||
Namespace: ns.Namespace,
|
||||
Name: ns.Name,
|
||||
}
|
||||
ctx.restoredItems[itemKey] = struct{}{}
|
||||
}
|
||||
|
||||
// Keep track of namespaces that we know exist so we don't
|
||||
// have to try to create them multiple times.
|
||||
existingNamespaces.Insert(selectedItem.targetNamespace)
|
||||
}
|
||||
|
||||
obj, err := archive.Unmarshal(ctx.fileSystem, selectedItem.path)
|
||||
if err != nil {
|
||||
errs.Add(
|
||||
selectedItem.targetNamespace,
|
||||
fmt.Errorf(
|
||||
"error decoding %q: %v",
|
||||
strings.Replace(selectedItem.path, ctx.restoreDir+"/", "", -1),
|
||||
err,
|
||||
),
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
w, e := ctx.restoreItem(obj, groupResource, selectedItem.targetNamespace)
|
||||
warnings.Merge(&w)
|
||||
errs.Merge(&e)
|
||||
processedItems++
|
||||
|
||||
// totalItems keeps the count of items previously known. There
|
||||
// may be additional items restored by plugins. We want to include
|
||||
// the additional items by looking at restoredItems at the same
|
||||
// time, we don't want previously known items counted twice as
|
||||
// they are present in both restoredItems and totalItems.
|
||||
actualTotalItems := len(ctx.restoredItems) + (totalItems - processedItems)
|
||||
update <- progressUpdate{
|
||||
totalItems: actualTotalItems,
|
||||
itemsRestored: len(ctx.restoredItems),
|
||||
}
|
||||
ctx.log.WithFields(map[string]interface{}{
|
||||
"progress": "",
|
||||
"resource": groupResource.String(),
|
||||
"namespace": selectedItem.targetNamespace,
|
||||
"name": selectedItem.name,
|
||||
}).Infof("Restored %d items out of an estimated total of %d (estimate will change throughout the restore)", len(ctx.restoredItems), actualTotalItems)
|
||||
}
|
||||
}
|
||||
|
||||
// If we just restored custom resource definitions (CRDs), refresh
|
||||
// discovery because the restored CRDs may have created new APIs that
|
||||
// didn't previously exist in the cluster, and we want to be able to
|
||||
// resolve & restore instances of them in subsequent loop iterations.
|
||||
if groupResource == kuberesource.CustomResourceDefinitions {
|
||||
if err := ctx.discoveryHelper.Refresh(); err != nil {
|
||||
warnings.Add("", errors.Wrap(err, "refresh discovery after restoring CRDs"))
|
||||
}
|
||||
}
|
||||
return processedItems, warnings, errs
|
||||
}
|
||||
|
||||
// getNamespace returns a namespace API object that we should attempt to
|
||||
// create before restoring anything into it. It will come from the backup
|
||||
// tarball if it exists, else will be a new one. If from the tarball, it
|
||||
@@ -1232,8 +1304,16 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
if groupResource == kuberesource.Pods && len(restic.GetVolumeBackupsForPod(ctx.podVolumeBackups, obj, originalNamespace)) > 0 {
|
||||
restorePodVolumeBackups(ctx, createdObj, originalNamespace)
|
||||
if groupResource == kuberesource.Pods {
|
||||
pod := new(v1.Pod)
|
||||
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), pod); err != nil {
|
||||
errs.Add(namespace, err)
|
||||
return warnings, errs
|
||||
}
|
||||
|
||||
if len(restic.GetVolumeBackupsForPod(ctx.podVolumeBackups, pod, originalNamespace)) > 0 {
|
||||
restorePodVolumeBackups(ctx, createdObj, originalNamespace)
|
||||
}
|
||||
}
|
||||
|
||||
if groupResource == kuberesource.Pods {
|
||||
@@ -1559,10 +1639,14 @@ type restoreableItem struct {
|
||||
// identifiers, applies resource include/exclude criteria, and Kubernetes
|
||||
// selectors to make a list of resources to be actually restored preserving the
|
||||
// original order.
|
||||
func (ctx *restoreContext) getOrderedResourceCollection(backupResources map[string]*archive.ResourceItems) ([]restoreableResource, Result, Result) {
|
||||
func (ctx *restoreContext) getOrderedResourceCollection(
|
||||
backupResources map[string]*archive.ResourceItems,
|
||||
restoreResourceCollection []restoreableResource,
|
||||
processedResources sets.String,
|
||||
resourcePriorities []string,
|
||||
includeAllResources bool,
|
||||
) ([]restoreableResource, sets.String, Result, Result) {
|
||||
var warnings, errs Result
|
||||
processedResources := sets.NewString()
|
||||
restoreResourceCollection := make([]restoreableResource, 0)
|
||||
// Iterate through an ordered list of resources to restore, checking each
|
||||
// one to see if it should be restored. Note that resources *may* be in this
|
||||
// list twice, i.e. once due to being a prioritized resource, and once due
|
||||
@@ -1577,7 +1661,13 @@ func (ctx *restoreContext) getOrderedResourceCollection(backupResources map[stri
|
||||
// Since we keep track of the fully-resolved group-resources that we *have*
|
||||
// restored, we won't try to restore a resource twice even if it's in the
|
||||
// ordered list twice.
|
||||
for _, resource := range getOrderedResources(ctx.resourcePriorities, backupResources) {
|
||||
var resourceList []string
|
||||
if includeAllResources {
|
||||
resourceList = getOrderedResources(resourcePriorities, backupResources)
|
||||
} else {
|
||||
resourceList = resourcePriorities
|
||||
}
|
||||
for _, resource := range resourceList {
|
||||
// try to resolve the resource via discovery to a complete group/version/resource
|
||||
gvr, _, err := ctx.discoveryHelper.ResourceFor(schema.ParseGroupResource(resource).WithVersion(""))
|
||||
if err != nil {
|
||||
@@ -1650,7 +1740,7 @@ func (ctx *restoreContext) getOrderedResourceCollection(backupResources map[stri
|
||||
// record that we've restored the resource
|
||||
processedResources.Insert(groupResource.String())
|
||||
}
|
||||
return restoreResourceCollection, warnings, errs
|
||||
return restoreResourceCollection, processedResources, warnings, errs
|
||||
}
|
||||
|
||||
// getSelectedRestoreableItems applies Kubernetes selectors on individual items
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 the Velero contributors.
|
||||
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.
|
||||
@@ -1139,6 +1139,22 @@ func TestRestoreActionsRunForCorrectItems(t *testing.T) {
|
||||
new(recordResourcesAction).ForNamespace("ns-1").ForResource("pods"): {"ns-1/pod-1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "single action with a resource and label selector runs only for resources matching that label",
|
||||
restore: defaultRestore().Result(),
|
||||
backup: defaultBackup().Result(),
|
||||
tarball: test.NewTarWriter(t).
|
||||
AddItems("pods",
|
||||
builder.ForPod("ns-1", "pod-1").ObjectMeta(builder.WithLabels("restore-resource", "true")).Result(),
|
||||
builder.ForPod("ns-1", "pod-2").ObjectMeta(builder.WithLabels("do-not-restore-resource", "true")).Result(),
|
||||
builder.ForPod("ns-2", "pod-1").Result(),
|
||||
builder.ForPod("ns-2", "pod-2").ObjectMeta(builder.WithLabels("restore-resource")).Result(),
|
||||
).Done(),
|
||||
apiResources: []*test.APIResource{test.Pods()},
|
||||
actions: map[*recordResourcesAction][]string{
|
||||
new(recordResourcesAction).ForResource("pods").ForLabelSelector("restore-resource"): {"ns-1/pod-1", "ns-2/pod-2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple actions, each with a different resource selector using short name, run for matching resources",
|
||||
restore: defaultRestore().Result(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2017, 2019 the Velero contributors.
|
||||
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.
|
||||
@@ -23,16 +23,14 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
corev1listers "k8s.io/client-go/listers/core/v1"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// NamespaceAndName returns a string in the format <namespace>/<name>
|
||||
@@ -148,8 +146,23 @@ func GetVolumeDirectory(pod *corev1api.Pod, volumeName string, pvcLister corev1l
|
||||
return pvc.Spec.VolumeName, nil
|
||||
}
|
||||
|
||||
// IsCRDReady checks a CRD to see if it's ready, with both the Established and NamesAccepted conditions.
|
||||
func IsCRDReady(crd *apiextv1beta1.CustomResourceDefinition) bool {
|
||||
// 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
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
if cond.Type == apiextv1.Established && cond.Status == apiextv1.ConditionTrue {
|
||||
isEstablished = true
|
||||
}
|
||||
if cond.Type == apiextv1.NamesAccepted && cond.Status == apiextv1.ConditionTrue {
|
||||
namesAccepted = true
|
||||
}
|
||||
}
|
||||
|
||||
return (isEstablished && namesAccepted)
|
||||
}
|
||||
|
||||
// IsV1Beta1CRDReady checks a v1beta1 CRD to see if it's ready, with both the Established and NamesAccepted conditions.
|
||||
func IsV1Beta1CRDReady(crd *apiextv1beta1.CustomResourceDefinition) bool {
|
||||
var isEstablished, namesAccepted bool
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
if cond.Type == apiextv1beta1.Established && cond.Status == apiextv1beta1.ConditionTrue {
|
||||
@@ -164,8 +177,8 @@ func IsCRDReady(crd *apiextv1beta1.CustomResourceDefinition) bool {
|
||||
}
|
||||
|
||||
// IsUnstructuredCRDReady checks an unstructured CRD to see if it's ready, with both the Established and NamesAccepted conditions.
|
||||
// TODO: Delete this function and use IsCRDReady when the upstream runtime.FromUnstructured function properly handles int64 field conversions.
|
||||
// Duplicated function because the velero install package uses IsCRDReady with the beta types.
|
||||
// TODO: Delete this function and use IsV1CRDReady/IsV1Beta1CRDReady when the upstream runtime.FromUnstructured function properly handles int64 field conversions.
|
||||
// Duplicated function because the velero install package uses IsV1CRDReady/IsV1Beta1CRDReady with instances of v1/v1beta1 types.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/87675
|
||||
// This is different from the fix for https://github.com/vmware-tanzu/velero/issues/2319 because here,
|
||||
// we need to account for *both* v1beta1 and v1 CRDs, so doing marshalling into JSON to convert to a Go type may not be as useful here, unless we do
|
||||
@@ -210,6 +223,7 @@ func IsUnstructuredCRDReady(crd *unstructured.Unstructured) (bool, error) {
|
||||
|
||||
// Here is the actual logic of the function
|
||||
// Cast the API's types into strings since we're pulling strings out of the unstructured data.
|
||||
// We are using the v1beta1 constants here but they are the same as the v1 constants.
|
||||
if conditionType == string(apiextv1beta1.Established) && status == string(apiextv1beta1.ConditionTrue) {
|
||||
isEstablished = true
|
||||
}
|
||||
@@ -220,26 +234,3 @@ func IsUnstructuredCRDReady(crd *unstructured.Unstructured) (bool, error) {
|
||||
|
||||
return (isEstablished && namesAccepted), nil
|
||||
}
|
||||
|
||||
// GetClusterClient instantiates and returns a client for the cluster.
|
||||
func GetClusterClient() (*kubernetes.Clientset, *apiextensionsclientset.Clientset, error) {
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
configOverrides := &clientcmd.ConfigOverrides{}
|
||||
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
|
||||
clientConfig, err := kubeConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
client, err := kubernetes.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
extensionClientSet, err := apiextensionsclientset.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return client, extensionClientSet, nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2017 the Velero contributors.
|
||||
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.
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -210,7 +211,7 @@ func TestGetVolumeDirectorySuccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsCRDReady(t *testing.T) {
|
||||
func TestIsV1Beta1CRDReady(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
crd *apiextv1beta1.CustomResourceDefinition
|
||||
@@ -218,33 +219,72 @@ func TestIsCRDReady(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "CRD is not established & not accepting names - not ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").Result(),
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is established & not accepting names - not ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is not established & accepting names - not ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is established & accepting names - ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
Result(),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
result := IsCRDReady(tc.crd)
|
||||
result := IsV1Beta1CRDReady(tc.crd)
|
||||
assert.Equal(t, tc.want, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsV1CRDReady(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
crd *apiextv1.CustomResourceDefinition
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "CRD is not established & not accepting names - not ready",
|
||||
crd: builder.ForV1CustomResourceDefinition("MyCRD").Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is established & not accepting names - not ready",
|
||||
crd: builder.ForV1CustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForV1CustomResourceDefinitionCondition().Type(apiextv1.Established).Status(apiextv1.ConditionTrue).Result()).Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is not established & accepting names - not ready",
|
||||
crd: builder.ForV1CustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForV1CustomResourceDefinitionCondition().Type(apiextv1.NamesAccepted).Status(apiextv1.ConditionTrue).Result()).Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is established & accepting names - ready",
|
||||
crd: builder.ForV1CustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForV1CustomResourceDefinitionCondition().Type(apiextv1.Established).Status(apiextv1.ConditionTrue).Result()).
|
||||
Condition(builder.ForV1CustomResourceDefinitionCondition().Type(apiextv1.NamesAccepted).Status(apiextv1.ConditionTrue).Result()).
|
||||
Result(),
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
result := IsV1CRDReady(tc.crd)
|
||||
assert.Equal(t, tc.want, result)
|
||||
}
|
||||
}
|
||||
@@ -257,26 +297,26 @@ func TestIsUnstructuredCRDReady(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "CRD is not established & not accepting names - not ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").Result(),
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is established & not accepting names - not ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is not established & accepting names - not ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).Result(),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "CRD is established & accepting names - ready",
|
||||
crd: builder.ForCustomResourceDefinition("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
Condition(builder.ForCustomResourceDefinitionCondition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
crd: builder.ForCustomResourceDefinitionV1Beta1("MyCRD").
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.Established).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
Condition(builder.ForCustomResourceDefinitionV1Beta1Condition().Type(apiextv1beta1.NamesAccepted).Status(apiextv1beta1.ConditionTrue).Result()).
|
||||
Result(),
|
||||
want: true,
|
||||
},
|
||||
|
||||
@@ -43,4 +43,14 @@ To run unit tests, use `make test`.
|
||||
|
||||
If you need to add or update the vendored dependencies, see [Vendoring dependencies][11].
|
||||
|
||||
## Using the main branch
|
||||
|
||||
If you are developing or using the main branch, note that you may need to update the Velero CRDs to get new changes as other development work is completed.
|
||||
|
||||
```bash
|
||||
velero install --crds-only --dry-run -o yaml | kubectl apply -f -
|
||||
```
|
||||
|
||||
**NOTE:** You could change the default CRD API version (v1beta1 _or_ v1) if Velero CLI can't discover the Kubernetes preferred CRD API version. The Kubernetes version < 1.16 preferred CRD API version is v1beta1; the Kubernetes version >= 1.16 preferred CRD API version is v1.
|
||||
|
||||
[11]: vendoring-dependencies.md
|
||||
|
||||
@@ -39,6 +39,8 @@ If you're not yet running at least Velero v1.5, see the following:
|
||||
velero install --crds-only --dry-run -o yaml | kubectl apply -f -
|
||||
```
|
||||
|
||||
**NOTE:** You could change the default CRD API version (v1beta1 _or_ v1) if Velero CLI can't discover the Kubernetes preferred CRD API version. The Kubernetes version < 1.16 preferred CRD API version is v1beta1; the Kubernetes version >= 1.16 preferred CRD API version is v1.
|
||||
|
||||
**NOTE:** If you are upgrading Velero in Kubernetes 1.14.x or earlier, you will need to use `kubectl apply`'s `--validate=false` option when applying the CRD configuration above. See [issue 2077][6] and [issue 2311][7] for more context.
|
||||
|
||||
1. Update the container image used by the Velero deployment and, optionally, the restic daemon set:
|
||||
|
||||
@@ -459,7 +459,7 @@ cqlsh:demodb> select * from emp;
|
||||
cqlsh:demodb>
|
||||
```
|
||||
|
||||
It looks like the restore has been successful. Velero v1.1 has successfully restored the Kubenetes objects for the Cassandra application, as well as restored the database and table contents.
|
||||
It looks like the restore has been successful. Velero v1.1 has successfully restored the Kubernetes objects for the Cassandra application, as well as restored the database and table contents.
|
||||
|
||||
## Feedback and Participation
|
||||
|
||||
|
||||
@@ -48,7 +48,8 @@ OUTPUT_DIR := _output/$(GOOS)/$(GOARCH)/bin
|
||||
GINKGO_FOCUS ?=
|
||||
VELERO_CLI ?=$$(pwd)/../../_output/bin/$(GOOS)/$(GOARCH)/velero
|
||||
VELERO_IMAGE ?= velero/velero:main
|
||||
VELERO_NAMESPACE ?=
|
||||
CRDS_VERSION ?= v1
|
||||
VELERO_NAMESPACE ?= velero
|
||||
CREDS_FILE ?=
|
||||
BSL_BUCKET ?=
|
||||
BSL_PREFIX ?=
|
||||
@@ -79,6 +80,7 @@ run: ginkgo
|
||||
@$(GINKGO) -v -focus="$(GINKGO_FOCUS)" . -- -velerocli=$(VELERO_CLI) \
|
||||
-velero-image=$(VELERO_IMAGE) \
|
||||
-velero-namespace=$(VELERO_NAMESPACE) \
|
||||
-crds-version=$(CRDS_VERSION) \
|
||||
-credentials-file=$(CREDS_FILE) \
|
||||
-bucket=$(BSL_BUCKET) \
|
||||
-prefix=$(BSL_PREFIX) \
|
||||
|
||||
@@ -88,9 +88,9 @@ For example, E2E tests can be run from Velero repository roots using the command
|
||||
BSL_CONFIG="resourceGroup=$AZURE_BACKUP_RESOURCE_GROUP,storageAccount=$AZURE_STORAGE_ACCOUNT_ID,subscriptionId=$AZURE_BACKUP_SUBSCRIPTION_ID" BSL_BUCKET=<BUCKET_FOR_E2E_TEST_BACKUP> CREDS_FILE=/path/to/azure-creds CLOUD_PROVIDER=azure make test-e2e
|
||||
```
|
||||
Please refer to `velero-plugin-for-microsoft-azure` documentation for instruction to [set up permissions for Velero](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure#set-permissions-for-velero) and to [set up azure storage account and blob container](https://github.com/vmware-tanzu/velero-plugin-for-microsoft-azure#setup-azure-storage-account-and-blob-container)
|
||||
1. Run Ginko-focused Restore Multi-API Groups tests using an image built for PR #3133 and Minio as the backup storage location:
|
||||
1. Run Ginko-focused Restore Multi-API Groups tests using Minio as the backup storage location:
|
||||
```bash
|
||||
BSL_CONFIG="region=minio,s3ForcePathStyle=\"true\",s3Url=http://192.168.1.124:9000" BSL_PREFIX=veldat BSL_BUCKET=velero CREDS_FILE=~/go/src/github.com/vmware-tanzu/velero/frankie-secrets/credentials-minio PLUGIN_PROVIDER=aws VELERO_IMAGE=projects.registry.vmware.com/tanzu_migrator/velero-pr3133:0.0.5 GINKGO_FOCUS="API group versions" make test-e2e
|
||||
BSL_CONFIG="region=minio,s3ForcePathStyle=\"true\",s3Url=<ip address>:9000" BSL_PREFIX=<prefix> BSL_BUCKET=<bucket> CREDS_FILE=<absolute path to minio credentials file> CLOUD_PROVIDER=kind OBJECT_STORE_PROVIDER=aws VELERO_NAMESPACE="velero" GINKGO_FOCUS="API group versions" make test-e2e
|
||||
```
|
||||
1. Run Velero tests in a kind cluster with AWS (or Minio) as the storage provider and use Microsoft Azure as the storage provider for an additional Backup Storage Location:
|
||||
```bash
|
||||
@@ -105,3 +105,11 @@ For example, E2E tests can be run from Velero repository roots using the command
|
||||
Velero E2E tests uses [Ginkgo](https://onsi.github.io/ginkgo/) testing framework which allows a subset of the tests to be run using the [`-focus` and `-skip`](https://onsi.github.io/ginkgo/#focused-specs) flags to ginkgo.
|
||||
|
||||
The `-focus` flag is passed to ginkgo using the `GINKGO_FOCUS` make variable. This can be used to focus on specific tests.
|
||||
|
||||
## Adding tests
|
||||
|
||||
### API clients
|
||||
When adding a test, aim to instantiate an API client only once at the beginning of the test. There is a constructor `newTestClient` that facilitates the configuration and instantiation of clients. Also, please use the `kubebuilder` runtime controller client for any new test, as we will phase out usage of `client-go` API clients.
|
||||
|
||||
### Tips
|
||||
Look for the ⛵ emoji printed at the end of each install and uninstall log. There should not be two install/unintall in a row, and there should be tests between an install and an uninstall.
|
||||
@@ -1,18 +1,28 @@
|
||||
/*
|
||||
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 e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -34,12 +44,12 @@ func backup_restore_with_restic() {
|
||||
|
||||
func backup_restore_test(useVolumeSnapshots bool) {
|
||||
var (
|
||||
client *kubernetes.Clientset
|
||||
extensionsClient *apiextensionsclientset.Clientset
|
||||
backupName string
|
||||
restoreName string
|
||||
backupName, restoreName string
|
||||
)
|
||||
|
||||
client, err := newTestClient()
|
||||
Expect(err).To(Succeed(), "Failed to instantiate cluster client for backup tests")
|
||||
|
||||
BeforeEach(func() {
|
||||
if useVolumeSnapshots && cloudProvider == "kind" {
|
||||
Skip("Volume snapshots not supported on kind")
|
||||
@@ -49,21 +59,16 @@ func backup_restore_test(useVolumeSnapshots bool) {
|
||||
uuidgen, err = uuid.NewRandom()
|
||||
Expect(err).To(Succeed())
|
||||
if installVelero {
|
||||
Expect(VeleroInstall(context.Background(), veleroImage, veleroNamespace, cloudProvider, objectStoreProvider, useVolumeSnapshots,
|
||||
cloudCredentialsFile, bslBucket, bslPrefix, bslConfig, vslConfig, "")).To(Succeed())
|
||||
|
||||
Expect(veleroInstall(context.Background(), veleroImage, veleroNamespace, cloudProvider, objectStoreProvider, useVolumeSnapshots,
|
||||
cloudCredentialsFile, bslBucket, bslPrefix, bslConfig, vslConfig, crdsVersion, "")).To(Succeed())
|
||||
}
|
||||
client, extensionsClient, err = kube.GetClusterClient()
|
||||
Expect(err).To(Succeed(), "Failed to instantiate cluster client")
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
if installVelero {
|
||||
timeoutCTX, _ := context.WithTimeout(context.Background(), time.Minute)
|
||||
err := VeleroUninstall(timeoutCTX, client, extensionsClient, veleroNamespace)
|
||||
err = veleroUninstall(context.Background(), client.kubebuilder, installVelero, veleroNamespace)
|
||||
Expect(err).To(Succeed())
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
When("kibishii is the sample workload", func() {
|
||||
@@ -72,7 +77,7 @@ func backup_restore_test(useVolumeSnapshots bool) {
|
||||
restoreName = "restore-" + uuidgen.String()
|
||||
// Even though we are using Velero's CloudProvider plugin for object storage, the kubernetes cluster is running on
|
||||
// KinD. So use the kind installation for Kibishii.
|
||||
Expect(RunKibishiiTests(client, cloudProvider, veleroCLI, veleroNamespace, backupName, restoreName, "", useVolumeSnapshots)).To(Succeed(),
|
||||
Expect(runKibishiiTests(client, cloudProvider, veleroCLI, veleroNamespace, backupName, restoreName, "", useVolumeSnapshots)).To(Succeed(),
|
||||
"Failed to successfully backup and restore Kibishii namespace")
|
||||
})
|
||||
|
||||
@@ -89,7 +94,7 @@ func backup_restore_test(useVolumeSnapshots bool) {
|
||||
Skip("no additional BSL credentials given, not running multiple BackupStorageLocation with unique credentials tests")
|
||||
}
|
||||
|
||||
Expect(VeleroAddPluginsForProvider(context.TODO(), veleroCLI, veleroNamespace, additionalBSLProvider)).To(Succeed())
|
||||
Expect(veleroAddPluginsForProvider(context.TODO(), veleroCLI, veleroNamespace, additionalBSLProvider)).To(Succeed())
|
||||
|
||||
// Create Secret for additional BSL
|
||||
secretName := fmt.Sprintf("bsl-credentials-%s", uuidgen)
|
||||
@@ -98,11 +103,11 @@ func backup_restore_test(useVolumeSnapshots bool) {
|
||||
secretKey: additionalBSLCredentials,
|
||||
}
|
||||
|
||||
Expect(CreateSecretFromFiles(context.TODO(), client, veleroNamespace, secretName, files)).To(Succeed())
|
||||
Expect(createSecretFromFiles(context.TODO(), client, veleroNamespace, secretName, files)).To(Succeed())
|
||||
|
||||
// Create additional BSL using credential
|
||||
additionalBsl := fmt.Sprintf("bsl-%s", uuidgen)
|
||||
Expect(VeleroCreateBackupLocation(context.TODO(),
|
||||
Expect(veleroCreateBackupLocation(context.TODO(),
|
||||
veleroCLI,
|
||||
veleroNamespace,
|
||||
additionalBsl,
|
||||
@@ -120,7 +125,7 @@ func backup_restore_test(useVolumeSnapshots bool) {
|
||||
backupName = fmt.Sprintf("backup-%s-%s", bsl, uuidgen)
|
||||
restoreName = fmt.Sprintf("restore-%s-%s", bsl, uuidgen)
|
||||
|
||||
Expect(RunKibishiiTests(client, cloudProvider, veleroCLI, veleroNamespace, backupName, restoreName, bsl, useVolumeSnapshots)).To(Succeed(),
|
||||
Expect(runKibishiiTests(client, cloudProvider, veleroCLI, veleroNamespace, backupName, restoreName, bsl, useVolumeSnapshots)).To(Succeed(),
|
||||
"Failed to successfully backup and restore Kibishii namespace using BSL %s", bsl)
|
||||
}
|
||||
})
|
||||
|
||||
79
test/e2e/client.go
Normal file
79
test/e2e/client.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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 e2e
|
||||
|
||||
import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
)
|
||||
|
||||
// testClient contains different API clients that are in use throughout
|
||||
// the e2e tests.
|
||||
|
||||
type testClient struct {
|
||||
kubebuilder kbclient.Client
|
||||
|
||||
// clientGo returns a client-go API client.
|
||||
//
|
||||
// Deprecated, TODO(2.0): presuming all controllers and resources are converted to the
|
||||
// controller runtime framework by v2.0, it is the intent to remove all
|
||||
// client-go API clients. Please use the controller runtime to make API calls for tests.
|
||||
clientGo kubernetes.Interface
|
||||
|
||||
// dynamicFactory returns a client-go API client for retrieving dynamic clients
|
||||
// for GroupVersionResources and GroupVersionKinds.
|
||||
//
|
||||
// Deprecated, TODO(2.0): presuming all controllers and resources are converted to the
|
||||
// controller runtime framework by v2.0, it is the intent to remove all
|
||||
// client-go API clients. Please use the controller runtime to make API calls for tests.
|
||||
dynamicFactory client.DynamicFactory
|
||||
}
|
||||
|
||||
// newTestClient returns a set of ready-to-use API clients.
|
||||
func newTestClient() (testClient, error) {
|
||||
config, err := client.LoadConfig()
|
||||
if err != nil {
|
||||
return testClient{}, err
|
||||
}
|
||||
|
||||
f := client.NewFactory("e2e", config)
|
||||
|
||||
clientGo, err := f.KubeClient()
|
||||
if err != nil {
|
||||
return testClient{}, err
|
||||
}
|
||||
|
||||
kb, err := f.KubebuilderClient()
|
||||
if err != nil {
|
||||
return testClient{}, err
|
||||
}
|
||||
|
||||
dynamicClient, err := f.DynamicClient()
|
||||
if err != nil {
|
||||
return testClient{}, err
|
||||
}
|
||||
|
||||
factory := client.NewDynamicFactory(dynamicClient)
|
||||
|
||||
return testClient{
|
||||
kubebuilder: kb,
|
||||
clientGo: clientGo,
|
||||
dynamicFactory: factory,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
@@ -13,30 +29,29 @@ import (
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
)
|
||||
|
||||
// EnsureClusterExists returns whether or not a kubernetes cluster exists for tests to be run on.
|
||||
func EnsureClusterExists(ctx context.Context) error {
|
||||
// ensureClusterExists returns whether or not a kubernetes cluster exists for tests to be run on.
|
||||
func ensureClusterExists(ctx context.Context) error {
|
||||
return exec.CommandContext(ctx, "kubectl", "cluster-info").Run()
|
||||
}
|
||||
|
||||
// CreateNamespace creates a kubernetes namespace
|
||||
func CreateNamespace(ctx context.Context, client *kubernetes.Clientset, namespace string) error {
|
||||
// createNamespace creates a kubernetes namespace
|
||||
func createNamespace(ctx context.Context, client testClient, namespace string) error {
|
||||
ns := builder.ForNamespace(namespace).Result()
|
||||
_, err := client.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
|
||||
_, err := client.clientGo.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{})
|
||||
if apierrors.IsAlreadyExists(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitForNamespaceDeletion Waits for namespace to be deleted.
|
||||
func WaitForNamespaceDeletion(interval, timeout time.Duration, client *kubernetes.Clientset, ns string) error {
|
||||
// waitForNamespaceDeletion waits for namespace to be deleted.
|
||||
func waitForNamespaceDeletion(interval, timeout time.Duration, client testClient, ns string) error {
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
_, err := client.CoreV1().Namespaces().Get(context.TODO(), ns, metav1.GetOptions{})
|
||||
_, err := client.clientGo.CoreV1().Namespaces().Get(context.TODO(), ns, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return true, nil
|
||||
@@ -49,7 +64,7 @@ func WaitForNamespaceDeletion(interval, timeout time.Duration, client *kubernete
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateSecretFromFiles(ctx context.Context, client *kubernetes.Clientset, namespace string, name string, files map[string]string) error {
|
||||
func createSecretFromFiles(ctx context.Context, client testClient, namespace string, name string, files map[string]string) error {
|
||||
data := make(map[string][]byte)
|
||||
|
||||
for key, filePath := range files {
|
||||
@@ -62,19 +77,17 @@ func CreateSecretFromFiles(ctx context.Context, client *kubernetes.Clientset, na
|
||||
}
|
||||
|
||||
secret := builder.ForSecret(namespace, name).Data(data).Result()
|
||||
_, err := client.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{})
|
||||
_, err := client.clientGo.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
Waits until all of the pods have gone to PodRunning state
|
||||
*/
|
||||
func WaitForPods(ctx context.Context, client *kubernetes.Clientset, namespace string, pods []string) error {
|
||||
// waitForPods waits until all of the pods have gone to PodRunning state
|
||||
func waitForPods(ctx context.Context, client testClient, namespace string, pods []string) error {
|
||||
timeout := 10 * time.Minute
|
||||
interval := 5 * time.Second
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
for _, podName := range pods {
|
||||
checkPod, err := client.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
|
||||
checkPod, err := client.clientGo.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, errors.WithMessage(err, fmt.Sprintf("Failed to verify pod %s/%s is %s", namespace, podName, corev1api.PodRunning))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
@@ -9,9 +25,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
veleroCLI, veleroImage, cloudCredentialsFile, bslConfig, bslBucket, bslPrefix, vslConfig, cloudProvider, objectStoreProvider, veleroNamespace string
|
||||
additionalBSLProvider, additionalBSLBucket, additionalBSLPrefix, additionalBSLConfig, additionalBSLCredentials string
|
||||
installVelero bool
|
||||
veleroCLI, veleroImage, cloudCredentialsFile, bslConfig, bslBucket, bslPrefix, vslConfig, cloudProvider, objectStoreProvider, veleroNamespace, crdsVersion string
|
||||
additionalBSLProvider, additionalBSLBucket, additionalBSLPrefix, additionalBSLConfig, additionalBSLCredentials string
|
||||
installVelero bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -33,6 +49,7 @@ func init() {
|
||||
flag.StringVar(&additionalBSLPrefix, "additional-bsl-prefix", "", "prefix under which all Velero data should be stored within the bucket for additional backup storage location. Optional.")
|
||||
flag.StringVar(&additionalBSLConfig, "additional-bsl-config", "", "configuration to use for the additional backup storage location. Format is key1=value1,key2=value2")
|
||||
flag.StringVar(&additionalBSLCredentials, "additional-bsl-credentials-file", "", "file containing credentials for additional backup storage location provider. Required if testing multiple credentials support.")
|
||||
flag.StringVar(&crdsVersion, "crds-version", "v1", "CRD apiVersion for velero CRD creation.")
|
||||
}
|
||||
|
||||
func TestE2e(t *testing.T) {
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
@@ -5,24 +21,16 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
|
||||
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/pkg/errors"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/builder"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
@@ -30,156 +38,145 @@ import (
|
||||
|
||||
var _ = Describe("[APIGroup] Velero tests with various CRD API group versions", func() {
|
||||
var (
|
||||
resource, group string
|
||||
certMgrCRD map[string]string
|
||||
client *kubernetes.Clientset
|
||||
extensionsClient *apiextensionsclient.Clientset
|
||||
err error
|
||||
ctx = context.Background()
|
||||
resource, group string
|
||||
err error
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
client, err := newTestClient()
|
||||
Expect(err).To(Succeed(), "Failed to instantiate cluster client for group version tests")
|
||||
|
||||
BeforeEach(func() {
|
||||
resource = "rockbands"
|
||||
group = "music.example.io"
|
||||
certMgrCRD = map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/cert-manager.yaml",
|
||||
"namespace": "cert-manager",
|
||||
}
|
||||
|
||||
client, extensionsClient, err = kube.GetClusterClient() // Currently we ignore the API extensions client
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = InstallCRD(ctx, certMgrCRD["url"], certMgrCRD["namespace"])
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
uuidgen, err = uuid.NewRandom()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// TODO: install Velero once for the test suite once feature flag is
|
||||
// removed and velero installation becomes the same as other e2e tests.
|
||||
if installVelero {
|
||||
err = veleroInstall(
|
||||
context.Background(),
|
||||
veleroImage,
|
||||
veleroNamespace,
|
||||
cloudProvider,
|
||||
objectStoreProvider,
|
||||
false,
|
||||
cloudCredentialsFile,
|
||||
bslBucket,
|
||||
bslPrefix,
|
||||
bslConfig,
|
||||
vslConfig,
|
||||
crdsVersion,
|
||||
"EnableAPIGroupVersions", // TODO: remove when feature flag is removed
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "namespace", "music-system")
|
||||
_, _, _ = veleroexec.RunCommand(cmd)
|
||||
fmt.Printf("Clean up resource: kubectl delete crd %s.%s\n", resource, group)
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "crd", resource+"."+group)
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
if strings.Contains(stderr, "NotFound") {
|
||||
fmt.Printf("Ignore error: %v\n", stderr)
|
||||
err = nil
|
||||
}
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
cmd = exec.CommandContext(ctx, "kubectl", "delete", "crd", "rockbands.music.example.io")
|
||||
_, _, _ = veleroexec.RunCommand(cmd)
|
||||
if installVelero {
|
||||
err = veleroUninstall(ctx, client.kubebuilder, installVelero, veleroNamespace)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
_ = DeleteCRD(ctx, certMgrCRD["url"], certMgrCRD["namespace"])
|
||||
})
|
||||
|
||||
Context("When EnableAPIGroupVersions flag is set", func() {
|
||||
It("Should back up API group version and restore by version priority", func() {
|
||||
Expect(RunEnableAPIGroupVersionsTests(
|
||||
Expect(runEnableAPIGroupVersionsTests(
|
||||
ctx,
|
||||
client,
|
||||
resource,
|
||||
group,
|
||||
client,
|
||||
extensionsClient,
|
||||
)).To(Succeed(), "Failed to successfully backup and restore multiple API Groups")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func RunEnableAPIGroupVersionsTests(ctx context.Context, resource, group string, client *kubernetes.Clientset,
|
||||
extensionsClient *apiextensionsclient.Clientset) error {
|
||||
func runEnableAPIGroupVersionsTests(ctx context.Context, client testClient, resource, group string) error {
|
||||
tests := []struct {
|
||||
name string
|
||||
namespaces []string
|
||||
srcCRD map[string]string
|
||||
srcCrdYaml string
|
||||
srcCRs map[string]string
|
||||
tgtCRD map[string]string
|
||||
tgtCrdYaml string
|
||||
tgtVer string
|
||||
cm *corev1api.ConfigMap
|
||||
gvs map[string][]string
|
||||
want map[string]map[string]string
|
||||
}{
|
||||
{
|
||||
name: "Target and source cluster preferred versions match; Preferred version v1 is restored (Priority 1, Case A).",
|
||||
srcCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-a-source.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
name: "Target and source cluster preferred versions match; Preferred version v1 is restored (Priority 1, Case A).",
|
||||
srcCrdYaml: "testdata/enable_api_group_versions/case-a-source.yaml",
|
||||
srcCRs: map[string]string{
|
||||
"v1": "testdata/enable_api_group_versions/music_v1_rockband.yaml",
|
||||
"v1alpha1": "testdata/enable_api_group_versions/music_v1alpha1_rockband.yaml",
|
||||
},
|
||||
tgtCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-a-target.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
tgtVer: "v1",
|
||||
cm: nil,
|
||||
tgtCrdYaml: "testdata/enable_api_group_versions/case-a-target.yaml",
|
||||
tgtVer: "v1",
|
||||
cm: nil,
|
||||
want: map[string]map[string]string{
|
||||
|
||||
"annotations": {
|
||||
"rockbands.music.example.io/originalVersion": "v1",
|
||||
},
|
||||
"specs": {
|
||||
"leadSinger": "John Lennon",
|
||||
"genre": "60s rock",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Latest common non-preferred supported version v2beta2 is restored (Priority 3, Case D).",
|
||||
srcCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-b-source-manually-added-mutations.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
name: "Latest common non-preferred supported version v2beta2 is restored (Priority 3, Case D).",
|
||||
srcCrdYaml: "testdata/enable_api_group_versions/case-b-source-manually-added-mutations.yaml",
|
||||
srcCRs: map[string]string{
|
||||
"v2beta2": "testdata/enable_api_group_versions/music_v2beta2_rockband.yaml",
|
||||
"v2beta1": "testdata/enable_api_group_versions/music_v2beta1_rockband.yaml",
|
||||
"v1": "testdata/enable_api_group_versions/music_v1_rockband.yaml",
|
||||
},
|
||||
tgtCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-d-target-manually-added-mutations.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
tgtVer: "v2beta2",
|
||||
cm: nil,
|
||||
tgtCrdYaml: "testdata/enable_api_group_versions/case-d-target-manually-added-mutations.yaml",
|
||||
tgtVer: "v2beta2",
|
||||
cm: nil,
|
||||
want: map[string]map[string]string{
|
||||
"annotations": {
|
||||
"rockbands.music.example.io/originalVersion": "v2beta2",
|
||||
},
|
||||
"specs": {
|
||||
"leadSinger": "John Lennon",
|
||||
"leadGuitar": "George Harrison",
|
||||
"drummer": "Ringo Starr",
|
||||
"genre": "60s rock",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "No common supported versions means no rockbands custom resource is restored.",
|
||||
srcCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-a-source.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
name: "No common supported versions means no rockbands custom resource is restored.",
|
||||
srcCrdYaml: "testdata/enable_api_group_versions/case-a-source.yaml",
|
||||
srcCRs: map[string]string{
|
||||
"v1": "testdata/enable_api_group_versions/music_v1_rockband.yaml",
|
||||
"v1alpha1": "testdata/enable_api_group_versions/music_v1alpha1_rockband.yaml",
|
||||
},
|
||||
tgtCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-b-target-manually-added-mutations.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
tgtVer: "",
|
||||
cm: nil,
|
||||
want: nil,
|
||||
tgtCrdYaml: "testdata/enable_api_group_versions/case-b-target-manually-added-mutations.yaml",
|
||||
tgtVer: "",
|
||||
cm: nil,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "User config map overrides Priority 3, Case D and restores v2beta1",
|
||||
srcCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-b-source-manually-added-mutations.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
name: "User config map overrides Priority 3, Case D and restores v2beta1",
|
||||
srcCrdYaml: "testdata/enable_api_group_versions/case-b-source-manually-added-mutations.yaml",
|
||||
srcCRs: map[string]string{
|
||||
"v2beta2": "testdata/enable_api_group_versions/music_v2beta2_rockband.yaml",
|
||||
"v2beta1": "testdata/enable_api_group_versions/music_v2beta1_rockband.yaml",
|
||||
"v1": "testdata/enable_api_group_versions/music_v1_rockband.yaml",
|
||||
},
|
||||
tgtCRD: map[string]string{
|
||||
"url": "testdata/enable_api_group_versions/case-d-target-manually-added-mutations.yaml",
|
||||
"namespace": "music-system",
|
||||
},
|
||||
tgtVer: "v2beta1",
|
||||
tgtCrdYaml: "testdata/enable_api_group_versions/case-d-target-manually-added-mutations.yaml",
|
||||
tgtVer: "v2beta1",
|
||||
cm: builder.ForConfigMap(veleroNamespace, "enableapigroupversions").Data(
|
||||
"restoreResourcesVersionPriority",
|
||||
`rockbands.music.example.io=v2beta1,v2beta2,v2`,
|
||||
@@ -189,101 +186,119 @@ func RunEnableAPIGroupVersionsTests(ctx context.Context, resource, group string,
|
||||
"rockbands.music.example.io/originalVersion": "v2beta1",
|
||||
},
|
||||
"specs": {
|
||||
"leadSinger": "John Lennon",
|
||||
"leadGuitar": "George Harrison",
|
||||
"genre": "60s rock",
|
||||
"genre": "60s rock",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Restore successful when CRD doesn't (yet) exist in target",
|
||||
srcCrdYaml: "testdata/enable_api_group_versions/case-a-source.yaml",
|
||||
srcCRs: map[string]string{
|
||||
"v1": "testdata/enable_api_group_versions/music_v1_rockband.yaml",
|
||||
},
|
||||
tgtCrdYaml: "",
|
||||
tgtVer: "v1",
|
||||
cm: nil,
|
||||
want: map[string]map[string]string{
|
||||
"annotations": {
|
||||
"rockbands.music.example.io/originalVersion": "v1",
|
||||
},
|
||||
"specs": {
|
||||
"genre": "60s rock",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
fmt.Printf("\n====== Test Case %d ======\n", i)
|
||||
fmt.Printf("\n====== Test Case %d: %s ======\n", i, tc.name)
|
||||
|
||||
err := InstallCRD(ctx, tc.srcCRD["url"], tc.srcCRD["namespace"])
|
||||
err := installCRD(ctx, tc.srcCrdYaml)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "installing music-system CRD for source cluster")
|
||||
return errors.Wrap(err, "install music-system CRD on source cluster")
|
||||
}
|
||||
|
||||
for version, cr := range tc.srcCRs {
|
||||
ns := resource + "-src-" + version
|
||||
|
||||
if err := CreateNamespace(ctx, client, ns); err != nil {
|
||||
return errors.Wrapf(err, "creating %s namespace", ns)
|
||||
if err := createNamespace(ctx, client, ns); err != nil {
|
||||
return errors.Wrapf(err, "create %s namespace", ns)
|
||||
}
|
||||
|
||||
if err := InstallCR(ctx, cr, ns); err != nil {
|
||||
return errors.Wrapf(err, "installing %s custom resource on source cluster namespace %s", cr, ns)
|
||||
if err := installCR(ctx, cr, ns); err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "install %s custom resource on source cluster in namespace %s", cr, ns)
|
||||
}
|
||||
|
||||
tc.namespaces = append(tc.namespaces, ns)
|
||||
}
|
||||
|
||||
// TODO - Velero needs to be installed AFTER CRDs are installed because of https://github.com/vmware-tanzu/velero/issues/3471
|
||||
// Once that issue is fixed, we should install Velero once for the test suite
|
||||
if installVelero {
|
||||
VeleroInstall(context.Background(), veleroImage, veleroNamespace, cloudProvider, objectStoreProvider, false,
|
||||
cloudCredentialsFile, bslBucket, bslPrefix, bslConfig, vslConfig,
|
||||
"EnableAPIGroupVersions" /* TODO - remove this when the feature flag is removed */)
|
||||
fmt.Println("Sleep 20s to wait for Velero to stabilize after install.")
|
||||
time.Sleep(time.Second * 20)
|
||||
// Restart Velero pods in order to recognize music-system CRD right away
|
||||
// instead of waiting for discovery helper to refresh. See
|
||||
// https://github.com/vmware-tanzu/velero/issues/3471.
|
||||
if err := restartPods(ctx, veleroNamespace); err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "restart Velero pods")
|
||||
}
|
||||
|
||||
backup := "backup-rockbands-" + uuidgen.String() + "-" + strconv.Itoa(i)
|
||||
namespacesStr := strings.Join(tc.namespaces, ",")
|
||||
|
||||
err = VeleroBackupNamespace(ctx, veleroCLI, veleroNamespace, backup, namespacesStr, "", false)
|
||||
err = veleroBackupNamespace(ctx, veleroCLI, veleroNamespace, backup, namespacesStr, "", false)
|
||||
if err != nil {
|
||||
VeleroBackupLogs(ctx, veleroCLI, veleroNamespace, backup)
|
||||
return errors.Wrapf(err, "backing up %s namespaces on source cluster", namespacesStr)
|
||||
veleroBackupLogs(ctx, veleroCLI, veleroNamespace, backup)
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "back up %s namespaces on source cluster", namespacesStr)
|
||||
}
|
||||
|
||||
// Delete music-system CRD and controllers installed on source cluster.
|
||||
if err := DeleteCRD(ctx, tc.srcCRD["url"], tc.srcCRD["namespace"]); err != nil {
|
||||
return errors.Wrapf(err, "deleting music-system CRD from source cluster")
|
||||
if err := deleteCRD(ctx, tc.srcCrdYaml); err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "delete music-system CRD from source cluster")
|
||||
}
|
||||
|
||||
for _, ns := range tc.namespaces {
|
||||
if err := client.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrapf(err, "deleting %s namespace from source cluster", ns)
|
||||
}
|
||||
|
||||
if err := WaitNamespaceDelete(ctx, ns); err != nil {
|
||||
return errors.Wrapf(err, "deleting %s namespace from source cluster", ns)
|
||||
if err := deleteNamespace(ctx, ns); err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "delete %s namespace from source cluster", ns)
|
||||
}
|
||||
}
|
||||
|
||||
// Install music-system CRD for target cluster.
|
||||
if err := InstallCRD(ctx, tc.tgtCRD["url"], tc.tgtCRD["namespace"]); err != nil {
|
||||
return errors.Wrapf(err, "installing music-system CRD for target cluster")
|
||||
if tc.tgtCrdYaml != "" {
|
||||
if err := installCRD(ctx, tc.tgtCrdYaml); err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "install music-system CRD on target cluster")
|
||||
}
|
||||
}
|
||||
|
||||
// Apply config map if there is one.
|
||||
if tc.cm != nil {
|
||||
_, err := client.CoreV1().ConfigMaps(veleroNamespace).Create(ctx, tc.cm, metav1.CreateOptions{})
|
||||
_, err := client.clientGo.CoreV1().ConfigMaps(veleroNamespace).Create(ctx, tc.cm, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating config map with user version priorities")
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrap(err, "create config map with user version priorities")
|
||||
}
|
||||
}
|
||||
|
||||
// Reset Velero to recognize music-system CRD.
|
||||
if err := RestartPods(ctx, veleroNamespace); err != nil {
|
||||
return errors.Wrapf(err, "restarting Velero pods")
|
||||
if err := restartPods(ctx, veleroNamespace); err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "restart Velero pods")
|
||||
}
|
||||
fmt.Println("Sleep 20s to wait for Velero to stabilize after restart.")
|
||||
time.Sleep(time.Second * 20)
|
||||
|
||||
// Restore rockbands namespace.
|
||||
// Restore rockbands namespaces.
|
||||
restore := "restore-rockbands-" + uuidgen.String() + "-" + strconv.Itoa(i)
|
||||
|
||||
if tc.want != nil {
|
||||
if err := VeleroRestore(ctx, veleroCLI, veleroNamespace, restore, backup); err != nil {
|
||||
VeleroRestoreLogs(ctx, veleroCLI, veleroNamespace, restore)
|
||||
return errors.Wrapf(err, "restoring %s namespaces on target cluster", namespacesStr)
|
||||
if err := veleroRestore(ctx, veleroCLI, veleroNamespace, restore, backup); err != nil {
|
||||
veleroRestoreLogs(ctx, veleroCLI, veleroNamespace, restore)
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(err, "restore %s namespaces on target cluster", namespacesStr)
|
||||
}
|
||||
|
||||
annoSpec, err := resourceInfo(ctx, group, tc.tgtVer, resource)
|
||||
if err != nil {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.Wrapf(
|
||||
err,
|
||||
"get annotation and spec from %s.%s/%s object",
|
||||
@@ -300,6 +315,7 @@ func RunEnableAPIGroupVersionsTests(ctx context.Context, resource, group string,
|
||||
annoSpec["annotations"],
|
||||
tc.want["annotations"],
|
||||
)
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
@@ -310,180 +326,104 @@ func RunEnableAPIGroupVersionsTests(ctx context.Context, resource, group string,
|
||||
annoSpec["specs"],
|
||||
tc.want["specs"],
|
||||
)
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
} else {
|
||||
// No custom resource should have been restored. Expect "no resource found"
|
||||
// error during restore.
|
||||
err := VeleroRestore(ctx, veleroCLI, veleroNamespace, restore, backup)
|
||||
err := veleroRestore(ctx, veleroCLI, veleroNamespace, restore, backup)
|
||||
|
||||
if err.Error() != "Unexpected restore phase got PartiallyFailed, expecting Completed" {
|
||||
deleteNamespacesOnErr(ctx, tc.namespaces)
|
||||
return errors.New("expected error but not none")
|
||||
}
|
||||
}
|
||||
|
||||
// Delete namespaces created for CRs
|
||||
// Clean up.
|
||||
for _, ns := range tc.namespaces {
|
||||
fmt.Println("Delete namespace", ns)
|
||||
_ = client.CoreV1().Namespaces().Delete(ctx, ns, metav1.DeleteOptions{})
|
||||
_ = WaitNamespaceDelete(ctx, ns)
|
||||
deleteNamespace(ctx, ns)
|
||||
}
|
||||
|
||||
// Delete source cluster music-system CRD
|
||||
_ = DeleteCRD(
|
||||
ctx,
|
||||
tc.srcCRD["url"],
|
||||
tc.srcCRD["namespace"],
|
||||
)
|
||||
|
||||
// Delete target cluster music-system CRD
|
||||
_ = DeleteCRD(
|
||||
ctx,
|
||||
tc.tgtCRD["url"],
|
||||
tc.srcCRD["namespace"],
|
||||
)
|
||||
|
||||
// Uninstall Velero
|
||||
if installVelero {
|
||||
err = VeleroUninstall(ctx, client, extensionsClient, veleroNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = deleteCRD(ctx, tc.srcCrdYaml)
|
||||
if tc.tgtCrdYaml != "" {
|
||||
_ = deleteCRD(ctx, tc.tgtCrdYaml)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func installVeleroForAPIGroups(ctx context.Context) error {
|
||||
if err := EnsureClusterExists(ctx); err != nil {
|
||||
return errors.Wrap(err, "check cluster exists")
|
||||
}
|
||||
func installCRD(ctx context.Context, yaml string) error {
|
||||
fmt.Printf("Install CRD with %s.\n", yaml)
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "apply", "-f", yaml)
|
||||
|
||||
// Pass global variables to option parameters.
|
||||
options, err := GetProviderVeleroInstallOptions(
|
||||
cloudProvider,
|
||||
cloudCredentialsFile,
|
||||
bslBucket,
|
||||
bslPrefix,
|
||||
bslConfig,
|
||||
vslConfig,
|
||||
getProviderPlugins(cloudProvider),
|
||||
"EnableAPIGroupVersions",
|
||||
)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get velero install options")
|
||||
}
|
||||
|
||||
options.UseRestic = false
|
||||
options.Features = "EnableAPIGroupVersions"
|
||||
options.Image = veleroImage
|
||||
|
||||
if err := InstallVeleroServer(options); err != nil {
|
||||
return errors.Wrap(err, "install velero server")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func InstallCRD(ctx context.Context, crdFile, ns string) error {
|
||||
fmt.Printf("Install CRD %s.\n", crdFile)
|
||||
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "apply", "-f", crdFile)
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
fmt.Println("Wait for CRD to be ready.")
|
||||
if err := WaitForPodContainers(ctx, ns); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
// WaitForPodContainers will get the pods and container status in a namespace.
|
||||
// If the ratio of the number of containers running to total in a pod is not 1,
|
||||
// it is not ready. Otherwise, if all container ratios are 1, the pod is running.
|
||||
func WaitForPodContainers(ctx context.Context, ns string) error {
|
||||
err := wait.Poll(3*time.Second, 4*time.Minute, func() (bool, error) {
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "get", "pods", "-n", ns)
|
||||
stdout, stderr, err := veleroexec.RunCommand(cmd)
|
||||
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`(\d)/(\d)\s+Running`)
|
||||
|
||||
// Default allRunning needs to be false for when no match is found.
|
||||
var allRunning bool
|
||||
for i, v := range re.FindAllStringSubmatch(stdout, -1) {
|
||||
if i == 0 {
|
||||
allRunning = true
|
||||
}
|
||||
allRunning = v[1] == v[2] && allRunning
|
||||
}
|
||||
return allRunning, nil
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
fmt.Println("Sleep for 20s for cluster to stabilize.")
|
||||
time.Sleep(time.Second * 20)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteCRD(ctx context.Context, crdFile, ns string) error {
|
||||
fmt.Println("Delete CRD", crdFile)
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "-f", crdFile, "--wait")
|
||||
func deleteCRD(ctx context.Context, yaml string) error {
|
||||
fmt.Println("Delete CRD", yaml)
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "-f", yaml, "--wait")
|
||||
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
if strings.Contains(stderr, "not found") {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
err = wait.Poll(1*time.Second, 3*time.Minute, func() (bool, error) {
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "get", "namespace", ns)
|
||||
stdout, stderr, err := veleroexec.RunCommand(cmd)
|
||||
|
||||
if strings.Contains(stderr, "not found") {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(ns)
|
||||
return re.MatchString(stdout), nil
|
||||
})
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func RestartPods(ctx context.Context, ns string) error {
|
||||
func restartPods(ctx context.Context, ns string) error {
|
||||
fmt.Printf("Restart pods in %s namespace.\n", ns)
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "pod", "--all", "-n", ns, "--wait=true")
|
||||
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "pod", "--all", "-n", ns)
|
||||
_, _, err := veleroexec.RunCommand(cmd)
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
if strings.Contains(stderr, "not found") {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, stderr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
fmt.Println("Wait for pods to be ready.")
|
||||
if err := WaitForPodContainers(ctx, ns); err != nil {
|
||||
return err
|
||||
}
|
||||
func deleteNamespace(ctx context.Context, ns string) error {
|
||||
fmt.Println("Delete namespace", ns)
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "delete", "ns", ns, "--wait")
|
||||
|
||||
_, stderr, err := veleroexec.RunCommand(cmd)
|
||||
if strings.Contains(stderr, "not found") {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func InstallCR(ctx context.Context, crFile, ns string) error {
|
||||
// DeleteNamespacesOnErr cleans up the namespaces created for a test cast after an
|
||||
// error interrupts a test case.
|
||||
func deleteNamespacesOnErr(ctx context.Context, namespaces []string) {
|
||||
if len(namespaces) > 0 {
|
||||
fmt.Println("An error has occurred. Cleaning up test case namespaces.")
|
||||
}
|
||||
|
||||
for _, ns := range namespaces {
|
||||
deleteNamespace(ctx, ns)
|
||||
}
|
||||
}
|
||||
|
||||
func installCR(ctx context.Context, crFile, ns string) error {
|
||||
retries := 5
|
||||
var stderr string
|
||||
var err error
|
||||
@@ -503,22 +443,6 @@ func InstallCR(ctx context.Context, crFile, ns string) error {
|
||||
return errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
func WaitNamespaceDelete(ctx context.Context, ns string) error {
|
||||
err := wait.Poll(1*time.Second, 3*time.Minute, func() (bool, error) {
|
||||
cmd := exec.CommandContext(ctx, "kubectl", "get", "namespace", ns)
|
||||
|
||||
stdout, stderr, err := veleroexec.RunCommand(cmd)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(ns)
|
||||
return re.MatchString(stdout), nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func resourceInfo(ctx context.Context, g, v, r string) (map[string]map[string]string, error) {
|
||||
rvg := r + "." + v + "." + g
|
||||
ns := r + "-src-" + v
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
@@ -8,7 +24,6 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@@ -77,15 +92,15 @@ func verifyData(ctx context.Context, namespace string, levels int, filesPerLevel
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunKibishiiTests runs kibishii tests on the provider.
|
||||
func RunKibishiiTests(client *kubernetes.Clientset, providerName, veleroCLI, veleroNamespace, backupName, restoreName, backupLocation string,
|
||||
// runKibishiiTests runs kibishii tests on the provider.
|
||||
func runKibishiiTests(client testClient, providerName, veleroCLI, veleroNamespace, backupName, restoreName, backupLocation string,
|
||||
useVolumeSnapshots bool) error {
|
||||
fiveMinTimeout, _ := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
oneHourTimeout, _ := context.WithTimeout(context.Background(), time.Minute*60)
|
||||
timeout := 10 * time.Minute
|
||||
interval := 5 * time.Second
|
||||
|
||||
if err := CreateNamespace(fiveMinTimeout, client, kibishiiNamespace); err != nil {
|
||||
if err := createNamespace(fiveMinTimeout, client, kibishiiNamespace); err != nil {
|
||||
return errors.Wrapf(err, "Failed to create namespace %s to install Kibishii workload", kibishiiNamespace)
|
||||
}
|
||||
|
||||
@@ -104,8 +119,8 @@ func RunKibishiiTests(client *kubernetes.Clientset, providerName, veleroCLI, vel
|
||||
return errors.Wrap(err, "Failed to generate data")
|
||||
}
|
||||
|
||||
if err := VeleroBackupNamespace(oneHourTimeout, veleroCLI, veleroNamespace, backupName, kibishiiNamespace, backupLocation, useVolumeSnapshots); err != nil {
|
||||
VeleroBackupLogs(fiveMinTimeout, veleroCLI, veleroNamespace, backupName)
|
||||
if err := veleroBackupNamespace(oneHourTimeout, veleroCLI, veleroNamespace, backupName, kibishiiNamespace, backupLocation, useVolumeSnapshots); err != nil {
|
||||
veleroBackupLogs(fiveMinTimeout, veleroCLI, veleroNamespace, backupName)
|
||||
return errors.Wrapf(err, "Failed to backup kibishii namespace %s", kibishiiNamespace)
|
||||
}
|
||||
|
||||
@@ -118,17 +133,17 @@ func RunKibishiiTests(client *kubernetes.Clientset, providerName, veleroCLI, vel
|
||||
}
|
||||
}
|
||||
fmt.Printf("Simulating a disaster by removing namespace %s\n", kibishiiNamespace)
|
||||
if err := client.CoreV1().Namespaces().Delete(oneHourTimeout, kibishiiNamespace, metav1.DeleteOptions{}); err != nil {
|
||||
if err := client.clientGo.CoreV1().Namespaces().Delete(oneHourTimeout, kibishiiNamespace, metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrap(err, "Failed to simulate a disaster")
|
||||
}
|
||||
// wait for ns delete
|
||||
err := WaitForNamespaceDeletion(interval, timeout, client, kibishiiNamespace)
|
||||
err := waitForNamespaceDeletion(interval, timeout, client, kibishiiNamespace)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, fmt.Sprintf("Failed to wait for deletion of namespace %s", kibishiiNamespace))
|
||||
}
|
||||
|
||||
if err := VeleroRestore(oneHourTimeout, veleroCLI, veleroNamespace, restoreName, backupName); err != nil {
|
||||
VeleroRestoreLogs(fiveMinTimeout, veleroCLI, veleroNamespace, restoreName)
|
||||
if err := veleroRestore(oneHourTimeout, veleroCLI, veleroNamespace, restoreName, backupName); err != nil {
|
||||
veleroRestoreLogs(fiveMinTimeout, veleroCLI, veleroNamespace, restoreName)
|
||||
return errors.Wrapf(err, "Restore %s failed from backup %s", restoreName, backupName)
|
||||
}
|
||||
|
||||
@@ -145,17 +160,17 @@ func RunKibishiiTests(client *kubernetes.Clientset, providerName, veleroCLI, vel
|
||||
return errors.Wrap(err, "Failed to verify data generated by kibishii")
|
||||
}
|
||||
|
||||
if err := client.CoreV1().Namespaces().Delete(oneHourTimeout, kibishiiNamespace, metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrapf(err, "Failed to cleanup %s wrokload namespace", kibishiiNamespace)
|
||||
if err := client.clientGo.CoreV1().Namespaces().Delete(oneHourTimeout, kibishiiNamespace, metav1.DeleteOptions{}); err != nil {
|
||||
return errors.Wrapf(err, "Failed to cleanup %s workload namespace", kibishiiNamespace)
|
||||
}
|
||||
// wait for ns delete
|
||||
if err = WaitForNamespaceDeletion(interval, timeout, client, kibishiiNamespace); err != nil {
|
||||
if err = waitForNamespaceDeletion(interval, timeout, client, kibishiiNamespace); err != nil {
|
||||
return errors.Wrapf(err, fmt.Sprintf("Failed to wait for deletion of namespace %s", kibishiiNamespace))
|
||||
}
|
||||
fmt.Printf("kibishii test completed successfully\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
func waitForKibishiiPods(ctx context.Context, client *kubernetes.Clientset, kibishiiNamespace string) error {
|
||||
return WaitForPods(ctx, client, kibishiiNamespace, []string{"jump-pad", "etcd0", "etcd1", "etcd2", "kibishii-deployment-0", "kibishii-deployment-1"})
|
||||
func waitForKibishiiPods(ctx context.Context, client testClient, kibishiiNamespace string) error {
|
||||
return waitForPods(ctx, client, kibishiiNamespace, []string{"jump-pad", "etcd0", "etcd1", "etcd2", "kibishii-deployment-0", "kibishii-deployment-1"})
|
||||
}
|
||||
|
||||
@@ -4,18 +4,12 @@ This directory contains Kubernetes manifests that are used for the enable API gr
|
||||
|
||||
## Documentation
|
||||
|
||||
Read more about cert-manager in the [Jet Stack repo](https://github.com/jetstack/cert-manager/blob/master/README.md).
|
||||
|
||||
Read more about the music-system custom resource definitions and rockbands custom resources created for Velero tests at [@brito-rafa's repo](https://github.com/brito-rafa/k8s-webhooks/blob/master/examples-for-projectvelero/README.md).
|
||||
|
||||
## Reference
|
||||
|
||||
These manifests, listed below, come from two different sources: github.com/jetstack/cert-manager and github.com/brito-rafa/k8s-webhooks:
|
||||
|
||||
cert-manager.yaml
|
||||
|
||||
- source: https://github.com/jetstack/cert-manager/releases/download/v1.0.3/cert-manager.yaml
|
||||
- license: https://github.com/jetstack/cert-manager/blob/master/LICENSE
|
||||
These manifests, listed below, come from github.com/brito-rafa/k8s-webhooks:
|
||||
|
||||
case-a-source.yaml
|
||||
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-system
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -13,18 +6,6 @@ metadata:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
name: rockbands.music.example.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v1
|
||||
- v1alpha1
|
||||
group: music.example.io
|
||||
names:
|
||||
kind: RockBand
|
||||
@@ -33,363 +14,77 @@ spec:
|
||||
singular: rockband
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
leadSinger:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
required:
|
||||
- lastPlayed
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
|
||||
type: string
|
||||
kind:
|
||||
description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
leadSinger:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
- name: v1alpha1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
|
||||
type: string
|
||||
kind:
|
||||
description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
required:
|
||||
- lastPlayed
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: music-leader-election-role
|
||||
namespace: music-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: music-manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: music-leader-election-rolebinding
|
||||
namespace: music-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: music-leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager-metrics-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager
|
||||
namespace: music-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
- --logtostderr=true
|
||||
- --v=10
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
name: kube-rbac-proxy
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- args:
|
||||
- --metrics-addr=127.0.0.1:8080
|
||||
- --enable-leader-election
|
||||
command:
|
||||
- /manager
|
||||
image: quay.io/brito_rafa/music-controller:case-a-source-v0.1
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: music-serving-cert
|
||||
namespace: music-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- music-webhook-service.music-system.svc
|
||||
- music-webhook-service.music-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: music-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: music-selfsigned-issuer
|
||||
namespace: music-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-validating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /validate-music-example-io-v1-rockband
|
||||
failurePolicy: Fail
|
||||
name: vrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-system
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -13,18 +6,6 @@ metadata:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
name: rockbands.music.example.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v1
|
||||
- v1alpha1
|
||||
group: music.example.io
|
||||
names:
|
||||
kind: RockBand
|
||||
@@ -33,367 +14,81 @@ spec:
|
||||
singular: rockband
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
leadSinger:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
- name: v2beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
leadGuitar:
|
||||
type: string
|
||||
leadSinger:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
required:
|
||||
- lastPlayed
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
- name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
|
||||
type: string
|
||||
kind:
|
||||
description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
leadSinger:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
- name: v2beta1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: RockBand is the Schema for the rockbands API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources"
|
||||
type: string
|
||||
kind:
|
||||
description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds"
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: RockBandSpec defines the desired state of RockBand
|
||||
properties:
|
||||
genre:
|
||||
type: string
|
||||
leadGuitar:
|
||||
type: string
|
||||
leadSinger:
|
||||
type: string
|
||||
numberComponents:
|
||||
format: int32
|
||||
type: integer
|
||||
type: object
|
||||
status:
|
||||
description: RockBandStatus defines the observed state of RockBand
|
||||
properties:
|
||||
lastPlayed:
|
||||
type: string
|
||||
required:
|
||||
- lastPlayed
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: false
|
||||
status:
|
||||
acceptedNames:
|
||||
kind: ""
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: music-leader-election-role
|
||||
namespace: music-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: music-manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: music-leader-election-rolebinding
|
||||
namespace: music-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: music-leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager-metrics-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager
|
||||
namespace: music-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
- --logtostderr=true
|
||||
- --v=10
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
name: kube-rbac-proxy
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- args:
|
||||
- --metrics-addr=127.0.0.1:8080
|
||||
- --enable-leader-election
|
||||
command:
|
||||
- /manager
|
||||
image: quay.io/brito_rafa/music-controller:case-a-target-v0.2
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: music-serving-cert
|
||||
namespace: music-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- music-webhook-service.music-system.svc
|
||||
- music-webhook-service.music-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: music-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: music-selfsigned-issuer
|
||||
namespace: music-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-validating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /validate-music-example-io-v1-rockband
|
||||
failurePolicy: Fail
|
||||
name: vrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-system
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -13,19 +6,6 @@ metadata:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
name: rockbands.music.example.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v1
|
||||
- v2beta1
|
||||
- v2beta2
|
||||
group: music.example.io
|
||||
names:
|
||||
kind: RockBand
|
||||
@@ -151,325 +131,3 @@ status:
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: music-leader-election-role
|
||||
namespace: music-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: music-manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: music-leader-election-rolebinding
|
||||
namespace: music-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: music-leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager-metrics-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager
|
||||
namespace: music-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
- --logtostderr=true
|
||||
- --v=10
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
name: kube-rbac-proxy
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- args:
|
||||
- --metrics-addr=127.0.0.1:8080
|
||||
- --enable-leader-election
|
||||
command:
|
||||
- /manager
|
||||
image: quay.io/brito_rafa/music-controller:case-b-source-v0.1
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: music-serving-cert
|
||||
namespace: music-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- music-webhook-service.music-system.svc
|
||||
- music-webhook-service.music-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: music-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: music-selfsigned-issuer
|
||||
namespace: music-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta2-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-validating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /validate-music-example-io-v2beta2-rockband
|
||||
failurePolicy: Fail
|
||||
name: vrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-system
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -13,19 +6,6 @@ metadata:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
name: rockbands.music.example.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v2beta2
|
||||
- v2beta1
|
||||
- v1
|
||||
group: music.example.io
|
||||
names:
|
||||
kind: RockBand
|
||||
@@ -116,307 +96,3 @@ status:
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: music-leader-election-role
|
||||
namespace: music-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: music-manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: music-leader-election-rolebinding
|
||||
namespace: music-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: music-leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager-metrics-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager
|
||||
namespace: music-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
- --logtostderr=true
|
||||
- --v=10
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
name: kube-rbac-proxy
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- args:
|
||||
- --metrics-addr=127.0.0.1:8080
|
||||
- --enable-leader-election
|
||||
command:
|
||||
- /manager
|
||||
image: quay.io/brito_rafa/music-controller:case-b-target-v0.1
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: music-serving-cert
|
||||
namespace: music-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- music-webhook-service.music-system.svc
|
||||
- music-webhook-service.music-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: music-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: music-selfsigned-issuer
|
||||
namespace: music-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta2-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-validating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /validate-music-example-io-v2beta2-rockband
|
||||
failurePolicy: Fail
|
||||
name: vrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-system
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -13,18 +6,6 @@ metadata:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
name: rockbands.music.example.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v2
|
||||
- v1
|
||||
group: music.example.io
|
||||
names:
|
||||
kind: RockBand
|
||||
@@ -115,307 +96,3 @@ status:
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: music-leader-election-role
|
||||
namespace: music-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: music-manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: music-leader-election-rolebinding
|
||||
namespace: music-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: music-leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager-metrics-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager
|
||||
namespace: music-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
- --logtostderr=true
|
||||
- --v=10
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
name: kube-rbac-proxy
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- args:
|
||||
- --metrics-addr=127.0.0.1:8080
|
||||
- --enable-leader-election
|
||||
command:
|
||||
- /manager
|
||||
image: quay.io/brito_rafa/music-controller:case-c-target-v0.1
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: music-serving-cert
|
||||
namespace: music-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- music-webhook-service.music-system.svc
|
||||
- music-webhook-service.music-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: music-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: music-selfsigned-issuer
|
||||
namespace: music-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-validating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /validate-music-example-io-v1-rockband
|
||||
failurePolicy: Fail
|
||||
name: vrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-system
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -13,20 +6,6 @@ metadata:
|
||||
controller-gen.kubebuilder.io/version: v0.2.5
|
||||
name: rockbands.music.example.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /convert
|
||||
conversionReviewVersions:
|
||||
- v2
|
||||
- v2beta2
|
||||
- v2beta1
|
||||
- v1
|
||||
group: music.example.io
|
||||
names:
|
||||
kind: RockBand
|
||||
@@ -158,325 +137,3 @@ status:
|
||||
plural: ""
|
||||
conditions: []
|
||||
storedVersions: []
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: music-leader-election-role
|
||||
namespace: music-system
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps/status
|
||||
verbs:
|
||||
- get
|
||||
- update
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: music-manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
resources:
|
||||
- rockbands/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-proxy-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: music-metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: music-leader-election-rolebinding
|
||||
namespace: music-system
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: music-leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: music-proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: music-proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: music-system
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager-metrics-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
spec:
|
||||
ports:
|
||||
- port: 443
|
||||
targetPort: 9443
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: music-controller-manager
|
||||
namespace: music-system
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- --secure-listen-address=0.0.0.0:8443
|
||||
- --upstream=http://127.0.0.1:8080/
|
||||
- --logtostderr=true
|
||||
- --v=10
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
name: kube-rbac-proxy
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- args:
|
||||
- --metrics-addr=127.0.0.1:8080
|
||||
- --enable-leader-election
|
||||
command:
|
||||
- /manager
|
||||
image: quay.io/brito_rafa/music-controller:case-d-target-v0.1
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 9443
|
||||
name: webhook-server
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
volumeMounts:
|
||||
- mountPath: /tmp/k8s-webhook-server/serving-certs
|
||||
name: cert
|
||||
readOnly: true
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: cert
|
||||
secret:
|
||||
defaultMode: 420
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: music-serving-cert
|
||||
namespace: music-system
|
||||
spec:
|
||||
dnsNames:
|
||||
- music-webhook-service.music-system.svc
|
||||
- music-webhook-service.music-system.svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: music-selfsigned-issuer
|
||||
secretName: webhook-server-cert
|
||||
---
|
||||
apiVersion: cert-manager.io/v1alpha2
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: music-selfsigned-issuer
|
||||
namespace: music-system
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-mutating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta2-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2beta1-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /mutate-music-example-io-v2-rockband
|
||||
failurePolicy: Fail
|
||||
name: mrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
---
|
||||
apiVersion: admissionregistration.k8s.io/v1beta1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: music-system/music-serving-cert
|
||||
name: music-validating-webhook-configuration
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: music-webhook-service
|
||||
namespace: music-system
|
||||
path: /validate-music-example-io-v2beta2-rockband
|
||||
failurePolicy: Fail
|
||||
name: vrockband.kb.io
|
||||
rules:
|
||||
- apiGroups:
|
||||
- music.example.io
|
||||
apiVersions:
|
||||
- v2beta2
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- rockbands
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,5 @@ metadata:
|
||||
annotations:
|
||||
rockbands.music.example.io/originalVersion: v1
|
||||
spec:
|
||||
# Add fields here
|
||||
genre: '60s rock'
|
||||
genre: "60s rock"
|
||||
numberComponents: 4
|
||||
leadSinger: John
|
||||
|
||||
@@ -5,7 +5,5 @@ metadata:
|
||||
annotations:
|
||||
rockbands.music.example.io/originalVersion: v1alpha1
|
||||
spec:
|
||||
# Add fields here
|
||||
genre: '60s rock'
|
||||
genre: "60s rock"
|
||||
numberComponents: 4
|
||||
|
||||
|
||||
@@ -3,10 +3,5 @@ kind: RockBand
|
||||
metadata:
|
||||
name: beatles
|
||||
spec:
|
||||
# Add fields here
|
||||
genre: '60s rock'
|
||||
genre: "60s rock"
|
||||
numberComponents: 4
|
||||
leadSinger: John
|
||||
leadGuitar: George
|
||||
drummer: Ringo
|
||||
bass: Paul
|
||||
|
||||
@@ -5,9 +5,5 @@ metadata:
|
||||
annotations:
|
||||
rockbands.music.example.io/originalVersion: v2beta1
|
||||
spec:
|
||||
# Add fields here
|
||||
genre: '60s rock'
|
||||
genre: "60s rock"
|
||||
numberComponents: 4
|
||||
leadSinger: John
|
||||
leadGuitar: George
|
||||
|
||||
|
||||
@@ -5,9 +5,5 @@ metadata:
|
||||
annotations:
|
||||
rockbands.music.example.io/originalVersion: v2beta2
|
||||
spec:
|
||||
# Add fields here
|
||||
genre: '60s rock'
|
||||
genre: "60s rock"
|
||||
numberComponents: 4
|
||||
leadSinger: John
|
||||
leadGuitar: George
|
||||
drummer: Ringo
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
Copyright the Velero contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
@@ -12,21 +28,16 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/client"
|
||||
cliinstall "github.com/vmware-tanzu/velero/pkg/cmd/cli/install"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/cli/uninstall"
|
||||
"github.com/vmware-tanzu/velero/pkg/cmd/util/flag"
|
||||
"github.com/vmware-tanzu/velero/pkg/install"
|
||||
veleroexec "github.com/vmware-tanzu/velero/pkg/util/exec"
|
||||
)
|
||||
|
||||
func getProviderPlugins(providerName string) []string {
|
||||
@@ -43,8 +54,8 @@ func getProviderPlugins(providerName string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
// GetProviderVeleroInstallOptions returns Velero InstallOptions for the provider.
|
||||
func GetProviderVeleroInstallOptions(
|
||||
// getProviderVeleroInstallOptions returns Velero InstallOptions for the provider.
|
||||
func getProviderVeleroInstallOptions(
|
||||
pluginProvider,
|
||||
credentialsFile,
|
||||
objectStoreBucket,
|
||||
@@ -84,52 +95,44 @@ func GetProviderVeleroInstallOptions(
|
||||
return io, nil
|
||||
}
|
||||
|
||||
// InstallVeleroServer installs velero in the cluster.
|
||||
func InstallVeleroServer(io *cliinstall.InstallOptions) error {
|
||||
config, err := client.LoadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// installVeleroServer installs velero in the cluster.
|
||||
func installVeleroServer(io *cliinstall.InstallOptions) error {
|
||||
vo, err := io.AsVeleroOptions()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to translate InstallOptions to VeleroOptions for Velero")
|
||||
}
|
||||
|
||||
f := client.NewFactory("e2e", config)
|
||||
resources, err := install.AllResources(vo)
|
||||
client, err := newTestClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to install Velero in the cluster")
|
||||
return errors.Wrap(err, "Failed to instantiate cluster client for installing Velero")
|
||||
}
|
||||
|
||||
dynamicClient, err := f.DynamicClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
factory := client.NewDynamicFactory(dynamicClient)
|
||||
errorMsg := "\n\nError installing Velero. Use `kubectl logs deploy/velero -n velero` to check the deploy logs"
|
||||
err = install.Install(factory, resources, os.Stdout)
|
||||
resources := install.AllResources(vo)
|
||||
err = install.Install(client.dynamicFactory, client.kubebuilder, resources, os.Stdout)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
|
||||
fmt.Println("Waiting for Velero deployment to be ready.")
|
||||
if _, err = install.DeploymentIsReady(factory, io.Namespace); err != nil {
|
||||
if _, err = install.DeploymentIsReady(client.dynamicFactory, io.Namespace); err != nil {
|
||||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
|
||||
if io.UseRestic {
|
||||
fmt.Println("Waiting for Velero restic daemonset to be ready.")
|
||||
if _, err = install.DaemonSetIsReady(factory, io.Namespace); err != nil {
|
||||
if _, err = install.DaemonSetIsReady(client.dynamicFactory, io.Namespace); err != nil {
|
||||
return errors.Wrap(err, errorMsg)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Velero is installed and ready to be tested in the %s namespace! ⛵ \n", io.Namespace)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckBackupPhase uses veleroCLI to inspect the phase of a Velero backup.
|
||||
func CheckBackupPhase(ctx context.Context, veleroCLI string, veleroNamespace string, backupName string,
|
||||
// checkBackupPhase uses veleroCLI to inspect the phase of a Velero backup.
|
||||
func checkBackupPhase(ctx context.Context, veleroCLI string, veleroNamespace string, backupName string,
|
||||
expectedPhase velerov1api.BackupPhase) error {
|
||||
checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "backup", "get", "-o", "json",
|
||||
backupName)
|
||||
@@ -172,8 +175,8 @@ func CheckBackupPhase(ctx context.Context, veleroCLI string, veleroNamespace str
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckRestorePhase uses veleroCLI to inspect the phase of a Velero restore.
|
||||
func CheckRestorePhase(ctx context.Context, veleroCLI string, veleroNamespace string, restoreName string,
|
||||
// checkRestorePhase uses veleroCLI to inspect the phase of a Velero restore.
|
||||
func checkRestorePhase(ctx context.Context, veleroCLI string, veleroNamespace string, restoreName string,
|
||||
expectedPhase velerov1api.RestorePhase) error {
|
||||
checkCMD := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "restore", "get", "-o", "json",
|
||||
restoreName)
|
||||
@@ -216,8 +219,8 @@ func CheckRestorePhase(ctx context.Context, veleroCLI string, veleroNamespace st
|
||||
return nil
|
||||
}
|
||||
|
||||
// VeleroBackupNamespace uses the veleroCLI to backup a namespace.
|
||||
func VeleroBackupNamespace(ctx context.Context, veleroCLI string, veleroNamespace string, backupName string, namespace string, backupLocation string,
|
||||
// veleroBackupNamespace uses the veleroCLI to backup a namespace.
|
||||
func veleroBackupNamespace(ctx context.Context, veleroCLI string, veleroNamespace string, backupName string, namespace string, backupLocation string,
|
||||
useVolumeSnapshots bool) error {
|
||||
args := []string{
|
||||
"--namespace", veleroNamespace,
|
||||
@@ -243,13 +246,13 @@ func VeleroBackupNamespace(ctx context.Context, veleroCLI string, veleroNamespac
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = CheckBackupPhase(ctx, veleroCLI, veleroNamespace, backupName, velerov1api.BackupPhaseCompleted)
|
||||
err = checkBackupPhase(ctx, veleroCLI, veleroNamespace, backupName, velerov1api.BackupPhaseCompleted)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// VeleroRestore uses the veleroCLI to restore from a Velero backup.
|
||||
func VeleroRestore(ctx context.Context, veleroCLI string, veleroNamespace string, restoreName string, backupName string) error {
|
||||
// veleroRestore uses the veleroCLI to restore from a Velero backup.
|
||||
func veleroRestore(ctx context.Context, veleroCLI string, veleroNamespace string, restoreName string, backupName string) error {
|
||||
restoreCmd := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "create", "restore", restoreName,
|
||||
"--from-backup", backupName, "--wait")
|
||||
|
||||
@@ -260,12 +263,12 @@ func VeleroRestore(ctx context.Context, veleroCLI string, veleroNamespace string
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return CheckRestorePhase(ctx, veleroCLI, veleroNamespace, restoreName, velerov1api.RestorePhaseCompleted)
|
||||
return checkRestorePhase(ctx, veleroCLI, veleroNamespace, restoreName, velerov1api.RestorePhaseCompleted)
|
||||
}
|
||||
|
||||
func VeleroInstall(ctx context.Context, veleroImage string, veleroNamespace string, cloudProvider string, objectStoreProvider string, useVolumeSnapshots bool,
|
||||
func veleroInstall(ctx context.Context, veleroImage string, veleroNamespace string, cloudProvider string, objectStoreProvider string, useVolumeSnapshots bool,
|
||||
cloudCredentialsFile string, bslBucket string, bslPrefix string, bslConfig string, vslConfig string,
|
||||
features string) error {
|
||||
crdsVersion string, features string) error {
|
||||
|
||||
if cloudProvider != "kind" {
|
||||
if objectStoreProvider != "" {
|
||||
@@ -278,6 +281,7 @@ func VeleroInstall(ctx context.Context, veleroImage string, veleroNamespace stri
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the plugins for the provider before checking for the object store provider below.
|
||||
providerPlugins := getProviderPlugins(objectStoreProvider)
|
||||
|
||||
// TODO - handle this better
|
||||
@@ -287,12 +291,16 @@ func VeleroInstall(ctx context.Context, veleroImage string, veleroNamespace stri
|
||||
// Snapshot location specified
|
||||
objectStoreProvider = "aws"
|
||||
}
|
||||
err := EnsureClusterExists(ctx)
|
||||
err := ensureClusterExists(ctx)
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "Failed to ensure kubernetes cluster exists")
|
||||
return errors.WithMessage(err, "Failed to ensure Kubernetes cluster exists")
|
||||
}
|
||||
veleroInstallOptions, err := GetProviderVeleroInstallOptions(objectStoreProvider, cloudCredentialsFile, bslBucket,
|
||||
|
||||
veleroInstallOptions, err := getProviderVeleroInstallOptions(objectStoreProvider, cloudCredentialsFile, bslBucket,
|
||||
bslPrefix, bslConfig, vslConfig, providerPlugins, features)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "Failed to get Velero InstallOptions for plugin provider %s", objectStoreProvider)
|
||||
}
|
||||
if useVolumeSnapshots {
|
||||
if cloudProvider != "vsphere" {
|
||||
veleroInstallOptions.UseVolumeSnapshots = true
|
||||
@@ -302,25 +310,24 @@ func VeleroInstall(ctx context.Context, veleroImage string, veleroNamespace stri
|
||||
// being an AWS VSL which causes problems)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "Failed to get Velero InstallOptions for plugin provider %s", objectStoreProvider)
|
||||
}
|
||||
veleroInstallOptions.UseRestic = !useVolumeSnapshots
|
||||
|
||||
veleroInstallOptions.Image = veleroImage
|
||||
veleroInstallOptions.CRDsVersion = crdsVersion
|
||||
veleroInstallOptions.Namespace = veleroNamespace
|
||||
err = InstallVeleroServer(veleroInstallOptions)
|
||||
|
||||
err = installVeleroServer(veleroInstallOptions)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "Failed to install Velero in cluster")
|
||||
return errors.WithMessagef(err, "Failed to install Velero in the cluster")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func VeleroUninstall(ctx context.Context, client *kubernetes.Clientset, extensionsClient *apiextensionsclient.Clientset, veleroNamespace string) error {
|
||||
return uninstall.Run(ctx, client, extensionsClient, veleroNamespace, true)
|
||||
func veleroUninstall(ctx context.Context, client kbclient.Client, installVelero bool, veleroNamespace string) error {
|
||||
return uninstall.Run(ctx, client, veleroNamespace, true)
|
||||
}
|
||||
|
||||
func VeleroBackupLogs(ctx context.Context, veleroCLI string, veleroNamespace string, backupName string) error {
|
||||
func veleroBackupLogs(ctx context.Context, veleroCLI string, veleroNamespace string, backupName string) error {
|
||||
describeCmd := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "backup", "describe", backupName)
|
||||
describeCmd.Stdout = os.Stdout
|
||||
describeCmd.Stderr = os.Stderr
|
||||
@@ -338,7 +345,7 @@ func VeleroBackupLogs(ctx context.Context, veleroCLI string, veleroNamespace str
|
||||
return nil
|
||||
}
|
||||
|
||||
func VeleroRestoreLogs(ctx context.Context, veleroCLI string, veleroNamespace string, restoreName string) error {
|
||||
func veleroRestoreLogs(ctx context.Context, veleroCLI string, veleroNamespace string, restoreName string) error {
|
||||
describeCmd := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "restore", "describe", restoreName)
|
||||
describeCmd.Stdout = os.Stdout
|
||||
describeCmd.Stderr = os.Stderr
|
||||
@@ -356,7 +363,7 @@ func VeleroRestoreLogs(ctx context.Context, veleroCLI string, veleroNamespace st
|
||||
return nil
|
||||
}
|
||||
|
||||
func VeleroCreateBackupLocation(ctx context.Context,
|
||||
func veleroCreateBackupLocation(ctx context.Context,
|
||||
veleroCLI string,
|
||||
veleroNamespace string,
|
||||
name string,
|
||||
@@ -393,16 +400,16 @@ func VeleroCreateBackupLocation(ctx context.Context,
|
||||
return bslCreateCmd.Run()
|
||||
}
|
||||
|
||||
// VeleroAddPluginsForProvider determines which plugins need to be installed for a provider and
|
||||
// veleroAddPluginsForProvider determines which plugins need to be installed for a provider and
|
||||
// installs them in the current Velero installation, skipping over those that are already installed.
|
||||
func VeleroAddPluginsForProvider(ctx context.Context, veleroCLI string, veleroNamespace string, provider string) error {
|
||||
func veleroAddPluginsForProvider(ctx context.Context, veleroCLI string, veleroNamespace string, provider string) error {
|
||||
for _, plugin := range getProviderPlugins(provider) {
|
||||
stdoutBuf := new(bytes.Buffer)
|
||||
stderrBuf := new(bytes.Buffer)
|
||||
|
||||
installPluginCmd := exec.CommandContext(ctx, veleroCLI, "--namespace", veleroNamespace, "plugin", "add", plugin)
|
||||
installPluginCmd.Stdout = stdoutBuf
|
||||
installPluginCmd.Stderr = stdoutBuf
|
||||
installPluginCmd.Stderr = stderrBuf
|
||||
|
||||
err := installPluginCmd.Run()
|
||||
|
||||
@@ -421,10 +428,8 @@ func VeleroAddPluginsForProvider(ctx context.Context, veleroCLI string, veleroNa
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
Waits for uploads started by the Velero Plug-in for vSphere to complete
|
||||
TODO - remove after upload progress monitoring is implemented
|
||||
*/
|
||||
// waitForVSphereUploadCompletion waits for uploads started by the Velero Plug-in for vSphere to complete
|
||||
// TODO - remove after upload progress monitoring is implemented
|
||||
func waitForVSphereUploadCompletion(ctx context.Context, timeout time.Duration, namespace string) error {
|
||||
err := wait.PollImmediate(time.Minute, timeout, func() (bool, error) {
|
||||
checkSnapshotCmd := exec.CommandContext(ctx, "kubectl",
|
||||
|
||||
Reference in New Issue
Block a user