Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package k8up-cli for openSUSE:Factory checked in at 2025-03-05 15:18:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/k8up-cli (Old) and /work/SRC/openSUSE:Factory/.k8up-cli.new.19136 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "k8up-cli" Wed Mar 5 15:18:51 2025 rev:4 rq:1250355 version:2.12.0 Changes: -------- --- /work/SRC/openSUSE:Factory/k8up-cli/k8up-cli.changes 2024-12-16 19:14:00.530679516 +0100 +++ /work/SRC/openSUSE:Factory/.k8up-cli.new.19136/k8up-cli.changes 2025-03-05 15:18:56.783875199 +0100 @@ -1,0 +2,6 @@ +Wed Mar 05 10:04:05 UTC 2025 - [email protected] + +- Update to version 2.12.0: + No CLI-related changes in the changelog + +------------------------------------------------------------------- Old: ---- k8up-cli-2.11.3.obscpio New: ---- k8up-cli-2.12.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ k8up-cli.spec ++++++ --- /var/tmp/diff_new_pack.wFv7Nt/_old 2025-03-05 15:18:57.843919430 +0100 +++ /var/tmp/diff_new_pack.wFv7Nt/_new 2025-03-05 15:18:57.843919430 +0100 @@ -1,7 +1,7 @@ # # spec file for package k8up-cli # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,12 +16,10 @@ # -%define __arch_install_post export NO_BRP_STRIP_DEBUG=true - %define executable_name k8up Name: k8up-cli -Version: 2.11.3 +Version: 2.12.0 Release: 0 Summary: CLI for the K8up Kubernetes and OpenShift Backup Operator License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.wFv7Nt/_old 2025-03-05 15:18:57.871920598 +0100 +++ /var/tmp/diff_new_pack.wFv7Nt/_new 2025-03-05 15:18:57.875920766 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/k8up-io/k8up/</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v2.11.3</param> + <param name="revision">v2.12.0</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.wFv7Nt/_old 2025-03-05 15:18:57.891921433 +0100 +++ /var/tmp/diff_new_pack.wFv7Nt/_new 2025-03-05 15:18:57.895921600 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/k8up-io/k8up/</param> - <param name="changesrevision">be9529f1242148b614a3d0911e7c655955b2835e</param></service></servicedata> + <param name="changesrevision">0e10a932db96ef91d6fb2b69bbb16439e2fcdb73</param></service></servicedata> (No newline at EOF) ++++++ k8up-cli-2.11.3.obscpio -> k8up-cli-2.12.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/Makefile new/k8up-cli-2.12.0/Makefile --- old/k8up-cli-2.11.3/Makefile 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/Makefile 2025-02-28 12:47:40.000000000 +0100 @@ -75,7 +75,7 @@ --set image.registry=$(E2E_REGISTRY) \ --set image.repository=$(E2E_REPO) \ --set image.tag=$(E2E_TAG) \ - --values ./e2e/definitions/operator/deploy.yaml \ + --values ./e2e/definitions/operator/values.yaml \ --wait $(deploy_args) .PHONY: generate diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/README.md new/k8up-cli-2.12.0/README.md --- old/k8up-cli-2.11.3/README.md 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/README.md 2025-02-28 12:47:40.000000000 +0100 @@ -43,7 +43,7 @@ - `helm` (version 3) - `jq` -- `yq` +- `yq` (make sure to use [mikefarah/yq](https://github.com/mikefarah/yq) and not [kislyuk/yq](https://github.com/kislyuk/yq)) - `node` and `npm` - `bash` (installed, doesn't have to be your default shell) - `base64` @@ -52,11 +52,11 @@ These are the most common make targets: `build`, `test`, `docker-build`, `run`, `kind-run`. Run `make help` to get an overview over the relevant targets and their intentions. -You can find the project roadmap at [k8up.io](https://k8up.io/k8up/about/roadmap.html). +You can find the project roadmap [here](https://github.com/orgs/k8up-io/projects/2). We use [Snyk](https://snyk.io/test/github/k8up-io/k8up) to test the code regularly for vulnerabilities and other security issues. -If you find any security issue, please follow our [Vulnerability Reporting](https://k8up.io/k8up/about/vulnerability_reporting.html) process. +If you find any security issue, please follow our [Vulnerability Reporting](https://k8up.io/vulnerabilities/) process. ### Code Structure @@ -145,7 +145,7 @@ # Community -Read more about our community [in the documentation](https://k8up.io/k8up/about/community.html). +Read more about our community [in the documentation](https://k8up.io/community/). ## Chat with us @@ -153,11 +153,11 @@ ## Monthly community meeting -We host a monthly community meeting. For more information, head over to [the community documentation](https://k8up.io/k8up/about/community.html). +We host a monthly community meeting. For more information, head over to [the community documentation](https://k8up.io/community/). ## Code of Conduct -Our code of conduct can be read at [k8up.io](https://k8up.io/k8up/about/code_of_conduct.html). +Our code of conduct can be read at [k8up.io](https://k8up.io/coc/). [build]: https://github.com/k8up-io/k8up/actions?query=workflow%3ATest [releases]: https://github.com/k8up-io/k8up/releases diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/api/v1/backup_types.go new/k8up-cli-2.12.0/api/v1/backup_types.go --- old/k8up-cli-2.11.3/api/v1/backup_types.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/api/v1/backup_types.go 2025-02-28 12:47:40.000000000 +0100 @@ -33,6 +33,10 @@ // +optional PromURL string `json:"promURL,omitempty"` + // ClusterName sets the kubernetes cluster name to send to pushgateway for grouping metrics + // +optional + ClusterName string `json:"clusterName,omitempty"` + // StatsURL sets an arbitrary URL where the restic container posts metrics and // information about the snapshots to. This is in addition to the prometheus // pushgateway. @@ -40,6 +44,11 @@ // Tags is a list of arbitrary tags that get added to the backup via Restic's tagging system Tags []string `json:"tags,omitempty"` + + // LabelSelectors is a list of selectors that we filter for. + // When defined, only PVCs and PreBackupPods matching them are backed up. + // +optional + LabelSelectors []metav1.LabelSelector `json:"labelSelectors,omitempty"` } type BackupTemplate struct { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/api/v1/check_types.go new/k8up-cli-2.12.0/api/v1/check_types.go --- old/k8up-cli-2.11.3/api/v1/check_types.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/api/v1/check_types.go 2025-02-28 12:47:40.000000000 +0100 @@ -18,6 +18,10 @@ // +optional PromURL string `json:"promURL,omitempty"` + // ClusterName sets the kubernetes cluster name to send to pushgateway for grouping metrics + // +optional + ClusterName string `json:"clusterName,omitempty"` + // KeepJobs amount of jobs to keep for later analysis. // // Deprecated: Use FailedJobsHistoryLimit and SuccessfulJobsHistoryLimit respectively. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/api/v1/zz_generated.deepcopy.go new/k8up-cli-2.12.0/api/v1/zz_generated.deepcopy.go --- old/k8up-cli-2.11.3/api/v1/zz_generated.deepcopy.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/api/v1/zz_generated.deepcopy.go 2025-02-28 12:47:40.000000000 +0100 @@ -342,6 +342,13 @@ *out = make([]string, len(*in)) copy(*out, *in) } + if in.LabelSelectors != nil { + in, out := &in.LabelSelectors, &out.LabelSelectors + *out = make([]metav1.LabelSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BackupSpec. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/charts/k8up/Chart.yaml new/k8up-cli-2.12.0/charts/k8up/Chart.yaml --- old/k8up-cli-2.11.3/charts/k8up/Chart.yaml 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/charts/k8up/Chart.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -6,7 +6,7 @@ - backup - operator - restic -version: 4.8.2 +version: 4.8.3 sources: - https://github.com/k8up-io/k8up maintainers: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/charts/k8up/README.md new/k8up-cli-2.12.0/charts/k8up/README.md --- old/k8up-cli-2.11.3/charts/k8up/README.md 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/charts/k8up/README.md 2025-02-28 12:47:40.000000000 +0100 @@ -1,6 +1,6 @@ # k8up - + Kubernetes and OpenShift Backup Operator based on restic @@ -13,7 +13,7 @@ helm install k8up k8up-io/k8up ``` ```bash -kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.8.2/k8up-crd.yaml --server-side +kubectl apply -f https://github.com/k8up-io/k8up/releases/download/k8up-4.8.3/k8up-crd.yaml --server-side ``` <!--- @@ -48,7 +48,7 @@ | image.pullPolicy | string | `"IfNotPresent"` | Operator image pull policy | | image.registry | string | `"ghcr.io"` | Operator image registry | | image.repository | string | `"k8up-io/k8up"` | Operator image repository | -| image.tag | string | `"v2.11.2"` | Operator image tag (version) | +| image.tag | string | `"v2.11.3"` | Operator image tag (version) | | imagePullSecrets | list | `[]` | | | k8up.backupImage.repository | string | `""` | The backup runner image repository. Defaults to `{image.registry}/{image.repository}`. Specify an image repository including registry, e.g. `example.com/repo/image` | | k8up.backupImage.tag | string | `""` | The backup runner image tag Defaults to `{image.tag}` | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/charts/k8up/values.yaml new/k8up-cli-2.12.0/charts/k8up/values.yaml --- old/k8up-cli-2.11.3/charts/k8up/values.yaml 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/charts/k8up/values.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -10,7 +10,7 @@ # -- Operator image repository repository: k8up-io/k8up # -- Operator image tag (version) - tag: v2.11.2 + tag: v2.11.3 imagePullSecrets: [] serviceAccount: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/cmd/operator/main.go new/k8up-cli-2.12.0/cmd/operator/main.go --- old/k8up-cli-2.11.3/cmd/operator/main.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/cmd/operator/main.go 2025-02-28 12:47:40.000000000 +0100 @@ -39,6 +39,7 @@ &cli.StringFlag{Destination: &cfg.Config.BackupAnnotation, Name: "annotation", EnvVars: []string{"BACKUP_ANNOTATION"}, Value: "k8up.io/backup", Usage: "the annotation to be used for filtering"}, &cli.StringFlag{Destination: &cfg.Config.BackupCommandAnnotation, Name: "backupcommandannotation", EnvVars: []string{"BACKUP_BACKUPCOMMANDANNOTATION"}, Value: "k8up.io/backupcommand", Usage: "set the annotation name that identify the backup commands on Pods"}, &cli.StringFlag{Destination: &cfg.Config.FileExtensionAnnotation, Name: "fileextensionannotation", EnvVars: []string{"BACKUP_FILEEXTENSIONANNOTATION"}, Value: "k8up.io/file-extension", Usage: "set the annotation name where the file extension is stored for backup commands"}, + &cli.StringFlag{Destination: &cfg.Config.BackupResticArgsAnnotation, Name: "backupresticargsannotation", EnvVars: []string{"BACKUP_RESTICARGSANNOTATION"}, Value: "k8up.io/backup-restic-args", Usage: "set the annotation name to be used to modify restic wrapper call args on backup (e.g. to add excludes)"}, &cli.IntFlag{Destination: &cfg.Config.GlobalKeepJobs, Hidden: true, Name: "globalkeepjobs", EnvVars: []string{"BACKUP_GLOBALKEEPJOBS"}, Value: -1, DefaultText: "unlimited", Usage: "set the number of old jobs to keep when cleaning up, applies to all job types"}, &cli.IntFlag{Destination: &cfg.Config.GlobalBackoffLimit, Name: "global-backoff-limit", EnvVars: []string{"BACKUP_GLOBAL_BACKOFF_LIMIT"}, Value: 6, Usage: "set the backoff limit for all backup jobs"}, @@ -74,7 +75,7 @@ &cli.StringFlag{Destination: &cfg.Config.GlobalStatsURL, Name: "globalstatsurl", EnvVars: []string{"BACKUP_GLOBALSTATSURL"}, Usage: "set the URL to post metrics globally"}, &cli.StringFlag{Destination: &cfg.Config.MetricsBindAddress, Name: "metrics-bindaddress", EnvVars: []string{"BACKUP_METRICS_BINDADDRESS"}, Value: ":8080", Usage: "set the bind address for the prometheus endpoint"}, &cli.StringFlag{Destination: &cfg.Config.PromURL, Name: "promurl", EnvVars: []string{"BACKUP_PROMURL"}, Value: "http://127.0.0.1/", Usage: "set the operator wide default prometheus push gateway"}, - + &cli.StringFlag{Destination: &cfg.Config.ClusterName, Name: "clusterName", EnvVars: []string{"CLUSTER_NAME"}, Value: "default", Usage: "set the operator wide kubernetes cluster name to send to push gateway for grouping metrics"}, &cli.StringFlag{Destination: &cfg.Config.RestartPolicy, Name: "restartpolicy", EnvVars: []string{"BACKUP_RESTARTPOLICY"}, Value: "OnFailure", Usage: "set the RestartPolicy for the backup jobs. According to https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/, this should be 'OnFailure' for jobs that terminate"}, &cli.StringFlag{Destination: &cfg.Config.PodFilter, Name: "podfilter", EnvVars: []string{"BACKUP_PODFILTER"}, Value: "backupPod=true", Usage: "the filter used to find the backup pods"}, &cli.StringFlag{Destination: &cfg.Config.ServiceAccount, Name: "podexecaccountname", Aliases: []string{"serviceaccount"}, EnvVars: []string{"BACKUP_PODEXECACCOUNTNAME"}, Value: "pod-executor", Usage: "set the service account name that should be used for the pod command execution"}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/cmd/restic/integration_test.go new/k8up-cli-2.12.0/cmd/restic/integration_test.go --- old/k8up-cli-2.11.3/cmd/restic/integration_test.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/cmd/restic/integration_test.go 2025-02-28 12:47:40.000000000 +0100 @@ -91,9 +91,10 @@ ctx := context.Background() cfg.Config = &cfg.Configuration{ - Hostname: os.Getenv("HOSTNAME"), - PromURL: os.Getenv("PROM_URL"), - WebhookURL: os.Getenv("STATS_URL"), + Hostname: os.Getenv("HOSTNAME"), + PromURL: os.Getenv("PROM_URL"), + ClusterName: os.Getenv("CLUSTER_NAME"), + WebhookURL: os.Getenv("STATS_URL"), RestoreS3Endpoint: os.Getenv("RESTORE_S3ENDPOINT"), RestoreS3AccessKey: os.Getenv("RESTORE_ACCESSKEYID"), @@ -105,7 +106,7 @@ } mainLogger := zapr.NewLogger(zaptest.NewLogger(t)) - statHandler := stats.NewHandler(cfg.Config.PromURL, cfg.Config.Hostname, cfg.Config.WebhookURL, mainLogger) + statHandler := stats.NewHandler(cfg.Config.PromURL, cfg.Config.ClusterName, cfg.Config.Hostname, cfg.Config.WebhookURL, mainLogger) resticCli := cli.New(ctx, mainLogger, statHandler) cleanupDirs(t) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/cmd/restic/main.go new/k8up-cli-2.12.0/cmd/restic/main.go --- old/k8up-cli-2.11.3/cmd/restic/main.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/cmd/restic/main.go 2025-02-28 12:47:40.000000000 +0100 @@ -55,6 +55,7 @@ &cli.BoolFlag{Destination: &cfg.Config.SkipPreBackup, Name: "skipPreBackup", EnvVars: []string{"SKIP_PREBACKUP"}, Usage: "If the job should skip the backup command and only backup volumes."}, &cli.StringFlag{Destination: &cfg.Config.PromURL, Name: "promURL", EnvVars: []string{"PROM_URL"}, Usage: "Sets the URL of a prometheus push gateway to report metrics."}, + &cli.StringFlag{Destination: &cfg.Config.ClusterName, Name: "clusterName", EnvVars: []string{"CLUSTER_NAME"}, Usage: "Sets the Kubernetes cluster name for grouping metrics in push gateway"}, &cli.StringFlag{Destination: &cfg.Config.WebhookURL, Name: "webhookURL", Aliases: []string{"statsURL"}, EnvVars: []string{"STATS_URL"}, Usage: "Sets the URL of a server which will retrieve a webhook after the action completes."}, &cli.StringFlag{Destination: &cfg.Config.Hostname, Name: "hostname", EnvVars: []string{"HOSTNAME"}, Usage: "Sets the hostname to use in reports.", Hidden: true, Required: true}, @@ -79,6 +80,18 @@ &cli.StringFlag{Destination: &cfg.Config.ResticRepository, Name: "resticRepository", EnvVars: []string{"RESTIC_REPOSITORY"}, Usage: "The restic repository to perform the action with", Required: true}, &cli.StringFlag{Destination: &cfg.Config.ResticOptions, Name: "resticOptions", EnvVars: []string{"RESTIC_OPTIONS"}, Usage: "Additional options to pass to restic in the format 'key=value,key2=value2'"}, + &cli.StringSliceFlag{Name: "exclude", EnvVars: []string{"RESTIC_EXCLUDE"}, Usage: "In backup, passed to restic: exclude a `pattern` (can be specified multiple times)"}, + &cli.BoolFlag{Destination: &cfg.Config.ExcludeCaches, Name: "excludeCaches", EnvVars: []string{"RESTIC_EXCLUDE_CACHES"}, Usage: "In backup, passed to restic: excludes cache directories that are marked with a CACHEDIR.TAG file. See https://bford.info/cachedir/ for the Cache Directory Tagging Standard"}, + &cli.StringSliceFlag{Name: "excludeFile", EnvVars: []string{"RESTIC_EXCLUDE_FILE"}, Usage: "In backup, passed to restic: read exclude patterns from a `file` (can be specified multiple times). This file MUST be available in backup job container (e.g. in the directory being backed up)"}, + &cli.StringSliceFlag{Name: "excludeIfPresent", EnvVars: []string{"RESTIC_EXCLUDE_IF_PRESENT"}, Usage: "In backup, passed to restic: takes `filename[:header]`, exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times)"}, + &cli.StringFlag{Destination: &cfg.Config.ExcludeLargerThan, Name: "excludeLargerThan", EnvVars: []string{"RESTIC_EXCLUDE_LARGER_THAT"}, Usage: "In backup, passed to restic: max `size` of the files to be backed up (allowed suffixes: k/K, m/M, g/G, t/T)"}, + &cli.StringSliceFlag{Name: "filesFrom", EnvVars: []string{"RESTIC_FILES_FROM"}, Usage: "In backup, passed to restic: read the files to backup from `file` (can be combined with file args; can be specified multiple times)"}, + &cli.StringSliceFlag{Name: "filesFromRaw", EnvVars: []string{"RESTIC_FILES_FROM_RAW"}, Usage: "In backup, passed to restic: read the files to backup from `file` (can be combined with file args; can be specified multiple times)"}, + &cli.StringSliceFlag{Name: "filesFromVerbatim", EnvVars: []string{"RESTIC_FILES_FROM_VERBATIM"}, Usage: "In backup, passed to restic: read the files to backup from `file` (can be combined with file args; can be specified multiple times)"}, + &cli.StringSliceFlag{Name: "iExclude", EnvVars: []string{"RESTIC_IEXCLUDE"}, Usage: "In backup, passed to restic: same as --exclude `pattern` but ignores the casing of filenames"}, + &cli.StringSliceFlag{Name: "iExcludeFile", EnvVars: []string{"RESTIC_IEXCLUDE_FILE"}, Usage: "In backup, passed to restic: same as --exclude-file `pattern` but ignores the casing of filenames"}, + &cli.BoolFlag{Destination: &cfg.Config.OneFileSystem, Name: "oneFileSystem", EnvVars: []string{"RESTIC_ONE_FILESYSTEM"}, Usage: "In backup, passed to restic: exclude other file systems, don't cross filesystem boundaries and subvolumes"}, + &cli.IntFlag{Destination: &cfg.Config.PruneKeepLast, Name: "keepLatest", EnvVars: []string{"KEEP_LAST", "KEEP_LATEST"}, Usage: "While pruning, keep at the latest snapshot"}, &cli.IntFlag{Destination: &cfg.Config.PruneKeepHourly, Name: "keepHourly", EnvVars: []string{"KEEP_HOURLY"}, Usage: "While pruning, keep hourly snapshots"}, &cli.IntFlag{Destination: &cfg.Config.PruneKeepDaily, Name: "keepDaily", EnvVars: []string{"KEEP_DAILY"}, Usage: "While pruning, keep daily snapshots"}, @@ -112,6 +125,15 @@ cfg.Config.Tags = c.StringSlice("tag") cfg.Config.TargetPods = c.StringSlice("targetPods") + cfg.Config.Exclude = c.StringSlice("exclude") + cfg.Config.ExcludeFile = c.StringSlice("excludeFile") + cfg.Config.ExcludeIfPresent = c.StringSlice("excludeIfPresent") + cfg.Config.FilesFrom = c.StringSlice("filesFrom") + cfg.Config.FilesFromRaw = c.StringSlice("filesFromRaw") + cfg.Config.FilesFromVerbatim = c.StringSlice("filesFromVerbatim") + cfg.Config.IExclude = c.StringSlice("iExclude") + cfg.Config.IExcludeFile = c.StringSlice("iExcludeFile") + err := cfg.Config.Validate() if err != nil { return err @@ -120,7 +142,7 @@ ctx, cancel := context.WithCancel(c.Context) cancelOnTermination(cancel, resticLog) - statHandler := stats.NewHandler(cfg.Config.PromURL, cfg.Config.Hostname, cfg.Config.WebhookURL, resticLog) + statHandler := stats.NewHandler(cfg.Config.PromURL, cfg.Config.ClusterName, cfg.Config.Hostname, cfg.Config.WebhookURL, resticLog) resticCLI := resticCli.New(ctx, resticLog.WithName("restic"), statHandler) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/config/crd/apiextensions.k8s.io/v1/k8up.io_backups.yaml new/k8up-cli-2.12.0/config/crd/apiextensions.k8s.io/v1/k8up.io_backups.yaml --- old/k8up-cli-2.11.3/config/crd/apiextensions.k8s.io/v1/k8up.io_backups.yaml 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/config/crd/apiextensions.k8s.io/v1/k8up.io_backups.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -436,6 +436,10 @@ type: object type: array type: object + clusterName: + description: ClusterName sets the kubernetes cluster name to send + to pushgateway for grouping metrics + type: string failedJobsHistoryLimit: description: |- FailedJobsHistoryLimit amount of failed jobs to keep for later analysis. @@ -448,6 +452,58 @@ Deprecated: Use FailedJobsHistoryLimit and SuccessfulJobsHistoryLimit respectively. type: integer + labelSelectors: + description: |- + LabelSelectors is a list of selectors that we filter for. + When defined, only PVCs and PreBackupPods matching them are backed up. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + x-kubernetes-map-type: atomic + type: array podConfigRef: description: |- PodConfigRef describes the pod spec with wich this action shall be executed. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/config/crd/apiextensions.k8s.io/v1/k8up.io_checks.yaml new/k8up-cli-2.12.0/config/crd/apiextensions.k8s.io/v1/k8up.io_checks.yaml --- old/k8up-cli-2.11.3/config/crd/apiextensions.k8s.io/v1/k8up.io_checks.yaml 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/config/crd/apiextensions.k8s.io/v1/k8up.io_checks.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -431,6 +431,10 @@ type: object type: array type: object + clusterName: + description: ClusterName sets the kubernetes cluster name to send + to pushgateway for grouping metrics + type: string failedJobsHistoryLimit: description: |- FailedJobsHistoryLimit amount of failed jobs to keep for later analysis. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/config/crd/apiextensions.k8s.io/v1/k8up.io_schedules.yaml new/k8up-cli-2.12.0/config/crd/apiextensions.k8s.io/v1/k8up.io_schedules.yaml --- old/k8up-cli-2.11.3/config/crd/apiextensions.k8s.io/v1/k8up.io_schedules.yaml 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/config/crd/apiextensions.k8s.io/v1/k8up.io_schedules.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -1742,6 +1742,10 @@ type: object type: array type: object + clusterName: + description: ClusterName sets the kubernetes cluster name to send + to pushgateway for grouping metrics + type: string concurrentRunsAllowed: type: boolean failedJobsHistoryLimit: @@ -1756,6 +1760,58 @@ Deprecated: Use FailedJobsHistoryLimit and SuccessfulJobsHistoryLimit respectively. type: integer + labelSelectors: + description: |- + LabelSelectors is a list of selectors that we filter for. + When defined, only PVCs and PreBackupPods matching them are backed up. + items: + description: |- + A label selector is a label query over a set of resources. The result of matchLabels and + matchExpressions are ANDed. An empty label selector matches all objects. A null + label selector matches no objects. + 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 + x-kubernetes-map-type: atomic + type: array podConfigRef: description: |- PodConfigRef describes the pod spec with wich this action shall be executed. @@ -2574,6 +2630,10 @@ type: object type: array type: object + clusterName: + description: ClusterName sets the kubernetes cluster name to send + to pushgateway for grouping metrics + type: string concurrentRunsAllowed: type: boolean failedJobsHistoryLimit: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/config/samples/k8up_v1_schedule.yaml new/k8up-cli-2.12.0/config/samples/k8up_v1_schedule.yaml --- old/k8up-cli-2.11.3/config/samples/k8up_v1_schedule.yaml 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/config/samples/k8up_v1_schedule.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -41,6 +41,7 @@ failedJobsHistoryLimit: 2 successfulJobsHistoryLimit: 2 promURL: http://minio.minio:9000 + clusterName: default resources: requests: memory: "64Mi" @@ -55,6 +56,7 @@ cpu: "250m" schedule: '@hourly-random' promURL: http://minio.minio:9000 + clusterName: default prune: schedule: '*/4 * * * *' retention: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/docs/modules/ROOT/examples/usage/operator.txt new/k8up-cli-2.12.0/docs/modules/ROOT/examples/usage/operator.txt --- old/k8up-cli-2.11.3/docs/modules/ROOT/examples/usage/operator.txt 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/docs/modules/ROOT/examples/usage/operator.txt 2025-02-28 12:47:40.000000000 +0100 @@ -11,6 +11,8 @@ --annotation value the annotation to be used for filtering (default: "k8up.io/backup") [$BACKUP_ANNOTATION] --backupcommandannotation value set the annotation name that identify the backup commands on Pods (default: "k8up.io/backupcommand") [$BACKUP_BACKUPCOMMANDANNOTATION] --fileextensionannotation value set the annotation name where the file extension is stored for backup commands (default: "k8up.io/file-extension") [$BACKUP_FILEEXTENSIONANNOTATION] + --backupresticargsannotation value set the annotation name to be used to modify restic wrapper call args on backup (e.g. to add excludes) (default: "k8up.io/backup-restic-args") [$BACKUP_RESTICARGSANNOTATION] + --global-backoff-limit value set the backoff limit for all backup jobs (default: 6) [$BACKUP_GLOBAL_BACKOFF_LIMIT] --global-failed-jobs-history-limit value set the number of old, failed jobs to keep when cleaning up, applies to all job types (default: 3) [$BACKUP_GLOBAL_FAILED_JOBS_HISTORY_LIMIT] --global-successful-jobs-history-limit value set the number of old, successful jobs to keep when cleaning up, applies to all job types (default: 3) [$BACKUP_GLOBAL_SUCCESSFUL_JOBS_HISTORY_LIMIT] --global-concurrent-archive-jobs-limit value set the limit of concurrent archive jobs (default: unlimited) [$BACKUP_GLOBAL_CONCURRENT_ARCHIVE_JOBS_LIMIT] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/docs/modules/ROOT/examples/usage/restic.txt new/k8up-cli-2.12.0/docs/modules/ROOT/examples/usage/restic.txt --- old/k8up-cli-2.11.3/docs/modules/ROOT/examples/usage/restic.txt 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/docs/modules/ROOT/examples/usage/restic.txt 2025-02-28 12:47:40.000000000 +0100 @@ -8,50 +8,61 @@ Start k8up in restic mode OPTIONS: - --check Set, if the container should do a check (default: false) - --prune Set, if the container should do a prune (default: false) - --restore Set, if the container should attempt a restore (default: false) - --archive Set, if the container should do an archive (default: false) - --tag value [ --tag value ] List of tags to consider for given operation - --backupCommandAnnotation value Defines the command to invoke when doing a backup via STDOUT. [$BACKUPCOMMAND_ANNOTATION] - --fileExtensionAnnotation value Defines the file extension to use for STDOUT backups. [$FILEEXTENSION_ANNOTATION] - --backucontainerannotation value set the annotation name that specify the backup container inside the Pod (default: "k8up.io/backupcommand-container") [$BACKUP_CONTAINERANNOTATION] - --skipPreBackup If the job should skip the backup command and only backup volumes. (default: false) [$SKIP_PREBACKUP] - --promURL value Sets the URL of a prometheus push gateway to report metrics. [$PROM_URL] - --webhookURL value, --statsURL value Sets the URL of a server which will retrieve a webhook after the action completes. [$STATS_URL] - --backupDir value Set from which directory the backup should be performed. (default: "/data") [$BACKUP_DIR] - --restoreDir value Set to which directory the restore should be performed. (default: "/data") [$RESTORE_DIR] - --restoreFilter value Simple filter to define what should get restored. For example the PVC name - --restoreSnap value Snapshot ID, if empty takes the latest snapshot - --restoreType value Type of this restore, 'folder' or 's3' - --restoreS3AccessKey value S3 access key used to connect to the S3 endpoint when restoring [$RESTORE_ACCESSKEYID] - --restoreS3SecretKey value S3 secret key used to connect to the S3 endpoint when restoring [$RESTORE_SECRETACCESSKEY] - --restoreS3Endpoint value S3 endpoint to connect to when restoring, e.g. 'https://minio.svc:9000/backup [$RESTORE_S3ENDPOINT] - --restoreCaCert value The certificate authority file path using for restore [$RESTORE_CA_CERT_FILE] - --restoreClientCert value The client certificate file path using for restore [$RESTORE_CLIENT_CERT_FILE] - --restoreClientKey value The client private key file path using for restore [$RESTORE_CLIENT_KEY_FILE] - --verifyRestore If the restore should get verified, only for PVCs restore (default: false) - --trimRestorePath If set, strips the value of --restoreDir from the lefts side of the remote restore path value (default: enabled) [$TRIM_RESTOREPATH] - --resticBin value The path to the restic binary. (default: "/usr/local/bin/restic") [$RESTIC_BINARY] - --resticRepository value The restic repository to perform the action with [$RESTIC_REPOSITORY] - --resticOptions value Additional options to pass to restic in the format 'key=value,key2=value2' [$RESTIC_OPTIONS] - --keepLatest value While pruning, keep at the latest snapshot (default: 0) [$KEEP_LAST, $KEEP_LATEST] - --keepHourly value While pruning, keep hourly snapshots (default: 0) [$KEEP_HOURLY] - --keepDaily value While pruning, keep daily snapshots (default: 0) [$KEEP_DAILY] - --keepWeekly value While pruning, keep weekly snapshots (default: 0) [$KEEP_WEEKLY] - --keepMonthly value While pruning, keep monthly snapshots (default: 0) [$KEEP_MONTHLY] - --keepYearly value While pruning, keep yearly snapshots (default: 0) [$KEEP_YEARLY] - --keepTags While pruning, keep tagged snapshots (default: false) [$KEEP_TAG, $KEEP_TAGS] - --keepWithinHourly value While pruning, keep hourly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_HOURLY] - --keepWithinDaily value While pruning, keep daily snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_DAILY] - --keepWithinWeekly value While pruning, keep weekly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_WEEKLY] - --keepWithinMonthly value While pruning, keep monthly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_MONTHLY] - --keepWithinYearly value While pruning, keep yearly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_YEARLY] - --keepWithin value While pruning, keep tagged snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN] - --targetPods value [ --targetPods value ] Filter list of pods by TARGET_PODS names [$TARGET_PODS] - --sleepDuration value Sleep for specified amount until init starts (default: 0s) [$SLEEP_DURATION] - --varDir value The var directory is stored k8up metadata files and temporary files (default: "/k8up") - --caCert value The certificate authority file path [$CA_CERT_FILE] - --clientCert value The client certificate file path [$CLIENT_CERT_FILE] - --clientKey value The client private key file path [$CLIENT_KEY_FILE] - --help, -h show help (default: false) + --check Set, if the container should do a check (default: false) + --prune Set, if the container should do a prune (default: false) + --restore Set, if the container should attempt a restore (default: false) + --archive Set, if the container should do an archive (default: false) + --tag value [ --tag value ] List of tags to consider for given operation + --backupCommandAnnotation value Defines the command to invoke when doing a backup via STDOUT. [$BACKUPCOMMAND_ANNOTATION] + --fileExtensionAnnotation value Defines the file extension to use for STDOUT backups. [$FILEEXTENSION_ANNOTATION] + --backucontainerannotation value set the annotation name that specify the backup container inside the Pod (default: "k8up.io/backupcommand-container") [$BACKUP_CONTAINERANNOTATION] + --skipPreBackup If the job should skip the backup command and only backup volumes. (default: false) [$SKIP_PREBACKUP] + --promURL value Sets the URL of a prometheus push gateway to report metrics. [$PROM_URL] + --webhookURL value, --statsURL value Sets the URL of a server which will retrieve a webhook after the action completes. [$STATS_URL] + --backupDir value Set from which directory the backup should be performed. (default: "/data") [$BACKUP_DIR] + --restoreDir value Set to which directory the restore should be performed. (default: "/data") [$RESTORE_DIR] + --restoreFilter value Simple filter to define what should get restored. For example the PVC name + --restoreSnap value Snapshot ID, if empty takes the latest snapshot + --restoreType value Type of this restore, 'folder' or 's3' + --restoreS3AccessKey value S3 access key used to connect to the S3 endpoint when restoring [$RESTORE_ACCESSKEYID] + --restoreS3SecretKey value S3 secret key used to connect to the S3 endpoint when restoring [$RESTORE_SECRETACCESSKEY] + --restoreS3Endpoint value S3 endpoint to connect to when restoring, e.g. 'https://minio.svc:9000/backup [$RESTORE_S3ENDPOINT] + --restoreCaCert value The certificate authority file path using for restore [$RESTORE_CA_CERT_FILE] + --restoreClientCert value The client certificate file path using for restore [$RESTORE_CLIENT_CERT_FILE] + --restoreClientKey value The client private key file path using for restore [$RESTORE_CLIENT_KEY_FILE] + --verifyRestore If the restore should get verified, only for PVCs restore (default: false) + --trimRestorePath If set, strips the value of --restoreDir from the lefts side of the remote restore path value (default: enabled) [$TRIM_RESTOREPATH] + --resticBin value The path to the restic binary. (default: "/usr/local/bin/restic") [$RESTIC_BINARY] + --resticRepository value The restic repository to perform the action with [$RESTIC_REPOSITORY] + --resticOptions value Additional options to pass to restic in the format 'key=value,key2=value2' [$RESTIC_OPTIONS] + --exclude pattern [ --exclude pattern ] In backup, passed to restic: exclude a pattern (can be specified multiple times) [$RESTIC_EXCLUDE] + --excludeCaches In backup, passed to restic: excludes cache directories that are marked with a CACHEDIR.TAG file. See https://bford.info/cachedir/ for the Cache Directory Tagging Standard (default: false) [$RESTIC_EXCLUDE_CACHES] + --excludeFile file [ --excludeFile file ] In backup, passed to restic: read exclude patterns from a file (can be specified multiple times). This file MUST be available in backup job container (e.g. in the directory being backed up) [$RESTIC_EXCLUDE_FILE] + --excludeIfPresent filename[:header] [ --excludeIfPresent filename[:header] ] In backup, passed to restic: takes filename[:header], exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times) [$RESTIC_EXCLUDE_IF_PRESENT] + --excludeLargerThan size In backup, passed to restic: max size of the files to be backed up (allowed suffixes: k/K, m/M, g/G, t/T) [$RESTIC_EXCLUDE_LARGER_THAT] + --filesFrom file [ --filesFrom file ] In backup, passed to restic: read the files to backup from file (can be combined with file args; can be specified multiple times) [$RESTIC_FILES_FROM] + --filesFromRaw file [ --filesFromRaw file ] In backup, passed to restic: read the files to backup from file (can be combined with file args; can be specified multiple times) [$RESTIC_FILES_FROM_RAW] + --filesFromVerbatim file [ --filesFromVerbatim file ] In backup, passed to restic: read the files to backup from file (can be combined with file args; can be specified multiple times) [$RESTIC_FILES_FROM_VERBATIM] + --iExclude pattern [ --iExclude pattern ] In backup, passed to restic: same as --exclude pattern but ignores the casing of filenames [$RESTIC_IEXCLUDE] + --iExcludeFile pattern [ --iExcludeFile pattern ] In backup, passed to restic: same as --exclude-file pattern but ignores the casing of filenames [$RESTIC_IEXCLUDE_FILE] + --oneFileSystem In backup, passed to restic: exclude other file systems, don't cross filesystem boundaries and subvolumes (default: false) [$RESTIC_ONE_FILESYSTEM] + --keepLatest value While pruning, keep at the latest snapshot (default: 0) [$KEEP_LAST, $KEEP_LATEST] + --keepHourly value While pruning, keep hourly snapshots (default: 0) [$KEEP_HOURLY] + --keepDaily value While pruning, keep daily snapshots (default: 0) [$KEEP_DAILY] + --keepWeekly value While pruning, keep weekly snapshots (default: 0) [$KEEP_WEEKLY] + --keepMonthly value While pruning, keep monthly snapshots (default: 0) [$KEEP_MONTHLY] + --keepYearly value While pruning, keep yearly snapshots (default: 0) [$KEEP_YEARLY] + --keepTags While pruning, keep tagged snapshots (default: false) [$KEEP_TAG, $KEEP_TAGS] + --keepWithinHourly value While pruning, keep hourly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_HOURLY] + --keepWithinDaily value While pruning, keep daily snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_DAILY] + --keepWithinWeekly value While pruning, keep weekly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_WEEKLY] + --keepWithinMonthly value While pruning, keep monthly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_MONTHLY] + --keepWithinYearly value While pruning, keep yearly snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN_YEARLY] + --keepWithin value While pruning, keep tagged snapshots within the given duration, e.g. '2y5m7d3h' [$KEEP_WITHIN] + --targetPods value [ --targetPods value ] Filter list of pods by TARGET_PODS names [$TARGET_PODS] + --sleepDuration value Sleep for specified amount until init starts (default: 0s) [$SLEEP_DURATION] + --varDir value The var directory is stored k8up metadata files and temporary files (default: "/k8up") + --caCert value The certificate authority file path [$CA_CERT_FILE] + --clientCert value The client certificate file path [$CLIENT_CERT_FILE] + --clientKey value The client private key file path [$CLIENT_KEY_FILE] + --help, -h show help (default: false) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/docs/modules/ROOT/pages/how-tos/backup.adoc new/k8up-cli-2.12.0/docs/modules/ROOT/pages/how-tos/backup.adoc --- old/k8up-cli-2.11.3/docs/modules/ROOT/pages/how-tos/backup.adoc 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/docs/modules/ROOT/pages/how-tos/backup.adoc 2025-02-28 12:47:40.000000000 +0100 @@ -219,3 +219,70 @@ podConfigRef: name: podconfig ---- + +== Target specific PVCs or PreBackupPods + +An optional labelSelectors field can be specified to target PVCs or PreBackupPods matching those expressions. +You can specify multiple selectors - as long as at least one matches, the PVC/PreBackupPod will be included in the backup. + +Keep in mind that does NOT apply to terms within an individual labelSelector - this will be processed as usual, as we use the standard K8s API for this. +To find out how selectors themselves work, you can consult the upstream Kubernetes documentation: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + +Below you can find a practical example. It would back up any resources with "my-label-key" defined OR "another-label-key" with one of the accepted values. + +[source,yaml] +---- +apiVersion: k8up.io/v1 +kind: Backup +metadata: + name: backup-test +spec: + labelSelectors: + - matchExpressions: + - key: my-label-key + operator: Exists + - matchExpressions: + - key: another-label-key + operator: In + values: + - acceptable-value + - another-acceptable-value + failedJobsHistoryLimit: 2 + successfulJobsHistoryLimit: 2 + backend: + repoPasswordSecretRef: + name: backup-repo + key: password + s3: + endpoint: http://minio:9000 + bucket: backups + accessKeyIDSecretRef: + name: minio-credentials + key: username + secretAccessKeySecretRef: + name: minio-credentials + key: password + +---- + +If you'd like to only target entities having both labels, you can use a single labelSelector. +This change will cause the backup to select only entities matching both conditions. + +[source,yaml] +---- +apiVersion: k8up.io/v1 +kind: Backup +metadata: + name: backup-test +spec: + labelSelectors: + - matchExpressions: + - key: my-label-key + operator: Exists + - key: another-label-key + operator: In + values: + - acceptable-value + - another-acceptable-value +... +---- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/docs/modules/ROOT/pages/references/api-reference.adoc new/k8up-cli-2.12.0/docs/modules/ROOT/pages/references/api-reference.adoc --- old/k8up-cli-2.11.3/docs/modules/ROOT/pages/references/api-reference.adoc 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/docs/modules/ROOT/pages/references/api-reference.adoc 2025-02-28 12:47:40.000000000 +0100 @@ -257,6 +257,8 @@ information about the snapshots to. This is in addition to the prometheus pushgateway. | *`tags`* __string array__ | Tags is a list of arbitrary tags that get added to the backup via Restic's tagging system +| *`labelSelectors`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#labelselector-v1-meta[$$LabelSelector$$] array__ | LabelSelectors is a list of selectors that we filter for. +When defined, only PVCs and PreBackupPods matching them are backed up. |=== @@ -299,6 +301,8 @@ information about the snapshots to. This is in addition to the prometheus pushgateway. | *`tags`* __string array__ | Tags is a list of arbitrary tags that get added to the backup via Restic's tagging system +| *`labelSelectors`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#labelselector-v1-meta[$$LabelSelector$$] array__ | LabelSelectors is a list of selectors that we filter for. +When defined, only PVCs and PreBackupPods matching them are backed up. |=== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/docs/modules/ROOT/pages/tutorials/tutorial.adoc new/k8up-cli-2.12.0/docs/modules/ROOT/pages/tutorials/tutorial.adoc --- old/k8up-cli-2.11.3/docs/modules/ROOT/pages/tutorials/tutorial.adoc 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/docs/modules/ROOT/pages/tutorials/tutorial.adoc 2025-02-28 12:47:40.000000000 +0100 @@ -75,10 +75,10 @@ . Install the CRDs K8up uses: ifeval::["{page-component-version}" == "master"] -* `kubectl apply -f \https://github.com/k8up-io/k8up/releases/download/v{page-component-latest-version}.0/k8up-crd.yaml` +* `kubectl apply -f \https://github.com/k8up-io/k8up/releases/download/v{page-component-latest-version}.0/k8up-crd.yaml` --server-side endif::[] ifeval::["{page-component-version}" != "master"] -* `kubectl apply -f \https://github.com/k8up-io/k8up/releases/download/{releaseVersion}/k8up-crd.yaml` +* `kubectl apply -f \https://github.com/k8up-io/k8up/releases/download/{releaseVersion}/k8up-crd.yaml` --server-side endif::[] . Install K8up in Minikube: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/definitions/backup/backup-selectors.yaml new/k8up-cli-2.12.0/e2e/definitions/backup/backup-selectors.yaml --- old/k8up-cli-2.11.3/e2e/definitions/backup/backup-selectors.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/definitions/backup/backup-selectors.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -0,0 +1,34 @@ +--- +apiVersion: k8up.io/v1 +kind: Backup +metadata: + name: k8up-backup-selectors + namespace: k8up-e2e-subject +spec: + labelSelectors: + - matchExpressions: + - key: exists + operator: Exists + - matchExpressions: + - key: specific-values + operator: In + values: + - specific-value-1 + - specific-value-2 + failedJobsHistoryLimit: 1 + successfulJobsHistoryLimit: 1 + backend: + repoPasswordSecretRef: + name: backup-repo + key: password + s3: + endpoint: http://minio.minio-e2e.svc.cluster.local:9000 + bucket: backup + accessKeyIDSecretRef: + name: backup-credentials + key: username + secretAccessKeySecretRef: + name: backup-credentials + key: password + podSecurityContext: + runAsUser: $ID diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/definitions/prebackup/prebackup-match-labels.yaml new/k8up-cli-2.12.0/e2e/definitions/prebackup/prebackup-match-labels.yaml --- old/k8up-cli-2.11.3/e2e/definitions/prebackup/prebackup-match-labels.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/definitions/prebackup/prebackup-match-labels.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -0,0 +1,38 @@ +--- +apiVersion: k8up.io/v1 +kind: PreBackupPod +metadata: + name: prebackup-label-specific-value-1 + namespace: k8up-e2e-subject + labels: + specific-values: specific-value-1 +spec: + backupCommand: sh -c 'echo hello there' + pod: + spec: + containers: + - image: busybox + command: + - 'sleep' + - 'infinity' + imagePullPolicy: Always + name: specific-label-value-1 +--- +apiVersion: k8up.io/v1 +kind: PreBackupPod +metadata: + name: prebackup-label-exists + namespace: k8up-e2e-subject + labels: + exists: arbitrary +spec: + backupCommand: sh -c 'echo whatup' + pod: + spec: + containers: + - image: busybox + command: + - 'sleep' + - 'infinity' + imagePullPolicy: Always + name: arbitrary-label-value diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/definitions/prebackup/prebackup-no-labels.yaml new/k8up-cli-2.12.0/e2e/definitions/prebackup/prebackup-no-labels.yaml --- old/k8up-cli-2.11.3/e2e/definitions/prebackup/prebackup-no-labels.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/definitions/prebackup/prebackup-no-labels.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -0,0 +1,18 @@ +--- +apiVersion: k8up.io/v1 +kind: PreBackupPod +metadata: + name: prebackup + namespace: k8up-e2e-subject +spec: + backupCommand: sh -c 'echo hello there' + pod: + spec: + containers: + - image: busybox + command: + - 'sleep' + - 'infinity' + imagePullPolicy: Always + name: busybox + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/definitions/pv/pvcs-matching-labels.yaml new/k8up-cli-2.12.0/e2e/definitions/pv/pvcs-matching-labels.yaml --- old/k8up-cli-2.11.3/e2e/definitions/pv/pvcs-matching-labels.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/definitions/pv/pvcs-matching-labels.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -0,0 +1,51 @@ +--- +# used to test a backup with labelSelectors - the below match and should be picked up +# The other, non-labeled PVC is expected to be ignored +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: subject-pvc-label-exists + namespace: k8up-e2e-subject + labels: + exists: value +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 100Mi + storageClassName: standard + volumeMode: Filesystem +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: subject-pvc-specific-value-1 + namespace: k8up-e2e-subject + labels: + specific-values: specific-value-1 +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 100Mi + storageClassName: standard + volumeMode: Filesystem +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: subject-pvc-specific-value-2 + namespace: k8up-e2e-subject + labels: + specific-values: specific-value-2 +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 100Mi + storageClassName: standard + volumeMode: Filesystem + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/definitions/subject/deployment-pvc-with-labels.yaml new/k8up-cli-2.12.0/e2e/definitions/subject/deployment-pvc-with-labels.yaml --- old/k8up-cli-2.11.3/e2e/definitions/subject/deployment-pvc-with-labels.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/definitions/subject/deployment-pvc-with-labels.yaml 2025-02-28 12:47:40.000000000 +0100 @@ -0,0 +1,44 @@ +--- +# Those are used to validate +apiVersion: apps/v1 +kind: Deployment +metadata: + name: subject-deployment + namespace: k8up-e2e-subject +spec: + replicas: 1 + selector: + matchLabels: + app: subject + template: + metadata: + labels: + app: subject + spec: + containers: + - name: subject-container + image: quay.io/prometheus/busybox:latest + imagePullPolicy: IfNotPresent + args: + - sh + - -c + - | + printf "$BACKUP_FILE_CONTENT" | tee "/data/$BACKUP_FILE_NAME" && \ + echo && \ + ls -la /data && \ + echo "test file /data/$BACKUP_FILE_NAME written, sleeping now" && \ + sleep infinity + securityContext: + runAsUser: $ID + volumeMounts: + - name: volume + mountPath: /data + env: + - name: BACKUP_FILE_CONTENT + value: "" + - name: BACKUP_FILE_NAME + value: "" + volumes: + - name: volume + persistentVolumeClaim: + claimName: subject-pvc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/lib/k8up.bash new/k8up-cli-2.12.0/e2e/lib/k8up.bash --- old/k8up-cli-2.11.3/e2e/lib/k8up.bash 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/lib/k8up.bash 2025-02-28 12:47:40.000000000 +0100 @@ -141,13 +141,18 @@ } given_a_subject() { - require_args 2 ${#} + (require_args 2 ${#}) || require_args 3 ${#} export BACKUP_FILE_NAME=${1} export BACKUP_FILE_CONTENT=${2} + CLAIM_NAME=${3-subject-pvc} + DEPLOYMENT_NAME_SUFFIX=${3-""} kubectl apply -f definitions/pv/pvc.yaml - yq e '.spec.template.spec.containers[0].securityContext.runAsUser='$(id -u)' | .spec.template.spec.containers[0].env[0].value=strenv(BACKUP_FILE_CONTENT) | .spec.template.spec.containers[0].env[1].value=strenv(BACKUP_FILE_NAME)' definitions/subject/deployment.yaml | kubectl apply -f - + yq e '.spec.template.spec.containers[0].securityContext.runAsUser='$(id -u)' | .spec.template.spec.containers[0].env[0].value=strenv(BACKUP_FILE_CONTENT) | .spec.template.spec.containers[0].env[1].value=strenv(BACKUP_FILE_NAME) | .metadata.name="subject-deployment'${DEPLOYMENT_NAME_SUFFIX}'" | .spec.template.spec.volumes[0].persistentVolumeClaim.claimName="'${CLAIM_NAME}'"' definitions/subject/deployment.yaml | kubectl apply -f - + + # Let's wait for the deployment to actually be ready + kubectl -n k8up-e2e-subject wait --timeout 1m --for=condition=available deployment "subject-deployment${DEPLOYMENT_NAME_SUFFIX}" # Let's wait for the deployment to actually be ready kubectl -n k8up-e2e-subject wait --timeout 1m --for=condition=available deployment subject-deployment diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/e2e/test-15-backup-with-selectors.bats new/k8up-cli-2.12.0/e2e/test-15-backup-with-selectors.bats --- old/k8up-cli-2.11.3/e2e/test-15-backup-with-selectors.bats 1970-01-01 01:00:00.000000000 +0100 +++ new/k8up-cli-2.12.0/e2e/test-15-backup-with-selectors.bats 2025-02-28 12:47:40.000000000 +0100 @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +load "lib/utils" +load "lib/detik" +load "lib/k8up" + +# shellcheck disable=SC2034 +DETIK_CLIENT_NAME="kubectl" +# shellcheck disable=SC2034 +DETIK_CLIENT_NAMESPACE="k8up-e2e-subject" +# shellcheck disable=SC2034 +DEBUG_DETIK="true" + +@test "Given multiple labeled&non-labeled PVCs and PreBackupPods, When creating a Backup with selectors, Then expect Snapshot resources only for resources with matching labels" { + given_a_running_operator + given_a_clean_ns + given_s3_storage + given_a_clean_s3_storage + + backup_file_name="testfile" + backup_file_content="hello" + + kubectl apply -f definitions/pv/pvc.yaml + kubectl apply -f definitions/pv/pvcs-matching-labels.yaml + kubectl apply -f definitions/prebackup/prebackup-match-labels.yaml + kubectl apply -f definitions/prebackup/prebackup-no-labels.yaml + + given_a_subject "${backup_file_name}" "${backup_file_content}" + given_a_subject "${backup_file_name}" "${backup_file_content}" subject-pvc-specific-value-1 + given_a_subject "${backup_file_name}" "${backup_file_content}" subject-pvc-specific-value-2 + given_a_subject "${backup_file_name}" "${backup_file_content}" subject-pvc-label-exists + + kubectl apply -f definitions/secrets + yq e '.spec.podSecurityContext.runAsUser='$(id -u)'' definitions/backup/backup-selectors.yaml | \ + kubectl apply -f - + + try "at most 10 times every 5s to get backup named 'k8up-backup-selectors' and verify that '.status.started' is 'true'" + + wait_until backup/k8up-backup-selectors completed + + verify_snapshot_count 5 "${DETIK_CLIENT_NAMESPACE}" + run get_latest_snap_by_path /data/subject-pvc-specific-value-2 + run get_latest_snap_by_path k8up-e2e-subject-specific-label-value-1 + run get_latest_snap_by_path data/subject-pvc-label-exists + run get_latest_snap_by_path data/subject-pvc-specific-value-1 + run get_latest_snap_by_path k8up-e2e-subject-arbitrary-label-value + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/envtest/envsuite.go new/k8up-cli-2.12.0/envtest/envsuite.go --- old/k8up-cli-2.11.3/envtest/envsuite.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/envtest/envsuite.go 2025-02-28 12:47:40.000000000 +0100 @@ -224,6 +224,7 @@ BackupAnnotation: "k8up.io/backup", BackupCommandAnnotation: "k8up.io/backupcommand", FileExtensionAnnotation: "k8up.io/file-extension", + BackupResticArgsAnnotation: "k8up.io/backup-restic-args", ServiceAccount: "pod-executor", BackupCheckSchedule: "0 0 * * 0", GlobalFailedJobsHistoryLimit: 3, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/operator/backupcontroller/backup_utils.go new/k8up-cli-2.12.0/operator/backupcontroller/backup_utils.go --- old/k8up-cli-2.11.3/operator/backupcontroller/backup_utils.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/operator/backupcontroller/backup_utils.go 2025-02-28 12:47:40.000000000 +0100 @@ -3,19 +3,58 @@ import ( "context" "fmt" + "maps" + "path" + "slices" + "github.com/k8up-io/k8up/v2/operator/executor" "github.com/k8up-io/k8up/v2/operator/utils" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - "path" controllerruntime "sigs.k8s.io/controller-runtime" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "github.com/k8up-io/k8up/v2/operator/cfg" ) -func (b *BackupExecutor) fetchPVCs(ctx context.Context, list client.ObjectList) error { - return b.Config.Client.List(ctx, list, client.InNamespace(b.backup.Namespace)) +func (b *BackupExecutor) fetchPVCs(ctx context.Context, list *corev1.PersistentVolumeClaimList) (err error) { + err = nil + if b.backup.Spec.LabelSelectors == nil { + return b.Config.Client.List(ctx, list, client.InNamespace(b.backup.Namespace)) + } + + labelSelectors := b.backup.Spec.LabelSelectors + uniquePVCs := make(map[string]corev1.PersistentVolumeClaim) + + for _, labelSelector := range labelSelectors { + selector, err := metav1.LabelSelectorAsSelector(&labelSelector) + if err != nil { + return fmt.Errorf("cannot convert labelSelector %v to selector: %w", labelSelector, err) + } + + options := client.ListOptions{ + LabelSelector: selector, + } + + matchingPVCs := &corev1.PersistentVolumeClaimList{} + err = b.Config.Client.List(ctx, matchingPVCs, client.InNamespace(b.backup.Namespace), &options) + + if err != nil { + return fmt.Errorf("cannot list PVCs using labelSelector %v: %w", labelSelector, err) + } + + for _, pvc := range matchingPVCs.Items { + uniquePVCs[pvc.Name] = pvc + } + + } + + list.Items = slices.Collect(maps.Values(uniquePVCs)) + + return err + } func (b *BackupExecutor) newVolumeMounts(claims []corev1.Volume) []corev1.VolumeMount { @@ -74,7 +113,7 @@ return err } -func (b *BackupExecutor) setupArgs() []string { +func (b *BackupExecutor) setupArgs(userArgs []string) []string { args := []string{"-varDir", cfg.Config.PodVarDir} if len(b.backup.Spec.Tags) > 0 { args = append(args, executor.BuildTagArgs(b.backup.Spec.Tags)...) @@ -82,6 +121,7 @@ if b.backup.Spec.Backend != nil { args = append(args, utils.AppendTLSOptionsArgs(b.backup.Spec.Backend.TLSOptions)...) } + args = append(args, userArgs...) return args } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/operator/backupcontroller/executor.go new/k8up-cli-2.12.0/operator/backupcontroller/executor.go --- old/k8up-cli-2.11.3/operator/backupcontroller/executor.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/operator/backupcontroller/executor.go 2025-02-28 12:47:40.000000000 +0100 @@ -56,6 +56,7 @@ node string tolerations []corev1.Toleration targetPod string + resticArgs utils.JsonArgsArray } // listAndFilterPVCs lists all PVCs in the given namespace and filters them for K8up specific usage. @@ -129,6 +130,18 @@ }, } + resticArgsAnnotation, hasResticArgsAnnotation := pvc.GetAnnotations()[cfg.Config.BackupResticArgsAnnotation] + if hasResticArgsAnnotation { + var argsArray utils.JsonArgsArray + if err := argsArray.UnmarshalJSON([]byte(resticArgsAnnotation)); err != nil { + log.Error(err, "failed to parse restic backup args from the annotation, skipping pvc", "annotation", resticArgsAnnotation) + continue + } else { + log.Info("adding restic args from annotation", "annotation", resticArgsAnnotation) + bi.resticArgs = argsArray + } + } + if pod, ok := pvcPodMap[pvc.GetName()]; ok { bi.node = pod.Spec.NodeName bi.tolerations = pod.Spec.Tolerations @@ -194,25 +207,28 @@ job *batchv1.Job targetPods []string volumes []corev1.Volume + resticArgs []string skipPreBackup bool } backupJobs := map[string]jobItem{} for index, item := range backupItems { - if _, ok := backupJobs[item.node]; !ok { - backupJobs[item.node] = jobItem{ + jobName := item.node + strings.Join(item.resticArgs, ",") + if _, ok := backupJobs[jobName]; !ok { + backupJobs[jobName] = jobItem{ job: b.createJob(strconv.Itoa(index), item.node, item.tolerations), targetPods: make([]string, 0), volumes: make([]corev1.Volume, 0), + resticArgs: []string(item.resticArgs), skipPreBackup: true, } } - j := backupJobs[item.node] + j := backupJobs[jobName] if item.targetPod != "" { j.targetPods = append(j.targetPods, item.targetPod) } j.volumes = append(j.volumes, item.volume) - backupJobs[item.node] = j + backupJobs[jobName] = j } if err != nil { @@ -275,7 +291,7 @@ batchJob.job.Spec.Template.Spec.Containers[0].VolumeMounts = append(b.newVolumeMounts(batchJob.volumes), b.attachTLSVolumeMounts()...) batchJob.job.Spec.BackoffLimit = ptr.To(int32(cfg.Config.GlobalBackoffLimit)) - batchJob.job.Spec.Template.Spec.Containers[0].Args = b.setupArgs() + batchJob.job.Spec.Template.Spec.Containers[0].Args = b.setupArgs(batchJob.resticArgs) if batchJob.job.Spec.Template.Spec.ServiceAccountName == "" { batchJob.job.Spec.Template.Spec.ServiceAccountName = cfg.Config.ServiceAccount diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/operator/backupcontroller/prebackup_utils.go new/k8up-cli-2.12.0/operator/backupcontroller/prebackup_utils.go --- old/k8up-cli-2.11.3/operator/backupcontroller/prebackup_utils.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/operator/backupcontroller/prebackup_utils.go 2025-02-28 12:47:40.000000000 +0100 @@ -2,6 +2,8 @@ import ( "fmt" + "maps" + "slices" "golang.org/x/net/context" appsv1 "k8s.io/api/apps/v1" @@ -19,14 +21,43 @@ "github.com/k8up-io/k8up/v2/operator/cfg" ) -// fetchPreBackupPodTemplates fetches all PreBackupPods from the same namespace as the originating backup. +// fetchPreBackupPodTemplates fetches all PreBackupPods from the same namespace as the originating backup +// when labelSelectors are defined for the backups, we only return PreBackupPods matching defined conditions func (b *BackupExecutor) fetchPreBackupPodTemplates(ctx context.Context) (*k8upv1.PreBackupPodList, error) { podList := &k8upv1.PreBackupPodList{} - err := b.Client.List(ctx, podList, client.InNamespace(b.Obj.GetNamespace())) - if err != nil { - return nil, fmt.Errorf("could not list pod templates: %w", err) + labelSelectors := b.backup.Spec.LabelSelectors + if labelSelectors == nil { + err := b.Client.List(ctx, podList, client.InNamespace(b.Obj.GetNamespace())) + if err != nil { + return nil, fmt.Errorf("could not list pod templates: %w", err) + } + + return podList, nil + } + + uniquePreBackupPods := make(map[string]k8upv1.PreBackupPod) + + for _, labelSelector := range labelSelectors { + selector, err := metav1.LabelSelectorAsSelector(&labelSelector) + if err != nil { + return nil, fmt.Errorf("cannot convert labelSelector %v to selector: %w", labelSelector, err) + } + + options := client.ListOptions{ + LabelSelector: selector, + } + + matchingPreBackupPods := &k8upv1.PreBackupPodList{} + err = b.Client.List(ctx, matchingPreBackupPods, client.InNamespace(b.Obj.GetNamespace()), &options) + if err != nil { + return nil, fmt.Errorf("cannot list pod templates using labelSelector %v: %w", labelSelector, err) + } + for _, preBackupPod := range matchingPreBackupPods.Items { + uniquePreBackupPods[preBackupPod.Name] = preBackupPod + } } + podList.Items = slices.Collect(maps.Values(uniquePreBackupPods)) return podList, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/operator/cfg/config.go new/k8up-cli-2.12.0/operator/cfg/config.go --- old/k8up-cli-2.11.3/operator/cfg/config.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/operator/cfg/config.go 2025-02-28 12:47:40.000000000 +0100 @@ -45,6 +45,8 @@ BackupContainerAnnotation string BackupCommandAnnotation string FileExtensionAnnotation string + BackupResticArgsAnnotation string + RestoreResticArgsAnnotation string ServiceAccount string BackupCheckSchedule string GlobalAccessKey string @@ -76,6 +78,7 @@ PodExecRoleName string PodFilter string PromURL string + ClusterName string RestartPolicy string SkipWithoutAnnotation bool diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/operator/utils/utils.go new/k8up-cli-2.12.0/operator/utils/utils.go --- old/k8up-cli-2.11.3/operator/utils/utils.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/operator/utils/utils.go 2025-02-28 12:47:40.000000000 +0100 @@ -1,6 +1,8 @@ package utils import ( + "encoding/json" + "errors" "math/rand" "reflect" "time" @@ -156,3 +158,30 @@ return moreVolumeMounts } + +type JsonArgsArray []string + +func (aa *JsonArgsArray) UnmarshalJSON(data []byte) error { + var jsonObj interface{} + err := json.Unmarshal(data, &jsonObj) + if err != nil { + return err + } + switch obj := jsonObj.(type) { + case string: + *aa = JsonArgsArray([]string{obj}) + return nil + case []interface{}: + s := make([]string, 0, len(obj)) + for _, v := range obj { + value, ok := v.(string) + if !ok { + return errors.New("unexpected arg item, string expected") + } + s = append(s, value) + } + *aa = JsonArgsArray(s) + return nil + } + return errors.New("unexpected args array") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/restic/cfg/config.go new/k8up-cli-2.12.0/restic/cfg/config.go --- old/k8up-cli-2.11.3/restic/cfg/config.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/restic/cfg/config.go 2025-02-28 12:47:40.000000000 +0100 @@ -35,8 +35,9 @@ SkipPreBackup bool - PromURL string - WebhookURL string + PromURL string + ClusterName string + WebhookURL string Hostname string KubeConfig string @@ -45,6 +46,18 @@ ResticRepository string ResticOptions string + Exclude []string + ExcludeCaches bool + ExcludeFile []string + ExcludeIfPresent []string + ExcludeLargerThan string + FilesFrom []string + FilesFromRaw []string + FilesFromVerbatim []string + IExclude []string + IExcludeFile []string + OneFileSystem bool + RestoreDir string RestoreS3Endpoint string RestoreS3AccessKey string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/restic/cli/backup.go new/k8up-cli-2.12.0/restic/cli/backup.go --- old/k8up-cli-2.11.3/restic/cli/backup.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/restic/cli/backup.go 2025-02-28 12:47:40.000000000 +0100 @@ -48,6 +48,35 @@ return nil } +func mixinBackupFlags(flags Flags) Flags { + toMix := map[string][]string{ + "--exclude": cfg.Config.Exclude, + "--exclude-file": cfg.Config.ExcludeFile, + "--exclude-if-present": cfg.Config.ExcludeIfPresent, + "--files-from": cfg.Config.FilesFrom, + "--files-from-raw": cfg.Config.FilesFromRaw, + "--files-from-verbatim": cfg.Config.FilesFromVerbatim, + "--iexclude": cfg.Config.IExclude, + "--iexclude-file": cfg.Config.IExcludeFile, + } + + for k, v := range toMix { + if len(v) > 0 { + flags = Combine(flags, Flags{k: v}) + } + } + + if cfg.Config.ExcludeCaches { + flags = Combine(flags, Flags{"--exclude-caches": {}}) + } + + if cfg.Config.OneFileSystem { + flags = Combine(flags, Flags{"--one-file-system": {}}) + } + + return flags +} + func (r *Restic) folderBackup(folder string, backuplogger logr.Logger, tags ArrayOpts) error { outputWriter := r.newParseBackupOutput(backuplogger, folder) @@ -59,6 +88,8 @@ "--json": {}, }) + flags = mixinBackupFlags(flags) + opts := CommandOptions{ Path: r.resticPath, Args: flags.ApplyToCommand("backup", folder), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/restic/cli/restic.go new/k8up-cli-2.12.0/restic/cli/restic.go --- old/k8up-cli-2.11.3/restic/cli/restic.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/restic/cli/restic.go 2025-02-28 12:47:40.000000000 +0100 @@ -57,8 +57,8 @@ func New(ctx context.Context, logger logr.Logger, statsHandler StatsHandler) *Restic { globalFlags := Flags{} - options := strings.Split(cfg.Config.ResticOptions, ",") - if len(options) > 0 { + if cfg.Config.ResticOptions != "" { + options := strings.Split(cfg.Config.ResticOptions, ",") logger.Info("using the following restic options", "options", options) globalFlags.AddFlag("--option", options...) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/k8up-cli-2.11.3/restic/stats/handler.go new/k8up-cli-2.12.0/restic/stats/handler.go --- old/k8up-cli-2.11.3/restic/stats/handler.go 2024-12-13 16:21:00.000000000 +0100 +++ new/k8up-cli-2.12.0/restic/stats/handler.go 2025-02-28 12:47:40.000000000 +0100 @@ -23,14 +23,16 @@ promURL string promHostname string webhookURL string + clusterName string log logr.Logger } -func NewHandler(promURL, promHostname, webhookURL string, log logr.Logger) *Handler { +func NewHandler(promURL, clusterName, promHostname, webhookURL string, log logr.Logger) *Handler { return &Handler{ promHostname: promHostname, promURL: promURL, webhookURL: webhookURL, + clusterName: clusterName, log: log.WithName("statsHandler"), } } @@ -55,7 +57,7 @@ func (h *Handler) updatePrometheus(collector prometheus.Collector) error { return push.New(h.promURL, subsystem).Collector(collector). - Grouping("instance", h.promHostname). + Grouping("instance", h.promHostname).Grouping("cluster", h.clusterName). Add() } ++++++ k8up-cli.obsinfo ++++++ --- /var/tmp/diff_new_pack.wFv7Nt/_old 2025-03-05 15:18:58.275937457 +0100 +++ /var/tmp/diff_new_pack.wFv7Nt/_new 2025-03-05 15:18:58.283937791 +0100 @@ -1,5 +1,5 @@ name: k8up-cli -version: 2.11.3 -mtime: 1734103260 -commit: be9529f1242148b614a3d0911e7c655955b2835e +version: 2.12.0 +mtime: 1740743260 +commit: 0e10a932db96ef91d6fb2b69bbb16439e2fcdb73 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/k8up-cli/vendor.tar.gz /work/SRC/openSUSE:Factory/.k8up-cli.new.19136/vendor.tar.gz differ: char 5, line 1
