diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a40b2d7e8..fc7f89322 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,6 +11,7 @@ `bug`, `enhancement`, `documentation`, `change`, `breaking`, `dependency` as they show up in the changelog - [ ] PR contains the label `area:operator` +- [ ] Commits are [signed off](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) - [ ] Link this PR to related issues - [ ] I have not made _any_ changes in the `charts/` directory. @@ -21,6 +22,7 @@ as they show up in the changelog - [ ] PR contains the label `area:chart` - [ ] PR contains the chart label, e.g. `chart:k8up` +- [ ] Commits are [signed off](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) - [ ] Variables are documented in the values.yaml using the format required by [Helm-Docs](https://github.com/norwoodj/helm-docs#valuesyaml-metadata). - [ ] Chart Version bumped if immediate release after merging is planned - [ ] I have run `make chart-docs` diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index da3bd69a7..47126912f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,4 +35,7 @@ jobs: ${{ runner.os }}-go- - name: Run tests + run: make test + + - name: Run integration tests run: make integration-test diff --git a/.gitignore b/.gitignore index f18f07550..0becf7a1e 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,11 @@ e2e/debug # Charts .cr-release-packages/ .cr-index/ + +# Vagrant +.vagrant/ + +# Container volumes mount +.config/ +.kube/ +.npm/ diff --git a/ADOPTERS.md b/ADOPTERS.md index fde5d11e8..fbaceb72e 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -25,3 +25,4 @@ This list is sorted in the order that organizations were added to it. | [VSHN](https://www.vshn.ch) | [@tobru](https://github.com/tobru/) | K8up was born at VSHN because at that time there was no other mature enough backup operator around. Today, K8up is integral part of the service offering and protects precious data every day. | | [amazee.io](https://www.amazee.io) | [@dasrecht](https://github.com/dasrecht/) | We use K8up as an integral part of our Disaster Recovery procedures. | | [Lagoon](https://github.com/uselagoon) | [@tobybellwood](https://github.com/tobybellwood/) | We've adopted K8up within [Lagoon](https://github.com/uselagoon). This keeps the data of all Lagoon customers safe and restorable. | +| [Kubezy](https://kubezy.com) | [@halil-bugol](https://github.com/halil-bugol/) | We use K8up as Backup Operator in our Kubernetes Management product.| diff --git a/Makefile b/Makefile index 0d3e4b409..f4629fb0c 100644 --- a/Makefile +++ b/Makefile @@ -27,21 +27,22 @@ include Makefile.restic-integration.mk envtest/integration.mk # E2E tests -include e2e/Makefile -go_build ?= go build -o $(BIN_FILENAME) $(K8UP_MAIN_GO) +go_build ?= $(GO_EXEC) build -o $(BIN_FILENAME) $(K8UP_MAIN_GO) .PHONY: test test: ## Run tests - go test ./... -coverprofile cover.out + $(GO_EXEC) test ./... -coverprofile cover.out .PHONY: build build: generate fmt vet $(BIN_FILENAME) docs-update-usage ## Build manager binary .PHONY: run +run: export ARGS := $(ARGS) operator run: export BACKUP_ENABLE_LEADER_ELECTION = $(ENABLE_LEADER_ELECTION) run: export K8UP_DEBUG = true run: export BACKUP_OPERATOR_NAMESPACE = default run: fmt vet ## Run against the configured Kubernetes cluster in ~/.kube/config. Use ARGS to pass arguments to the command, e.g. `make run ARGS="--help"` - go run $(K8UP_MAIN_GO) $(ARGS) $(CMD) $(CMD_ARGS) + $(GO_EXEC) run $(K8UP_MAIN_GO) $(ARGS) $(CMD) $(CMD_ARGS) .PHONY: run-operator run-operator: CMD := operator @@ -80,9 +81,9 @@ deploy: kind-load-image install ## Deploy controller in the configured Kubernete .PHONY: generate generate: ## Generate manifests e.g. CRD, RBAC etc. # Generate code - go run sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=".github/boilerplate.go.txt" paths="./..." + $(GO_EXEC) run sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=".github/boilerplate.go.txt" paths="./..." # Generate CRDs - go run sigs.k8s.io/controller-tools/cmd/controller-gen rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=$(CRD_ROOT_DIR)/v1 crd:crdVersions=v1 + $(GO_EXEC) run sigs.k8s.io/controller-tools/cmd/controller-gen rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=$(CRD_ROOT_DIR)/v1 crd:crdVersions=v1 .PHONY: crd crd: generate ## Generate CRD to file @@ -90,11 +91,11 @@ crd: generate ## Generate CRD to file .PHONY: fmt fmt: ## Run go fmt against code - go fmt ./... + $(GO_EXEC) fmt ./... .PHONY: vet vet: ## Run go vet against code - go vet ./... + $(GO_EXEC) vet ./... .PHONY: lint lint: fmt vet golangci-lint ## Invokes all linting targets diff --git a/Makefile.restic-integration.vars.mk b/Makefile.restic-integration.vars.mk index d3d0e2ff4..0555f857d 100644 --- a/Makefile.restic-integration.vars.mk +++ b/Makefile.restic-integration.vars.mk @@ -13,7 +13,7 @@ restore_dir ?= $(integrationtest_dir)/restore stats_url ?= http://localhost:8091 -restic_version ?= $(shell go mod edit -json | jq -r '.Require[] | select(.Path == "github.com/restic/restic").Version' | sed "s/v//") +restic_version ?= $(shell $(GO_EXEC) mod edit -json | jq -r '.Require[] | select(.Path == "github.com/restic/restic").Version' | sed "s/v//") restic_path ?= $(go_bin)/restic restic_pid ?= $(integrationtest_dir)/restic.pid restic_url ?= https://github.com/restic/restic/releases/download/v$(restic_version)/restic_$(restic_version)_$(os)_$(arch).bz2 diff --git a/Makefile.vars.mk b/Makefile.vars.mk index 6485686dc..6f499bba0 100644 --- a/Makefile.vars.mk +++ b/Makefile.vars.mk @@ -1,5 +1,6 @@ IMG_TAG ?= latest +GO_EXEC ?= go K8UP_MAIN_GO ?= cmd/k8up/main.go K8UP_GOOS ?= linux K8UP_GOARCH ?= amd64 diff --git a/api/v1/archive_types.go b/api/v1/archive_types.go index 6a1411b35..e6c68d4f9 100644 --- a/api/v1/archive_types.go +++ b/api/v1/archive_types.go @@ -1,10 +1,12 @@ package v1 import ( + "context" "reflect" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // ArchiveSpec defines the desired state of Archive. @@ -87,6 +89,13 @@ func (a *Archive) GetSuccessfulJobsHistoryLimit() *int { return a.Spec.KeepJobs } +func (a *Archive) GetPodConfig(ctx context.Context, c client.Client) (*PodConfig, error) { + if a.Spec.RunnableSpec.PodConfigRef == nil { + return nil, nil + } + return NewPodConfig(ctx, a.Spec.RunnableSpec.PodConfigRef.Name, a.GetNamespace(), c) +} + // GetJobObjects returns a sortable list of jobs func (a *ArchiveList) GetJobObjects() JobObjectList { items := make(JobObjectList, len(a.Items)) diff --git a/api/v1/backend.go b/api/v1/backend.go index 7afdf6034..426b0adfe 100644 --- a/api/v1/backend.go +++ b/api/v1/backend.go @@ -25,6 +25,11 @@ type ( Swift *SwiftSpec `json:"swift,omitempty"` B2 *B2Spec `json:"b2,omitempty"` Rest *RestServerSpec `json:"rest,omitempty"` + InsecureTLS bool `json:"insecureTLS,omitempty"` + + + TLSOptions *TLSOptions `json:"tlsOptions,omitempty"` + VolumeMounts *[]corev1.VolumeMount `json:"volumeMounts,omitempty"` } // +k8s:deepcopy-gen=false @@ -279,3 +284,9 @@ func (in *RestServerSpec) String() string { protocol, url, _ := strings.Cut(in.URL, "://") return fmt.Sprintf("rest:%s://%s:%s@%s", protocol, "$(USER)", "$(PASSWORD)", url) } + +type TLSOptions struct { + CACert string `json:"caCert,omitempty"` + ClientCert string `json:"clientCert,omitempty"` + ClientKey string `json:"clientKey,omitempty"` +} diff --git a/api/v1/backup_types.go b/api/v1/backup_types.go index 998ad509e..61b40a575 100644 --- a/api/v1/backup_types.go +++ b/api/v1/backup_types.go @@ -1,10 +1,12 @@ package v1 import ( + "context" "reflect" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // BackupSpec defines a single backup. It must contain all information to connect to @@ -127,6 +129,13 @@ func (b *Backup) GetSuccessfulJobsHistoryLimit() *int { return b.Spec.KeepJobs } +func (b *Backup) GetPodConfig(ctx context.Context, c client.Client) (*PodConfig, error) { + if b.Spec.RunnableSpec.PodConfigRef == nil { + return nil, nil + } + return NewPodConfig(ctx, b.Spec.RunnableSpec.PodConfigRef.Name, b.GetNamespace(), c) +} + // GetJobObjects returns a sortable list of jobs func (b *BackupList) GetJobObjects() JobObjectList { items := make(JobObjectList, len(b.Items)) diff --git a/api/v1/check_types.go b/api/v1/check_types.go index a93e4bde5..ffa3379a3 100644 --- a/api/v1/check_types.go +++ b/api/v1/check_types.go @@ -1,10 +1,12 @@ package v1 import ( + "context" "reflect" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // CheckSpec defines the desired state of Check. It needs to contain the repository @@ -106,6 +108,13 @@ func (c *Check) GetSuccessfulJobsHistoryLimit() *int { return c.Spec.KeepJobs } +func (b *Check) GetPodConfig(ctx context.Context, c client.Client) (*PodConfig, error) { + if b.Spec.RunnableSpec.PodConfigRef == nil { + return nil, nil + } + return NewPodConfig(ctx, b.Spec.RunnableSpec.PodConfigRef.Name, b.GetNamespace(), c) +} + // GetJobObjects returns a sortable list of jobs func (c *CheckList) GetJobObjects() JobObjectList { items := make(JobObjectList, len(c.Items)) diff --git a/api/v1/job_object.go b/api/v1/job_object.go index 194a2544c..4de1a4e2a 100644 --- a/api/v1/job_object.go +++ b/api/v1/job_object.go @@ -1,6 +1,8 @@ package v1 import ( + "context" + corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -19,6 +21,8 @@ type JobObject interface { GetPodSecurityContext() *corev1.PodSecurityContext // GetActiveDeadlineSeconds returns the specified active deadline seconds timeout. GetActiveDeadlineSeconds() *int64 + // GetPodConfig returns the defined PodSpec + GetPodConfig(context.Context, client.Client) (*PodConfig, error) } // +k8s:deepcopy-gen=false diff --git a/api/v1/podconfig_types.go b/api/v1/podconfig_types.go new file mode 100644 index 000000000..8a9e5d0d3 --- /dev/null +++ b/api/v1/podconfig_types.go @@ -0,0 +1,60 @@ +package v1 + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// +kubebuilder:rbac:groups=k8up.io,resources=podconfigs,verbs=get;list;watch + +// PodConfigSpec contains the podTemplate definition. +type PodConfigSpec struct { + Template corev1.PodTemplateSpec `json:"template,omitempty"` +} + +// PodConfigStatus defines the observed state of Snapshot +type PodConfigStatus struct { +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// PodConfig is the Schema for the PodConcig API +// Any annotations and labels set on this object will also be set on +// the final pod. +type PodConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PodConfigSpec `json:"spec,omitempty"` + Status PodConfigStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// SnapshotList contains a list of Snapshot +type PodConfigList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PodConfig `json:"items"` +} + +func NewPodConfig(ctx context.Context, name, namespace string, c client.Client) (*PodConfig, error) { + config := &PodConfig{} + err := c.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, config) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, nil + } + return nil, err + } + return config, nil +} + +func init() { + SchemeBuilder.Register(&PodConfig{}, &PodConfigList{}) +} diff --git a/api/v1/prune_types.go b/api/v1/prune_types.go index fb1fed0ac..31c452e0d 100644 --- a/api/v1/prune_types.go +++ b/api/v1/prune_types.go @@ -1,10 +1,12 @@ package v1 import ( + "context" "reflect" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // PruneSpec needs to contain the repository information as well as the desired @@ -115,6 +117,13 @@ func (p *Prune) GetSuccessfulJobsHistoryLimit() *int { return p.Spec.KeepJobs } +func (p *Prune) GetPodConfig(ctx context.Context, c client.Client) (*PodConfig, error) { + if p.Spec.RunnableSpec.PodConfigRef == nil { + return nil, nil + } + return NewPodConfig(ctx, p.Spec.RunnableSpec.PodConfigRef.Name, p.GetNamespace(), c) +} + // GetJobObjects returns a sortable list of jobs func (p *PruneList) GetJobObjects() JobObjectList { items := make(JobObjectList, len(p.Items)) diff --git a/api/v1/restore_types.go b/api/v1/restore_types.go index 780b69c66..fbfb72754 100644 --- a/api/v1/restore_types.go +++ b/api/v1/restore_types.go @@ -1,10 +1,12 @@ package v1 import ( + "context" "reflect" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // RestoreSpec can either contain an S3 restore point or a local one. For the local @@ -35,8 +37,10 @@ type RestoreSpec struct { // RestoreMethod contains how and where the restore should happen // all the settings are mutual exclusive. type RestoreMethod struct { - S3 *S3Spec `json:"s3,omitempty"` - Folder *FolderRestore `json:"folder,omitempty"` + S3 *S3Spec `json:"s3,omitempty"` + Folder *FolderRestore `json:"folder,omitempty"` + TLSOptions *TLSOptions `json:"tlsOptions,omitempty"` + VolumeMounts *[]corev1.VolumeMount `json:"volumeMounts,omitempty"` } type FolderRestore struct { @@ -105,6 +109,13 @@ func (r *Restore) GetSuccessfulJobsHistoryLimit() *int { return r.Spec.KeepJobs } +func (r *Restore) GetPodConfig(ctx context.Context, c client.Client) (*PodConfig, error) { + if r.Spec.RunnableSpec.PodConfigRef == nil { + return nil, nil + } + return NewPodConfig(ctx, r.Spec.RunnableSpec.PodConfigRef.Name, r.GetNamespace(), c) +} + // GetJobObjects returns a sortable list of jobs func (r *RestoreList) GetJobObjects() JobObjectList { items := make(JobObjectList, len(r.Items)) diff --git a/api/v1/runnable_types.go b/api/v1/runnable_types.go index a71249217..cc15cde76 100644 --- a/api/v1/runnable_types.go +++ b/api/v1/runnable_types.go @@ -15,11 +15,40 @@ type RunnableSpec struct { // PodSecurityContext describes the security context with which this action shall be executed. PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + // PodConfigRef describes the pod spec with wich this action shall be executed. + // It takes precedence over the Resources or PodSecurityContext field. + // It does not allow changing the image or the command of the resulting pod. + // This is for advanced use-cases only. Please only set this if you know what you're doing. + PodConfigRef *corev1.LocalObjectReference `json:"podConfigRef,omitempty"` + + // Volumes List of volumes that can be mounted by containers belonging to the pod. + Volumes *[]RunnableVolumeSpec `json:"volumes,omitempty"` + // ActiveDeadlineSeconds specifies the duration in seconds relative to the startTime that the job may be continuously active before the system tries to terminate it. // Value must be positive integer if given. ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"` } +type RunnableVolumeSpec struct { + // name of the volume. + // Must be a DNS_LABEL and unique within the pod. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + Name string `json:"name"` + + // persistentVolumeClaimVolumeSource represents a reference to a + // PersistentVolumeClaim in the same namespace. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + PersistentVolumeClaim *corev1.PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty"` + // secret represents a secret that should populate this volume. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + // +optional + Secret *corev1.SecretVolumeSource `json:"secret,omitempty"` + // configMap represents a configMap that should populate this volume + // +optional + ConfigMap *corev1.ConfigMapVolumeSource `json:"configMap,omitempty"` +} + // AppendEnvFromToContainer will add EnvFromSource from the given RunnableSpec to the Container func (in *RunnableSpec) AppendEnvFromToContainer(containerSpec *corev1.Container) { if in.Backend != nil { diff --git a/api/v1/schedule_types.go b/api/v1/schedule_types.go index cd77398c8..54fe13002 100644 --- a/api/v1/schedule_types.go +++ b/api/v1/schedule_types.go @@ -1,11 +1,13 @@ package v1 import ( + "context" "strings" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" ) // ScheduleSpec defines the schedules for the various job types. @@ -36,6 +38,10 @@ type ScheduleSpec struct { // PodSecurityContext describes the security context with which actions (such as backups) shall be executed. PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"` + + // PodConfigRef will apply the given template to all job definitions in this Schedule. + // It can be overriden for specific jobs if necessary. + PodConfigRef *corev1.LocalObjectReference `json:"podConfigRef,omitempty"` } // ScheduleDefinition is the actual cron-type expression that defines the interval of the actions. @@ -185,6 +191,13 @@ func (s *Schedule) GetSuccessfulJobsHistoryLimit() *int { return s.Spec.KeepJobs } +func (s *Schedule) GetPodConfig(ctx context.Context, c client.Client) (*PodConfig, error) { + if s.Spec.PodConfigRef == nil { + return nil, nil + } + return NewPodConfig(ctx, s.Spec.PodConfigRef.Name, s.GetNamespace(), c) +} + // String casts the value to string. // "aScheduleDefinition.String()" and "string(aScheduleDefinition)" are equivalent. func (s ScheduleDefinition) String() string { diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index f536307f7..85c50f571 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -210,6 +210,22 @@ func (in *Backend) DeepCopyInto(out *Backend) { *out = new(RestServerSpec) (*in).DeepCopyInto(*out) } + if in.TLSOptions != nil { + in, out := &in.TLSOptions, &out.TLSOptions + *out = new(TLSOptions) + **out = **in + } + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = new([]corev1.VolumeMount) + if **in != nil { + in, out := *in, *out + *out = make([]corev1.VolumeMount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backend. @@ -581,6 +597,96 @@ func (in *Pod) DeepCopy() *Pod { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodConfig) DeepCopyInto(out *PodConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodConfig. +func (in *PodConfig) DeepCopy() *PodConfig { + if in == nil { + return nil + } + out := new(PodConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodConfig) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodConfigList) DeepCopyInto(out *PodConfigList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PodConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodConfigList. +func (in *PodConfigList) DeepCopy() *PodConfigList { + if in == nil { + return nil + } + out := new(PodConfigList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PodConfigList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodConfigSpec) DeepCopyInto(out *PodConfigSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodConfigSpec. +func (in *PodConfigSpec) DeepCopy() *PodConfigSpec { + if in == nil { + return nil + } + out := new(PodConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodConfigStatus) DeepCopyInto(out *PodConfigStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodConfigStatus. +func (in *PodConfigStatus) DeepCopy() *PodConfigStatus { + if in == nil { + return nil + } + out := new(PodConfigStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PreBackupPod) DeepCopyInto(out *PreBackupPod) { *out = *in @@ -868,6 +974,22 @@ func (in *RestoreMethod) DeepCopyInto(out *RestoreMethod) { *out = new(FolderRestore) (*in).DeepCopyInto(*out) } + if in.TLSOptions != nil { + in, out := &in.TLSOptions, &out.TLSOptions + *out = new(TLSOptions) + **out = **in + } + if in.VolumeMounts != nil { + in, out := &in.VolumeMounts, &out.VolumeMounts + *out = new([]corev1.VolumeMount) + if **in != nil { + in, out := *in, *out + *out = make([]corev1.VolumeMount, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreMethod. @@ -986,6 +1108,22 @@ func (in *RunnableSpec) DeepCopyInto(out *RunnableSpec) { *out = new(corev1.PodSecurityContext) (*in).DeepCopyInto(*out) } + if in.PodConfigRef != nil { + in, out := &in.PodConfigRef, &out.PodConfigRef + *out = new(corev1.LocalObjectReference) + **out = **in + } + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = new([]RunnableVolumeSpec) + if **in != nil { + in, out := *in, *out + *out = make([]RunnableVolumeSpec, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + } if in.ActiveDeadlineSeconds != nil { in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds *out = new(int64) @@ -1003,6 +1141,36 @@ func (in *RunnableSpec) DeepCopy() *RunnableSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RunnableVolumeSpec) DeepCopyInto(out *RunnableVolumeSpec) { + *out = *in + if in.PersistentVolumeClaim != nil { + in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim + *out = new(corev1.PersistentVolumeClaimVolumeSource) + **out = **in + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(corev1.SecretVolumeSource) + (*in).DeepCopyInto(*out) + } + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(corev1.ConfigMapVolumeSource) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnableVolumeSpec. +func (in *RunnableVolumeSpec) DeepCopy() *RunnableVolumeSpec { + if in == nil { + return nil + } + out := new(RunnableVolumeSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S3Spec) DeepCopyInto(out *S3Spec) { *out = *in @@ -1156,6 +1324,11 @@ func (in *ScheduleSpec) DeepCopyInto(out *ScheduleSpec) { *out = new(corev1.PodSecurityContext) (*in).DeepCopyInto(*out) } + if in.PodConfigRef != nil { + in, out := &in.PodConfigRef, &out.PodConfigRef + *out = new(corev1.LocalObjectReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScheduleSpec. @@ -1343,3 +1516,18 @@ func (in *SwiftSpec) DeepCopy() *SwiftSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSOptions) DeepCopyInto(out *TLSOptions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSOptions. +func (in *TLSOptions) DeepCopy() *TLSOptions { + if in == nil { + return nil + } + out := new(TLSOptions) + in.DeepCopyInto(out) + return out +} diff --git a/charts/k8up/Chart.yaml b/charts/k8up/Chart.yaml index 5ba505310..98fea299f 100644 --- a/charts/k8up/Chart.yaml +++ b/charts/k8up/Chart.yaml @@ -6,7 +6,7 @@ keywords: - backup - operator - restic -version: 4.5.1 +version: 4.7.0 sources: - https://github.com/k8up-io/k8up maintainers: diff --git a/charts/k8up/README.md b/charts/k8up/README.md index bf7e622f2..7f89a9b7a 100644 --- a/charts/k8up/README.md +++ b/charts/k8up/README.md @@ -1,6 +1,6 @@ # k8up -![Version: 4.5.1](https://img.shields.io/badge/Version-4.5.1-informational?style=flat-square) +![Version: 4.7.0](https://img.shields.io/badge/Version-4.7.0-informational?style=flat-square) Kubernetes and OpenShift Backup Operator based on restic @@ -13,7 +13,7 @@ helm repo add k8up-io https://k8up-io.github.io/k8up helm install k8up k8up-io/k8up ``` ```bash -kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.5.1/k8up-crd.yaml +kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.7.0/k8up-crd.yaml ```