diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index d00e1650..3eaa1606 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,16 +1,19 @@ agents: queue: "public" +env: + GO_VERSION_FILE: "go1.22.5.linux-amd64.tar.gz" + # Mount the docker.sock as to the docker container, so that we are able to # run docker build command and kind is spawned as a sibling container. steps: - name: "Upgrade Test" command: - apk add g++ make bash gcompat curl mysql mysql-client libc6-compat - - wget https://golang.org/dl/go1.22.2.linux-amd64.tar.gz - - tar -C /usr/local -xzf go1.22.2.linux-amd64.tar.gz + - wget https://golang.org/dl/$GO_VERSION_FILE + - tar -C /usr/local -xzf $GO_VERSION_FILE - export PATH=$PATH:/usr/local/go/bin - - rm go1.22.2.linux-amd64.tar.gz + - rm $GO_VERSION_FILE - ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 - make upgrade-test concurrency: 1 @@ -26,10 +29,10 @@ steps: - name: "Backup Restore Test" command: - apk add g++ make bash gcompat curl mysql mysql-client libc6-compat - - wget https://golang.org/dl/go1.22.2.linux-amd64.tar.gz - - tar -C /usr/local -xzf go1.22.2.linux-amd64.tar.gz + - wget https://golang.org/dl/$GO_VERSION_FILE + - tar -C /usr/local -xzf $GO_VERSION_FILE - export PATH=$PATH:/usr/local/go/bin - - rm go1.22.2.linux-amd64.tar.gz + - rm $GO_VERSION_FILE - ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 - make backup-restore-test concurrency: 1 @@ -42,13 +45,32 @@ steps: volumes: - "/var/run/docker.sock:/var/run/docker.sock" + - name: "Backup Schedule Test" + command: + - apk add g++ make bash gcompat curl mysql mysql-client libc6-compat + - wget https://golang.org/dl/$GO_VERSION_FILE + - tar -C /usr/local -xzf $GO_VERSION_FILE + - export PATH=$PATH:/usr/local/go/bin + - rm $GO_VERSION_FILE + - ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 + - make backup-schedule-test + concurrency: 1 + concurrency_group: 'vtop/backup-schedule-test' + timeout_in_minutes: 60 + plugins: + - docker#v3.12.0: + image: "docker:latest" + propagate-environment: true + volumes: + - "/var/run/docker.sock:/var/run/docker.sock" + - name: "VTOrc and VTAdmin Test" command: - apk add g++ make bash gcompat curl mysql mysql-client libc6-compat chromium - - wget https://golang.org/dl/go1.22.2.linux-amd64.tar.gz - - tar -C /usr/local -xzf go1.22.2.linux-amd64.tar.gz + - wget https://golang.org/dl/$GO_VERSION_FILE + - tar -C /usr/local -xzf $GO_VERSION_FILE - export PATH=$PATH:/usr/local/go/bin - - rm go1.22.2.linux-amd64.tar.gz + - rm $GO_VERSION_FILE - ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2 - make vtorc-vtadmin-test concurrency: 1 diff --git a/.github/workflows/integration-test.yaml b/.github/workflows/integration-test.yaml index 5cb8d447..4b085212 100644 --- a/.github/workflows/integration-test.yaml +++ b/.github/workflows/integration-test.yaml @@ -17,7 +17,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.22.2 + go-version: 1.22.5 id: go - name: Check out code into the Go module directory diff --git a/.github/workflows/make-generate-and-diff.yaml b/.github/workflows/make-generate-and-diff.yaml index 18143dd4..fda09291 100644 --- a/.github/workflows/make-generate-and-diff.yaml +++ b/.github/workflows/make-generate-and-diff.yaml @@ -17,7 +17,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.22.2 + go-version: 1.22.5 id: go - name: Check out code into the Go module directory diff --git a/.github/workflows/unit-test.yaml b/.github/workflows/unit-test.yaml index 428c252c..6dae74ab 100644 --- a/.github/workflows/unit-test.yaml +++ b/.github/workflows/unit-test.yaml @@ -17,7 +17,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.22.2 + go-version: 1.22.5 id: go - name: Check out code into the Go module directory diff --git a/.github/workflows/upgrade-vitess-dependency.yaml b/.github/workflows/upgrade-vitess-dependency.yaml index f03e5fb7..548e938b 100644 --- a/.github/workflows/upgrade-vitess-dependency.yaml +++ b/.github/workflows/upgrade-vitess-dependency.yaml @@ -20,7 +20,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.22.2 + go-version: 1.22.5 - name: Check out code into the Go module directory uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index f77e5e70..f135baca 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,5 @@ tags ### Intellij IDEs ### .idea/* # End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode + +**/vtdataroot \ No newline at end of file diff --git a/Makefile b/Makefile index 29cc2164..16506fc5 100644 --- a/Makefile +++ b/Makefile @@ -66,6 +66,10 @@ backup-restore-test: build e2e-test-setup echo "Running Backup-Restore test" test/endtoend/backup_restore_test.sh +backup-schedule-test: build e2e-test-setup + echo "Running Backup-Schedule test" + test/endtoend/backup_schedule_test.sh + vtorc-vtadmin-test: build e2e-test-setup echo "Running VTOrc and VtAdmin test" test/endtoend/vtorc_vtadmin_test.sh diff --git a/README.md b/README.md index 5f93a724..a6641fb8 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ compatible with certain Vitess and Kubernetes versions, as shown in this table: | `v2.10.*` | `v17.0.*` | `v1.22.*`, `v1.23.*`, `v1.24.*`, or `v1.25.*` | | `v2.11.*` | `v18.0.*` | `v1.22.*`, `v1.23.*`, `v1.24.*`, or `v1.25.*` | | `v2.12.*` | `v19.0.*` | `v1.25.*`, `v1.26.*`, `v1.27.*`, or `v1.28.*` | +| `v2.13.*` | `v20.0.*` | `v1.25.*`, `v1.26.*`, `v1.27.*`, or `v1.28.*` | | `latest` | `latest` | `v1.25.*`, `v1.26.*`, `v1.27.*`, or `v1.28.*` | If for some reason you must attempt to use versions outside the recommend diff --git a/build/Dockerfile.release b/build/Dockerfile.release index 4e193c9e..3b5b5cd0 100755 --- a/build/Dockerfile.release +++ b/build/Dockerfile.release @@ -11,7 +11,7 @@ # without messing up file permissions, since the Docker container doesn't run as # your actual user. -FROM golang:1.22.2 AS build +FROM golang:1.22.5 AS build ENV GO111MODULE=on WORKDIR /go/src/planetscale.dev/vitess-operator diff --git a/deploy/crds/planetscale.com_vitessbackupschedules.yaml b/deploy/crds/planetscale.com_vitessbackupschedules.yaml new file mode 100644 index 00000000..b0b5e6af --- /dev/null +++ b/deploy/crds/planetscale.com_vitessbackupschedules.yaml @@ -0,0 +1,171 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + creationTimestamp: null + name: vitessbackupschedules.planetscale.com +spec: + group: planetscale.com + names: + kind: VitessBackupSchedule + listKind: VitessBackupScheduleList + plural: vitessbackupschedules + singular: vitessbackupschedule + scope: Namespaced + versions: + - name: v2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + x-kubernetes-preserve-unknown-fields: true + allowedMissedRun: + minimum: 0 + type: integer + annotations: + additionalProperties: + type: string + type: object + cluster: + type: string + concurrencyPolicy: + enum: + - Allow + - Forbid + example: Forbid + type: string + failedJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + image: + type: string + imagePullPolicy: + type: string + jobTimeoutMinute: + default: 10 + format: int32 + minimum: 0 + type: integer + name: + example: every-day + minLength: 1 + pattern: ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + schedule: + example: 0 0 * * * + minLength: 0 + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + type: integer + strategies: + items: + properties: + extraFlags: + additionalProperties: + type: string + type: object + keyspace: + example: commerce + type: string + name: + enum: + - BackupShard + type: string + shard: + example: '-' + type: string + required: + - keyspace + - name + - shard + type: object + minItems: 1 + type: array + successfulJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + suspend: + type: boolean + required: + - cluster + - name + - resources + - schedule + - strategies + type: object + status: + properties: + active: + items: + properties: + apiVersion: + type: string + fieldPath: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + resourceVersion: + type: string + uid: + type: string + type: object + x-kubernetes-map-type: atomic + type: array + lastScheduledTime: + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/crds/planetscale.com_vitessclusters.yaml b/deploy/crds/planetscale.com_vitessclusters.yaml index e54649dd..818304f1 100644 --- a/deploy/crds/planetscale.com_vitessclusters.yaml +++ b/deploy/crds/planetscale.com_vitessclusters.yaml @@ -152,6 +152,114 @@ spec: type: object minItems: 1 type: array + schedules: + items: + properties: + affinity: + x-kubernetes-preserve-unknown-fields: true + allowedMissedRun: + minimum: 0 + type: integer + annotations: + additionalProperties: + type: string + type: object + concurrencyPolicy: + enum: + - Allow + - Forbid + example: Forbid + type: string + failedJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + jobTimeoutMinute: + default: 10 + format: int32 + minimum: 0 + type: integer + name: + example: every-day + minLength: 1 + pattern: ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + schedule: + example: 0 0 * * * + minLength: 0 + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + type: integer + strategies: + items: + properties: + extraFlags: + additionalProperties: + type: string + type: object + keyspace: + example: commerce + type: string + name: + enum: + - BackupShard + type: string + shard: + example: '-' + type: string + required: + - keyspace + - name + - shard + type: object + minItems: 1 + type: array + successfulJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + suspend: + type: boolean + required: + - name + - resources + - schedule + - strategies + type: object + type: array subcontroller: properties: serviceAccountName: diff --git a/deploy/kustomization.yaml b/deploy/kustomization.yaml index 87aac4c5..e6a77663 100644 --- a/deploy/kustomization.yaml +++ b/deploy/kustomization.yaml @@ -11,3 +11,4 @@ resources: - crds/planetscale.com_vitessbackups.yaml - crds/planetscale.com_vitessbackupstorages.yaml - crds/planetscale.com_etcdlockservers.yaml +- crds/planetscale.com_vitessbackupschedules.yaml diff --git a/deploy/role.yaml b/deploy/role.yaml index ac7e8951..d482ebe6 100644 --- a/deploy/role.yaml +++ b/deploy/role.yaml @@ -68,5 +68,14 @@ rules: - vitessbackupstorages - vitessbackupstorages/status - vitessbackupstorages/finalizers + - vitessbackupschedules + - vitessbackupschedules/status + - vitessbackupschedules/finalizers + verbs: + - '*' +- apiGroups: + - batch + resources: + - jobs verbs: - '*' \ No newline at end of file diff --git a/docs/api/index.html b/docs/api/index.html index 2163c9b9..f541d840 100644 --- a/docs/api/index.html +++ b/docs/api/index.html @@ -575,6 +575,16 @@
string
alias)+(Appears on: +VitessBackupScheduleStrategy) +
++
BackupStrategyName describes the vtctldclient command that will be used to take a backup. +When scheduling a backup, you must specify at least one strategy.
+@@ -679,8 +689,33 @@
Subcontroller specifies any parameters needed for launching the VitessBackupStorage subcontroller pod.
+schedules
+
+
+[]VitessBackupScheduleTemplate
+
+
+Schedules defines how often we want to perform a backup and how to perform the backup. +This is a list of VitessBackupScheduleTemplate where the “name” field has to be unique +across all the items of the list.
+string
alias)+(Appears on: +VitessBackupScheduleTemplate) +
++
ConcurrencyPolicy describes how the concurrency of new jobs created by VitessBackupSchedule +is handled, the default is set to AllowConcurrent.
+@@ -2310,6 +2345,513 @@
+
VitessBackupSchedule is the Schema for the VitessBackupSchedule API.
+ +Field | +Description | +||||||||
---|---|---|---|---|---|---|---|---|---|
+metadata
+
+
+Kubernetes meta/v1.ObjectMeta
+
+
+ |
+
+Refer to the Kubernetes API documentation for the fields of the
+metadata field.
+ |
+||||||||
+spec
+
+
+VitessBackupScheduleSpec
+
+
+ |
+
+ + +
|
+||||||||
+status
+
+
+VitessBackupScheduleStatus
+
+
+ |
++ | +
+(Appears on: +VitessBackupSchedule) +
++
VitessBackupScheduleSpec defines the desired state of VitessBackupSchedule.
+ +Field | +Description | +
---|---|
+VitessBackupScheduleTemplate
+
+
+VitessBackupScheduleTemplate
+
+
+ |
+
+
+(Members of VitessBackupScheduleTemplate contains the user-specific parts of VitessBackupScheduleSpec. +These are the parts that are configurable through the VitessCluster CRD. + |
+
+cluster
+
+string
+
+ |
+
+ Cluster on which this schedule runs. + |
+
+image
+
+string
+
+ |
+
+ Image should be any image that already contains vtctldclient installed. +The controller will re-use the vtctld image by default. + |
+
+imagePullPolicy
+
+
+Kubernetes core/v1.PullPolicy
+
+
+ |
+
+ ImagePullPolicy defines the policy to pull the Docker image in the job’s pod. +The PullPolicy used will be the same as the one used to pull the vtctld image. + |
+
+(Appears on: +VitessBackupSchedule) +
++
VitessBackupScheduleStatus defines the observed state of VitessBackupSchedule
+ +Field | +Description | +
---|---|
+active
+
+
+[]Kubernetes core/v1.ObjectReference
+
+
+ |
+
+(Optional)
+ A list of pointers to currently running jobs. + |
+
+lastScheduledTime
+
+
+Kubernetes meta/v1.Time
+
+
+ |
+
+(Optional)
+ Information when was the last time the job was successfully scheduled. + |
+
+(Appears on: +VitessBackupScheduleTemplate) +
++
VitessBackupScheduleStrategy defines how we are going to take a backup. +The VitessBackupSchedule controller uses this data to build the vtctldclient +command line that will be executed in the Job’s pod.
+ +Field | +Description | +
---|---|
+name
+
+
+BackupStrategyName
+
+
+ |
+
+ Name of the backup strategy. + |
+
+keyspace
+
+string
+
+ |
+
+ Keyspace defines the keyspace on which we want to take the backup. + |
+
+shard
+
+string
+
+ |
+
+ Shard defines the shard on which we want to take a backup. + |
+
+extraFlags
+
+map[string]string
+
+ |
+
+(Optional)
+ ExtraFlags is a map of flags that will be sent down to vtctldclient when taking the backup. + |
+
+(Appears on: +ClusterBackupSpec, +VitessBackupScheduleSpec) +
++
VitessBackupScheduleTemplate contains all the user-specific fields that the user will be +able to define when writing their YAML file.
+ +Field | +Description | +
---|---|
+name
+
+string
+
+ |
+
+ Name is the schedule name, this name must be unique across all the different VitessBackupSchedule +objects in the cluster. + |
+
+schedule
+
+string
+
+ |
+
+ The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + |
+
+strategies
+
+
+[]VitessBackupScheduleStrategy
+
+
+ |
+
+ Strategy defines how we are going to take a backup. +If you want to take several backups within the same schedule you can add more items +to the Strategy list. Each VitessBackupScheduleStrategy will be executed by the same +kubernetes job. This is useful if for instance you have one schedule, and you want to +take a backup of all shards in a keyspace and don’t want to re-create a second schedule. +All the VitessBackupScheduleStrategy are concatenated into a single shell command that +is executed when the Job’s container starts. + |
+
+resources
+
+
+Kubernetes core/v1.ResourceRequirements
+
+
+ |
+
+ Resources specify the compute resources to allocate for every Jobs’s pod. + |
+
+successfulJobsHistoryLimit
+
+int32
+
+ |
+
+(Optional)
+ SuccessfulJobsHistoryLimit defines how many successful jobs will be kept around. + |
+
+failedJobsHistoryLimit
+
+int32
+
+ |
+
+(Optional)
+ FailedJobsHistoryLimit defines how many failed jobs will be kept around. + |
+
+suspend
+
+bool
+
+ |
+
+(Optional)
+ Suspend pause the associated backup schedule. Pausing any further scheduled +runs until Suspend is set to false again. This is useful if you want to pause backup without +having to remove the entire VitessBackupSchedule object from the cluster. + |
+
+startingDeadlineSeconds
+
+int64
+
+ |
+
+(Optional)
+ StartingDeadlineSeconds enables the VitessBackupSchedule to start a job even though it is late by +the given amount of seconds. Let’s say for some reason the controller process a schedule run on +second after its scheduled time, if StartingDeadlineSeconds is set to 0, the job will be skipped +as it’s too late, but on the other hand, if StartingDeadlineSeconds is greater than one second, +the job will be processed as usual. + |
+
+concurrencyPolicy
+
+
+ConcurrencyPolicy
+
+
+ |
+
+(Optional)
+ ConcurrencyPolicy specifies ho to treat concurrent executions of a Job. +Valid values are: +- “Allow” (default): allows CronJobs to run concurrently; +- “Forbid”: forbids concurrent runs, skipping next run if previous run hasn’t finished yet; +- “Replace”: cancels currently running job and replaces it with a new one. + |
+
+allowedMissedRun
+
+int
+
+ |
+
+(Optional)
+ AllowedMissedRuns defines how many missed run of the schedule will be allowed before giving up on finding the last job. +If the operator’s clock is skewed and we end-up missing a certain number of jobs, finding the last +job might be very time-consuming, depending on the frequency of the schedule and the duration during which +the operator’s clock was misbehaving. Also depending on how laggy the clock is, we can end-up with thousands +of missed runs. For this reason, AllowedMissedRun, which is set to 100 by default, will short circuit the search +and simply wait for the next job on the schedule. +Unless you are experiencing issue with missed runs due to a misconfiguration of the clock, we recommend leaving +this field to its default value. + |
+
+jobTimeoutMinute
+
+int32
+
+ |
+
+(Optional)
+ JobTimeoutMinutes defines after how many minutes a job that has not yet finished should be stopped and removed. +Default value is 10 minutes. + |
+
+annotations
+
+map[string]string
+
+ |
+
+(Optional)
+ Annotations are the set of annotations that will be attached to the pods created by VitessBackupSchedule. + |
+
+affinity
+
+
+Kubernetes core/v1.Affinity
+
+
+ |
+
+(Optional)
+ Affinity allows you to set rules that constrain the scheduling of the pods that take backups. +WARNING: These affinity rules will override all default affinities that we set; in turn, we can’t +guarantee optimal scheduling of your pods if you choose to set this field. + |
+
diff --git a/docs/release-notes/2_13_0_summary.md b/docs/release-notes/2_13_0_summary.md new file mode 100644 index 00000000..22a5b168 --- /dev/null +++ b/docs/release-notes/2_13_0_summary.md @@ -0,0 +1,15 @@ +## Major Changes + +### Automated and Scheduled Backups + +As part of `v2.13.0` we are adding a new feature to the `vitess-operator`: automated and scheduled backups. The PR +implementing this change is available here: [#553](https://github.com/planetscale/vitess-operator/pull/553). + +This feature is for now experimental as we await feedback from the community on its usage. There are a few things to +take into account when using this feature: + +- If you are using the `xtrabackup` engine, your vttablet pods will need more memory, think about provisioning more memory for it. +- If you are using the `builtin` engine, you will lose a replica during the backup, think about adding a new tablet. + +If you are usually using specific flags when taking backups with `vtctldclient` you can set those flags on the `extraFlags` +field of the backup `strategy` (`VitessBackupScheduleStrategy`). \ No newline at end of file diff --git a/go.mod b/go.mod index 99c85585..817844c9 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,13 @@ module planetscale.dev/vitess-operator -go 1.22.2 +go 1.22.5 require ( github.com/ahmetb/gen-crd-api-reference-docs v0.1.5-0.20190629210212-52e137b8d003 github.com/google/uuid v1.6.0 github.com/planetscale/operator-sdk-libs v0.0.0-20220216002626-1af183733234 - github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/client_golang v1.19.1 + github.com/robfig/cron v1.2.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 @@ -17,35 +18,35 @@ require ( k8s.io/klog v1.0.0 k8s.io/kubectl v0.21.9 k8s.io/kubernetes v1.28.5 - k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 + k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 sigs.k8s.io/controller-runtime v0.16.3 sigs.k8s.io/controller-tools v0.11.3 sigs.k8s.io/kustomize v2.0.3+incompatible - vitess.io/vitess v0.10.3-0.20240427144732-1e143c30e01b + vitess.io/vitess v0.10.3-0.20240704214316-d303601040eb ) require ( - cloud.google.com/go v0.112.2 // indirect - cloud.google.com/go/auth v0.2.2 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.1 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.7 // indirect - cloud.google.com/go/storage v1.40.0 // indirect + cloud.google.com/go v0.115.0 // indirect + cloud.google.com/go/auth v0.6.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect + cloud.google.com/go/compute/metadata v0.4.0 // indirect + cloud.google.com/go/iam v1.1.10 // indirect + cloud.google.com/go/storage v1.42.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-storage-blob-go v0.15.0 // indirect - github.com/DataDog/appsec-internal-go v1.5.0 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.52.1 // indirect - github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.1 // indirect + github.com/DataDog/appsec-internal-go v1.6.0 // indirect + github.com/DataDog/datadog-agent/pkg/obfuscate v0.54.0 // indirect + github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.54.0 // indirect github.com/DataDog/datadog-go/v5 v5.5.0 // indirect - github.com/DataDog/go-libddwaf/v2 v2.4.2 // indirect - github.com/DataDog/go-sqllexer v0.0.11 // indirect + github.com/DataDog/go-libddwaf/v3 v3.2.1 // indirect + github.com/DataDog/go-sqllexer v0.0.12 // indirect github.com/DataDog/go-tuf v1.1.0-0.5.2 // indirect - github.com/DataDog/sketches-go v1.4.4 // indirect + github.com/DataDog/sketches-go v1.4.6 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/aquarapid/vaultlib v0.5.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/aws/aws-sdk-go v1.51.25 // indirect + github.com/aws/aws-sdk-go v1.54.13 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -55,20 +56,20 @@ require ( github.com/docker/distribution v2.8.2+incompatible // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ebitengine/purego v0.7.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.0 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.2.4 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/spec v0.19.5 // indirect - github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/gobuffalo/flect v0.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.2.1 // indirect @@ -82,10 +83,10 @@ require ( github.com/google/safehtml v0.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/googleapis/gax-go/v2 v2.12.5 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/hashicorp/consul/api v1.28.2 // indirect + github.com/hashicorp/consul/api v1.29.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect @@ -100,12 +101,12 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-ieproxy v0.0.11 // indirect + github.com/mattn/go-ieproxy v0.0.12 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/minio/minio-go v0.0.0-20190131015406-c8a261de75c1 // indirect @@ -120,7 +121,7 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/outcaste-io/ristretto v0.2.3 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pelletier/go-toml/v2 v2.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pires/go-proxyproto v0.7.0 // indirect @@ -128,57 +129,57 @@ require ( github.com/planetscale/pargzip v0.0.0-20201116224723-90c7fc03ea8a // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.53.0 // indirect - github.com/prometheus/procfs v0.14.0 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.18.2 // indirect + github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tinylib/msgp v1.1.9 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/z-division/go-zookeeper v1.0.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.13 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect - go.etcd.io/etcd/client/v3 v3.5.13 // indirect + go.etcd.io/etcd/api/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/v3 v3.5.14 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 // indirect - go.opentelemetry.io/otel v1.25.0 // indirect - go.opentelemetry.io/otel/metric v1.25.0 // indirect - go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/oauth2 v0.19.0 // indirect + golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/tools v0.22.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/api v0.176.0 // indirect - google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect - google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect - gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 // indirect + google.golang.org/api v0.187.0 // indirect + google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/DataDog/dd-trace-go.v1 v1.65.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -186,10 +187,10 @@ require ( k8s.io/apiserver v0.28.5 // indirect k8s.io/component-base v0.28.5 // indirect k8s.io/gengo v0.0.0-20221011193443-fad74ee6edd9 // indirect - k8s.io/klog/v2 v2.100.1 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 626164df..9135d0a5 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,18 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.112.2 h1:ZaGT6LiG7dBzi6zNOvVZwacaXlmf3lRqnC4DQzqyRQw= -cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= -cloud.google.com/go/auth v0.2.2 h1:gmxNJs4YZYcw6YvKRtVBaF2fyUE6UrWPyzU8jHvYfmI= -cloud.google.com/go/auth v0.2.2/go.mod h1:2bDNJWtWziDT3Pu1URxHHbkHE/BbOCuyUiKIGcNvafo= -cloud.google.com/go/auth/oauth2adapt v0.2.1 h1:VSPmMmUlT8CkIZ2PzD9AlLN+R3+D1clXMWHHa6vG/Ag= -cloud.google.com/go/auth/oauth2adapt v0.2.1/go.mod h1:tOdK/k+D2e4GEwfBRA48dKNQiDsqIXxLh7VU319eV0g= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= -cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= -cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw= -cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= +cloud.google.com/go/auth v0.6.1 h1:T0Zw1XM5c1GlpN2HYr2s+m3vr1p2wy+8VN+Z1FKxW38= +cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= +cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= +cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/compute/metadata v0.4.0 h1:vHzJCWaM4g8XIcm8kopr3XmDA4Gy/lblD3EhhSux05c= +cloud.google.com/go/compute/metadata v0.4.0/go.mod h1:SIQh1Kkb4ZJ8zJ874fqVkslA29PRXuleyj6vOzlbK7M= +cloud.google.com/go/iam v1.1.10 h1:ZSAr64oEhQSClwBL670MsJAW5/RLiC6kfw3Bqmd5ZDI= +cloud.google.com/go/iam v1.1.10/go.mod h1:iEgMq62sg8zx446GCaijmA2Miwg5o3UbO+nI47WHJps= +cloud.google.com/go/longrunning v0.5.8 h1:QThI5BFSlYlS7K0wnABCdmKsXbG/htLc3nTPzrfOgeU= +cloud.google.com/go/longrunning v0.5.8/go.mod h1:oJDErR/mm5h44gzsfjQlxd6jyjFvuBPOxR1TLy2+cQk= +cloud.google.com/go/storage v1.42.0 h1:4QtGpplCVt1wz6g5o1ifXd656P5z+yNgzdw1tVfp0cU= +cloud.google.com/go/storage v1.42.0/go.mod h1:HjMXRFq65pGKFn6hxj6x3HCyR41uSB72Z0SO/Vn6JFQ= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= @@ -31,32 +33,30 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/DataDog/appsec-internal-go v1.5.0 h1:8kS5zSx5T49uZ8dZTdT19QVAvC/B8ByyZdhQKYQWHno= -github.com/DataDog/appsec-internal-go v1.5.0/go.mod h1:pEp8gjfNLtEOmz+iZqC8bXhu0h4k7NUsW/qiQb34k1U= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.52.1 h1:/oxF4p/4XUGNpNw2TE7vDu/pJV3elEAZ+jES0/MWtiI= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.52.1/go.mod h1:AVPQWekk3h9AOC7+plBlNB68Sy6UIGFoMMVUDeSoNoI= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.1 h1:mmkGuCHBFuDBpuwNMcqtY1x1I2fCaPH2Br4xPAAjbkM= -github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.52.1/go.mod h1:JhAilx32dkIgoDkFXquCTfaWDsAOfe+vfBaxbiZoPI0= +github.com/DataDog/appsec-internal-go v1.6.0 h1:QHvPOv/O0s2fSI/BraZJNpRDAtdlrRm5APJFZNBxjAw= +github.com/DataDog/appsec-internal-go v1.6.0/go.mod h1:pEp8gjfNLtEOmz+iZqC8bXhu0h4k7NUsW/qiQb34k1U= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.54.0 h1:rLQBdJQSvuFXGs5jK9Mc8BSpD5dalmxwKPPiwzXmlTk= +github.com/DataDog/datadog-agent/pkg/obfuscate v0.54.0/go.mod h1:4/9D8y6pQo5a/Tg8GAQN8SaRIRWxxyl5QHzPRuu8D0k= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.54.0 h1:6t+OZCHDCzaCZwanZI+XD/gw5L4va6d/7hGjI1F1mms= +github.com/DataDog/datadog-agent/pkg/remoteconfig/state v0.54.0/go.mod h1:3yFk56PJ57yS1GqI9HAsS4PSlAeGCC9RQA7jxKzYj6g= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go/v5 v5.5.0 h1:G5KHeB8pWBNXT4Jtw0zAkhdxEAWSpWH00geHI6LDrKU= github.com/DataDog/datadog-go/v5 v5.5.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= -github.com/DataDog/go-libddwaf/v2 v2.4.2 h1:ilquGKUmN9/Ty0sIxiEyznVRxP3hKfmH15Y1SMq5gjA= -github.com/DataDog/go-libddwaf/v2 v2.4.2/go.mod h1:gsCdoijYQfj8ce/T2bEDNPZFIYnmHluAgVDpuQOWMZE= -github.com/DataDog/go-sqllexer v0.0.11 h1:OfPBjmayreblOXreszbrOTICNZ3qWrA6Bg4sypvxpbw= -github.com/DataDog/go-sqllexer v0.0.11/go.mod h1:KwkYhpFEVIq+BfobkTC1vfqm4gTi65skV/DpDBXtexc= +github.com/DataDog/go-libddwaf/v3 v3.2.1 h1:lZPc6UxCOwioHc++nsldKR50FpIrRh1uGnGLuryqnE8= +github.com/DataDog/go-libddwaf/v3 v3.2.1/go.mod h1:AP+7Atb8ftSsrha35wht7+K3R+xuzfVSQhabSO4w6CY= +github.com/DataDog/go-sqllexer v0.0.12 h1:ncvAr5bbwtc7JMezzcU2379oKz1oHhRF1hkR6BSvhqM= +github.com/DataDog/go-sqllexer v0.0.12/go.mod h1:KwkYhpFEVIq+BfobkTC1vfqm4gTi65skV/DpDBXtexc= github.com/DataDog/go-tuf v1.1.0-0.5.2 h1:4CagiIekonLSfL8GMHRHcHudo1fQnxELS9g4tiAupQ4= github.com/DataDog/go-tuf v1.1.0-0.5.2/go.mod h1:zBcq6f654iVqmkk8n2Cx81E1JnNTMOAx1UEO/wZR+P0= github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4= github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM= -github.com/DataDog/sketches-go v1.4.4 h1:dF52vzXRFSPOj2IjXSWLvXq3jubL4CI69kwYjJ1w5Z8= -github.com/DataDog/sketches-go v1.4.4/go.mod h1:XR0ns2RtEEF09mDKXiKZiQg+nfZStrq1ZuL1eezeZe0= +github.com/DataDog/sketches-go v1.4.6 h1:acd5fb+QdUzGrosfNLwrIhqyrbMORpvBy7mE+vHlT3I= +github.com/DataDog/sketches-go v1.4.6/go.mod h1:7Y8GN8Jf66DLyDhc94zuWA3uHEt/7ttt8jHOBWWrSOg= github.com/HdrHistogram/hdrhistogram-go v0.9.0 h1:dpujRju0R4M/QZzcnR1LH1qm+TVG3UzkWdp5tH1WMcg= github.com/HdrHistogram/hdrhistogram-go v0.9.0/go.mod h1:nxrse8/Tzg2tg3DZcZjm6qEclQKK70g0KxO61gFFZD4= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/toxiproxy/v2 v2.9.0 h1:DIaDZG2/r/kv3Em6UxYBUVnnWl1mHlYTGFv+sTPV7VI= github.com/Shopify/toxiproxy/v2 v2.9.0/go.mod h1:2uPRyxR46fsx2yUr9i8zcejzdkWfK7p6G23jV/X6YNs= github.com/ahmetb/gen-crd-api-reference-docs v0.1.5-0.20190629210212-52e137b8d003 h1:mfPmvD5Nr9GTQnSgOg5OXusjS8uqDAZhJdYjmr1SWMc= @@ -73,8 +73,8 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.51.25 h1:DjTT8mtmsachhV6yrXR8+yhnG6120dazr720nopRsls= -github.com/aws/aws-sdk-go v1.51.25/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go v1.54.13 h1:zpCuiG+/mFdDY/klKJvmSioAZWk45F4rLGq0JWVAAzk= +github.com/aws/aws-sdk-go v1.54.13/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -97,8 +97,7 @@ github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -110,10 +109,13 @@ github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4 h1:8EXxF+tCLqaVk8AOC29zl2mnhQjwyLxxOTuhUazWRsg= +github.com/eapache/queue/v2 v2.0.0-20230407133247-75960ed334e4/go.mod h1:I5sHm0Y0T1u5YjlyqC5GVArM7aNZRUYtTjmJ8mPJFds= github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= +github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -125,8 +127,8 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -146,33 +148,28 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk= github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -200,7 +197,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -216,7 +212,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -224,10 +219,10 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= -github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/safehtml v0.1.0 h1:EwLKo8qawTKfsi0orxcQAZzu07cICaBeFMegAU9eaT8= @@ -240,18 +235,20 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= +github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= -github.com/hashicorp/consul/api v1.28.2 h1:mXfkRHrpHN4YY3RqL09nXU1eHKLNiuAN4kHvDQ16k/8= -github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= -github.com/hashicorp/consul/sdk v0.16.0 h1:SE9m0W6DEfgIVCJX7xU+iv/hUl4m/nxqMTnCdMxDpJ8= -github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= +github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= +github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= +github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg= +github.com/hashicorp/consul/proto-public v0.6.1/go.mod h1:cXXbOg74KBNGajC+o8RlA502Esf0R9prcoJgiOX/2Tg= +github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg= +github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -273,6 +270,10 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= @@ -281,8 +282,8 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= -github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -313,8 +314,8 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -330,8 +331,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -342,8 +341,8 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= -github.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo= -github.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0= +github.com/mattn/go-ieproxy v0.0.12 h1:OZkUFJC3ESNZPQ+6LzC3VJIFSnreeFLQyqvBWtvfL2M= +github.com/mattn/go-ieproxy v0.0.12/go.mod h1:Vn+N61199DAnVeTgaF8eoB9PvLO8P3OBnG95ENh7B7c= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= @@ -386,10 +385,10 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= @@ -404,8 +403,8 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg= -github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= @@ -428,8 +427,8 @@ github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSg github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= -github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -438,26 +437,30 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE= -github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s= -github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ= -github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052 h1:Qp27Idfgi6ACvFQat5+VJvlYToylpM/hcyLBI3WaKPA= -github.com/richardartoul/molecule v1.0.1-0.20221107223329-32cfee06a052/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3 h1:4+LEVOB87y175cLJC/mbsgKmoDOjrBldtXvioEy96WY= +github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3/go.mod h1:vl5+MqJ1nBINuSsUI2mGgH79UweUT/B5Fy8857PqyyI= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= @@ -480,15 +483,15 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -498,7 +501,6 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -525,26 +527,26 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/z-division/go-zookeeper v1.0.0 h1:ULsCj0nP6+U1liDFWe+2oEF6o4amixoDcDlwEUghVUY= github.com/z-division/go-zookeeper v1.0.0/go.mod h1:6X4UioQXpvyezJJl4J9NHAJKsoffCwy5wCaaTktXjOA= -go.etcd.io/etcd/api/v3 v3.5.13 h1:8WXU2/NBge6AUF1K1gOexB6e07NgsN1hXK0rSTtgSp4= -go.etcd.io/etcd/api/v3 v3.5.13/go.mod h1:gBqlqkcMMZMVTMm4NDZloEVJzxQOQIls8splbqBDa0c= -go.etcd.io/etcd/client/pkg/v3 v3.5.13 h1:RVZSAnWWWiI5IrYAXjQorajncORbS0zI48LQlE2kQWg= -go.etcd.io/etcd/client/pkg/v3 v3.5.13/go.mod h1:XxHT4u1qU12E2+po+UVPrEeL94Um6zL58ppuJWXSAB8= -go.etcd.io/etcd/client/v3 v3.5.13 h1:o0fHTNJLeO0MyVbc7I3fsCf6nrOqn5d+diSarKnB2js= -go.etcd.io/etcd/client/v3 v3.5.13/go.mod h1:cqiAeY8b5DEEcpxvgWKsbLIWNM/8Wy2xJSDMtioMcoI= +go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= +go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= +go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= +go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= +go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0 h1:zvpPXY7RfYAGSdYQLjp6zxdJNSYD/+FFoCTQN9IPxBs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.50.0/go.mod h1:BMn8NB1vsxTljvuorms2hyOs8IBuuBEq0pl7ltOfy30= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -568,11 +570,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -580,8 +582,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -591,7 +593,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -602,11 +603,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= -golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -648,17 +649,17 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -675,8 +676,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -685,20 +686,20 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSm golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.176.0 h1:dHj1/yv5Dm/eQTXiP9hNCRT3xzJHWXeNdRq29XbMxoE= -google.golang.org/api v0.176.0/go.mod h1:Rra+ltKu14pps/4xTycZfobMgLpbosoaaL7c+SEMrO8= +google.golang.org/api v0.187.0 h1:Mxs7VATVC2v7CY+7Xwm4ndkX71hpElcvx0D1Ji/p1eo= +google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be h1:g4aX8SUFA8V5F4LrSY5EclyGYw1OZN4HS1jTyjB9ZDc= -google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be/go.mod h1:FeSdT5fk+lkxatqJP38MsUicGqHax5cLtmy/6TAuxO4= -google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU= -google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -706,8 +707,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/examples v0.0.0-20210430044426-28078834f35b h1:D/GTYPo6I1oEo08Bfpuj3xl5XE+UGHj7//5fVyKxhsQ= google.golang.org/grpc/examples v0.0.0-20210430044426-28078834f35b/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -719,12 +720,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/DataDog/dd-trace-go.v1 v1.62.0 h1:jeZxE4ZlfAc+R0zO5TEmJBwOLet3NThsOfYJeSQg1x0= -gopkg.in/DataDog/dd-trace-go.v1 v1.62.0/go.mod h1:YTvYkk3PTsfw0OWrRFxV/IQ5Gy4nZ5TRvxTAP3JcIzs= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/DataDog/dd-trace-go.v1 v1.65.1 h1:Ne7kzWr/br/jwhUJR7CnqPl/mUpNxa6LfgZs0S4htZM= +gopkg.in/DataDog/dd-trace-go.v1 v1.65.1/go.mod h1:beNFIWd/H04d0k96cfltgiDH2+t0T5sDbyYLF3VTXqk= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -773,16 +772,16 @@ k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= -k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM= +k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= k8s.io/kubectl v0.28.5 h1:jq8xtiCCZPR8Cl/Qe1D7bLU0h8KtcunwfROqIekCUeU= k8s.io/kubectl v0.28.5/go.mod h1:9WiwzqeKs3vLiDtEQPbjhqqysX+BIVMLt7C7gN+T5w8= k8s.io/kubernetes v1.28.5 h1:sqgm0Tk6lqfsfcLUxZ0rfNmtugtABSLUhCqhXtfV1C0= k8s.io/kubernetes v1.28.5/go.mod h1:lRbvAZMgn+BrOtymmJAp85Jsa7GlL01av29axiPJ+E0= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= -k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= +k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigwG62c4= sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= sigs.k8s.io/controller-tools v0.11.3 h1:T1xzLkog9saiyQSLz1XOImu4OcbdXWytc5cmYsBeBiE= @@ -791,10 +790,10 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= -vitess.io/vitess v0.10.3-0.20240427144732-1e143c30e01b h1:AXLO03FK3+j9v/312404AdaMGR+N9UDdc4VkTV8PTAs= -vitess.io/vitess v0.10.3-0.20240427144732-1e143c30e01b/go.mod h1:WO8SCR76mTZHmLqCszsHV7ueHJfVWG66e4Y3kXYSL4I= +vitess.io/vitess v0.10.3-0.20240704214316-d303601040eb h1:AcEdrd2v45PnIApmY7FYhGUYUCe2XTyjoUvtmGtljek= +vitess.io/vitess v0.10.3-0.20240704214316-d303601040eb/go.mod h1:moByk7CfKOddEnXmzFxF6sL0zhwXsq/TRByTwMUznl4= diff --git a/pkg/apis/planetscale/v2/labels.go b/pkg/apis/planetscale/v2/labels.go index 71c4421e..a88e6f62 100644 --- a/pkg/apis/planetscale/v2/labels.go +++ b/pkg/apis/planetscale/v2/labels.go @@ -40,6 +40,8 @@ const ( TabletPoolNameLabel = LabelPrefix + "/" + "pool-name" // TabletIndexLabel is the key for identifying the index of a Vitess tablet within its pool. TabletIndexLabel = LabelPrefix + "/" + "tablet-index" + // BackupScheduleLabel is the key for identifying to which VitessBackupSchedule a Job belongs to. + BackupScheduleLabel = LabelPrefix + "/" + "backup-schedule" // VtctldComponentName is the ComponentLabel value for vtctld. VtctldComponentName = "vtctld" diff --git a/pkg/apis/planetscale/v2/vitessbackupschedule_methods.go b/pkg/apis/planetscale/v2/vitessbackupschedule_methods.go new file mode 100644 index 00000000..86026b49 --- /dev/null +++ b/pkg/apis/planetscale/v2/vitessbackupschedule_methods.go @@ -0,0 +1,53 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +// GetFailedJobsLimit returns the number of failed jobs to keep. +// Returns -1 if the value was not specified by the user. +func (vbsc *VitessBackupSchedule) GetFailedJobsLimit() int32 { + if vbsc.Spec.FailedJobsHistoryLimit == nil { + return -1 + } + return *vbsc.Spec.FailedJobsHistoryLimit +} + +// GetSuccessfulJobsLimit returns the number of failed jobs to keep. +// Returns -1 if the value was not specified by the user. +func (vbsc *VitessBackupSchedule) GetSuccessfulJobsLimit() int32 { + if vbsc.Spec.SuccessfulJobsHistoryLimit == nil { + return -1 + } + return *vbsc.Spec.SuccessfulJobsHistoryLimit +} + +// DefaultAllowedMissedRuns is the default that will be used in case of bug in the operator, +// which could be caused by the apiserver's clock for instance. In the event of such bug, +// the VitessBackupSchedule will try catching up the missed scheduled runs one by one +// this can be extremely lengthy in the even of a big clock skew, if the number of missed scheduled +// jobs reaches either DefaultAllowedMissedRuns or the value specified by the user, the controller +// will give up looking for the previously missed run and error out. +// Setting the default to 100 is fair, catching up a up to 100 missed scheduled runs is not lengthy. +const DefaultAllowedMissedRuns = 100 + +// GetMissedRunsLimit returns the maximum number of missed run we can allow. +// Returns DefaultAllowedMissedRuns if the value was not specified by the user. +func (vbsc *VitessBackupSchedule) GetMissedRunsLimit() int { + if vbsc.Spec.AllowedMissedRuns == nil { + return DefaultAllowedMissedRuns + } + return *vbsc.Spec.AllowedMissedRuns +} diff --git a/pkg/apis/planetscale/v2/vitessbackupschedule_types.go b/pkg/apis/planetscale/v2/vitessbackupschedule_types.go new file mode 100644 index 00000000..ff29654d --- /dev/null +++ b/pkg/apis/planetscale/v2/vitessbackupschedule_types.go @@ -0,0 +1,211 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v2 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ConcurrencyPolicy describes how the concurrency of new jobs created by VitessBackupSchedule +// is handled, the default is set to AllowConcurrent. +// +kubebuilder:validation:Enum=Allow;Forbid +type ConcurrencyPolicy string + +const ( + // AllowConcurrent allows CronJobs to run concurrently. + AllowConcurrent ConcurrencyPolicy = "Allow" + + // ForbidConcurrent forbids concurrent runs, skipping next run if previous hasn't finished yet. + ForbidConcurrent ConcurrencyPolicy = "Forbid" +) + +// BackupStrategyName describes the vtctldclient command that will be used to take a backup. +// When scheduling a backup, you must specify at least one strategy. +// +kubebuilder:validation:Enum=BackupShard +type BackupStrategyName string + +const ( + // BackupShard will use the "vtctldclient BackupShard" command to take a backup + BackupShard BackupStrategyName = "BackupShard" +) + +// VitessBackupSchedule is the Schema for the VitessBackupSchedule API. +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type VitessBackupSchedule struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VitessBackupScheduleSpec `json:"spec,omitempty"` + Status VitessBackupScheduleStatus `json:"status,omitempty"` +} + +// VitessBackupScheduleList contains a list of VitessBackupSchedule. +// +kubebuilder:object:root=true +type VitessBackupScheduleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VitessBackupSchedule `json:"items"` +} + +// VitessBackupScheduleSpec defines the desired state of VitessBackupSchedule. +type VitessBackupScheduleSpec struct { + // VitessBackupScheduleTemplate contains the user-specific parts of VitessBackupScheduleSpec. + // These are the parts that are configurable through the VitessCluster CRD. + VitessBackupScheduleTemplate `json:",inline"` + + // Cluster on which this schedule runs. + Cluster string `json:"cluster"` + + // Image should be any image that already contains vtctldclient installed. + // The controller will re-use the vtctld image by default. + Image string `json:"image,omitempty"` + + // ImagePullPolicy defines the policy to pull the Docker image in the job's pod. + // The PullPolicy used will be the same as the one used to pull the vtctld image. + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` +} + +// VitessBackupScheduleTemplate contains all the user-specific fields that the user will be +// able to define when writing their YAML file. +type VitessBackupScheduleTemplate struct { + // Name is the schedule name, this name must be unique across all the different VitessBackupSchedule + // objects in the cluster. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + // +kubebuilder:example="every-day" + Name string `json:"name"` + + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + // +kubebuilder:validation:MinLength=0 + // +kubebuilder:example="0 0 * * *" + Schedule string `json:"schedule"` + + // Strategy defines how we are going to take a backup. + // If you want to take several backups within the same schedule you can add more items + // to the Strategy list. Each VitessBackupScheduleStrategy will be executed by the same + // kubernetes job. This is useful if for instance you have one schedule, and you want to + // take a backup of all shards in a keyspace and don't want to re-create a second schedule. + // All the VitessBackupScheduleStrategy are concatenated into a single shell command that + // is executed when the Job's container starts. + // +kubebuilder:validation:MinItems=1 + Strategy []VitessBackupScheduleStrategy `json:"strategies"` + + // Resources specify the compute resources to allocate for every Jobs's pod. + Resources corev1.ResourceRequirements `json:"resources"` + + // SuccessfulJobsHistoryLimit defines how many successful jobs will be kept around. + // +optional + // +kubebuilder:validation:Minimum=0 + SuccessfulJobsHistoryLimit *int32 `json:"successfulJobsHistoryLimit,omitempty"` + + // FailedJobsHistoryLimit defines how many failed jobs will be kept around. + // +optional + // +kubebuilder:validation:Minimum=0 + FailedJobsHistoryLimit *int32 `json:"failedJobsHistoryLimit,omitempty"` + + // Suspend pause the associated backup schedule. Pausing any further scheduled + // runs until Suspend is set to false again. This is useful if you want to pause backup without + // having to remove the entire VitessBackupSchedule object from the cluster. + // +optional + Suspend *bool `json:"suspend,omitempty"` + + // StartingDeadlineSeconds enables the VitessBackupSchedule to start a job even though it is late by + // the given amount of seconds. Let's say for some reason the controller process a schedule run on + // second after its scheduled time, if StartingDeadlineSeconds is set to 0, the job will be skipped + // as it's too late, but on the other hand, if StartingDeadlineSeconds is greater than one second, + // the job will be processed as usual. + // +optional + // +kubebuilder:validation:Minimum=0 + StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds,omitempty"` + + // ConcurrencyPolicy specifies ho to treat concurrent executions of a Job. + // Valid values are: + // - "Allow" (default): allows CronJobs to run concurrently; + // - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; + // - "Replace": cancels currently running job and replaces it with a new one. + // +optional + // +kubebuilder:example="Forbid" + ConcurrencyPolicy ConcurrencyPolicy `json:"concurrencyPolicy,omitempty"` + + // AllowedMissedRuns defines how many missed run of the schedule will be allowed before giving up on finding the last job. + // If the operator's clock is skewed and we end-up missing a certain number of jobs, finding the last + // job might be very time-consuming, depending on the frequency of the schedule and the duration during which + // the operator's clock was misbehaving. Also depending on how laggy the clock is, we can end-up with thousands + // of missed runs. For this reason, AllowedMissedRun, which is set to 100 by default, will short circuit the search + // and simply wait for the next job on the schedule. + // Unless you are experiencing issue with missed runs due to a misconfiguration of the clock, we recommend leaving + // this field to its default value. + // +optional + // +kubebuilder:validation:Minimum=0 + AllowedMissedRuns *int `json:"allowedMissedRun,omitempty"` + + // JobTimeoutMinutes defines after how many minutes a job that has not yet finished should be stopped and removed. + // Default value is 10 minutes. + // +optional + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:default=10 + JobTimeoutMinutes int32 `json:"jobTimeoutMinute,omitempty"` + + // Annotations are the set of annotations that will be attached to the pods created by VitessBackupSchedule. + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + + // Affinity allows you to set rules that constrain the scheduling of the pods that take backups. + // WARNING: These affinity rules will override all default affinities that we set; in turn, we can't + // guarantee optimal scheduling of your pods if you choose to set this field. + // +optional + // +kubebuilder:validation:Schemaless + // +kubebuilder:pruning:PreserveUnknownFields + Affinity *corev1.Affinity `json:"affinity,omitempty"` +} + +// VitessBackupScheduleStrategy defines how we are going to take a backup. +// The VitessBackupSchedule controller uses this data to build the vtctldclient +// command line that will be executed in the Job's pod. +type VitessBackupScheduleStrategy struct { + // Name of the backup strategy. + Name BackupStrategyName `json:"name"` + + // Keyspace defines the keyspace on which we want to take the backup. + // +kubebuilder:example="commerce" + Keyspace string `json:"keyspace"` + + // Shard defines the shard on which we want to take a backup. + // +kubebuilder:example="-" + Shard string `json:"shard"` + + // ExtraFlags is a map of flags that will be sent down to vtctldclient when taking the backup. + // +optional + ExtraFlags map[string]string `json:"extraFlags,omitempty"` +} + +// VitessBackupScheduleStatus defines the observed state of VitessBackupSchedule +type VitessBackupScheduleStatus struct { + // A list of pointers to currently running jobs. + // +optional + Active []corev1.ObjectReference `json:"active,omitempty"` + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduledTime *metav1.Time `json:"lastScheduledTime,omitempty"` +} + +func init() { + SchemeBuilder.Register(&VitessBackupSchedule{}, &VitessBackupScheduleList{}) +} diff --git a/pkg/apis/planetscale/v2/vitesscluster_types.go b/pkg/apis/planetscale/v2/vitesscluster_types.go index f796d11b..000088e9 100644 --- a/pkg/apis/planetscale/v2/vitesscluster_types.go +++ b/pkg/apis/planetscale/v2/vitesscluster_types.go @@ -320,6 +320,13 @@ type ClusterBackupSpec struct { Engine VitessBackupEngine `json:"engine,omitempty"` // Subcontroller specifies any parameters needed for launching the VitessBackupStorage subcontroller pod. Subcontroller *VitessBackupSubcontrollerSpec `json:"subcontroller,omitempty"` + + // Schedules defines how often we want to perform a backup and how to perform the backup. + // This is a list of VitessBackupScheduleTemplate where the "name" field has to be unique + // across all the items of the list. + // +patchMergeKey=name + // +patchStrategy=merge + Schedules []VitessBackupScheduleTemplate `json:"schedules,omitempty"` } // VitessBackupEngine is the backup implementation to use. diff --git a/pkg/apis/planetscale/v2/zz_generated.deepcopy.go b/pkg/apis/planetscale/v2/zz_generated.deepcopy.go index e30236a6..66ac030b 100644 --- a/pkg/apis/planetscale/v2/zz_generated.deepcopy.go +++ b/pkg/apis/planetscale/v2/zz_generated.deepcopy.go @@ -57,6 +57,13 @@ func (in *ClusterBackupSpec) DeepCopyInto(out *ClusterBackupSpec) { *out = new(VitessBackupSubcontrollerSpec) **out = **in } + if in.Schedules != nil { + in, out := &in.Schedules, &out.Schedules + *out = make([]VitessBackupScheduleTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBackupSpec. @@ -752,6 +759,187 @@ func (in *VitessBackupLocation) DeepCopy() *VitessBackupLocation { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VitessBackupSchedule) DeepCopyInto(out *VitessBackupSchedule) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VitessBackupSchedule. +func (in *VitessBackupSchedule) DeepCopy() *VitessBackupSchedule { + if in == nil { + return nil + } + out := new(VitessBackupSchedule) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VitessBackupSchedule) 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 *VitessBackupScheduleList) DeepCopyInto(out *VitessBackupScheduleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VitessBackupSchedule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VitessBackupScheduleList. +func (in *VitessBackupScheduleList) DeepCopy() *VitessBackupScheduleList { + if in == nil { + return nil + } + out := new(VitessBackupScheduleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VitessBackupScheduleList) 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 *VitessBackupScheduleSpec) DeepCopyInto(out *VitessBackupScheduleSpec) { + *out = *in + in.VitessBackupScheduleTemplate.DeepCopyInto(&out.VitessBackupScheduleTemplate) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VitessBackupScheduleSpec. +func (in *VitessBackupScheduleSpec) DeepCopy() *VitessBackupScheduleSpec { + if in == nil { + return nil + } + out := new(VitessBackupScheduleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VitessBackupScheduleStatus) DeepCopyInto(out *VitessBackupScheduleStatus) { + *out = *in + if in.Active != nil { + in, out := &in.Active, &out.Active + *out = make([]v1.ObjectReference, len(*in)) + copy(*out, *in) + } + if in.LastScheduledTime != nil { + in, out := &in.LastScheduledTime, &out.LastScheduledTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VitessBackupScheduleStatus. +func (in *VitessBackupScheduleStatus) DeepCopy() *VitessBackupScheduleStatus { + if in == nil { + return nil + } + out := new(VitessBackupScheduleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VitessBackupScheduleStrategy) DeepCopyInto(out *VitessBackupScheduleStrategy) { + *out = *in + if in.ExtraFlags != nil { + in, out := &in.ExtraFlags, &out.ExtraFlags + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VitessBackupScheduleStrategy. +func (in *VitessBackupScheduleStrategy) DeepCopy() *VitessBackupScheduleStrategy { + if in == nil { + return nil + } + out := new(VitessBackupScheduleStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VitessBackupScheduleTemplate) DeepCopyInto(out *VitessBackupScheduleTemplate) { + *out = *in + if in.Strategy != nil { + in, out := &in.Strategy, &out.Strategy + *out = make([]VitessBackupScheduleStrategy, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Resources.DeepCopyInto(&out.Resources) + if in.SuccessfulJobsHistoryLimit != nil { + in, out := &in.SuccessfulJobsHistoryLimit, &out.SuccessfulJobsHistoryLimit + *out = new(int32) + **out = **in + } + if in.FailedJobsHistoryLimit != nil { + in, out := &in.FailedJobsHistoryLimit, &out.FailedJobsHistoryLimit + *out = new(int32) + **out = **in + } + if in.Suspend != nil { + in, out := &in.Suspend, &out.Suspend + *out = new(bool) + **out = **in + } + if in.StartingDeadlineSeconds != nil { + in, out := &in.StartingDeadlineSeconds, &out.StartingDeadlineSeconds + *out = new(int64) + **out = **in + } + if in.AllowedMissedRuns != nil { + in, out := &in.AllowedMissedRuns, &out.AllowedMissedRuns + *out = new(int) + **out = **in + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(v1.Affinity) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VitessBackupScheduleTemplate. +func (in *VitessBackupScheduleTemplate) DeepCopy() *VitessBackupScheduleTemplate { + if in == nil { + return nil + } + out := new(VitessBackupScheduleTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VitessBackupSpec) DeepCopyInto(out *VitessBackupSpec) { *out = *in diff --git a/pkg/controller/add_vitessbackupschedule.go b/pkg/controller/add_vitessbackupschedule.go new file mode 100644 index 00000000..836fd975 --- /dev/null +++ b/pkg/controller/add_vitessbackupschedule.go @@ -0,0 +1,26 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "planetscale.dev/vitess-operator/pkg/controller/vitessbackupschedule" +) + +func init() { + // AddToManagerFuncs is a list of functions to create controllers and add them to a manager. + AddToManagerFuncs = append(AddToManagerFuncs, vitessbackupschedule.Add) +} diff --git a/pkg/controller/vitessbackupschedule/metrics.go b/pkg/controller/vitessbackupschedule/metrics.go new file mode 100644 index 00000000..03d3f343 --- /dev/null +++ b/pkg/controller/vitessbackupschedule/metrics.go @@ -0,0 +1,55 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vitessbackupschedule + +import ( + "github.com/prometheus/client_golang/prometheus" + + "planetscale.dev/vitess-operator/pkg/operator/metrics" +) + +const ( + metricsSubsystemName = "backup_schedule" +) + +var ( + backupScheduleLabels = []string{ + metrics.BackupScheduleLabel, + metrics.ResultLabel, + } + + reconcileCount = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: metrics.Namespace, + Subsystem: metricsSubsystemName, + Name: "reconcile_count", + Help: "Reconciliation attempts for a VitessBackupSchedule", + }, backupScheduleLabels) + + timeoutJobsCount = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: metrics.Namespace, + Subsystem: metricsSubsystemName, + Name: "timeout_jobs_removed_count", + Help: "Number of timed out jobs that were removed for a VitessBackupSchedule", + }, backupScheduleLabels) +) + +func init() { + metrics.Registry.MustRegister( + reconcileCount, + timeoutJobsCount, + ) +} diff --git a/pkg/controller/vitessbackupschedule/vitessbackupschedule_controller.go b/pkg/controller/vitessbackupschedule/vitessbackupschedule_controller.go new file mode 100644 index 00000000..4ce56b21 --- /dev/null +++ b/pkg/controller/vitessbackupschedule/vitessbackupschedule_controller.go @@ -0,0 +1,619 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vitessbackupschedule + +import ( + "context" + "flag" + "fmt" + "maps" + "math/rand/v2" + "strings" + + "sort" + "time" + + "github.com/robfig/cron" + "github.com/sirupsen/logrus" + kbatch "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + apilabels "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/record" + "planetscale.dev/vitess-operator/pkg/operator/metrics" + "planetscale.dev/vitess-operator/pkg/operator/reconciler" + "planetscale.dev/vitess-operator/pkg/operator/results" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + ref "k8s.io/client-go/tools/reference" + planetscalev2 "planetscale.dev/vitess-operator/pkg/apis/planetscale/v2" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + controllerName = "vitessbackupschedule-controller" + vtctldclientPath = "/vt/bin/vtctldclient" +) + +var ( + maxConcurrentReconciles = flag.Int("vitessbackupschedule_concurrent_reconciles", 10, "the maximum number of different vitessbackupschedule resources to reconcile concurrently") + + scheduledTimeAnnotation = "planetscale.com/backup-scheduled-at" + + log = logrus.WithField("controller", "VitessBackupSchedule") +) + +// watchResources should contain all the resource types that this controller creates. +var watchResources = []client.Object{ + &kbatch.Job{}, +} + +type ( + // ReconcileVitessBackupsSchedule reconciles a VitessBackupSchedule object + ReconcileVitessBackupsSchedule struct { + client client.Client + scheme *runtime.Scheme + recorder record.EventRecorder + reconciler *reconciler.Reconciler + } + + jobsList struct { + active []*kbatch.Job + successful []*kbatch.Job + failed []*kbatch.Job + } +) + +var _ reconcile.Reconciler = &ReconcileVitessBackupsSchedule{} + +// Add creates a new Controller and adds it to the Manager. +func Add(mgr manager.Manager) error { + r, err := newReconciler(mgr) + if err != nil { + return err + } + return add(mgr, r) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) (*ReconcileVitessBackupsSchedule, error) { + c := mgr.GetClient() + scheme := mgr.GetScheme() + recorder := mgr.GetEventRecorderFor(controllerName) + + return &ReconcileVitessBackupsSchedule{ + client: c, + scheme: scheme, + recorder: recorder, + reconciler: reconciler.New(c, scheme, recorder), + }, nil +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r *ReconcileVitessBackupsSchedule) error { + // Create a new controller + c, err := controller.New(controllerName, mgr, controller.Options{ + Reconciler: r, + MaxConcurrentReconciles: *maxConcurrentReconciles, + }) + if err != nil { + return err + } + + // Watch for changes to primary resource VitessBackupSchedule + if err := c.Watch(source.Kind(mgr.GetCache(), &planetscalev2.VitessBackupSchedule{}), &handler.EnqueueRequestForObject{}); err != nil { + return err + } + + // Watch for changes to kbatch.Job and requeue the owner VitessBackupSchedule. + for _, resource := range watchResources { + err := c.Watch(source.Kind(mgr.GetCache(), resource), handler.EnqueueRequestForOwner( + mgr.GetScheme(), + mgr.GetRESTMapper(), + &planetscalev2.VitessBackupStorage{}, + handler.OnlyControllerOwner(), + )) + if err != nil { + return err + } + } + + return nil +} + +// Reconcile implements the kubernetes Reconciler interface. +// The main goal of this function is to create new Job k8s object according to the VitessBackupSchedule schedule. +// It also takes care of removing old failed and successful jobs, given the settings of VitessBackupSchedule. +// The function is structured as follows: +// - Get the VitessBackupSchedule object +// - List all jobs and define the last scheduled Job +// - Clean up old Job objects +// - Create a new Job if needed +func (r *ReconcileVitessBackupsSchedule) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + resultBuilder := &results.Builder{} + + log = log.WithFields(logrus.Fields{ + "namespace": req.Namespace, + "VitessBackupSchedule": req.Name, + }) + log.Info("Reconciling VitessBackupSchedule") + + var err error + var vbsc planetscalev2.VitessBackupSchedule + if err = r.client.Get(ctx, req.NamespacedName, &vbsc); err != nil { + log.WithError(err).Error(" unable to fetch VitessBackupSchedule") + if apierrors.IsNotFound(err) { + // Request object not found, could have been deleted after reconcile request. + // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. + // Return and don't requeue + return resultBuilder.Result() + } + // Error reading the object - requeue the request. + return resultBuilder.Error(err) + } + + // Register this reconciling attempt no matter if we fail or succeed. + defer func() { + reconcileCount.WithLabelValues(vbsc.Name, metrics.Result(err)).Inc() + }() + + jobs, mostRecentTime, err := r.getJobsList(ctx, req, vbsc.Name) + if err != nil { + // We had an error reading the jobs, we can requeue. + return resultBuilder.Error(err) + } + + err = r.updateVitessBackupScheduleStatus(ctx, mostRecentTime, vbsc, jobs.active) + if err != nil { + // We had an error updating the status, we can requeue. + return resultBuilder.Error(err) + } + + // We must clean up old jobs to not overcrowd the number of Pods and Jobs in the cluster. + // This will be done according to both failedJobsHistoryLimit and successfulJobsHistoryLimit fields. + r.cleanupJobsWithLimit(ctx, jobs.failed, vbsc.GetFailedJobsLimit()) + r.cleanupJobsWithLimit(ctx, jobs.successful, vbsc.GetSuccessfulJobsLimit()) + + err = r.removeTimeoutJobs(ctx, jobs.active, vbsc.Name, vbsc.Spec.JobTimeoutMinutes) + if err != nil { + // We had an error while removing timed out jobs, we can requeue + return resultBuilder.Error(err) + } + + // If the Suspend setting is set to true, we can skip adding any job, our work is done here. + if vbsc.Spec.Suspend != nil && *vbsc.Spec.Suspend { + log.Info("VitessBackupSchedule suspended, skipping") + return ctrl.Result{}, nil + } + + missedRun, nextRun, err := getNextSchedule(vbsc, time.Now()) + if err != nil { + log.Error(err, "unable to figure out VitessBackupSchedule schedule") + // Re-queuing here does not make sense as we have an error with the schedule and the user needs to fix it first. + return ctrl.Result{}, nil + } + + // Ask kubernetes to re-queue for the next scheduled job, and skip if we don't miss any run. + scheduledResult := ctrl.Result{RequeueAfter: nextRun.Sub(time.Now())} + if missedRun.IsZero() { + return scheduledResult, nil + } + + // Check whether we are too late to create this Job or not. The startingDeadlineSeconds field will help us + // schedule Jobs that are late. + tooLate := false + if vbsc.Spec.StartingDeadlineSeconds != nil { + tooLate = missedRun.Add(time.Duration(*vbsc.Spec.StartingDeadlineSeconds) * time.Second).Before(time.Now()) + } + if tooLate { + log.Infof("missed starting deadline for latest run; skipping; next run is scheduled for: %s", nextRun.Format(time.RFC3339)) + return scheduledResult, nil + } + + // Check concurrency policy and skip this job if we have ForbidConcurrent set plus an active job + if vbsc.Spec.ConcurrencyPolicy == planetscalev2.ForbidConcurrent && len(jobs.active) > 0 { + log.Infof("concurrency policy blocks concurrent runs: skipping, number of active jobs: %d", len(jobs.active)) + return scheduledResult, nil + } + + // Now that the different policies are checked, we can create and apply our new job. + job, err := r.createJob(ctx, &vbsc, missedRun) + if err != nil { + // Re-queuing here does not make sense as we have an error with the template and the user needs to fix it first. + log.WithError(err).Error("unable to construct job from template") + return ctrl.Result{}, err + } + if err = r.client.Create(ctx, job); err != nil { + // if the job already exists it means another reconciling loop created the job since we last fetched + // the list of jobs to create, we can safely return without failing. + if apierrors.IsAlreadyExists(err) { + return ctrl.Result{}, nil + } + // Simply re-queue here + return resultBuilder.Error(err) + } + + log.Infof("created new job: %s, next job scheduled in %s", job.Name, scheduledResult.RequeueAfter.String()) + return scheduledResult, nil +} + +func getNextSchedule(vbsc planetscalev2.VitessBackupSchedule, now time.Time) (time.Time, time.Time, error) { + sched, err := cron.ParseStandard(vbsc.Spec.Schedule) + if err != nil { + return time.Time{}, time.Time{}, fmt.Errorf("unable to parse schedule %q: %v", vbsc.Spec.Schedule, err) + } + + // Set the last scheduled time by either looking at the VitessBackupSchedule's Status or + // by looking at its creation time. + var latestRun time.Time + if vbsc.Status.LastScheduledTime != nil { + latestRun = vbsc.Status.LastScheduledTime.Time + } else { + latestRun = vbsc.ObjectMeta.CreationTimestamp.Time + } + + if vbsc.Spec.StartingDeadlineSeconds != nil { + // controller is not going to schedule anything below this point + schedulingDeadline := now.Add(-time.Second * time.Duration(*vbsc.Spec.StartingDeadlineSeconds)) + + if schedulingDeadline.After(latestRun) { + latestRun = schedulingDeadline + } + } + + // Next schedule is later, simply return the next scheduled time. + if latestRun.After(now) { + return time.Time{}, sched.Next(now), nil + } + + var lastMissed time.Time + missedRuns := 0 + for t := sched.Next(latestRun); !t.After(now); t = sched.Next(t) { + lastMissed = t + missedRuns++ + + // If we have too many missed jobs, just bail out as the clock lag is too big + if missedRuns > vbsc.GetMissedRunsLimit() { + return time.Time{}, time.Time{}, fmt.Errorf("too many missed runs, check clock skew or increase .spec.allowedMissedRun") + } + } + + return lastMissed, sched.Next(now), nil +} + +func (r *ReconcileVitessBackupsSchedule) updateVitessBackupScheduleStatus(ctx context.Context, mostRecentTime *time.Time, vbsc planetscalev2.VitessBackupSchedule, activeJobs []*kbatch.Job) error { + if mostRecentTime != nil { + vbsc.Status.LastScheduledTime = &metav1.Time{Time: *mostRecentTime} + } else { + vbsc.Status.LastScheduledTime = nil + } + + vbsc.Status.Active = make([]corev1.ObjectReference, 0, len(activeJobs)) + for _, activeJob := range activeJobs { + jobRef, err := ref.GetReference(r.scheme, activeJob) + if err != nil { + log.WithError(err).Errorf("unable to make reference to active job: %s", jobRef.Name) + continue + } + vbsc.Status.Active = append(vbsc.Status.Active, *jobRef) + } + + if err := r.client.Status().Update(ctx, &vbsc); err != nil { + log.WithError(err).Error("unable to update VitessBackupSchedule status") + return err + } + return nil +} + +// getJobsList fetches all existing Jobs in the cluster and return them by categories: active, failed or successful. +// It also returns at what time was the last job created, which is needed to update VitessBackupSchedule's status, +// and plan future jobs. +func (r *ReconcileVitessBackupsSchedule) getJobsList(ctx context.Context, req ctrl.Request, vbscName string) (jobsList, *time.Time, error) { + var existingJobs kbatch.JobList + + err := r.client.List(ctx, &existingJobs, client.InNamespace(req.Namespace), client.MatchingLabels{planetscalev2.BackupScheduleLabel: vbscName}) + if err != nil && !apierrors.IsNotFound(err) { + log.WithError(err).Error("unable to list Jobs in cluster") + return jobsList{}, nil, err + } + + var jobs jobsList + + var mostRecentTime *time.Time + + for i, job := range existingJobs.Items { + _, jobType := isJobFinished(&job) + switch jobType { + case kbatch.JobFailed, kbatch.JobFailureTarget: + jobs.failed = append(jobs.failed, &existingJobs.Items[i]) + case kbatch.JobComplete: + jobs.successful = append(jobs.successful, &existingJobs.Items[i]) + case kbatch.JobSuspended, "": + jobs.active = append(jobs.active, &existingJobs.Items[i]) + default: + return jobsList{}, nil, fmt.Errorf("unknown job type: %s", jobType) + } + + scheduledTimeForJob, err := getScheduledTimeForJob(&job) + if err != nil { + log.WithError(err).Errorf("unable to parse schedule time for existing job, found: %s", job.Annotations[scheduledTimeAnnotation]) + continue + } + if scheduledTimeForJob != nil && (mostRecentTime == nil || mostRecentTime.Before(*scheduledTimeForJob)) { + mostRecentTime = scheduledTimeForJob + } + } + return jobs, mostRecentTime, nil +} + +// cleanupJobsWithLimit removes all Job objects from the cluster ordered by oldest to newest and +// respecting the given limit, keeping minimum "limit" jobs in the cluster. +func (r *ReconcileVitessBackupsSchedule) cleanupJobsWithLimit(ctx context.Context, jobs []*kbatch.Job, limit int32) { + if limit == -1 { + return + } + + sort.SliceStable(jobs, func(i, j int) bool { + if jobs[i].Status.StartTime == nil { + return jobs[j].Status.StartTime != nil + } + return jobs[i].Status.StartTime.Before(jobs[j].Status.StartTime) + }) + + for i, job := range jobs { + if int32(i) >= int32(len(jobs))-limit { + break + } + if err := r.client.Delete(ctx, job, client.PropagationPolicy(metav1.DeletePropagationBackground)); (err) != nil { + log.WithError(err).Errorf("unable to delete old job: %s", job.Name) + } else { + log.Infof("deleted old job: %s", job.Name) + } + } +} + +func (r *ReconcileVitessBackupsSchedule) removeTimeoutJobs(ctx context.Context, jobs []*kbatch.Job, vbscName string, timeout int32) error { + if timeout == -1 { + return nil + } + for _, job := range jobs { + jobStartTime, err := getScheduledTimeForJob(job) + if err != nil { + return err + } + if jobStartTime.Add(time.Minute * time.Duration(timeout)).Before(time.Now()) { + if err = r.client.Delete(ctx, job, client.PropagationPolicy(metav1.DeletePropagationBackground)); (err) != nil { + log.WithError(err).Errorf("unable to delete timed out job: %s", job.Name) + } else { + log.Infof("deleted timed out job: %s", job.Name) + } + timeoutJobsCount.WithLabelValues(vbscName, metrics.Result(err)).Inc() + } + } + return nil +} + +func isJobFinished(job *kbatch.Job) (bool, kbatch.JobConditionType) { + for _, c := range job.Status.Conditions { + if (c.Type == kbatch.JobComplete || c.Type == kbatch.JobFailed) && c.Status == corev1.ConditionTrue { + return true, c.Type + } + } + + return false, "" +} + +func getScheduledTimeForJob(job *kbatch.Job) (*time.Time, error) { + timeRaw := job.Annotations[scheduledTimeAnnotation] + if len(timeRaw) == 0 { + return nil, nil + } + + timeParsed, err := time.Parse(time.RFC3339, timeRaw) + if err != nil { + return nil, err + } + + return &timeParsed, nil +} + +func (r *ReconcileVitessBackupsSchedule) createJob(ctx context.Context, vbsc *planetscalev2.VitessBackupSchedule, scheduledTime time.Time) (*kbatch.Job, error) { + name := fmt.Sprintf("%s-%d", vbsc.Name, scheduledTime.Unix()) + + meta := metav1.ObjectMeta{ + Labels: map[string]string{ + planetscalev2.BackupScheduleLabel: vbsc.Name, + }, + Annotations: make(map[string]string), + Name: name, + Namespace: vbsc.Namespace, + } + maps.Copy(meta.Annotations, vbsc.Annotations) + maps.Copy(meta.Annotations, vbsc.Spec.Annotations) + + meta.Annotations[scheduledTimeAnnotation] = scheduledTime.Format(time.RFC3339) + + maps.Copy(meta.Labels, vbsc.Labels) + + pod, err := r.createJobPod(ctx, vbsc, name) + if err != nil { + return nil, err + } + job := &kbatch.Job{ + ObjectMeta: meta, + Spec: kbatch.JobSpec{ + Template: corev1.PodTemplateSpec{ + ObjectMeta: meta, + Spec: pod, + }, + }, + } + + if err := ctrl.SetControllerReference(vbsc, job, r.scheme); err != nil { + return nil, err + } + + return job, nil +} + +func (r *ReconcileVitessBackupsSchedule) createJobPod(ctx context.Context, vbsc *planetscalev2.VitessBackupSchedule, name string) (pod corev1.PodSpec, err error) { + getVtctldServiceName := func(cluster string) (string, error) { + vtctldServiceName, vtctldServicePort, err := r.getVtctldServiceName(ctx, vbsc, cluster) + if err != nil { + return "", err + } + return fmt.Sprintf("--server=%s:%d", vtctldServiceName, vtctldServicePort), nil + } + + // It is fine to not have any default in the event there is no strategy as the CRD validation + // ensures that there will be at least one item in this list. The YAML cannot be applied with + // empty list of strategies. + var cmd strings.Builder + + addNewCmd := func(i int) { + if i > 0 { + cmd.WriteString(" && ") + } + } + + for i, strategy := range vbsc.Spec.Strategy { + vtctldclientServerArg, err := getVtctldServiceName(vbsc.Spec.Cluster) + if err != nil { + return corev1.PodSpec{}, err + } + + addNewCmd(i) + switch strategy.Name { + case planetscalev2.BackupShard: + createVtctldClientCommand(&cmd, vtctldclientServerArg, strategy.ExtraFlags, strategy.Keyspace, strategy.Shard) + } + + } + + pod = corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: name, + Image: vbsc.Spec.Image, + ImagePullPolicy: vbsc.Spec.ImagePullPolicy, + Resources: vbsc.Spec.Resources, + Args: []string{"/bin/sh", "-c", cmd.String()}, + }}, + RestartPolicy: corev1.RestartPolicyOnFailure, + Affinity: vbsc.Spec.Affinity, + } + return pod, nil +} + +func createVtctldClientCommand(cmd *strings.Builder, serverAddr string, extraFlags map[string]string, keyspace, shard string) { + cmd.WriteString(fmt.Sprintf("%s %s BackupShard", vtctldclientPath, serverAddr)) + + // Add any flags + for key, value := range extraFlags { + cmd.WriteString(fmt.Sprintf(" --%s=%s", key, value)) + } + + // Add keyspace/shard + cmd.WriteString(fmt.Sprintf(" %s/%s", keyspace, shard)) +} + +func (r *ReconcileVitessBackupsSchedule) getVtctldServiceName(ctx context.Context, vbsc *planetscalev2.VitessBackupSchedule, cluster string) (svcName string, svcPort int32, err error) { + svcList := &corev1.ServiceList{} + listOpts := &client.ListOptions{ + Namespace: vbsc.Namespace, + LabelSelector: apilabels.Set{ + planetscalev2.ClusterLabel: cluster, + planetscalev2.ComponentLabel: planetscalev2.VtctldComponentName, + }.AsSelector(), + } + if err = r.client.List(ctx, svcList, listOpts); err != nil { + return "", 0, fmt.Errorf("unable to list vtctld service in %q: %v", vbsc.Namespace, err) + } + + if len(svcList.Items) > 0 { + service := svcList.Items[rand.IntN(len(svcList.Items))] + svcName = service.Name + for _, port := range service.Spec.Ports { + if port.Name == planetscalev2.DefaultGrpcPortName { + svcPort = port.Port + break + } + } + } + + if svcName == "" || svcPort == 0 { + return "", 0, fmt.Errorf("no vtctld service found in %q namespace", vbsc.Namespace) + } + return svcName, svcPort, nil +} + +func (r *ReconcileVitessBackupsSchedule) getAllShardsInKeyspace(ctx context.Context, namespace, cluster, keyspace string) ([]string, error) { + shardsList := &planetscalev2.VitessShardList{} + listOpts := &client.ListOptions{ + Namespace: namespace, + LabelSelector: apilabels.Set{ + planetscalev2.ClusterLabel: cluster, + planetscalev2.KeyspaceLabel: keyspace, + }.AsSelector(), + } + if err := r.client.List(ctx, shardsList, listOpts); err != nil { + return nil, fmt.Errorf("unable to list shards of keyspace %s in %s: %v", keyspace, namespace, err) + } + var result []string + for _, item := range shardsList.Items { + result = append(result, item.Spec.Name) + } + return result, nil +} + +type keyspace struct { + name string + shards []string +} + +func (r *ReconcileVitessBackupsSchedule) getAllShardsInCluster(ctx context.Context, namespace, cluster string) ([]keyspace, error) { + ksList := &planetscalev2.VitessKeyspaceList{} + listOpts := &client.ListOptions{ + Namespace: namespace, + LabelSelector: apilabels.Set{ + planetscalev2.ClusterLabel: cluster, + }.AsSelector(), + } + if err := r.client.List(ctx, ksList, listOpts); err != nil { + return nil, fmt.Errorf("unable to list shards in namespace %s: %v", namespace, err) + } + result := make([]keyspace, 0, len(ksList.Items)) + for _, item := range ksList.Items { + ks := keyspace{ + name: item.Spec.Name, + } + for shardName := range item.Status.Shards { + ks.shards = append(ks.shards, shardName) + } + if len(ks.shards) > 0 { + result = append(result, ks) + } + } + return result, nil +} diff --git a/pkg/controller/vitesscluster/reconcile_backup_schedule.go b/pkg/controller/vitesscluster/reconcile_backup_schedule.go new file mode 100644 index 00000000..f8d777b3 --- /dev/null +++ b/pkg/controller/vitesscluster/reconcile_backup_schedule.go @@ -0,0 +1,76 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vitesscluster + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "planetscale.dev/vitess-operator/pkg/operator/vitessbackup" + "sigs.k8s.io/controller-runtime/pkg/client" + + planetscalev2 "planetscale.dev/vitess-operator/pkg/apis/planetscale/v2" + "planetscale.dev/vitess-operator/pkg/operator/reconciler" +) + +func (r *ReconcileVitessCluster) reconcileBackupSchedule(ctx context.Context, vt *planetscalev2.VitessCluster) error { + labels := map[string]string{ + planetscalev2.ClusterLabel: vt.Name, + } + + // Generate keys (object names) for all desired cells. + // Keep a map back from generated names to the specs. + var keys []client.ObjectKey + scheduleMap := make(map[client.ObjectKey]*planetscalev2.VitessBackupScheduleTemplate) + if vt.Spec.Backup != nil { + for i := range vt.Spec.Backup.Schedules { + schedule := &vt.Spec.Backup.Schedules[i] + key := client.ObjectKey{ + Namespace: vt.Namespace, + Name: vitessbackup.ScheduleName(vt.Name, schedule.Name), + } + keys = append(keys, key) + scheduleMap[key] = schedule + } + } + + return r.reconciler.ReconcileObjectSet(ctx, vt, keys, labels, reconciler.Strategy{ + Kind: &planetscalev2.VitessBackupSchedule{}, + + New: func(key client.ObjectKey) runtime.Object { + vbsc := vitessbackup.NewVitessBackupSchedule(key, vt, scheduleMap[key], labels) + if vbsc == nil { + return &planetscalev2.VitessBackupSchedule{} + } + return vbsc + }, + + UpdateInPlace: func(key client.ObjectKey, obj runtime.Object) { + newObj := obj.(*planetscalev2.VitessBackupSchedule) + newVbsc := vitessbackup.NewVitessBackupSchedule(key, vt, scheduleMap[key], labels) + if newVbsc == nil { + return + } + newObj.Spec = newVbsc.Spec + }, + + PrepareForTurndown: func(key client.ObjectKey, newObj runtime.Object) *planetscalev2.OrphanStatus { + // If we want to remove the schedule, delete it immediately. + return nil + }, + }) +} diff --git a/pkg/controller/vitesscluster/vitesscluster_controller.go b/pkg/controller/vitesscluster/vitesscluster_controller.go index 98933312..a7d2a7bb 100644 --- a/pkg/controller/vitesscluster/vitesscluster_controller.go +++ b/pkg/controller/vitesscluster/vitesscluster_controller.go @@ -186,6 +186,11 @@ func (r *ReconcileVitessCluster) Reconcile(cctx context.Context, request reconci resultBuilder.Error(err) } + // Create/update VitessBackupSchedule object. + if err := r.reconcileBackupSchedule(ctx, vt); err != nil { + resultBuilder.Error(err) + } + // Create/update desired VitessCells. if err := r.reconcileCells(ctx, vt); err != nil { resultBuilder.Error(err) diff --git a/pkg/controller/vitessshardreplication/init_restored_shard.go b/pkg/controller/vitessshardreplication/init_restored_shard.go index 957200e4..266a66a5 100644 --- a/pkg/controller/vitessshardreplication/init_restored_shard.go +++ b/pkg/controller/vitessshardreplication/init_restored_shard.go @@ -269,7 +269,7 @@ func electInitialShardPrimary(ctx context.Context, keyspaceName, shardName strin wg.Add(1) go func(tablet *topo.TabletInfo) { defer wg.Done() - err := wr.TabletManagerClient().SetReplicationSource(ctx, tablet.Tablet, candidatePrimary.tablet.Alias, 0 /* don't try to wait for a reparent journal entry */, "" /* don't wait for any position */, true /* forceStartReplication */, reparentutil.IsReplicaSemiSync(durability, candidatePrimary.tablet.Tablet, tablet.Tablet)) + err := wr.TabletManagerClient().SetReplicationSource(ctx, tablet.Tablet, candidatePrimary.tablet.Alias, 0 /* don't try to wait for a reparent journal entry */, "" /* don't wait for any position */, true /* forceStartReplication */, reparentutil.IsReplicaSemiSync(durability, candidatePrimary.tablet.Tablet, tablet.Tablet), 0) if err != nil { log.Warningf("best-effort configuration of replication for tablet %v failed: %v", tablet.AliasString(), err) } diff --git a/pkg/operator/metrics/metrics.go b/pkg/operator/metrics/metrics.go index b53af6e3..198ac47a 100644 --- a/pkg/operator/metrics/metrics.go +++ b/pkg/operator/metrics/metrics.go @@ -34,6 +34,8 @@ const ( ShardLabel = "shard" // BackupStorageLabel is the label whose value gives the name of a VitessBackupStorage object. BackupStorageLabel = "backup_storage" + // BackupScheduleLabel is the label whose value gives the name of a VitessBackupSchedule object. + BackupScheduleLabel = "backup_schedule" // ResultLabel is a common metrics label for the success/failure of an operation. ResultLabel = "result" diff --git a/pkg/operator/vitessbackup/schedule.go b/pkg/operator/vitessbackup/schedule.go new file mode 100644 index 00000000..fc5ced6b --- /dev/null +++ b/pkg/operator/vitessbackup/schedule.go @@ -0,0 +1,53 @@ +/* +Copyright 2024 PlanetScale Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vitessbackup + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + planetscalev2 "planetscale.dev/vitess-operator/pkg/apis/planetscale/v2" + "planetscale.dev/vitess-operator/pkg/operator/names" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func ScheduleName(clusterName string, scheduleName string) string { + return names.JoinWithConstraints(names.DefaultConstraints, clusterName, "vbsc", scheduleName) +} + +func NewVitessBackupSchedule(key client.ObjectKey, vt *planetscalev2.VitessCluster, vbsc *planetscalev2.VitessBackupScheduleTemplate, labels map[string]string) *planetscalev2.VitessBackupSchedule { + if vt.Spec.Backup == nil || vbsc == nil || vbsc.Schedule == "" { + return nil + } + + return &planetscalev2.VitessBackupSchedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: key.Name, + Namespace: key.Namespace, + Labels: labels, + }, + Spec: planetscalev2.VitessBackupScheduleSpec{ + // We simply re-apply the same template that was written by the user. + VitessBackupScheduleTemplate: *vbsc, + + Cluster: vt.Name, + + // To take backups we only care about having the vtctldclient installed in the container. + // For this reason, we re-use the vtctld Docker image and the same image pull policy. + Image: vt.Spec.Images.Vtctld, + ImagePullPolicy: vt.Spec.ImagePullPolicies.Vtctld, + }, + } +} diff --git a/test/endtoend/backup_restore_test.sh b/test/endtoend/backup_restore_test.sh index f4fc04cd..5332382f 100755 --- a/test/endtoend/backup_restore_test.sh +++ b/test/endtoend/backup_restore_test.sh @@ -30,14 +30,14 @@ function resurrectShard() { sleep 5 echo "show databases;" | mysql | grep "commerce" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "Could not find commerce database" printMysqlErrorFiles exit 1 fi echo "show tables;" | mysql commerce | grep -E 'corder|customer|product' | wc -l | grep 3 > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "Could not find commerce's tables" printMysqlErrorFiles exit 1 @@ -76,7 +76,7 @@ EOF } function setupKindConfig() { - if [ "$BUILDKITE_BUILD_ID" != "0" ]; then + if [[ "$BUILDKITE_BUILD_ID" != "0" ]]; then # The script is being run from buildkite, so we can't mount the current # working directory to kind. The current directory in the docker is workdir # So if we try and mount that, we get an error. Instead we need to mount the @@ -99,7 +99,7 @@ docker build -f build/Dockerfile.release -t vitess-operator-pr:latest . echo "Setting up the kind config" setupKindConfig echo "Creating Kind cluster" -kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --config ./vtdataroot/config.yaml --image kindest/node:v1.28.0 +kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --config ./vtdataroot/config.yaml --image ${KIND_VERSION} echo "Loading docker image into Kind cluster" kind load docker-image vitess-operator-pr:latest --name kind-${BUILDKITE_BUILD_ID} @@ -108,7 +108,7 @@ killall kubectl setupKubectlAccessForCI get_started "operator-latest.yaml" "101_initial_cluster_backup.yaml" -verifyVtGateVersion "20.0.0" +verifyVtGateVersion "21.0.0" checkSemiSyncSetup takeBackup "commerce/-" verifyListBackupsOutput diff --git a/test/endtoend/backup_schedule_test.sh b/test/endtoend/backup_schedule_test.sh new file mode 100755 index 00000000..ef2c45f3 --- /dev/null +++ b/test/endtoend/backup_schedule_test.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +source ./tools/test.env +source ./test/endtoend/utils.sh + +function takedownShard() { + echo "Apply 102_keyspace_teardown.yaml" + kubectl apply -f 102_keyspace_teardown.yaml + + # wait for all the vttablets to disappear + checkPodStatusWithTimeout "example-vttablet-zone1" 0 +} + +function checkVitessBackupScheduleStatusWithTimeout() { + regex=$1 + + for i in {1..1200} ; do + if [[ $(kubectl get VitessBackupSchedule | grep -E "${regex}" | wc -l) -eq 1 ]]; then + echo "$regex found" + return + fi + sleep 1 + done + echo -e "ERROR: checkPodStatusWithTimeout timeout to find pod matching:\ngot:\n$out\nfor regex: $regex" + exit 1 +} + +function verifyListBackupsOutputWithSchedule() { + echo -e "Check for VitessBackupSchedule status" + checkVitessBackupScheduleStatusWithTimeout "example-vbsc-every-minute(.*)" + checkVitessBackupScheduleStatusWithTimeout "example-vbsc-every-five-minute(.*)" + + echo -e "Check for number of backups in the cluster" + # Sleep for 6 minutes, during this time we should have at the very minimum 7 backups. + # At least: 6 backups from the every-minute schedule, and 1 backup from the every-five-minute schedule. + sleep 360 + + backupCount=$(kubectl get vtb --no-headers | wc -l) + if [[ "${backupCount}" -lt 7 ]]; then + echo "Did not find at least 7 backups" + return 0 + fi + + echo -e "Check for Jobs' pods" + checkPodStatusWithTimeout "example-vbsc-every-minute-(.*)0/1(.*)Completed(.*)" 3 + checkPodStatusWithTimeout "example-vbsc-every-five-minute-(.*)0/1(.*)Completed(.*)" 2 +} + +function setupKindConfig() { + if [[ "$BUILDKITE_BUILD_ID" != "0" ]]; then + # The script is being run from buildkite, so we can't mount the current + # working directory to kind. The current directory in the docker is workdir + # So if we try and mount that, we get an error. Instead we need to mount the + # path where the code was checked out be buildkite + dockerContainerName=$(docker container ls --filter "ancestor=docker" --format '{{.Names}}') + CHECKOUT_PATH=$(docker container inspect -f '{{range .Mounts}}{{ if eq .Destination "/workdir" }}{{println .Source }}{{ end }}{{end}}' "$dockerContainerName") + BACKUP_DIR="$CHECKOUT_PATH/vtdataroot/backup" + else + BACKUP_DIR="$PWD/vtdataroot/backup" + fi + cat ./test/endtoend/kindBackupConfig.yaml | sed "s,PATH,$BACKUP_DIR,1" > ./vtdataroot/config.yaml +} + +# Test setup +STARTING_DIR="$PWD" +echo "Make temporary directory for the test" +mkdir -p -m 777 ./vtdataroot/backup +echo "Building the docker image" +docker build -f build/Dockerfile.release -t vitess-operator-pr:latest . +echo "Setting up the kind config" +setupKindConfig +echo "Creating Kind cluster" +kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --config ./vtdataroot/config.yaml --image ${KIND_VERSION} +echo "Loading docker image into Kind cluster" +kind load docker-image vitess-operator-pr:latest --name kind-${BUILDKITE_BUILD_ID} + +cd "$PWD/test/endtoend/operator" +killall kubectl +setupKubectlAccessForCI + +get_started "operator-latest.yaml" "101_initial_cluster_backup_schedule.yaml" +verifyVtGateVersion "21.0.0" +checkSemiSyncSetup +verifyListBackupsOutputWithSchedule + +echo "Removing the temporary directory" +removeBackupFiles +rm -rf "$STARTING_DIR/vtdataroot" +echo "Deleting Kind cluster. This also deletes the volume associated with it" +kind delete cluster --name kind-${BUILDKITE_BUILD_ID} diff --git a/test/endtoend/operator/101_initial_cluster.yaml b/test/endtoend/operator/101_initial_cluster.yaml index 1282f691..0cca4994 100644 --- a/test/endtoend/operator/101_initial_cluster.yaml +++ b/test/endtoend/operator/101_initial_cluster.yaml @@ -8,11 +8,11 @@ metadata: name: example spec: images: - vtctld: vitess/lite:v19.0.0 - vtgate: vitess/lite:v19.0.0 - vttablet: vitess/lite:v19.0.0 - vtorc: vitess/lite:v19.0.0 - vtbackup: vitess/lite:v19.0.0 + vtctld: vitess/lite:v20.0.0-rc2 + vtgate: vitess/lite:v20.0.0-rc2 + vttablet: vitess/lite:v20.0.0-rc2 + vtorc: vitess/lite:v20.0.0-rc2 + vtbackup: vitess/lite:v20.0.0-rc2 mysqld: mysql80Compatible: mysql:8.0.30 mysqldExporter: prom/mysqld-exporter:v0.11.0 diff --git a/test/endtoend/operator/101_initial_cluster_backup_schedule.yaml b/test/endtoend/operator/101_initial_cluster_backup_schedule.yaml new file mode 100644 index 00000000..c1cf7737 --- /dev/null +++ b/test/endtoend/operator/101_initial_cluster_backup_schedule.yaml @@ -0,0 +1,248 @@ +# The following example is minimalist. The security policies +# and resource specifications are not meant to be used in production. +# Please refer to the operator documentation for recommendations on +# production settings. +apiVersion: planetscale.com/v2 +kind: VitessCluster +metadata: + name: example +spec: + backup: + engine: xtrabackup + locations: + - volume: + hostPath: + path: /backup + type: Directory + schedules: + - name: "every-minute" + schedule: "* * * * *" + resources: + requests: + cpu: 100m + memory: 1024Mi + limits: + memory: 1024Mi + successfulJobsHistoryLimit: 2 + failedJobsHistoryLimit: 3 + jobTimeoutMinute: 5 + strategies: + - name: BackupShard + keyspace: "commerce" + shard: "-" + - name: "every-five-minute" + schedule: "*/5 * * * *" + resources: + requests: + cpu: 100m + memory: 1024Mi + limits: + memory: 1024Mi + successfulJobsHistoryLimit: 2 + failedJobsHistoryLimit: 3 + jobTimeoutMinute: 5 + strategies: + - name: BackupShard + keyspace: "commerce" + shard: "-" + images: + vtctld: vitess/lite:latest + vtgate: vitess/lite:latest + vttablet: vitess/lite:latest + vtorc: vitess/lite:latest + vtbackup: vitess/lite:latest + mysqld: + mysql80Compatible: mysql:8.0.30 + mysqldExporter: prom/mysqld-exporter:v0.11.0 + cells: + - name: zone1 + gateway: + authentication: + static: + secret: + name: example-cluster-config + key: users.json + replicas: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + memory: 256Mi + vitessDashboard: + cells: + - zone1 + extraFlags: + security_policy: read-only + replicas: 1 + resources: + limits: + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + + keyspaces: + - name: commerce + durabilityPolicy: semi_sync + turndownPolicy: Immediate + vitessOrchestrator: + resources: + limits: + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + extraFlags: + recovery-period-block-duration: 5s + partitionings: + - equal: + parts: 1 + shardTemplate: + databaseInitScriptSecret: + name: example-cluster-config + key: init_db.sql + tabletPools: + - cell: zone1 + type: replica + replicas: 3 + vttablet: + extraFlags: + db_charset: utf8mb4 + wait_for_backup_interval: "0" + resources: + limits: + memory: 1024Mi + requests: + cpu: 100m + memory: 1024Mi + mysqld: + resources: + limits: + memory: 1024Mi + requests: + cpu: 100m + memory: 512Mi + dataVolumeClaimTemplate: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 10Gi + updateStrategy: + type: Immediate +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-cluster-config +type: Opaque +stringData: + users.json: | + { + "user": [{ + "UserData": "user", + "Password": "" + }] + } + init_db.sql: | + # This file is executed immediately after mysql_install_db, + # to initialize a fresh data directory. + + ############################################################################### + # Equivalent of mysql_secure_installation + ############################################################################### + + # We need to ensure that super_read_only is disabled so that we can execute + # these commands. Note that disabling it does NOT disable read_only. + # We save the current value so that we only re-enable it at the end if it was + # enabled before. + SET @original_super_read_only=IF(@@global.super_read_only=1, 'ON', 'OFF'); + SET GLOBAL super_read_only='OFF'; + + # Changes during the init db should not make it to the binlog. + # They could potentially create errant transactions on replicas. + SET sql_log_bin = 0; + # Remove anonymous users. + DELETE FROM mysql.user WHERE User = ''; + + # Disable remote root access (only allow UNIX socket). + DELETE FROM mysql.user WHERE User = 'root' AND Host != 'localhost'; + + # Remove test database. + DROP DATABASE IF EXISTS test; + + ############################################################################### + # Vitess defaults + ############################################################################### + + # Vitess-internal database. + CREATE DATABASE IF NOT EXISTS _vt; + # Note that definitions of local_metadata and shard_metadata should be the same + # as in production which is defined in go/vt/mysqlctl/metadata_tables.go. + CREATE TABLE IF NOT EXISTS _vt.local_metadata ( + name VARCHAR(255) NOT NULL, + value VARCHAR(255) NOT NULL, + db_name VARBINARY(255) NOT NULL, + PRIMARY KEY (db_name, name) + ) ENGINE=InnoDB; + CREATE TABLE IF NOT EXISTS _vt.shard_metadata ( + name VARCHAR(255) NOT NULL, + value MEDIUMBLOB NOT NULL, + db_name VARBINARY(255) NOT NULL, + PRIMARY KEY (db_name, name) + ) ENGINE=InnoDB; + + # Admin user with all privileges. + CREATE USER 'vt_dba'@'localhost'; + GRANT ALL ON *.* TO 'vt_dba'@'localhost'; + GRANT GRANT OPTION ON *.* TO 'vt_dba'@'localhost'; + + # User for app traffic, with global read-write access. + CREATE USER 'vt_app'@'localhost'; + GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_app'@'localhost'; + + # User for app debug traffic, with global read access. + CREATE USER 'vt_appdebug'@'localhost'; + GRANT SELECT, SHOW DATABASES, PROCESS ON *.* TO 'vt_appdebug'@'localhost'; + + # User for administrative operations that need to be executed as non-SUPER. + # Same permissions as vt_app here. + CREATE USER 'vt_allprivs'@'localhost'; + GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_allprivs'@'localhost'; + + # User for slave replication connections. + # TODO: Should we set a password on this since it allows remote connections? + CREATE USER 'vt_repl'@'%'; + GRANT REPLICATION SLAVE ON *.* TO 'vt_repl'@'%'; + + # User for Vitess filtered replication (binlog player). + CREATE USER 'vt_filtered'@'localhost'; + GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, FILE, + REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, + LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, + SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER + ON *.* TO 'vt_filtered'@'localhost'; + + # User for Orchestrator (https://github.com/openark/orchestrator). + # TODO: Reenable when the password is randomly generated. + #CREATE USER 'orc_client_user'@'%' IDENTIFIED BY 'orc_client_user_password'; + #GRANT SUPER, PROCESS, REPLICATION SLAVE, RELOAD + # ON *.* TO 'orc_client_user'@'%'; + #GRANT SELECT + # ON _vt.* TO 'orc_client_user'@'%'; + + FLUSH PRIVILEGES; + + RESET SLAVE ALL; + RESET MASTER; + + # We need to set super_read_only back to what it was before + SET GLOBAL super_read_only=IFNULL(@original_super_read_only, 'ON'); \ No newline at end of file diff --git a/test/endtoend/operator/operator-latest.yaml b/test/endtoend/operator/operator-latest.yaml index b687b7d7..b2e6122f 100644 --- a/test/endtoend/operator/operator-latest.yaml +++ b/test/endtoend/operator/operator-latest.yaml @@ -1,4 +1,3 @@ ---- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -382,6 +381,177 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + creationTimestamp: null + name: vitessbackupschedules.planetscale.com +spec: + group: planetscale.com + names: + kind: VitessBackupSchedule + listKind: VitessBackupScheduleList + plural: vitessbackupschedules + singular: vitessbackupschedule + scope: Namespaced + versions: + - name: v2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + x-kubernetes-preserve-unknown-fields: true + allowedMissedRun: + minimum: 0 + type: integer + annotations: + additionalProperties: + type: string + type: object + cluster: + type: string + concurrencyPolicy: + enum: + - Allow + - Forbid + example: Forbid + type: string + failedJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + image: + type: string + imagePullPolicy: + type: string + jobTimeoutMinute: + default: 10 + format: int32 + minimum: 0 + type: integer + name: + example: every-day + minLength: 1 + pattern: ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + schedule: + example: 0 0 * * * + minLength: 0 + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + type: integer + strategies: + items: + properties: + extraFlags: + additionalProperties: + type: string + type: object + keyspace: + example: commerce + type: string + name: + enum: + - BackupShard + type: string + shard: + example: '-' + type: string + required: + - keyspace + - name + - shard + type: object + minItems: 1 + type: array + successfulJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + suspend: + type: boolean + required: + - cluster + - name + - resources + - schedule + - strategies + type: object + status: + properties: + active: + items: + properties: + apiVersion: + type: string + fieldPath: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + resourceVersion: + type: string + uid: + type: string + type: object + x-kubernetes-map-type: atomic + type: array + lastScheduledTime: + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.11.3 @@ -1470,6 +1640,114 @@ spec: type: object minItems: 1 type: array + schedules: + items: + properties: + affinity: + x-kubernetes-preserve-unknown-fields: true + allowedMissedRun: + minimum: 0 + type: integer + annotations: + additionalProperties: + type: string + type: object + concurrencyPolicy: + enum: + - Allow + - Forbid + example: Forbid + type: string + failedJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + jobTimeoutMinute: + default: 10 + format: int32 + minimum: 0 + type: integer + name: + example: every-day + minLength: 1 + pattern: ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + schedule: + example: 0 0 * * * + minLength: 0 + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + type: integer + strategies: + items: + properties: + extraFlags: + additionalProperties: + type: string + type: object + keyspace: + example: commerce + type: string + name: + enum: + - BackupShard + type: string + shard: + example: '-' + type: string + required: + - keyspace + - name + - shard + type: object + minItems: 1 + type: array + successfulJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + suspend: + type: boolean + required: + - name + - resources + - schedule + - strategies + type: object + type: array subcontroller: properties: serviceAccountName: @@ -2490,6 +2768,16 @@ spec: type: string durabilityPolicy: type: string + images: + properties: + mysqld: + properties: + mysql56Compatible: + type: string + mysql80Compatible: + type: string + type: object + type: object name: maxLength: 63 minLength: 1 @@ -6518,6 +6806,15 @@ rules: - vitessbackupstorages - vitessbackupstorages/status - vitessbackupstorages/finalizers + - vitessbackupschedules + - vitessbackupschedules/status + - vitessbackupschedules/finalizers + verbs: + - '*' + - apiGroups: + - batch + resources: + - jobs verbs: - '*' --- @@ -6533,6 +6830,22 @@ subjects: - kind: ServiceAccount name: vitess-operator --- +apiVersion: scheduling.k8s.io/v1 +description: Vitess components (vttablet, vtgate, vtctld, etcd) +globalDefault: false +kind: PriorityClass +metadata: + name: vitess +value: 1000 +--- +apiVersion: scheduling.k8s.io/v1 +description: The vitess-operator control plane. +globalDefault: false +kind: PriorityClass +metadata: + name: vitess-operator-control-plane +value: 5000 +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -6583,19 +6896,3 @@ spec: memory: 128Mi priorityClassName: vitess-operator-control-plane serviceAccountName: vitess-operator ---- -apiVersion: scheduling.k8s.io/v1 -description: The vitess-operator control plane. -globalDefault: false -kind: PriorityClass -metadata: - name: vitess-operator-control-plane -value: 5000 ---- -apiVersion: scheduling.k8s.io/v1 -description: Vitess components (vttablet, vtgate, vtctld, etcd) -globalDefault: false -kind: PriorityClass -metadata: - name: vitess -value: 1000 diff --git a/test/endtoend/operator/operator.yaml b/test/endtoend/operator/operator.yaml index ea437f21..417caeed 100644 --- a/test/endtoend/operator/operator.yaml +++ b/test/endtoend/operator/operator.yaml @@ -1,4 +1,3 @@ ---- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -382,6 +381,177 @@ spec: --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + creationTimestamp: null + name: vitessbackupschedules.planetscale.com +spec: + group: planetscale.com + names: + kind: VitessBackupSchedule + listKind: VitessBackupScheduleList + plural: vitessbackupschedules + singular: vitessbackupschedule + scope: Namespaced + versions: + - name: v2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + affinity: + x-kubernetes-preserve-unknown-fields: true + allowedMissedRun: + minimum: 0 + type: integer + annotations: + additionalProperties: + type: string + type: object + cluster: + type: string + concurrencyPolicy: + enum: + - Allow + - Forbid + example: Forbid + type: string + failedJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + image: + type: string + imagePullPolicy: + type: string + jobTimeoutMinute: + default: 10 + format: int32 + minimum: 0 + type: integer + name: + example: every-day + minLength: 1 + pattern: ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + schedule: + example: 0 0 * * * + minLength: 0 + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + type: integer + strategies: + items: + properties: + extraFlags: + additionalProperties: + type: string + type: object + keyspace: + example: commerce + type: string + name: + enum: + - BackupShard + type: string + shard: + example: '-' + type: string + required: + - keyspace + - name + - shard + type: object + minItems: 1 + type: array + successfulJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + suspend: + type: boolean + required: + - cluster + - name + - resources + - schedule + - strategies + type: object + status: + properties: + active: + items: + properties: + apiVersion: + type: string + fieldPath: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + resourceVersion: + type: string + uid: + type: string + type: object + x-kubernetes-map-type: atomic + type: array + lastScheduledTime: + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.11.3 @@ -1470,6 +1640,114 @@ spec: type: object minItems: 1 type: array + schedules: + items: + properties: + affinity: + x-kubernetes-preserve-unknown-fields: true + allowedMissedRun: + minimum: 0 + type: integer + annotations: + additionalProperties: + type: string + type: object + concurrencyPolicy: + enum: + - Allow + - Forbid + example: Forbid + type: string + failedJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + jobTimeoutMinute: + default: 10 + format: int32 + minimum: 0 + type: integer + name: + example: every-day + minLength: 1 + pattern: ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + schedule: + example: 0 0 * * * + minLength: 0 + type: string + startingDeadlineSeconds: + format: int64 + minimum: 0 + type: integer + strategies: + items: + properties: + extraFlags: + additionalProperties: + type: string + type: object + keyspace: + example: commerce + type: string + name: + enum: + - BackupShard + type: string + shard: + example: '-' + type: string + required: + - keyspace + - name + - shard + type: object + minItems: 1 + type: array + successfulJobsHistoryLimit: + format: int32 + minimum: 0 + type: integer + suspend: + type: boolean + required: + - name + - resources + - schedule + - strategies + type: object + type: array subcontroller: properties: serviceAccountName: @@ -2490,6 +2768,16 @@ spec: type: string durabilityPolicy: type: string + images: + properties: + mysqld: + properties: + mysql56Compatible: + type: string + mysql80Compatible: + type: string + type: object + type: object name: maxLength: 63 minLength: 1 @@ -6518,6 +6806,15 @@ rules: - vitessbackupstorages - vitessbackupstorages/status - vitessbackupstorages/finalizers + - vitessbackupschedules + - vitessbackupschedules/status + - vitessbackupschedules/finalizers + verbs: + - '*' + - apiGroups: + - batch + resources: + - jobs verbs: - '*' --- @@ -6533,6 +6830,22 @@ subjects: - kind: ServiceAccount name: vitess-operator --- +apiVersion: scheduling.k8s.io/v1 +description: Vitess components (vttablet, vtgate, vtctld, etcd) +globalDefault: false +kind: PriorityClass +metadata: + name: vitess +value: 1000 +--- +apiVersion: scheduling.k8s.io/v1 +description: The vitess-operator control plane. +globalDefault: false +kind: PriorityClass +metadata: + name: vitess-operator-control-plane +value: 5000 +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -6572,7 +6885,7 @@ spec: fieldPath: metadata.name - name: OPERATOR_NAME value: vitess-operator - image: planetscale/vitess-operator:v2.12.0 + image: planetscale/vitess-operator:v2.13.0 name: vitess-operator resources: limits: @@ -6582,19 +6895,3 @@ spec: memory: 128Mi priorityClassName: vitess-operator-control-plane serviceAccountName: vitess-operator ---- -apiVersion: scheduling.k8s.io/v1 -description: The vitess-operator control plane. -globalDefault: false -kind: PriorityClass -metadata: - name: vitess-operator-control-plane -value: 5000 ---- -apiVersion: scheduling.k8s.io/v1 -description: Vitess components (vttablet, vtgate, vtctld, etcd) -globalDefault: false -kind: PriorityClass -metadata: - name: vitess -value: 1000 diff --git a/test/endtoend/upgrade_test.sh b/test/endtoend/upgrade_test.sh index 22d6e1cc..57a1ecc5 100755 --- a/test/endtoend/upgrade_test.sh +++ b/test/endtoend/upgrade_test.sh @@ -236,7 +236,7 @@ EOF echo "Building the docker image" docker build -f build/Dockerfile.release -t vitess-operator-pr:latest . echo "Creating Kind cluster" -kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --image kindest/node:v1.28.0 +kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --image ${KIND_VERSION} echo "Loading docker image into Kind cluster" kind load docker-image vitess-operator-pr:latest --name kind-${BUILDKITE_BUILD_ID} @@ -245,12 +245,12 @@ killall kubectl setupKubectlAccessForCI get_started "operator.yaml" "101_initial_cluster.yaml" -verifyVtGateVersion "19.0.0" +verifyVtGateVersion "20.0.0" checkSemiSyncSetup # Initially too durability policy should be specified verifyDurabilityPolicy "commerce" "semi_sync" upgradeToLatest -verifyVtGateVersion "20.0.0" +verifyVtGateVersion "21.0.0" checkSemiSyncSetup # After upgrading, we verify that the durability policy is still semi_sync verifyDurabilityPolicy "commerce" "semi_sync" diff --git a/test/endtoend/utils.sh b/test/endtoend/utils.sh index 88710b58..9d04d481 100644 --- a/test/endtoend/utils.sh +++ b/test/endtoend/utils.sh @@ -20,7 +20,7 @@ function checkSemiSyncWithRetry() { vttablet=$1 for i in {1..600} ; do kubectl exec "$vttablet" -c mysqld -- mysql -S "/vt/socket/mysql.sock" -u root -e "show variables like 'rpl_semi_sync_%_enabled'" | grep "ON" - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then return fi sleep 1 @@ -44,7 +44,7 @@ function runSQLWithRetry() { query=$1 for i in {1..600} ; do mysql -e "$query" - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then return fi echo "failed to run query $query, retrying (attempt #$i) ..." @@ -168,7 +168,7 @@ function verifyListBackupsOutput() { for i in {1..600} ; do out=$(vtctldclient LegacyVtctlCommand -- ListBackups "$keyspaceShard" | wc -l) echo "$out" | grep "$backupCount" > /dev/null 2>&1 - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then echo "ListBackupsOutputCorrect" return 0 fi @@ -193,7 +193,7 @@ function checkPodStatusWithTimeout() { nb=$2 # Number of pods to match defaults to one - if [ -z "$nb" ]; then + if [[ -z "$nb" ]]; then nb=1 fi @@ -202,7 +202,7 @@ function checkPodStatusWithTimeout() { for i in {1..1200} ; do out=$(kubectl get pods) echo "$out" | grep -E "$regex" | wc -l | grep "$nb" > /dev/null 2>&1 - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then echo "$regex found" return fi @@ -210,7 +210,7 @@ function checkPodStatusWithTimeout() { done echo -e "ERROR: checkPodStatusWithTimeout timeout to find pod matching:\ngot:\n$out\nfor regex: $regex" echo "$regex" | grep "vttablet" > /dev/null 2>&1 - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then printMysqlErrorFiles fi exit 1 @@ -230,7 +230,7 @@ function ensurePodResourcesSet() { numContainers=$(echo "$out" | grep -E "$regex" | awk '{print $2}' | awk -F ',' '{print NF}') numContainersWithResources=$(echo "$out" | grep -E "$regex" | awk '{print $3}' | awk -F ',' '{print NF}') - if [ $numContainers != $numContainersWithResources ]; then + if [[ $numContainers != $numContainersWithResources ]]; then echo "one or more containers in pods with $regex do not have $resource set" exit 1 fi @@ -240,7 +240,7 @@ function ensurePodResourcesSet() { function insertWithRetry() { for i in {1..600} ; do mysql --table < ../common/delete_commerce_data.sql && mysql --table < ../common/insert_commerce_data.sql - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then return fi echo "failed to insert commerce data, retrying (attempt #$i) ..." @@ -253,7 +253,7 @@ function verifyVtGateVersion() { podName=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" | grep "vtgate") data=$(kubectl logs "$podName" | head) echo "$data" | grep "$version" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The vtgate version is incorrect, expected: $version, got:\n$data" exit 1 fi @@ -267,7 +267,7 @@ function verifyDurabilityPolicy() { durabilityPolicy=$2 data=$(vtctldclient LegacyVtctlCommand -- GetKeyspace "$keyspace") echo "$data" | grep "\"durability_policy\": \"$durabilityPolicy\"" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The durability policy in $keyspace is incorrect, got:\n$data" exit 1 fi @@ -298,10 +298,10 @@ function applySchemaWithRetry() { drop_sql=$3 for i in {1..600} ; do vtctldclient ApplySchema --sql-file="$schema" $ks - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then return fi - if [ -n "$drop_sql" ]; then + if [[ -n "$drop_sql" ]]; then mysql --table < $drop_sql fi echo "failed to apply schema $schema, retrying (attempt #$i) ..." @@ -315,14 +315,14 @@ function assertSelect() { expected=$3 data=$(mysql --table < $sql) echo "$data" | grep "$expected" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The data in $shard's tables is incorrect, got:\n$data" exit 1 fi } function setupKubectlAccessForCI() { - if [ "$BUILDKITE_BUILD_ID" != "0" ]; then + if [[ "$BUILDKITE_BUILD_ID" != "0" ]]; then # The script is being run from buildkite, so we need to do stuff # https://github.com/kubernetes-sigs/kind/issues/1846#issuecomment-691565834 # Since kind is running in a sibling container, communicating with it through kubectl is not trivial. @@ -362,7 +362,7 @@ function get_started() { applySchemaWithRetry create_commerce_schema.sql commerce drop_all_commerce_tables.sql vtctldclient ApplyVSchema --vschema-file="vschema_commerce_initial.json" commerce - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "ApplySchema failed for initial commerce" printMysqlErrorFiles exit 1 @@ -370,14 +370,14 @@ function get_started() { sleep 5 echo "show databases;" | mysql | grep "commerce" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "Could not find commerce database" printMysqlErrorFiles exit 1 fi echo "show tables;" | mysql commerce | grep -E 'corder|customer|product' | wc -l | grep 3 > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "Could not find commerce's tables" printMysqlErrorFiles exit 1 diff --git a/test/endtoend/vtorc_vtadmin_test.sh b/test/endtoend/vtorc_vtadmin_test.sh index de515671..c5487bbc 100755 --- a/test/endtoend/vtorc_vtadmin_test.sh +++ b/test/endtoend/vtorc_vtadmin_test.sh @@ -31,7 +31,7 @@ function get_started_vtorc_vtadmin() { applySchemaWithRetry create_commerce_schema.sql commerce drop_all_commerce_tables.sql vtctldclient ApplyVSchema --vschema-file="vschema_commerce_initial.json" commerce - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "ApplySchema failed for initial commerce" printMysqlErrorFiles exit 1 @@ -39,14 +39,14 @@ function get_started_vtorc_vtadmin() { sleep 5 echo "show databases;" | mysql | grep "commerce" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "Could not find commerce database" printMysqlErrorFiles exit 1 fi echo "show tables;" | mysql commerce | grep -E 'corder|customer|product' | wc -l | grep 3 > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo "Could not find commerce's tables" printMysqlErrorFiles exit 1 @@ -159,9 +159,9 @@ function chromiumHeadlessRequest() { for i in {1..600} ; do chromiumBinary=$(getChromiumBinaryName) res=$($chromiumBinary --headless --no-sandbox --disable-gpu --enable-logging --dump-dom --virtual-time-budget=900000000 "$url") - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then echo "$res" | grep "$dataToAssert" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The data in $url is incorrect, got:\n$res, retrying" sleep 1 continue @@ -175,12 +175,12 @@ function chromiumHeadlessRequest() { function getChromiumBinaryName() { which chromium-browser > /dev/null - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then echo "chromium-browser" return fi which chromium > /dev/null - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then echo "chromium" return fi @@ -191,9 +191,9 @@ function curlGetRequestWithRetry() { dataToAssert=$2 for i in {1..600} ; do res=$(curl "$url") - if [ $? -eq 0 ]; then + if [[ $? -eq 0 ]]; then echo "$res" | grep "$dataToAssert" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The data in $url is incorrect, got:\n$res" exit 1 fi @@ -208,12 +208,12 @@ function curlDeleteRequest() { url=$1 dataToAssert=$2 res=$(curl -X DELETE "$url") - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The DELETE request to $url failed\n" exit 1 fi echo "$res" | grep "$dataToAssert" > /dev/null 2>&1 - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The data in delete request to $url is incorrect, got:\n$res" exit 1 fi @@ -223,7 +223,7 @@ function curlPostRequest() { url=$1 data=$2 curl -X POST -d "$data" "$url" - if [ $? -ne 0 ]; then + if [[ $? -ne 0 ]]; then echo -e "The POST request to $url with data $data failed\n" exit 1 fi @@ -233,7 +233,7 @@ function curlPostRequest() { echo "Building the docker image" docker build -f build/Dockerfile.release -t vitess-operator-pr:latest . echo "Creating Kind cluster" -kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --image kindest/node:v1.28.0 +kind create cluster --wait 30s --name kind-${BUILDKITE_BUILD_ID} --image ${KIND_VERSION} echo "Loading docker image into Kind cluster" kind load docker-image vitess-operator-pr:latest --name kind-${BUILDKITE_BUILD_ID} @@ -242,7 +242,7 @@ killall kubectl setupKubectlAccessForCI get_started_vtorc_vtadmin -verifyVtGateVersion "20.0.0" +verifyVtGateVersion "21.0.0" checkSemiSyncSetup # Check Vtadmin is setup diff --git a/tools/get-e2e-test-deps.sh b/tools/get-e2e-test-deps.sh index 330849bd..dfc11223 100755 --- a/tools/get-e2e-test-deps.sh +++ b/tools/get-e2e-test-deps.sh @@ -40,8 +40,8 @@ fi if ! command -v vtctldclient &> /dev/null then echo "Downloading vtctldclient..." - version=19.0.3 - file=vitess-${version}-cb5464e.tar.gz + version=20.0.0-rc2 + file=vitess-${version}-4af99b5.tar.gz wget https://github.com/vitessio/vitess/releases/download/v${version}/${file} tar -xzf ${file} cd ${file/.tar.gz/} diff --git a/tools/test.env b/tools/test.env index c427317c..6532efd6 100755 --- a/tools/test.env +++ b/tools/test.env @@ -3,3 +3,5 @@ # We add the tools/_bin directory to PATH variable # since this is where we install the binaries that are needed export PATH="$PATH:$PWD/tools/_bin" + +export KIND_VERSION=kindest/node:v1.28.0 \ No newline at end of file diff --git a/version/version.go b/version/version.go index d52979b0..ab4a5349 100644 --- a/version/version.go +++ b/version/version.go @@ -20,5 +20,5 @@ package version // THIS FILE IS AUTO-GENERATED DURING NEW RELEASES BY THE VITESS-RELEASER var ( - Version = "2.12.0" + Version = "2.13.0" )