From b9e36ff6e5fb78ba2fd5d4505f5c4978bc716fc6 Mon Sep 17 00:00:00 2001 From: brokenpip3 Date: Sun, 21 Dec 2025 14:35:41 +0100 Subject: [PATCH] update to go1.24 --- .golangci.yml | 54 +-- Makefile | 10 +- api/v1alpha2/jenkins_webhook.go | 39 ++- api/v1alpha2/jenkins_webhook_test.go | 13 +- config.base.env | 6 +- config/crd/bases/jenkins.io_jenkins.yaml | 320 ++++++++++-------- config/rbac/role.yaml | 123 +++---- flake.nix | 6 +- go.mod | 82 +++-- go.sum | 191 ++++++----- internal/controller/handler.go | 23 +- internal/controller/jenkins_controller.go | 17 +- .../backuprestore/backuprestore.go | 30 +- pkg/configuration/base/configmap.go | 6 +- pkg/configuration/base/deployment.go | 12 +- pkg/configuration/base/label.go | 18 +- pkg/configuration/base/plugin.go | 4 +- pkg/configuration/base/pod.go | 76 ++--- pkg/configuration/base/rbac.go | 6 +- pkg/configuration/base/reconciler.go | 58 ++-- .../resources/base_configuration_configmap.go | 4 +- .../resources/init_configuration_configmap.go | 2 +- pkg/configuration/base/resources/meta.go | 4 +- pkg/configuration/base/resources/pod_test.go | 5 +- .../base/resources/scripts_configmap.go | 2 +- pkg/configuration/base/resources/service.go | 12 +- pkg/configuration/base/route.go | 4 +- pkg/configuration/base/serviceaccount.go | 2 +- pkg/configuration/base/validate.go | 32 +- pkg/configuration/base/validate_test.go | 17 +- pkg/configuration/configuration.go | 6 +- pkg/configuration/user/reconcile.go | 15 +- pkg/configuration/user/seedjobs/seedjobs.go | 4 +- pkg/configuration/user/seedjobs/validate.go | 26 +- pkg/groovy/groovy.go | 6 +- test/e2e/configuration_test.go | 2 +- test/e2e/jenkins_test.go | 4 +- test/e2e/suite_test.go | 24 +- 38 files changed, 669 insertions(+), 596 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f5bb1ed7..b40be3df 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,41 +1,47 @@ +version: "2" run: - deadline: 5m allow-parallel-runners: true - skip-files: - - api/v1alpha2/zz_generated.deepcopy.go -issues: - exclude-use-default: false - exclude-rules: - - path: "internal/*" - linters: - - dupl - - path: (.+)_test.go - linters: - - dupl +output: + sort-order: + - file + - severity + - linter linters: - disable-all: true + default: none enable: - dupl - errcheck - - exportloopref - goconst - gocyclo - - gofmt - - goimports - - gosimple - govet - ineffassign - loggercheck - misspell - nakedret - staticcheck - - typecheck - unconvert - unparam - unused -output: - sort-results: true - sort-order: - - file - - severity - - linter + exclusions: + generated: lax + rules: + - linters: + - dupl + path: internal/* + - linters: + - dupl + path: (.+)_test.go + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/Makefile b/Makefile index 571fe644..7ea439e6 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,7 @@ HAS_GOLINT := $(shell which $(PROJECT_DIR)/bin/golangci-lint) lint: ## Verifies `golint` passes @echo "+ $@" ifndef HAS_GOLINT - GOBIN=$(PROJECT_DIR)/bin go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.0 + GOBIN=$(PROJECT_DIR)/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.5.0 endif @bin/golangci-lint run @@ -162,7 +162,7 @@ staticcheck: ## Verifies `staticcheck` passes @echo "+ $@" ifndef HAS_STATICCHECK $(eval TMP_DIR := $(shell mktemp -d)) - wget -O $(TMP_DIR)/staticcheck_$(PLATFORM)_amd64.tar.gz https://github.com/dominikh/go-tools/releases/download/2023.1.7/staticcheck_$(PLATFORM)_amd64.tar.gz + wget -O $(TMP_DIR)/staticcheck_$(PLATFORM)_amd64.tar.gz https://github.com/dominikh/go-tools/releases/download/2025.1.1/staticcheck_$(PLATFORM)_amd64.tar.gz tar zxvf $(TMP_DIR)/staticcheck_$(PLATFORM)_amd64.tar.gz -C $(TMP_DIR) mkdir -p $(PROJECT_DIR)/bin mv $(TMP_DIR)/staticcheck/staticcheck $(PROJECT_DIR)/bin @@ -174,7 +174,7 @@ endif cover: ## Runs go test with coverage @echo "" > coverage.txt @for d in $(PACKAGES); do \ - ENVTEST_K8S_VERSION = 1.26 + ENVTEST_K8S_VERSION = 1.33 KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" IMG_RUNNING_TESTS=1 go test -race -coverprofile=profile.out -covermode=atomic "$$d"; \ if [ -f profile.out ]; then \ cat profile.out >> coverage.txt; \ @@ -578,8 +578,8 @@ CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest ## Tool Versions -KUSTOMIZE_VERSION ?= v5.3.0 -CONTROLLER_TOOLS_VERSION ?= v0.14.0 +KUSTOMIZE_VERSION ?= v5.4.2 +CONTROLLER_TOOLS_VERSION ?= v0.18.0 KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize diff --git a/api/v1alpha2/jenkins_webhook.go b/api/v1alpha2/jenkins_webhook.go index 69d07b07..df64532a 100644 --- a/api/v1alpha2/jenkins_webhook.go +++ b/api/v1alpha2/jenkins_webhook.go @@ -18,6 +18,7 @@ package v1alpha2 import ( "compress/gzip" + "context" "encoding/json" "errors" "io" @@ -37,10 +38,10 @@ import ( ) var ( - jenkinslog = logf.Log.WithName("jenkins-resource") // log is for logging in this package. - SecValidator = *NewSecurityValidator() - _ webhook.Validator = &Jenkins{} - initialSecurityWarningsDownloadSucceded = false + jenkinslog = logf.Log.WithName("jenkins-resource") // log is for logging in this package. + SecValidator = *NewSecurityValidator() + _ webhook.CustomValidator = &Jenkins{} + initialSecurityWarningsDownloadSucceded = false ) const ( @@ -60,28 +61,36 @@ func (in *Jenkins) SetupWebhookWithManager(mgr ctrl.Manager) error { // TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation. // +kubebuilder:webhook:path=/validate-jenkins-io-jenkins-io-v1alpha2-jenkins,mutating=false,failurePolicy=fail,sideEffects=None,groups=jenkins.io.jenkins.io,resources=jenkins,verbs=create;update,versions=v1alpha2,name=vjenkins.kb.io,admissionReviewVersions={v1} -// ValidateCreate implements webhook.Validator so a webhook will be registered for the type -func (in *Jenkins) ValidateCreate() (admission.Warnings, error) { - if in.Spec.ValidateSecurityWarnings { - jenkinslog.Info("validate create", "name", in.Name) - err := Validate(*in) +// ValidateCreate implements webhook.CustomValidator so a webhook will be registered for the type +func (in *Jenkins) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { + jenkins, ok := obj.(*Jenkins) + if !ok { + return nil, errors.New("expected a Jenkins object") + } + if jenkins.Spec.ValidateSecurityWarnings { + jenkinslog.Info("validate create", "name", jenkins.Name) + err := Validate(*jenkins) return nil, err } return nil, nil } -// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type -func (in *Jenkins) ValidateUpdate(old runtime.Object) (admission.Warnings, error) { - if in.Spec.ValidateSecurityWarnings { - jenkinslog.Info("validate update", "name", in.Name) - return nil, Validate(*in) +// ValidateUpdate implements webhook.CustomValidator so a webhook will be registered for the type +func (in *Jenkins) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { + jenkins, ok := newObj.(*Jenkins) + if !ok { + return nil, errors.New("expected a Jenkins object") + } + if jenkins.Spec.ValidateSecurityWarnings { + jenkinslog.Info("validate update", "name", jenkins.Name) + return nil, Validate(*jenkins) } return nil, nil } -func (in *Jenkins) ValidateDelete() (admission.Warnings, error) { +func (in *Jenkins) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { return nil, nil } diff --git a/api/v1alpha2/jenkins_webhook_test.go b/api/v1alpha2/jenkins_webhook_test.go index 1cf7a0c3..c3284811 100644 --- a/api/v1alpha2/jenkins_webhook_test.go +++ b/api/v1alpha2/jenkins_webhook_test.go @@ -1,6 +1,7 @@ package v1alpha2 import ( + "context" "errors" "testing" @@ -79,7 +80,7 @@ func TestValidate(t *testing.T) { t.Run("Validating when plugins data file is not fetched", func(t *testing.T) { userplugins := []Plugin{{Name: "script-security", Version: "1.77"}, {Name: "git-client", Version: "3.9"}, {Name: "git", Version: "4.8.1"}, {Name: "plain-credentials", Version: "1.7"}} jenkinscr := *createJenkinsCR(userplugins, true) - _, got := jenkinscr.ValidateCreate() + _, got := jenkinscr.ValidateCreate(context.TODO(), &jenkinscr) assert.Equal(t, got, errors.New("plugins data has not been fetched")) }) @@ -95,7 +96,7 @@ func TestValidate(t *testing.T) { {Name: "plain-credentials"}}} userplugins := []Plugin{{Name: "script-security", Version: "1.77"}, {Name: "git-client", Version: "3.9"}, {Name: "git", Version: "4.8.1"}, {Name: "plain-credentials", Version: "1.7"}} jenkinscr := *createJenkinsCR(userplugins, true) - _, got := jenkinscr.ValidateCreate() + _, got := jenkinscr.ValidateCreate(context.TODO(), &jenkinscr) assert.Nil(t, got) }) @@ -113,7 +114,7 @@ func TestValidate(t *testing.T) { }} userplugins := []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}} jenkinscr := *createJenkinsCR(userplugins, true) - _, got := jenkinscr.ValidateCreate() + _, got := jenkinscr.ValidateCreate(context.TODO(), &jenkinscr) assert.Equal(t, got, errors.New("security vulnerabilities detected in the following user-defined plugins: \nworkflow-cps:2.59\ngoogle-login:1.2\nmailer:1.1")) }) @@ -136,19 +137,19 @@ func TestValidate(t *testing.T) { userplugins = []Plugin{{Name: "handy-uri-templates-2-api", Version: "2.1.8-1.0"}, {Name: "resource-disposer", Version: "0.8"}, {Name: "jjwt-api", Version: "0.11.2-9.c8b45b8bb173"}, {Name: "blueocean-github-pipeline", Version: "1.2.0-beta-3"}, {Name: "ghprb", Version: "1.39"}} newjenkinscr := *createJenkinsCR(userplugins, true) - _, got := newjenkinscr.ValidateUpdate(&oldjenkinscr) + _, got := newjenkinscr.ValidateUpdate(context.TODO(), &oldjenkinscr, &newjenkinscr) assert.Equal(t, got, errors.New("security vulnerabilities detected in the following user-defined plugins: \nhandy-uri-templates-2-api:2.1.8-1.0\nresource-disposer:0.8\nblueocean-github-pipeline:1.2.0-beta-3\nghprb:1.39")) }) t.Run("Validation is turned off", func(t *testing.T) { userplugins := []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}} jenkinscr := *createJenkinsCR(userplugins, false) - _, got := jenkinscr.ValidateCreate() + _, got := jenkinscr.ValidateCreate(context.TODO(), &jenkinscr) assert.Nil(t, got) userplugins = []Plugin{{Name: "google-login", Version: "1.2"}, {Name: "mailer", Version: "1.1"}, {Name: "git", Version: "4.8.1"}, {Name: "command-launcher", Version: "1.6"}, {Name: "workflow-cps", Version: "2.59"}} newjenkinscr := *createJenkinsCR(userplugins, false) - _, got = newjenkinscr.ValidateUpdate(&jenkinscr) + _, got = newjenkinscr.ValidateUpdate(context.TODO(), &jenkinscr, &newjenkinscr) assert.Nil(t, got) }) } diff --git a/config.base.env b/config.base.env index f36ffe0d..5b1ee857 100644 --- a/config.base.env +++ b/config.base.env @@ -3,14 +3,14 @@ API_VERSION_NEXT="v1alpha3" API_VERSION="v1alpha2" CLUSTER_DOMAIN="cluster.local" GEN_CRD_API="gen-crd-api-reference-docs" -GO_VERSION="1.22" -HELM_VERSION="3.12.3" +GO_VERSION="1.24" +HELM_VERSION="3.19.0" IMAGE_PULL_MODE="local" KIND_CLUSTER_NAME="jenkins" LATEST_LTS_VERSION="2.528.3" NAME="kubernetes-operator" NAMESPACE="default" -OPERATOR_SDK_VERSION="1.35.0" +OPERATOR_SDK_VERSION="1.41.1" PKG="github.com/jenkinsci/kubernetes-operator" QUAY_ORGANIZATION="jenkins-kubernetes-operator" QUAY_REGISTRY="operator" diff --git a/config/crd/bases/jenkins.io_jenkins.yaml b/config/crd/bases/jenkins.io_jenkins.yaml index db9a117c..927236c3 100644 --- a/config/crd/bases/jenkins.io_jenkins.yaml +++ b/config/crd/bases/jenkins.io_jenkins.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.18.0 name: jenkins.jenkins.io spec: group: jenkins.io @@ -301,9 +301,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap @@ -369,9 +367,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret or @@ -395,7 +391,7 @@ spec: Values defined by an Env with a duplicate key will take precedence. items: description: EnvFromSource represents the source of a - set of ConfigMaps + set of ConfigMaps or Secrets properties: configMapRef: description: The ConfigMap to select from @@ -407,9 +403,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the ConfigMap must @@ -418,8 +412,8 @@ spec: type: object x-kubernetes-map-type: atomic prefix: - description: An optional identifier to prepend to - each key in the ConfigMap. Must be a C_IDENTIFIER. + description: Optional text to prepend to the name + of each environment variable. Must be a C_IDENTIFIER. type: string secretRef: description: The Secret to select from @@ -431,9 +425,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: Specify whether the Secret must be @@ -466,7 +458,8 @@ spec: More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks properties: exec: - description: Exec specifies the action to take. + description: Exec specifies a command to execute + in the container. properties: command: description: |- @@ -481,7 +474,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies the http request + description: HTTPGet specifies an HTTP GET request to perform. properties: host: @@ -531,8 +524,8 @@ spec: - port type: object sleep: - description: Sleep represents the duration that - the container should sleep before being terminated. + description: Sleep represents a duration that the + container should sleep. properties: seconds: description: Seconds is the number of seconds @@ -545,8 +538,8 @@ spec: tcpSocket: description: |- Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept - for the backward compatibility. There are no validation of this field and - lifecycle hooks will fail in runtime when tcp handler is specified. + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. properties: host: description: 'Optional: Host name to connect @@ -578,7 +571,8 @@ spec: More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks properties: exec: - description: Exec specifies the action to take. + description: Exec specifies a command to execute + in the container. properties: command: description: |- @@ -593,7 +587,7 @@ spec: x-kubernetes-list-type: atomic type: object httpGet: - description: HTTPGet specifies the http request + description: HTTPGet specifies an HTTP GET request to perform. properties: host: @@ -643,8 +637,8 @@ spec: - port type: object sleep: - description: Sleep represents the duration that - the container should sleep before being terminated. + description: Sleep represents a duration that the + container should sleep. properties: seconds: description: Seconds is the number of seconds @@ -657,8 +651,8 @@ spec: tcpSocket: description: |- Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept - for the backward compatibility. There are no validation of this field and - lifecycle hooks will fail in runtime when tcp handler is specified. + for backward compatibility. There is no validation of this field and + lifecycle hooks will fail at runtime when it is specified. properties: host: description: 'Optional: Host name to connect @@ -677,6 +671,12 @@ spec: - port type: object type: object + stopSignal: + description: |- + StopSignal defines which signal will be sent to a container when it is being stopped. + If not specified, the default is defined by the container runtime in use. + StopSignal can only be set for Pods with a non-empty .spec.os.name + type: string type: object livenessProbe: description: |- @@ -684,7 +684,8 @@ spec: Container will be restarted if the probe fails. properties: exec: - description: Exec specifies the action to take. + description: Exec specifies a command to execute in + the container. properties: command: description: |- @@ -705,8 +706,7 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies an action involving a GRPC - port. + description: GRPC specifies a GRPC HealthCheckRequest. properties: port: description: Port number of the gRPC service. Number @@ -714,18 +714,19 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: - port type: object httpGet: - description: HTTPGet specifies the http request to perform. + description: HTTPGet specifies an HTTP GET request to + perform. properties: host: description: |- @@ -792,8 +793,8 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. + description: TCPSocket specifies a connection to a TCP + port. properties: host: description: 'Optional: Host name to connect to, @@ -890,7 +891,8 @@ spec: Container will be removed from service endpoints if the probe fails. properties: exec: - description: Exec specifies the action to take. + description: Exec specifies a command to execute in + the container. properties: command: description: |- @@ -911,8 +913,7 @@ spec: format: int32 type: integer grpc: - description: GRPC specifies an action involving a GRPC - port. + description: GRPC specifies a GRPC HealthCheckRequest. properties: port: description: Port number of the gRPC service. Number @@ -920,18 +921,19 @@ spec: format: int32 type: integer service: + default: "" description: |- Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). - If this is not specified, the default behavior is defined by gRPC. type: string required: - port type: object httpGet: - description: HTTPGet specifies the http request to perform. + description: HTTPGet specifies an HTTP GET request to + perform. properties: host: description: |- @@ -998,8 +1000,8 @@ spec: format: int32 type: integer tcpSocket: - description: TCPSocket specifies an action involving - a TCP port. + description: TCPSocket specifies a connection to a TCP + port. properties: host: description: 'Optional: Host name to connect to, @@ -1049,11 +1051,9 @@ spec: Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. - This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. - This field is immutable. It can only be set for containers. items: description: ResourceClaim references one entry in @@ -1065,6 +1065,12 @@ spec: the Pod where this field is used. It makes that resource available inside a container. type: string + request: + description: |- + Request is the name chosen for a request in the referenced claim. + If empty, everything from the claim is made available, otherwise + only the result of this request. + type: string required: - name type: object @@ -1170,7 +1176,7 @@ spec: procMount: description: |- procMount denotes the type of proc mount to use for the containers. - The default is DefaultProcMount which uses the container runtime defaults for + The default value is Default which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. @@ -1252,7 +1258,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -1326,10 +1331,8 @@ spec: RecursiveReadOnly specifies whether read-only mounts should be handled recursively. - If ReadOnly is false, this field has no meaning and must be unspecified. - If ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this @@ -1337,11 +1340,9 @@ spec: supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason. - If this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None). - If this field is not specified, it is treated as an equivalent of Disabled. type: string subPath: @@ -1416,9 +1417,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -1507,12 +1506,10 @@ spec: Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: - 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- - If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows. format: int64 @@ -1556,6 +1553,32 @@ spec: Note that this field cannot be set when spec.os.name is windows. format: int64 type: integer + seLinuxChangePolicy: + description: |- + seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. + It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. + Valid values are "MountOption" and "Recursive". + + "Recursive" means relabeling of all files on all Pod volumes by the container runtime. + This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. + + "MountOption" mounts all eligible Pod volumes with `-o context` mount option. + This requires all Pods that share the same volume to use the same SELinux label. + It is not possible to share the same volume among privileged and unprivileged Pods. + Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes + whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their + CSIDriver instance. Other volumes are always re-labelled recursively. + "MountOption" value is allowed only when SELinuxMount feature gate is enabled. + + If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. + If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes + and "Recursive" for all other volumes. + + This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. + + All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. + Note that this field cannot be set when spec.os.name is windows. + type: string seLinuxOptions: description: |- The SELinux context to be applied to all containers. @@ -1599,7 +1622,6 @@ spec: type indicates which kind of seccomp profile will be applied. Valid options are: - Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied. @@ -1609,18 +1631,28 @@ spec: type: object supplementalGroups: description: |- - A list of groups applied to the first process run in each container, in addition - to the container's primary GID, the fsGroup (if specified), and group memberships - defined in the container image for the uid of the container process. If unspecified, - no additional groups are added to any container. Note that group memberships - defined in the container image for the uid of the container process are still effective, - even if they are not included in this list. + A list of groups applied to the first process run in each container, in + addition to the container's primary GID and fsGroup (if specified). If + the SupplementalGroupsPolicy feature is enabled, the + supplementalGroupsPolicy field determines whether these are in addition + to or instead of any group memberships defined in the container image. + If unspecified, no additional groups are added, though group memberships + defined in the container image may still be used, depending on the + supplementalGroupsPolicy field. Note that this field cannot be set when spec.os.name is windows. items: format: int64 type: integer type: array x-kubernetes-list-type: atomic + supplementalGroupsPolicy: + description: |- + Defines how supplemental groups of the first container processes are calculated. + Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + and the container runtime must implement support for this feature. + Note that this field cannot be set when spec.os.name is windows. + type: string sysctls: description: |- Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported @@ -1737,6 +1769,8 @@ spec: description: |- awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet's host machine and then exposed to the pod. + Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree + awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore properties: fsType: @@ -1745,7 +1779,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -1769,8 +1802,10 @@ spec: - volumeID type: object azureDisk: - description: azureDisk represents an Azure Data Disk mount - on the host and bind mount to the pod. + description: |- + azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type + are redirected to the disk.csi.azure.com CSI driver. properties: cachingMode: description: 'cachingMode is the Host Caching mode: @@ -1785,6 +1820,7 @@ spec: blob storage type: string fsType: + default: ext4 description: |- fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -1798,6 +1834,7 @@ spec: to shared' type: string readOnly: + default: false description: |- readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. @@ -1807,8 +1844,10 @@ spec: - diskURI type: object azureFile: - description: azureFile represents an Azure File Service - mount on the host and bind mount to the pod. + description: |- + azureFile represents an Azure File Service mount on the host and bind mount to the pod. + Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type + are redirected to the file.csi.azure.com CSI driver. properties: readOnly: description: |- @@ -1827,8 +1866,9 @@ spec: - shareName type: object cephfs: - description: cephFS represents a Ceph FS mount on the host - that shares a pod's lifetime + description: |- + cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. + Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported. properties: monitors: description: |- @@ -1865,9 +1905,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -1882,6 +1920,8 @@ spec: cinder: description: |- cinder represents a cinder volume attached and mounted on kubelets host machine. + Deprecated: Cinder is deprecated. All operations for the in-tree cinder type + are redirected to the cinder.csi.openstack.org CSI driver. More info: https://examples.k8s.io/mysql-cinder-pd/README.md properties: fsType: @@ -1909,9 +1949,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -1984,9 +2022,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the ConfigMap @@ -1997,7 +2033,7 @@ spec: csi: description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external - CSI drivers (Beta feature). + CSI drivers. properties: driver: description: |- @@ -2025,9 +2061,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -2165,7 +2199,6 @@ spec: The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. - Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity @@ -2176,17 +2209,14 @@ spec: information on the connection between this volume type and PersistentVolumeClaim). - Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. - Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. - A pod can use both types of ephemeral volumes and persistent volumes at the same time. properties: @@ -2200,7 +2230,6 @@ spec: entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). - An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until @@ -2210,11 +2239,9 @@ spec: this should not be necessary, but it may be useful when manually reconstructing a broken cluster. - This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. - Required, must not be nil. properties: metadata: @@ -2417,7 +2444,7 @@ spec: set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource exists. More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ - (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + (Beta) Using this field requires the VolumeAttributesClass feature gate to be enabled (off by default). type: string volumeMode: description: |- @@ -2443,7 +2470,6 @@ spec: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. - TODO: how do we prevent errors in the filesystem from compromising the machine type: string lun: description: 'lun is Optional: FC target lun number' @@ -2474,6 +2500,7 @@ spec: description: |- flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. + Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead. properties: driver: description: driver is the name of the driver to use @@ -2511,9 +2538,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -2521,9 +2546,9 @@ spec: - driver type: object flocker: - description: flocker represents a Flocker volume attached - to a kubelet's host machine. This depends on the Flocker - control service being running + description: |- + flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running. + Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported. properties: datasetName: description: |- @@ -2539,6 +2564,8 @@ spec: description: |- gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet's host machine and then exposed to the pod. + Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree + gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk properties: fsType: @@ -2547,7 +2574,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk - TODO: how do we prevent errors in the filesystem from compromising the machine type: string partition: description: |- @@ -2575,7 +2601,7 @@ spec: gitRepo: description: |- gitRepo represents a git repository at a particular revision. - DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod's container. properties: @@ -2599,6 +2625,7 @@ spec: glusterfs: description: |- glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. More info: https://examples.k8s.io/volumes/glusterfs/README.md properties: endpoints: @@ -2628,9 +2655,6 @@ spec: used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath - --- - TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not - mount host directories as read/write. properties: path: description: |- @@ -2647,6 +2671,41 @@ spec: required: - path type: object + image: + description: |- + image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + The volume is resolved at pod startup depending on which PullPolicy value is provided: + + - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + + The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + The volume will be mounted read-only (ro) and non-executable files (noexec). + Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. + The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + properties: + pullPolicy: + description: |- + Policy for pulling OCI objects. Possible values are: + Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + type: string + reference: + description: |- + Required: Image or artifact reference to be used. + Behaves in the same way as pod.spec.containers[*].image. + Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + type: object iscsi: description: |- iscsi represents an ISCSI Disk resource that is attached to a @@ -2667,7 +2726,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi - TODO: how do we prevent errors in the filesystem from compromising the machine type: string initiatorName: description: |- @@ -2679,6 +2737,7 @@ spec: description: iqn is the target iSCSI Qualified Name. type: string iscsiInterface: + default: default description: |- iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). @@ -2711,9 +2770,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -2778,9 +2835,9 @@ spec: - claimName type: object photonPersistentDisk: - description: photonPersistentDisk represents a PhotonController - persistent disk attached and mounted on kubelets host - machine + description: |- + photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. + Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported. properties: fsType: description: |- @@ -2796,8 +2853,11 @@ spec: - pdID type: object portworxVolume: - description: portworxVolume represents a portworx volume - attached and mounted on kubelets host machine + description: |- + portworxVolume represents a portworx volume attached and mounted on kubelets host machine. + Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type + are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate + is on. properties: fsType: description: |- @@ -2832,24 +2892,24 @@ spec: format: int32 type: integer sources: - description: sources is the list of volume projections + description: |- + sources is the list of volume projections. Each entry in this list + handles one source. items: - description: Projection that may be projected along - with other supported volume types + description: |- + Projection that may be projected along with other supported volume types. + Exactly one of these fields must be set. properties: clusterTrustBundle: description: |- ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field of ClusterTrustBundle objects in an auto-updating file. - Alpha, gated by the ClusterTrustBundleProjection feature gate. - ClusterTrustBundle objects can either be selected by name, or by the combination of signer name and a label selector. - Kubelet performs aggressive normalization of the PEM contents written into the pod filesystem. Esoteric PEM features such as inter-block comments and block headers are stripped. Certificates are deduplicated. @@ -2983,9 +3043,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional specify whether the @@ -3124,9 +3182,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string optional: description: optional field specify whether @@ -3168,8 +3224,9 @@ spec: x-kubernetes-list-type: atomic type: object quobyte: - description: quobyte represents a Quobyte mount on the host - that shares a pod's lifetime + description: |- + quobyte represents a Quobyte mount on the host that shares a pod's lifetime. + Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported. properties: group: description: |- @@ -3208,6 +3265,7 @@ spec: rbd: description: |- rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. More info: https://examples.k8s.io/volumes/rbd/README.md properties: fsType: @@ -3216,7 +3274,6 @@ spec: Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd - TODO: how do we prevent errors in the filesystem from compromising the machine type: string image: description: |- @@ -3224,6 +3281,7 @@ spec: More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it type: string keyring: + default: /etc/ceph/keyring description: |- keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. @@ -3238,6 +3296,7 @@ spec: type: array x-kubernetes-list-type: atomic pool: + default: rbd description: |- pool is the rados pool name. Default is rbd. @@ -3263,13 +3322,12 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic user: + default: admin description: |- user is the rados user name. Default is admin. @@ -3280,10 +3338,12 @@ spec: - monitors type: object scaleIO: - description: scaleIO represents a ScaleIO persistent volume - attached and mounted on Kubernetes nodes. + description: |- + scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported. properties: fsType: + default: xfs description: |- fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. @@ -3315,9 +3375,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -3326,6 +3384,7 @@ spec: with Gateway, default false type: boolean storageMode: + default: ThinProvisioned description: |- storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. @@ -3414,8 +3473,9 @@ spec: type: string type: object storageos: - description: storageOS represents a StorageOS volume attached - and mounted on Kubernetes nodes. + description: |- + storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported. properties: fsType: description: |- @@ -3440,9 +3500,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -3462,8 +3520,10 @@ spec: type: string type: object vsphereVolume: - description: vsphereVolume represents a vSphere volume attached - and mounted on kubelets host machine + description: |- + vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. + Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type + are redirected to the csi.vsphere.vmware.com CSI driver. properties: fsType: description: |- @@ -3526,9 +3586,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -3571,9 +3629,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -3607,9 +3663,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -3643,9 +3697,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic @@ -3683,9 +3735,7 @@ spec: This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. - TODO: Add other useful fields. apiVersion, kind, uid? More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. type: string type: object x-kubernetes-map-type: atomic diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 361540a0..1dbaa206 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -4,6 +4,56 @@ kind: ClusterRole metadata: name: manager-role rules: +- apiGroups: + - "" + resources: + - configmaps + - secrets + - serviceaccounts + - services + verbs: + - create + - get + - list + - update + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - persistentvolumeclaims + - pods/log + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - pods + verbs: + - '*' +- apiGroups: + - "" + resources: + - pods/exec + verbs: + - '*' +- apiGroups: + - "" + resources: + - pods/portforward + verbs: + - create - apiGroups: - apps resources: @@ -29,79 +79,6 @@ rules: - get - list - watch -- apiGroups: - - "" - resources: - - configmaps - - secrets - - services - verbs: - - create - - get - - list - - update - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - get - - list - - patch - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - pods - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - pods - - pods/exec - verbs: - - '*' -- apiGroups: - - "" - resources: - - pods/log - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - pods/portforward - verbs: - - create -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - get - - list - - update - - watch - apiGroups: - image.openshift.io resources: diff --git a/flake.nix b/flake.nix index dd033ef7..a6fbc0d5 100644 --- a/flake.nix +++ b/flake.nix @@ -40,9 +40,9 @@ pkgs.helm-docs pkgs.pre-commit pkgs.kind - pkgs.golangci-lint - pkgs.go_1_22 - rolling.operator-sdk # 1.39.2 + rolling.golangci-lint + rolling.go_1_24 + pkgs.operator-sdk # 1.39.2 (pkgs.bats.withLibraries (p: [ p.bats-support diff --git a/go.mod b/go.mod index 7ee66305..8d46650a 100644 --- a/go.mod +++ b/go.mod @@ -1,29 +1,29 @@ module github.com/jenkinsci/kubernetes-operator -go 1.22.12 +go 1.24.0 require ( github.com/bndr/gojenkins v1.1.0 github.com/distribution/reference v0.6.0 - github.com/go-logr/logr v1.4.2 + github.com/go-logr/logr v1.4.3 github.com/go-logr/zapr v1.3.0 github.com/golang/mock v1.6.0 github.com/mailgun/mailgun-go/v3 v3.6.4 - github.com/onsi/ginkgo v1.14.1 - github.com/onsi/gomega v1.33.1 + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.38.2 github.com/openshift/api v3.9.0+incompatible github.com/pkg/errors v0.9.1 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.11.1 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.31.0 - golang.org/x/mod v0.19.0 + golang.org/x/crypto v0.41.0 + golang.org/x/mod v0.26.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df - k8s.io/api v0.30.3 - k8s.io/apimachinery v0.30.3 - k8s.io/cli-runtime v0.30.3 - k8s.io/client-go v0.30.3 - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - sigs.k8s.io/controller-runtime v0.18.4 + k8s.io/api v0.33.0 + k8s.io/apimachinery v0.33.0 + k8s.io/cli-runtime v0.33.0 + k8s.io/client-go v0.33.0 + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + sigs.k8s.io/controller-runtime v0.21.0 ) require ( @@ -34,32 +34,28 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20240721033354-7089f98c1d14 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.3 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/moby/spdystream v0.4.0 // indirect + github.com/moby/spdystream v0.5.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -70,37 +66,37 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect - go.starlark.net v0.0.0-20240705175910-70002002b310 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.5.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.43.0 // indirect + golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.9.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.30.3 // indirect + k8s.io/apiextensions-apiserver v0.33.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.17.3 // indirect - sigs.k8s.io/kustomize/kyaml v0.17.2 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/kustomize/api v0.19.0 // indirect + sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 7edb8e60..22a37802 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -23,8 +25,8 @@ github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtz github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= +github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -36,13 +38,15 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-chi/chi v4.0.0+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= -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/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -51,13 +55,12 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= 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-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= 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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -67,34 +70,30 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/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= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.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/pprof v0.0.0-20240721033354-7089f98c1d14 h1:m2fdPWWX/0mdyA1X3XbVTag5NEwmWv0mieoVuRq14A4= -github.com/google/pprof v0.0.0-20240721033354-7089f98c1d14/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= 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/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -103,10 +102,14 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailgun/mailgun-go/v3 v3.6.4 h1:+cvbZRgLSHivbz/w1iWLmxVl6Bqf4geD2D7QMj4+8PE= @@ -114,8 +117,8 @@ github.com/mailgun/mailgun-go/v3 v3.6.4/go.mod h1:ZjVnH8S0dR2BLjvkZc/rxwerdcirzl github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/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/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= -github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= +github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -130,18 +133,19 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= -github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -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/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.25.1 h1:Fwp6crTREKM+oA6Cz4MsO8RhKQzs2/gOIVOUscMAfZY= +github.com/onsi/ginkgo/v2 v2.25.1/go.mod h1:ppTWQ1dh9KM/F1XgpeRqelR+zHVwV81DGRSDnFxK7Sk= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= 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/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs= @@ -154,16 +158,16 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= 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/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -176,34 +180,37 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= 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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.starlark.net v0.0.0-20240705175910-70002002b310 h1:tEAOMoNmN2MqVNi0MMEWpTtPI4YNCXgxmAGtuv3mST0= -go.starlark.net v0.0.0-20240705175910-70002002b310/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= 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.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -212,17 +219,17 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -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/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -230,32 +237,32 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= 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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -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/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= 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= @@ -268,8 +275,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -286,38 +293,38 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= -k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= -k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U= -k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= -k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= -k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k= -k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30= -k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= -k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= +k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= +k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs= +k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc= +k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= +k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/cli-runtime v0.33.0 h1:Lbl/pq/1o8BaIuyn+aVLdEPHVN665tBAXUePs8wjX7c= +k8s.io/cli-runtime v0.33.0/go.mod h1:QcA+r43HeUM9jXFJx7A+yiTPfCooau/iCcP1wQh4NFw= +k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= +k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f h1:2sXuKesAYbRHxL3aE2PN6zX/gcJr22cjrsej+W784Tc= -k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw= -sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.17.3 h1:6GCuHSsxq7fN5yhF2XrC+AAr8gxQwhexgHflOAD/JJU= -sigs.k8s.io/kustomize/api v0.17.3/go.mod h1:TuDH4mdx7jTfK61SQ/j1QZM/QWR+5rmEiNjvYlhzFhc= -sigs.k8s.io/kustomize/kyaml v0.17.2 h1:+AzvoJUY0kq4QAhH/ydPHHMRLijtUKiyVyh7fOSshr0= -sigs.k8s.io/kustomize/kyaml v0.17.2/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= -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= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= +sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= +sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ= +sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o= +sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA= +sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/controller/handler.go b/internal/controller/handler.go index f421dfad..895a4b06 100644 --- a/internal/controller/handler.go +++ b/internal/controller/handler.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -20,13 +21,15 @@ import ( // enqueueRequestForJenkins enqueues a Request for Secrets and ConfigMaps created by jenkins-operator. type enqueueRequestForJenkins struct{} -func (e *enqueueRequestForJenkins) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) { +var _ handler.TypedEventHandler[client.Object, reconcile.Request] = &enqueueRequestForJenkins{} + +func (e *enqueueRequestForJenkins) Create(ctx context.Context, evt event.TypedCreateEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { if req := e.getOwnerReconcileRequests(ctx, evt.Object); req != nil { q.Add(*req) } } -func (e *enqueueRequestForJenkins) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) { +func (e *enqueueRequestForJenkins) Update(ctx context.Context, evt event.TypedUpdateEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { req1 := e.getOwnerReconcileRequests(ctx, evt.ObjectOld) req2 := e.getOwnerReconcileRequests(ctx, evt.ObjectNew) @@ -52,13 +55,13 @@ func (e *enqueueRequestForJenkins) Update(ctx context.Context, evt event.UpdateE } } -func (e *enqueueRequestForJenkins) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) { +func (e *enqueueRequestForJenkins) Delete(ctx context.Context, evt event.TypedDeleteEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { if req := e.getOwnerReconcileRequests(ctx, evt.Object); req != nil { q.Add(*req) } } -func (e *enqueueRequestForJenkins) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) { +func (e *enqueueRequestForJenkins) Generic(ctx context.Context, evt event.TypedGenericEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { if req := e.getOwnerReconcileRequests(ctx, evt.Object); req != nil { q.Add(*req) } @@ -77,15 +80,17 @@ func (e *enqueueRequestForJenkins) getOwnerReconcileRequests(_ context.Context, } type jenkinsDecorator struct { - handler handler.EventHandler + handler handler.TypedEventHandler[client.Object, reconcile.Request] } -func (e *jenkinsDecorator) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) { +var _ handler.TypedEventHandler[client.Object, reconcile.Request] = &jenkinsDecorator{} + +func (e *jenkinsDecorator) Create(ctx context.Context, evt event.TypedCreateEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { log.Log.WithValues("cr", evt.Object.GetName()).Info(fmt.Sprintf("%T/%s was created", evt.Object, evt.Object.GetName())) e.handler.Create(ctx, evt, q) } -func (e *jenkinsDecorator) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) { +func (e *jenkinsDecorator) Update(ctx context.Context, evt event.TypedUpdateEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { if !reflect.DeepEqual(evt.ObjectOld.(*v1alpha2.Jenkins).Spec, evt.ObjectNew.(*v1alpha2.Jenkins).Spec) { log.Log.WithValues("cr", evt.ObjectNew.GetName()).Info( fmt.Sprintf("%T/%s has been updated", evt.ObjectNew, evt.ObjectNew.GetName())) @@ -93,11 +98,11 @@ func (e *jenkinsDecorator) Update(ctx context.Context, evt event.UpdateEvent, q e.handler.Update(ctx, evt, q) } -func (e *jenkinsDecorator) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) { +func (e *jenkinsDecorator) Delete(ctx context.Context, evt event.TypedDeleteEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { log.Log.WithValues("cr", evt.Object.GetName()).Info(fmt.Sprintf("%T/%s was deleted", evt.Object, evt.Object.GetName())) e.handler.Delete(ctx, evt, q) } -func (e *jenkinsDecorator) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) { +func (e *jenkinsDecorator) Generic(ctx context.Context, evt event.TypedGenericEvent[client.Object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) { e.handler.Generic(ctx, evt, q) } diff --git a/internal/controller/jenkins_controller.go b/internal/controller/jenkins_controller.go index fce29a64..1f504f77 100644 --- a/internal/controller/jenkins_controller.go +++ b/internal/controller/jenkins_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "math/rand" "reflect" "time" @@ -200,13 +199,11 @@ func (r *JenkinsReconciler) Reconcile(_ context.Context, request ctrl.Request) ( []string{fmt.Sprintf("%s Source '%s' Name '%s' groovy script execution failed, logs: %+v", groovyErr.ConfigurationType, groovyErr.Source, groovyErr.Name, groovyErr.Logs)}..., ), } - return reconcile.Result{Requeue: false}, nil + return reconcile.Result{}, nil } - return reconcile.Result{Requeue: true}, nil - } - if result.Requeue && result.RequeueAfter == 0 { - result.RequeueAfter = time.Duration(rand.Intn(10)) * time.Second + return reconcile.Result{RequeueAfter: time.Second}, nil } + // Random delay logic removed as result.Requeue is deprecated return result, nil } @@ -265,11 +262,11 @@ func (r *JenkinsReconciler) reconcile(request reconcile.Request) (reconcile.Resu if err != nil { return reconcile.Result{}, jenkins, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, jenkins, nil } if jenkinsClient == nil { - return reconcile.Result{Requeue: false}, jenkins, nil + return reconcile.Result{}, jenkins, nil } if jenkins.Status.BaseConfigurationCompletedTime == nil { @@ -320,7 +317,7 @@ func (r *JenkinsReconciler) reconcile(request reconcile.Request) (reconcile.Resu if err != nil { return reconcile.Result{}, jenkins, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, jenkins, nil } @@ -329,7 +326,7 @@ func (r *JenkinsReconciler) reconcile(request reconcile.Request) (reconcile.Resu if err != nil { return reconcile.Result{}, jenkins, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, jenkins, nil } diff --git a/pkg/configuration/backuprestore/backuprestore.go b/pkg/configuration/backuprestore/backuprestore.go index 66258d9c..92764f7e 100644 --- a/pkg/configuration/backuprestore/backuprestore.go +++ b/pkg/configuration/backuprestore/backuprestore.go @@ -74,11 +74,11 @@ func New(configuration configuration.Configuration, logger logr.Logger) *BackupA func (bar *BackupAndRestore) Validate() []string { var messages []string allContainers := map[string]v1alpha2.Container{} - for _, container := range bar.Configuration.Jenkins.Spec.Master.Containers { + for _, container := range bar.Jenkins.Spec.Master.Containers { allContainers[container.Name] = container } - restore := bar.Configuration.Jenkins.Spec.Restore + restore := bar.Jenkins.Spec.Restore if len(restore.ContainerName) > 0 { _, found := allContainers[restore.ContainerName] if !found { @@ -89,7 +89,7 @@ func (bar *BackupAndRestore) Validate() []string { } } - backup := bar.Configuration.Jenkins.Spec.Backup + backup := bar.Jenkins.Spec.Backup if len(backup.ContainerName) > 0 { _, found := allContainers[backup.ContainerName] if !found { @@ -118,7 +118,7 @@ const noBackup = "-1" // Restore performs Jenkins restore backup operation func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error { - jenkins := bar.Configuration.Jenkins + jenkins := bar.Jenkins if len(jenkins.Spec.Restore.ContainerName) == 0 || jenkins.Spec.Restore.Action.Exec == nil { bar.logger.V(log.VDebug).Info("Skipping restore backup, backup restore not configured") return nil @@ -195,7 +195,7 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error if err != nil { return err } - bar.Configuration.Jenkins = jenkins + bar.Jenkins = jenkins jenkins.Status.RestoredBackup = backupNumber jenkins.Status.PendingBackup = backupNumber + 1 @@ -207,7 +207,7 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error // Backup performs Jenkins backup operation func (bar *BackupAndRestore) Backup(setBackupDoneBeforePodDeletion bool) error { - jenkins := bar.Configuration.Jenkins + jenkins := bar.Jenkins if len(jenkins.Spec.Backup.ContainerName) == 0 || jenkins.Spec.Backup.Action.Exec == nil { bar.logger.V(log.VDebug).Info("Skipping backup, backup creation not configured") return nil @@ -268,9 +268,9 @@ func triggerBackup(ticker *time.Ticker, k8sClient k8s.Client, logger logr.Logger // EnsureBackupTrigger creates or update trigger which update CR to make backup func (bar *BackupAndRestore) EnsureBackupTrigger() error { - trigger, found := triggers.get(bar.Configuration.Jenkins.Namespace, bar.Configuration.Jenkins.Name) + trigger, found := triggers.get(bar.Jenkins.Namespace, bar.Jenkins.Name) - isBackupConfigured := len(bar.Configuration.Jenkins.Spec.Backup.ContainerName) > 0 && bar.Configuration.Jenkins.Spec.Backup.Interval > 0 + isBackupConfigured := len(bar.Jenkins.Spec.Backup.ContainerName) > 0 && bar.Jenkins.Spec.Backup.Interval > 0 if found && !isBackupConfigured { bar.StopBackupTrigger() return nil @@ -282,7 +282,7 @@ func (bar *BackupAndRestore) EnsureBackupTrigger() error { return nil } - if found && isBackupConfigured && bar.Configuration.Jenkins.Spec.Backup.Interval != trigger.interval { + if found && isBackupConfigured && bar.Jenkins.Spec.Backup.Interval != trigger.interval { bar.StopBackupTrigger() bar.startBackupTrigger() } @@ -292,21 +292,21 @@ func (bar *BackupAndRestore) EnsureBackupTrigger() error { // StopBackupTrigger stops trigger which update CR to make backup func (bar *BackupAndRestore) StopBackupTrigger() { - triggers.stop(bar.logger, bar.Configuration.Jenkins.Namespace, bar.Configuration.Jenkins.Name) + triggers.stop(bar.logger, bar.Jenkins.Namespace, bar.Jenkins.Name) } // IsBackupTriggerEnabled returns true if the backup trigger is enabled func (bar *BackupAndRestore) IsBackupTriggerEnabled() bool { - _, enabled := triggers.get(bar.Configuration.Jenkins.Namespace, bar.Configuration.Jenkins.Name) + _, enabled := triggers.get(bar.Jenkins.Namespace, bar.Jenkins.Name) return enabled } func (bar *BackupAndRestore) startBackupTrigger() { bar.logger.Info("Starting backup trigger") - ticker := time.NewTicker(time.Duration(bar.Configuration.Jenkins.Spec.Backup.Interval) * time.Second) - triggers.add(bar.Configuration.Jenkins.Namespace, bar.Configuration.Jenkins.Name, backupTrigger{ - interval: bar.Configuration.Jenkins.Spec.Backup.Interval, + ticker := time.NewTicker(time.Duration(bar.Jenkins.Spec.Backup.Interval) * time.Second) + triggers.add(bar.Jenkins.Namespace, bar.Jenkins.Name, backupTrigger{ + interval: bar.Jenkins.Spec.Backup.Interval, ticker: ticker, }) - go triggerBackup(ticker, bar.Client, bar.logger, bar.Configuration.Jenkins.Namespace, bar.Configuration.Jenkins.Name) + go triggerBackup(ticker, bar.Client, bar.logger, bar.Jenkins.Namespace, bar.Jenkins.Name) } diff --git a/pkg/configuration/base/configmap.go b/pkg/configuration/base/configmap.go index 236afe86..26c44670 100644 --- a/pkg/configuration/base/configmap.go +++ b/pkg/configuration/base/configmap.go @@ -8,7 +8,7 @@ import ( ) func (r *JenkinsBaseConfigurationReconciler) createScriptsConfigMap(meta metav1.ObjectMeta) error { - configMap, err := resources.NewScriptsConfigMap(meta, r.Configuration.Jenkins) + configMap, err := resources.NewScriptsConfigMap(meta, r.Jenkins) if err != nil { return err } @@ -16,7 +16,7 @@ func (r *JenkinsBaseConfigurationReconciler) createScriptsConfigMap(meta metav1. } func (r *JenkinsBaseConfigurationReconciler) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error { - configMap, err := resources.NewInitConfigurationConfigMap(meta, r.Configuration.Jenkins) + configMap, err := resources.NewInitConfigurationConfigMap(meta, r.Jenkins) if err != nil { return err } @@ -24,7 +24,7 @@ func (r *JenkinsBaseConfigurationReconciler) createInitConfigurationConfigMap(me } func (r *JenkinsBaseConfigurationReconciler) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error { - configMap, err := resources.NewBaseConfigurationConfigMap(meta, r.Configuration.Jenkins, r.KubernetesClusterDomain) + configMap, err := resources.NewBaseConfigurationConfigMap(meta, r.Jenkins, r.KubernetesClusterDomain) if err != nil { return err } diff --git a/pkg/configuration/base/deployment.go b/pkg/configuration/base/deployment.go index 533a3a61..493b3e8b 100644 --- a/pkg/configuration/base/deployment.go +++ b/pkg/configuration/base/deployment.go @@ -24,9 +24,9 @@ func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsDeployment(meta metav1 _, err = r.GetJenkinsDeployment() if apierrors.IsNotFound(err) { - jenkinsDeployment := resources.NewJenkinsDeployment(meta, r.Configuration.Jenkins) + jenkinsDeployment := resources.NewJenkinsDeployment(meta, r.Jenkins) *r.Notifications <- event.Event{ - Jenkins: *r.Configuration.Jenkins, + Jenkins: *r.Jenkins, Phase: event.PhaseBase, Level: v1alpha2.NotificationLevelInfo, Reason: reason.NewPodCreation(reason.OperatorSource, []string{"Creating a Jenkins Deployment"}), @@ -39,14 +39,14 @@ func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsDeployment(meta metav1 } now := metav1.Now() - r.Configuration.Jenkins.Status = v1alpha2.JenkinsStatus{ + r.Jenkins.Status = v1alpha2.JenkinsStatus{ OperatorVersion: version.Version, ProvisionStartTime: &now, - LastBackup: r.Configuration.Jenkins.Status.LastBackup, - PendingBackup: r.Configuration.Jenkins.Status.LastBackup, + LastBackup: r.Jenkins.Status.LastBackup, + PendingBackup: r.Jenkins.Status.LastBackup, UserAndPasswordHash: userAndPasswordHash, } - return reconcile.Result{Requeue: true}, r.Client.Update(context.TODO(), r.Configuration.Jenkins) + return reconcile.Result{Requeue: true}, r.Client.Update(context.TODO(), r.Jenkins) } else if err != nil && !apierrors.IsNotFound(err) { return reconcile.Result{}, stackerr.WithStack(err) } diff --git a/pkg/configuration/base/label.go b/pkg/configuration/base/label.go index 415d5ecb..958c29ed 100644 --- a/pkg/configuration/base/label.go +++ b/pkg/configuration/base/label.go @@ -12,21 +12,21 @@ import ( ) func (r *JenkinsBaseConfigurationReconciler) addLabelForWatchesResources(customization v1alpha2.Customization) error { - labelsForWatchedResources := resources.BuildLabelsForWatchedResources(*r.Configuration.Jenkins) + labelsForWatchedResources := resources.BuildLabelsForWatchedResources(*r.Jenkins) if len(customization.Secret.Name) > 0 { secret := &corev1.Secret{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: customization.Secret.Name, Namespace: r.Configuration.Jenkins.Namespace}, secret) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: customization.Secret.Name, Namespace: r.Jenkins.Namespace}, secret) if err != nil { return stackerr.WithStack(err) } if !resources.VerifyIfLabelsAreSet(secret, labelsForWatchedResources) { - if len(secret.ObjectMeta.Labels) == 0 { - secret.ObjectMeta.Labels = map[string]string{} + if len(secret.Labels) == 0 { + secret.Labels = map[string]string{} } for key, value := range labelsForWatchedResources { - secret.ObjectMeta.Labels[key] = value + secret.Labels[key] = value } if err = r.Client.Update(context.TODO(), secret); err != nil { @@ -37,17 +37,17 @@ func (r *JenkinsBaseConfigurationReconciler) addLabelForWatchesResources(customi for _, configMapRef := range customization.Configurations { configMap := &corev1.ConfigMap{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: configMapRef.Name, Namespace: r.Configuration.Jenkins.Namespace}, configMap) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: configMapRef.Name, Namespace: r.Jenkins.Namespace}, configMap) if err != nil { return stackerr.WithStack(err) } if !resources.VerifyIfLabelsAreSet(configMap, labelsForWatchedResources) { - if len(configMap.ObjectMeta.Labels) == 0 { - configMap.ObjectMeta.Labels = map[string]string{} + if len(configMap.Labels) == 0 { + configMap.Labels = map[string]string{} } for key, value := range labelsForWatchedResources { - configMap.ObjectMeta.Labels[key] = value + configMap.Labels[key] = value } if err = r.Client.Update(context.TODO(), configMap); err != nil { diff --git a/pkg/configuration/base/plugin.go b/pkg/configuration/base/plugin.go index 8b9375eb..4258ea68 100644 --- a/pkg/configuration/base/plugin.go +++ b/pkg/configuration/base/plugin.go @@ -13,7 +13,7 @@ import ( ) func (r *JenkinsBaseConfigurationReconciler) verifyPlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) { - if r.Configuration.Jenkins.Spec.Master.SkipPlugins != nil && *r.Configuration.Jenkins.Spec.Master.SkipPlugins { + if r.Jenkins.Spec.Master.SkipPlugins != nil && *r.Jenkins.Spec.Master.SkipPlugins { return true, nil } allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins) @@ -30,7 +30,7 @@ func (r *JenkinsBaseConfigurationReconciler) verifyPlugins(jenkinsClient jenkins r.logger.V(log.VDebug).Info(fmt.Sprintf("Installed plugins '%+v'", installedPlugins)) status := true - allRequiredPlugins := [][]v1alpha2.Plugin{r.Configuration.Jenkins.Spec.Master.BasePlugins, r.Configuration.Jenkins.Spec.Master.Plugins} + allRequiredPlugins := [][]v1alpha2.Plugin{r.Jenkins.Spec.Master.BasePlugins, r.Jenkins.Spec.Master.Plugins} for _, requiredPlugins := range allRequiredPlugins { for _, plugin := range requiredPlugins { if _, ok := isPluginInstalled(allPluginsInJenkins, plugin); !ok { diff --git a/pkg/configuration/base/pod.go b/pkg/configuration/base/pod.go index 579e085f..99ab2abb 100644 --- a/pkg/configuration/base/pod.go +++ b/pkg/configuration/base/pod.go @@ -32,83 +32,83 @@ func (r *JenkinsBaseConfigurationReconciler) checkForPodRecreation(currentJenkin return reason.NewPodRestart(reason.KubernetesSource, messages, verbose...) } - userAndPasswordHashIsDifferent := userAndPasswordHash != r.Configuration.Jenkins.Status.UserAndPasswordHash - userAndPasswordHashStatusNotEmpty := r.Configuration.Jenkins.Status.UserAndPasswordHash != "" + userAndPasswordHashIsDifferent := userAndPasswordHash != r.Jenkins.Status.UserAndPasswordHash + userAndPasswordHashStatusNotEmpty := r.Jenkins.Status.UserAndPasswordHash != "" if userAndPasswordHashIsDifferent && userAndPasswordHashStatusNotEmpty { messages = append(messages, "User or password have changed") verbose = append(verbose, "User or password have changed, recreating pod") } - if r.Configuration.Jenkins.Spec.Restore.RecoveryOnce != 0 && r.Configuration.Jenkins.Status.RestoredBackup != 0 { + if r.Jenkins.Spec.Restore.RecoveryOnce != 0 && r.Jenkins.Status.RestoredBackup != 0 { messages = append(messages, "spec.restore.recoveryOnce is set") verbose = append(verbose, "spec.restore.recoveryOnce is set, recreating pod") } - if version.Version != r.Configuration.Jenkins.Status.OperatorVersion { + if version.Version != r.Jenkins.Status.OperatorVersion { messages = append(messages, "Jenkins Operator version has changed") verbose = append(verbose, fmt.Sprintf("Jenkins Operator version has changed, actual '%+v' new '%+v'", - r.Configuration.Jenkins.Status.OperatorVersion, version.Version)) + r.Jenkins.Status.OperatorVersion, version.Version)) } //FIXME too hacky var jenkinsSecurityContext *corev1.PodSecurityContext - if r.Configuration.Jenkins.Spec.Master.SecurityContext == nil { + if r.Jenkins.Spec.Master.SecurityContext == nil { jenkinsSecurityContext = &corev1.PodSecurityContext{} } else { - jenkinsSecurityContext = r.Configuration.Jenkins.Spec.Master.SecurityContext + jenkinsSecurityContext = r.Jenkins.Spec.Master.SecurityContext } if !reflect.DeepEqual(jenkinsSecurityContext, currentJenkinsMasterPod.Spec.SecurityContext) { messages = append(messages, "Jenkins pod security context has changed") verbose = append(verbose, fmt.Sprintf("Jenkins pod security context has changed, actual '%+v' required '%+v'", - currentJenkinsMasterPod.Spec.SecurityContext, r.Configuration.Jenkins.Spec.Master.SecurityContext)) + currentJenkinsMasterPod.Spec.SecurityContext, r.Jenkins.Spec.Master.SecurityContext)) } - if !compareImagePullSecrets(r.Configuration.Jenkins.Spec.Master.ImagePullSecrets, currentJenkinsMasterPod.Spec.ImagePullSecrets) { + if !compareImagePullSecrets(r.Jenkins.Spec.Master.ImagePullSecrets, currentJenkinsMasterPod.Spec.ImagePullSecrets) { messages = append(messages, "Jenkins Pod ImagePullSecrets has changed") verbose = append(verbose, fmt.Sprintf("Jenkins Pod ImagePullSecrets has changed, actual '%+v' required '%+v'", - currentJenkinsMasterPod.Spec.ImagePullSecrets, r.Configuration.Jenkins.Spec.Master.ImagePullSecrets)) + currentJenkinsMasterPod.Spec.ImagePullSecrets, r.Jenkins.Spec.Master.ImagePullSecrets)) } - if !compareMap(r.Configuration.Jenkins.Spec.Master.NodeSelector, currentJenkinsMasterPod.Spec.NodeSelector) { + if !compareMap(r.Jenkins.Spec.Master.NodeSelector, currentJenkinsMasterPod.Spec.NodeSelector) { messages = append(messages, "Jenkins pod node selector has changed") verbose = append(verbose, fmt.Sprintf("Jenkins pod node selector has changed, actual '%+v' required '%+v'", - currentJenkinsMasterPod.Spec.NodeSelector, r.Configuration.Jenkins.Spec.Master.NodeSelector)) + currentJenkinsMasterPod.Spec.NodeSelector, r.Jenkins.Spec.Master.NodeSelector)) } - if !compareMap(r.Configuration.Jenkins.Spec.Master.Labels, currentJenkinsMasterPod.Labels) { + if !compareMap(r.Jenkins.Spec.Master.Labels, currentJenkinsMasterPod.Labels) { messages = append(messages, "Jenkins pod labels have changed") verbose = append(verbose, fmt.Sprintf("Jenkins pod labels have changed, actual '%+v' required '%+v'", - currentJenkinsMasterPod.Labels, r.Configuration.Jenkins.Spec.Master.Labels)) + currentJenkinsMasterPod.Labels, r.Jenkins.Spec.Master.Labels)) } - if !compareMap(r.Configuration.Jenkins.Spec.Master.Annotations, currentJenkinsMasterPod.ObjectMeta.Annotations) { + if !compareMap(r.Jenkins.Spec.Master.Annotations, currentJenkinsMasterPod.Annotations) { messages = append(messages, "Jenkins pod annotations have changed") verbose = append(verbose, fmt.Sprintf("Jenkins pod annotations have changed, actual '%+v' required '%+v'", - currentJenkinsMasterPod.ObjectMeta.Annotations, r.Configuration.Jenkins.Spec.Master.Annotations)) + currentJenkinsMasterPod.Annotations, r.Jenkins.Spec.Master.Annotations)) } if !r.compareVolumes(currentJenkinsMasterPod) { messages = append(messages, "Jenkins pod volumes have changed") verbose = append(verbose, fmt.Sprintf("Jenkins pod volumes have changed, actual '%v' required '%v'", - currentJenkinsMasterPod.Spec.Volumes, r.Configuration.Jenkins.Spec.Master.Volumes)) + currentJenkinsMasterPod.Spec.Volumes, r.Jenkins.Spec.Master.Volumes)) } - if len(r.Configuration.Jenkins.Spec.Master.Containers) != len(currentJenkinsMasterPod.Spec.Containers) { + if len(r.Jenkins.Spec.Master.Containers) != len(currentJenkinsMasterPod.Spec.Containers) { messages = append(messages, "Jenkins amount of containers has changed") verbose = append(verbose, fmt.Sprintf("Jenkins amount of containers has changed, actual '%+v' required '%+v'", - len(currentJenkinsMasterPod.Spec.Containers), len(r.Configuration.Jenkins.Spec.Master.Containers))) + len(currentJenkinsMasterPod.Spec.Containers), len(r.Jenkins.Spec.Master.Containers))) } - if r.Configuration.Jenkins.Spec.Master.PriorityClassName != currentJenkinsMasterPod.Spec.PriorityClassName { + if r.Jenkins.Spec.Master.PriorityClassName != currentJenkinsMasterPod.Spec.PriorityClassName { messages = append(messages, "Jenkins priorityClassName has changed") verbose = append(verbose, fmt.Sprintf("Jenkins priorityClassName has changed, actual '%+v' required '%+v'", - currentJenkinsMasterPod.Spec.PriorityClassName, r.Configuration.Jenkins.Spec.Master.PriorityClassName)) + currentJenkinsMasterPod.Spec.PriorityClassName, r.Jenkins.Spec.Master.PriorityClassName)) } - customResourceReplaced := (r.Configuration.Jenkins.Status.BaseConfigurationCompletedTime == nil || - r.Configuration.Jenkins.Status.UserConfigurationCompletedTime == nil) && - r.Configuration.Jenkins.Status.UserAndPasswordHash == "" + customResourceReplaced := (r.Jenkins.Status.BaseConfigurationCompletedTime == nil || + r.Jenkins.Status.UserConfigurationCompletedTime == nil) && + r.Jenkins.Status.UserAndPasswordHash == "" if customResourceReplaced { messages = append(messages, "Jenkins CR has been replaced") @@ -117,14 +117,14 @@ func (r *JenkinsBaseConfigurationReconciler) checkForPodRecreation(currentJenkin for _, actualContainer := range currentJenkinsMasterPod.Spec.Containers { if actualContainer.Name == resources.JenkinsMasterContainerName { - containerMessages, verboseMessages := r.compareContainers(resources.NewJenkinsMasterContainer(r.Configuration.Jenkins), actualContainer) + containerMessages, verboseMessages := r.compareContainers(resources.NewJenkinsMasterContainer(r.Jenkins), actualContainer) messages = append(messages, containerMessages...) verbose = append(verbose, verboseMessages...) continue } var expectedContainer *corev1.Container - for _, jenkinsContainer := range r.Configuration.Jenkins.Spec.Master.Containers { + for _, jenkinsContainer := range r.Jenkins.Spec.Master.Containers { if jenkinsContainer.Name == actualContainer.Name { tmp := resources.ConvertJenkinsContainerToKubernetesContainer(jenkinsContainer) expectedContainer = &tmp @@ -153,11 +153,11 @@ func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1. } // Check if this Pod already exists - currentJenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod() + currentJenkinsMasterPod, err := r.GetJenkinsMasterPod() if err != nil && apierrors.IsNotFound(err) { - jenkinsMasterPod := resources.NewJenkinsMasterPod(meta, r.Configuration.Jenkins) + jenkinsMasterPod := resources.NewJenkinsMasterPod(meta, r.Jenkins) *r.Notifications <- event.Event{ - Jenkins: *r.Configuration.Jenkins, + Jenkins: *r.Jenkins, Phase: event.PhaseBase, Level: v1alpha2.NotificationLevelInfo, Reason: reason.NewPodCreation(reason.OperatorSource, []string{"Creating a new Jenkins Master Pod"}), @@ -169,14 +169,14 @@ func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1. } now := metav1.Now() - r.Configuration.Jenkins.Status = v1alpha2.JenkinsStatus{ + r.Jenkins.Status = v1alpha2.JenkinsStatus{ OperatorVersion: version.Version, ProvisionStartTime: &now, - LastBackup: r.Configuration.Jenkins.Status.LastBackup, - PendingBackup: r.Configuration.Jenkins.Status.LastBackup, + LastBackup: r.Jenkins.Status.LastBackup, + PendingBackup: r.Jenkins.Status.LastBackup, UserAndPasswordHash: userAndPasswordHash, } - return reconcile.Result{Requeue: true}, r.Client.Status().Update(context.TODO(), r.Configuration.Jenkins) + return reconcile.Result{Requeue: true}, r.Client.Status().Update(context.TODO(), r.Jenkins) } else if err != nil && !apierrors.IsNotFound(err) { return reconcile.Result{}, stackerr.WithStack(err) } @@ -185,15 +185,15 @@ func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1. return reconcile.Result{Requeue: true}, nil } - if r.IsJenkinsTerminating(*currentJenkinsMasterPod) && r.Configuration.Jenkins.Status.UserConfigurationCompletedTime != nil { + if r.IsJenkinsTerminating(*currentJenkinsMasterPod) && r.Jenkins.Status.UserConfigurationCompletedTime != nil { backupAndRestore := backuprestore.New(r.Configuration, r.logger) if backupAndRestore.IsBackupTriggerEnabled() { backupAndRestore.StopBackupTrigger() return reconcile.Result{Requeue: true}, nil } - if r.Configuration.Jenkins.Spec.Backup.MakeBackupBeforePodDeletion && !r.Configuration.Jenkins.Status.BackupDoneBeforePodDeletion { - if r.Configuration.Jenkins.Status.LastBackup == r.Configuration.Jenkins.Status.PendingBackup { - r.Configuration.Jenkins.Status.PendingBackup++ + if r.Jenkins.Spec.Backup.MakeBackupBeforePodDeletion && !r.Jenkins.Status.BackupDoneBeforePodDeletion { + if r.Jenkins.Status.LastBackup == r.Jenkins.Status.PendingBackup { + r.Jenkins.Status.PendingBackup++ } if err = backupAndRestore.Backup(true); err != nil { return reconcile.Result{}, err @@ -209,7 +209,7 @@ func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1. r.logger.Info(msg) } - return reconcile.Result{Requeue: true}, r.Configuration.RestartJenkinsMasterPod(restartReason) + return reconcile.Result{Requeue: true}, r.RestartJenkinsMasterPod(restartReason) } } diff --git a/pkg/configuration/base/rbac.go b/pkg/configuration/base/rbac.go index 711e1d29..6d3dc2e9 100644 --- a/pkg/configuration/base/rbac.go +++ b/pkg/configuration/base/rbac.go @@ -42,7 +42,7 @@ func (r *JenkinsBaseConfigurationReconciler) createRBAC(meta metav1.ObjectMeta) func (r *JenkinsBaseConfigurationReconciler) ensureExtraRBAC(meta metav1.ObjectMeta) error { var err error var name string - for _, roleRef := range r.Configuration.Jenkins.Spec.Roles { + for _, roleRef := range r.Jenkins.Spec.Roles { name = getExtraRoleBindingName(meta.Name, roleRef) roleBinding := resources.NewRoleBinding(name, meta.Namespace, meta.Name, roleRef) err := r.Client.Create(context.TODO(), roleBinding) @@ -55,7 +55,7 @@ func (r *JenkinsBaseConfigurationReconciler) ensureExtraRBAC(meta metav1.ObjectM } roleBindings := &rbacv1.RoleBindingList{} - err = r.Client.List(context.TODO(), roleBindings, client.InNamespace(r.Configuration.Jenkins.Namespace)) + err = r.Client.List(context.TODO(), roleBindings, client.InNamespace(r.Jenkins.Namespace)) if err != nil { return stackerr.WithStack(err) } @@ -66,7 +66,7 @@ func (r *JenkinsBaseConfigurationReconciler) ensureExtraRBAC(meta metav1.ObjectM } found := false - for _, roleRef := range r.Configuration.Jenkins.Spec.Roles { + for _, roleRef := range r.Jenkins.Spec.Roles { name = getExtraRoleBindingName(meta.Name, roleRef) if roleBinding.Name == name { found = true diff --git a/pkg/configuration/base/reconciler.go b/pkg/configuration/base/reconciler.go index e5096513..366c31bf 100644 --- a/pkg/configuration/base/reconciler.go +++ b/pkg/configuration/base/reconciler.go @@ -50,7 +50,7 @@ func New(config configuration.Configuration, jenkinsAPIConnectionSettings jenkin // Reconcile takes care of base configuration. func (r *JenkinsBaseConfigurationReconciler) Reconcile() (reconcile.Result, jenkinsclient.Jenkins, error) { - metaObject := resources.NewResourceObjectMeta(r.Configuration.Jenkins) + metaObject := resources.NewResourceObjectMeta(r.Jenkins) // Create Necessary Resources err := r.ensureResourcesRequiredForJenkinsPod(metaObject) @@ -59,12 +59,12 @@ func (r *JenkinsBaseConfigurationReconciler) Reconcile() (reconcile.Result, jenk } r.logger.V(log.VDebug).Info("Kubernetes resources are present") - if useDeploymentForJenkinsMaster(r.Configuration.Jenkins) { + if useDeploymentForJenkinsMaster(r.Jenkins) { result, err := r.ensureJenkinsDeployment(metaObject) if err != nil { return reconcile.Result{}, nil, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, nil, nil } r.logger.V(log.VDebug).Info("Jenkins Deployment is present") @@ -76,7 +76,7 @@ func (r *JenkinsBaseConfigurationReconciler) Reconcile() (reconcile.Result, jenk if err != nil { return reconcile.Result{}, nil, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, nil, nil } r.logger.V(log.VDebug).Info("Jenkins master pod is present") @@ -86,19 +86,19 @@ func (r *JenkinsBaseConfigurationReconciler) Reconcile() (reconcile.Result, jenk return reconcile.Result{}, nil, err } if stopReconcileLoop { - return reconcile.Result{Requeue: false}, nil, nil + return reconcile.Result{}, nil, nil } result, err = r.waitForJenkins() if err != nil { return reconcile.Result{}, nil, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, nil, nil } r.logger.V(log.VDebug).Info("Jenkins master pod is ready") - jenkinsClient, err := r.Configuration.GetJenkinsClient() + jenkinsClient, err := r.GetJenkinsClient() if err != nil { return reconcile.Result{}, nil, err } @@ -117,7 +117,7 @@ func (r *JenkinsBaseConfigurationReconciler) Reconcile() (reconcile.Result, jenk reason.OperatorSource, []string{message}, ) - return reconcile.Result{Requeue: true}, nil, r.Configuration.RestartJenkinsMasterPod(restartReason) + return reconcile.Result{Requeue: true}, nil, r.RestartJenkinsMasterPod(restartReason) } result, err = r.ensureBaseConfiguration(jenkinsClient) @@ -158,12 +158,12 @@ func (r *JenkinsBaseConfigurationReconciler) ensureResourcesRequiredForJenkinsPo } r.logger.V(log.VDebug).Info("Base configuration config map is present") - if err := r.addLabelForWatchesResources(r.Configuration.Jenkins.Spec.GroovyScripts.Customization); err != nil { + if err := r.addLabelForWatchesResources(r.Jenkins.Spec.GroovyScripts.Customization); err != nil { return err } r.logger.V(log.VDebug).Info("GroovyScripts Secret and ConfigMap added watched labels") - if err := r.addLabelForWatchesResources(r.Configuration.Jenkins.Spec.ConfigurationAsCode.Customization); err != nil { + if err := r.addLabelForWatchesResources(r.Jenkins.Spec.ConfigurationAsCode.Customization); err != nil { return err } r.logger.V(log.VDebug).Info("ConfigurationAsCode Secret and ConfigMap added watched labels") @@ -178,20 +178,20 @@ func (r *JenkinsBaseConfigurationReconciler) ensureResourcesRequiredForJenkinsPo } r.logger.V(log.VDebug).Info("Extra role bindings are present") - httpServiceName := resources.GetJenkinsHTTPServiceName(r.Configuration.Jenkins) - if err := r.createService(metaObject, httpServiceName, r.Configuration.Jenkins.Spec.Service, constants.DefaultHTTPPortInt32); err != nil { + httpServiceName := resources.GetJenkinsHTTPServiceName(r.Jenkins) + if err := r.createService(metaObject, httpServiceName, r.Jenkins.Spec.Service, constants.DefaultHTTPPortInt32); err != nil { return err } r.logger.V(log.VDebug).Info("Jenkins HTTP Service is present") - if err := r.createService(metaObject, resources.GetJenkinsSlavesServiceName(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.SlaveService, constants.DefaultSlavePortInt32); err != nil { + if err := r.createService(metaObject, resources.GetJenkinsSlavesServiceName(r.Jenkins), r.Jenkins.Spec.SlaveService, constants.DefaultSlavePortInt32); err != nil { return err } r.logger.V(log.VDebug).Info("Jenkins slave Service is present") if resources.IsRouteAPIAvailable(&r.ClientSet) { r.logger.V(log.VDebug).Info("Route API is available. Now creating route.") - if err := r.createRoute(metaObject, httpServiceName, r.Configuration.Jenkins); err != nil { + if err := r.createRoute(metaObject, httpServiceName, r.Jenkins); err != nil { return err } r.logger.V(log.VDebug).Info("Jenkins Route is present") @@ -202,10 +202,10 @@ func (r *JenkinsBaseConfigurationReconciler) ensureResourcesRequiredForJenkinsPo func (r *JenkinsBaseConfigurationReconciler) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error { found := &corev1.Secret{} - err := r.Configuration.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, found) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Jenkins), Namespace: r.Jenkins.Namespace}, found) if err != nil && apierrors.IsNotFound(err) { - return stackerr.WithStack(r.CreateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins))) + return stackerr.WithStack(r.CreateResource(resources.NewOperatorCredentialsSecret(meta, r.Jenkins))) } else if err != nil && !apierrors.IsNotFound(err) { return stackerr.WithStack(err) } @@ -214,12 +214,12 @@ func (r *JenkinsBaseConfigurationReconciler) createOperatorCredentialsSecret(met found.Data[resources.OperatorCredentialsSecretPasswordKey] != nil { return nil } - return stackerr.WithStack(r.UpdateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins))) + return stackerr.WithStack(r.UpdateResource(resources.NewOperatorCredentialsSecret(meta, r.Jenkins))) } func (r *JenkinsBaseConfigurationReconciler) calculateUserAndPasswordHash() (string, error) { credentialsSecret := &corev1.Secret{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, credentialsSecret) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Jenkins), Namespace: r.Jenkins.Namespace}, credentialsSecret) if err != nil { return "", stackerr.WithStack(err) } @@ -309,27 +309,27 @@ func (r *JenkinsBaseConfigurationReconciler) compareVolumes(actualPod corev1.Pod } return reflect.DeepEqual( - append(resources.GetJenkinsMasterPodBaseVolumes(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.Master.Volumes...), + append(resources.GetJenkinsMasterPodBaseVolumes(r.Jenkins), r.Jenkins.Spec.Master.Volumes...), toCompare, ) } func (r *JenkinsBaseConfigurationReconciler) detectJenkinsMasterPodStartingIssues() (stopReconcileLoop bool, err error) { - jenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod() + jenkinsMasterPod, err := r.GetJenkinsMasterPod() if err != nil { return false, err } - if r.Configuration.Jenkins.Status.ProvisionStartTime == nil { + if r.Jenkins.Status.ProvisionStartTime == nil { return true, nil } if jenkinsMasterPod.Status.Phase == corev1.PodPending { - timeout := r.Configuration.Jenkins.Status.ProvisionStartTime.Add(time.Minute * 2).UTC() + timeout := r.Jenkins.Status.ProvisionStartTime.Add(time.Minute * 2).UTC() now := time.Now().UTC() if now.After(timeout) { events := &corev1.EventList{} - err = r.Client.List(context.TODO(), events, client.InNamespace(r.Configuration.Jenkins.Namespace)) + err = r.Client.List(context.TODO(), events, client.InNamespace(r.Jenkins.Namespace)) if err != nil { return false, stackerr.WithStack(err) } @@ -351,13 +351,13 @@ func (r *JenkinsBaseConfigurationReconciler) detectJenkinsMasterPodStartingIssue func (r *JenkinsBaseConfigurationReconciler) filterEvents(source corev1.EventList, jenkinsMasterPod corev1.Pod) []string { events := []string{} for _, eventItem := range source.Items { - if r.Configuration.Jenkins.Status.ProvisionStartTime.UTC().After(eventItem.LastTimestamp.UTC()) { + if r.Jenkins.Status.ProvisionStartTime.UTC().After(eventItem.LastTimestamp.UTC()) { continue } if eventItem.Type == corev1.EventTypeNormal { continue } - if !strings.HasPrefix(eventItem.ObjectMeta.Name, jenkinsMasterPod.Name) { + if !strings.HasPrefix(eventItem.Name, jenkinsMasterPod.Name) { continue } events = append(events, fmt.Sprintf("Message: %s Subobject: %s", eventItem.Message, eventItem.InvolvedObject.FieldPath)) @@ -366,7 +366,7 @@ func (r *JenkinsBaseConfigurationReconciler) filterEvents(source corev1.EventLis } func (r *JenkinsBaseConfigurationReconciler) waitForJenkins() (reconcile.Result, error) { - jenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod() + jenkinsMasterPod, err := r.GetJenkinsMasterPod() if err != nil { return reconcile.Result{}, err } @@ -391,7 +391,7 @@ func (r *JenkinsBaseConfigurationReconciler) waitForJenkins() (reconcile.Result, reason.KubernetesSource, []string{message}, ) - return reconcile.Result{Requeue: true}, r.Configuration.RestartJenkinsMasterPod(restartReason) + return reconcile.Result{Requeue: true}, r.RestartJenkinsMasterPod(restartReason) } if !containerStatus.Ready { r.logger.V(log.VDebug).Info(fmt.Sprintf("Container '%s' not ready, readiness probe failed", containerStatus.Name)) @@ -410,10 +410,10 @@ func (r *JenkinsBaseConfigurationReconciler) ensureBaseConfiguration(jenkinsClie customization := v1alpha2.GroovyScripts{ Customization: v1alpha2.Customization{ Secret: v1alpha2.SecretRef{Name: ""}, - Configurations: []v1alpha2.ConfigMapRef{{Name: resources.GetBaseConfigurationConfigMapName(r.Configuration.Jenkins)}}, + Configurations: []v1alpha2.ConfigMapRef{{Name: resources.GetBaseConfigurationConfigMapName(r.Jenkins)}}, }, } - groovyClient := groovy.New(jenkinsClient, r.Client, r.Configuration.Jenkins, "base-groovy", customization.Customization) + groovyClient := groovy.New(jenkinsClient, r.Client, r.Jenkins, "base-groovy", customization.Customization) requeue, err := groovyClient.Ensure(func(name string) bool { return strings.HasSuffix(name, ".groovy") }, func(groovyScript string) string { diff --git a/pkg/configuration/base/resources/base_configuration_configmap.go b/pkg/configuration/base/resources/base_configuration_configmap.go index 0987fd4c..2b33908a 100644 --- a/pkg/configuration/base/resources/base_configuration_configmap.go +++ b/pkg/configuration/base/resources/base_configuration_configmap.go @@ -154,7 +154,7 @@ GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class).save() // GetBaseConfigurationConfigMapName returns name of Kubernetes config map used to base configuration. func GetBaseConfigurationConfigMapName(jenkins *v1alpha2.Jenkins) string { - return fmt.Sprintf("%s-base-configuration-%s", constants.OperatorName, jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-base-configuration-%s", constants.OperatorName, jenkins.Name) } // NewBaseConfigurationConfigMap builds Kubernetes config map used to base configuration. @@ -183,7 +183,7 @@ func NewBaseConfigurationConfigMap(meta metav1.ObjectMeta, jenkins *v1alpha2.Jen disableInsecureFeaturesGroovyScriptName: disableInsecureFeatures, configureKubernetesPluginGroovyScriptName: fmt.Sprintf(configureKubernetesPluginFmt, clusterDomain, - jenkins.ObjectMeta.Namespace, + jenkins.Namespace, fmt.Sprintf("http://%s:%d%s", jenkinsServiceFQDN, jenkins.Spec.Service.Port, suffix), fmt.Sprintf("%s:%d", jenkinsSlavesServiceFQDN, jenkins.Spec.SlaveService.Port), ), diff --git a/pkg/configuration/base/resources/init_configuration_configmap.go b/pkg/configuration/base/resources/init_configuration_configmap.go index bebed79f..1abbdbfd 100644 --- a/pkg/configuration/base/resources/init_configuration_configmap.go +++ b/pkg/configuration/base/resources/init_configuration_configmap.go @@ -63,7 +63,7 @@ func buildCreateJenkinsOperatorUserGroovyScript(jenkins *v1alpha2.Jenkins) (*str // GetInitConfigurationConfigMapName returns name of Kubernetes config map used to init configuration func GetInitConfigurationConfigMapName(jenkins *v1alpha2.Jenkins) string { - return fmt.Sprintf("%s-init-configuration-%s", constants.OperatorName, jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-init-configuration-%s", constants.OperatorName, jenkins.Name) } // NewInitConfigurationConfigMap builds Kubernetes config map used to init configuration diff --git a/pkg/configuration/base/resources/meta.go b/pkg/configuration/base/resources/meta.go index 5e6af861..900e0d0c 100644 --- a/pkg/configuration/base/resources/meta.go +++ b/pkg/configuration/base/resources/meta.go @@ -13,7 +13,7 @@ import ( func NewResourceObjectMeta(jenkins *v1alpha2.Jenkins) metav1.ObjectMeta { return metav1.ObjectMeta{ Name: GetResourceName(jenkins), - Namespace: jenkins.ObjectMeta.Namespace, + Namespace: jenkins.Namespace, Labels: BuildResourceLabels(jenkins), } } @@ -39,7 +39,7 @@ func BuildLabelsForWatchedResources(jenkins v1alpha2.Jenkins) map[string]string // GetResourceName returns name of Kubernetes resource base on Jenkins CR func GetResourceName(jenkins *v1alpha2.Jenkins) string { - return fmt.Sprintf("%s-%s", constants.LabelAppValue, jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-%s", constants.LabelAppValue, jenkins.Name) } // VerifyIfLabelsAreSet check is selected labels are set for specific resource diff --git a/pkg/configuration/base/resources/pod_test.go b/pkg/configuration/base/resources/pod_test.go index 988c9fb7..665d5c1e 100644 --- a/pkg/configuration/base/resources/pod_test.go +++ b/pkg/configuration/base/resources/pod_test.go @@ -148,9 +148,10 @@ func TestGetJenkinsMasterPodBaseVolumes(t *testing.T) { func checkSecretVolumesPresence(jenkins *v1alpha2.Jenkins) (groovyExists bool, cascExists bool) { for _, volume := range GetJenkinsMasterPodBaseVolumes(jenkins) { - if volume.Name == ("gs-" + jenkins.Spec.GroovyScripts.Secret.Name) { + switch volume.Name { + case "gs-" + jenkins.Spec.GroovyScripts.Secret.Name: groovyExists = true - } else if volume.Name == ("casc-" + jenkins.Spec.ConfigurationAsCode.Secret.Name) { + case "casc-" + jenkins.Spec.ConfigurationAsCode.Secret.Name: cascExists = true } } diff --git a/pkg/configuration/base/resources/scripts_configmap.go b/pkg/configuration/base/resources/scripts_configmap.go index a04b58b5..90448107 100644 --- a/pkg/configuration/base/resources/scripts_configmap.go +++ b/pkg/configuration/base/resources/scripts_configmap.go @@ -126,7 +126,7 @@ func buildInitBashScript(jenkins *v1alpha2.Jenkins) (*string, error) { } func getScriptsConfigMapName(jenkins *v1alpha2.Jenkins) string { - return fmt.Sprintf("%s-scripts-%s", constants.OperatorName, jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-scripts-%s", constants.OperatorName, jenkins.Name) } // NewScriptsConfigMap builds Kubernetes config map used to store scripts diff --git a/pkg/configuration/base/resources/service.go b/pkg/configuration/base/resources/service.go index a11fe9f1..465865b7 100644 --- a/pkg/configuration/base/resources/service.go +++ b/pkg/configuration/base/resources/service.go @@ -19,9 +19,9 @@ const ServiceKind = "Service" // UpdateService returns new service with override fields from config func UpdateService(actual corev1.Service, config v1alpha2.Service, targetPort int32) corev1.Service { - actual.ObjectMeta.Annotations = config.Annotations + actual.Annotations = config.Annotations for key, value := range config.Labels { - actual.ObjectMeta.Labels[key] = value + actual.Labels[key] = value } actual.Spec.Type = config.Type actual.Spec.LoadBalancerIP = config.LoadBalancerIP @@ -40,12 +40,12 @@ func UpdateService(actual corev1.Service, config v1alpha2.Service, targetPort in // GetJenkinsHTTPServiceName returns Kubernetes service name used for expose Jenkins HTTP endpoint func GetJenkinsHTTPServiceName(jenkins *v1alpha2.Jenkins) string { - return fmt.Sprintf("%s-http-%s", constants.OperatorName, jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-http-%s", constants.OperatorName, jenkins.Name) } // GetJenkinsSlavesServiceName returns Kubernetes service name used for expose Jenkins slave endpoint func GetJenkinsSlavesServiceName(jenkins *v1alpha2.Jenkins) string { - return fmt.Sprintf("%s-slave-%s", constants.OperatorName, jenkins.ObjectMeta.Name) + return fmt.Sprintf("%s-slave-%s", constants.OperatorName, jenkins.Name) } // GetJenkinsHTTPServiceFQDN returns Kubernetes service FQDN used for expose Jenkins HTTP endpoint @@ -55,7 +55,7 @@ func GetJenkinsHTTPServiceFQDN(jenkins *v1alpha2.Jenkins, kubernetesClusterDomai return "", err } - return fmt.Sprintf("%s-http-%s.%s.svc.%s", constants.OperatorName, jenkins.ObjectMeta.Name, jenkins.ObjectMeta.Namespace, clusterDomain), nil + return fmt.Sprintf("%s-http-%s.%s.svc.%s", constants.OperatorName, jenkins.Name, jenkins.Namespace, clusterDomain), nil } // GetJenkinsSlavesServiceFQDN returns Kubernetes service FQDN used for expose Jenkins slave endpoint @@ -65,7 +65,7 @@ func GetJenkinsSlavesServiceFQDN(jenkins *v1alpha2.Jenkins, kubernetesClusterDom return "", err } - return fmt.Sprintf("%s-slave-%s.%s.svc.%s", constants.OperatorName, jenkins.ObjectMeta.Name, jenkins.ObjectMeta.Namespace, clusterDomain), nil + return fmt.Sprintf("%s-slave-%s.%s.svc.%s", constants.OperatorName, jenkins.Name, jenkins.Namespace, clusterDomain), nil } // GetClusterDomain returns Kubernetes cluster domain, default to "cluster.local" diff --git a/pkg/configuration/base/route.go b/pkg/configuration/base/route.go index f55a15d6..2778919a 100644 --- a/pkg/configuration/base/route.go +++ b/pkg/configuration/base/route.go @@ -18,7 +18,7 @@ import ( // createRoute takes the ServiceName and Creates the Route based on it func (r *JenkinsBaseConfigurationReconciler) createRoute(meta metav1.ObjectMeta, serviceName string, config *v1alpha2.Jenkins) error { route := routev1.Route{} - name := fmt.Sprintf("jenkins-%s", config.ObjectMeta.Name) + name := fmt.Sprintf("jenkins-%s", config.Name) err := r.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: meta.Namespace}, &route) if err != nil && apierrors.IsNotFound(err) { port := &routev1.RoutePort{ @@ -52,7 +52,7 @@ func (r *JenkinsBaseConfigurationReconciler) createRoute(meta metav1.ObjectMeta, return stackerr.WithStack(err) } - route.ObjectMeta.Labels = meta.Labels // make sure that user won't break service by hand + route.Labels = meta.Labels // make sure that user won't break service by hand route = resources.UpdateRoute(route, config) return stackerr.WithStack(r.UpdateResource(&route)) } diff --git a/pkg/configuration/base/serviceaccount.go b/pkg/configuration/base/serviceaccount.go index ea30d29f..bb53e057 100644 --- a/pkg/configuration/base/serviceaccount.go +++ b/pkg/configuration/base/serviceaccount.go @@ -17,7 +17,7 @@ import ( func (r *JenkinsBaseConfigurationReconciler) createServiceAccount(meta metav1.ObjectMeta) error { serviceAccount := &corev1.ServiceAccount{} err := r.Client.Get(context.TODO(), types.NamespacedName{Name: meta.Name, Namespace: meta.Namespace}, serviceAccount) - annotations := r.Configuration.Jenkins.Spec.ServiceAccount.Annotations + annotations := r.Jenkins.Spec.ServiceAccount.Annotations msg := fmt.Sprintf("createServiceAccount with annotations %v", annotations) r.logger.V(log.VDebug).Info(msg) if err != nil && apierrors.IsNotFound(err) { diff --git a/pkg/configuration/base/validate.go b/pkg/configuration/base/validate.go index 3f396690..7029b033 100644 --- a/pkg/configuration/base/validate.go +++ b/pkg/configuration/base/validate.go @@ -52,12 +52,12 @@ func (r *JenkinsBaseConfigurationReconciler) Validate(jenkins *v1alpha2.Jenkins) messages = append(messages, msg...) } - if msg, err := r.validateCustomization(r.Configuration.Jenkins.Spec.GroovyScripts.Customization, "spec.groovyScripts"); err != nil { + if msg, err := r.validateCustomization(r.Jenkins.Spec.GroovyScripts.Customization, "spec.groovyScripts"); err != nil { return nil, err } else if len(msg) > 0 { messages = append(messages, msg...) } - if msg, err := r.validateCustomization(r.Configuration.Jenkins.Spec.ConfigurationAsCode.Customization, "spec.configurationAsCode"); err != nil { + if msg, err := r.validateCustomization(r.Jenkins.Spec.ConfigurationAsCode.Customization, "spec.configurationAsCode"); err != nil { return nil, err } else if len(msg) > 0 { messages = append(messages, msg...) @@ -71,7 +71,7 @@ func (r *JenkinsBaseConfigurationReconciler) Validate(jenkins *v1alpha2.Jenkins) } func (r *JenkinsBaseConfigurationReconciler) validateJenkinsMasterContainerCommand() []string { - masterContainer := r.Configuration.GetJenkinsMasterContainer() + masterContainer := r.GetJenkinsMasterContainer() if masterContainer == nil { return []string{} } @@ -104,7 +104,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateJenkinsMasterContainerComma func (r *JenkinsBaseConfigurationReconciler) validateImagePullSecrets() ([]string, error) { var messages []string - for _, sr := range r.Configuration.Jenkins.Spec.Master.ImagePullSecrets { + for _, sr := range r.Jenkins.Spec.Master.ImagePullSecrets { msg, err := r.validateImagePullSecret(sr.Name) if err != nil { return nil, err @@ -119,7 +119,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateImagePullSecrets() ([]strin func (r *JenkinsBaseConfigurationReconciler) validateImagePullSecret(secretName string) ([]string, error) { var messages []string secret := &corev1.Secret{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, secret) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: r.Jenkins.Namespace}, secret) if err != nil && apierrors.IsNotFound(err) { messages = append(messages, fmt.Sprintf("Secret %s not found defined in spec.master.imagePullSecrets", secretName)) } else if err != nil && !apierrors.IsNotFound(err) { @@ -144,7 +144,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateImagePullSecret(secretName func (r *JenkinsBaseConfigurationReconciler) validateVolumes() ([]string, error) { var messages []string - for _, volume := range r.Configuration.Jenkins.Spec.Master.Volumes { + for _, volume := range r.Jenkins.Spec.Master.Volumes { switch { case volume.ConfigMap != nil: if msg, err := r.validateConfigMapVolume(volume); err != nil { @@ -174,7 +174,7 @@ func (r *JenkinsBaseConfigurationReconciler) validatePersistentVolumeClaim(volum var messages []string pvc := &corev1.PersistentVolumeClaim{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: volume.PersistentVolumeClaim.ClaimName, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, pvc) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: volume.PersistentVolumeClaim.ClaimName, Namespace: r.Jenkins.Namespace}, pvc) if err != nil && apierrors.IsNotFound(err) { messages = append(messages, fmt.Sprintf("PersistentVolumeClaim '%s' not found for volume '%v'", volume.PersistentVolumeClaim.ClaimName, volume)) } else if err != nil && !apierrors.IsNotFound(err) { @@ -191,7 +191,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateConfigMapVolume(volume core } configMap := &corev1.ConfigMap{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: volume.ConfigMap.Name, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, configMap) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: volume.ConfigMap.Name, Namespace: r.Jenkins.Namespace}, configMap) if err != nil && apierrors.IsNotFound(err) { messages = append(messages, fmt.Sprintf("ConfigMap '%s' not found for volume '%v'", volume.ConfigMap.Name, volume)) } else if err != nil && !apierrors.IsNotFound(err) { @@ -208,7 +208,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateSecretVolume(volume corev1. } secret := &corev1.Secret{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: volume.Secret.SecretName, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, secret) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: volume.Secret.SecretName, Namespace: r.Jenkins.Namespace}, secret) if err != nil && apierrors.IsNotFound(err) { messages = append(messages, fmt.Sprintf("Secret '%s' not found for volume '%v'", volume.Secret.SecretName, volume)) } else if err != nil && !apierrors.IsNotFound(err) { @@ -221,8 +221,8 @@ func (r *JenkinsBaseConfigurationReconciler) validateSecretVolume(volume corev1. func (r *JenkinsBaseConfigurationReconciler) validateReservedVolumes() []string { var messages []string - for _, baseVolume := range resources.GetJenkinsMasterPodBaseVolumes(r.Configuration.Jenkins) { - for _, volume := range r.Configuration.Jenkins.Spec.Master.Volumes { + for _, baseVolume := range resources.GetJenkinsMasterPodBaseVolumes(r.Jenkins) { + for _, volume := range r.Jenkins.Spec.Master.Volumes { if baseVolume.Name == volume.Name { messages = append(messages, fmt.Sprintf("Jenkins Master pod volume '%s' is reserved please choose different one", volume.Name)) } @@ -255,7 +255,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateContainer(container v1alpha func (r *JenkinsBaseConfigurationReconciler) validateContainerVolumeMounts(container v1alpha2.Container) []string { var messages []string - allVolumes := append(resources.GetJenkinsMasterPodBaseVolumes(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.Master.Volumes...) + allVolumes := append(resources.GetJenkinsMasterPodBaseVolumes(r.Jenkins), r.Jenkins.Spec.Master.Volumes...) for _, volumeMount := range container.VolumeMounts { if len(volumeMount.MountPath) == 0 { @@ -279,14 +279,14 @@ func (r *JenkinsBaseConfigurationReconciler) validateContainerVolumeMounts(conta func (r *JenkinsBaseConfigurationReconciler) validateJenkinsMasterPodEnvs() []string { var messages []string - baseEnvs := resources.GetJenkinsMasterContainerBaseEnvs(r.Configuration.Jenkins) + baseEnvs := resources.GetJenkinsMasterContainerBaseEnvs(r.Jenkins) baseEnvNames := map[string]string{} for _, env := range baseEnvs { baseEnvNames[env.Name] = env.Value } javaOpts := corev1.EnvVar{} - for _, userEnv := range r.Configuration.Jenkins.Spec.Master.Containers[0].Env { + for _, userEnv := range r.Jenkins.Spec.Master.Containers[0].Env { if userEnv.Name == constants.JavaOpsVariableName { javaOpts = userEnv } @@ -383,7 +383,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateCustomization(customization if len(customization.Secret.Name) > 0 { secret := &corev1.Secret{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: customization.Secret.Name, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, secret) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: customization.Secret.Name, Namespace: r.Jenkins.Namespace}, secret) if err != nil && apierrors.IsNotFound(err) { messages = append(messages, fmt.Sprintf("Secret '%s' configured in %s.secret.name not found", customization.Secret.Name, name)) } else if err != nil && !apierrors.IsNotFound(err) { @@ -398,7 +398,7 @@ func (r *JenkinsBaseConfigurationReconciler) validateCustomization(customization } configMap := &corev1.ConfigMap{} - err := r.Client.Get(context.TODO(), types.NamespacedName{Name: configMapRef.Name, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, configMap) + err := r.Client.Get(context.TODO(), types.NamespacedName{Name: configMapRef.Name, Namespace: r.Jenkins.Namespace}, configMap) if err != nil && apierrors.IsNotFound(err) { messages = append(messages, fmt.Sprintf("ConfigMap '%s' configured in %s.configurations[%d] not found", configMapRef.Name, name, index)) } else if err != nil && !apierrors.IsNotFound(err) { diff --git a/pkg/configuration/base/validate_test.go b/pkg/configuration/base/validate_test.go index ad4d7c63..a24e238a 100644 --- a/pkg/configuration/base/validate_test.go +++ b/pkg/configuration/base/validate_test.go @@ -137,7 +137,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T Spec: v1alpha2.JenkinsSpec{ Master: v1alpha2.JenkinsMaster{ ImagePullSecrets: []corev1.LocalObjectReference{ - {Name: secret.ObjectMeta.Name}, + {Name: secret.Name}, }, }, }, @@ -197,7 +197,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T Spec: v1alpha2.JenkinsSpec{ Master: v1alpha2.JenkinsMaster{ ImagePullSecrets: []corev1.LocalObjectReference{ - {Name: secret.ObjectMeta.Name}, + {Name: secret.Name}, }, }, }, @@ -233,7 +233,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T Spec: v1alpha2.JenkinsSpec{ Master: v1alpha2.JenkinsMaster{ ImagePullSecrets: []corev1.LocalObjectReference{ - {Name: secret.ObjectMeta.Name}, + {Name: secret.Name}, }, }, }, @@ -269,7 +269,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T Spec: v1alpha2.JenkinsSpec{ Master: v1alpha2.JenkinsMaster{ ImagePullSecrets: []corev1.LocalObjectReference{ - {Name: secret.ObjectMeta.Name}, + {Name: secret.Name}, }, }, }, @@ -305,7 +305,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T Spec: v1alpha2.JenkinsSpec{ Master: v1alpha2.JenkinsMaster{ ImagePullSecrets: []corev1.LocalObjectReference{ - {Name: secret.ObjectMeta.Name}, + {Name: secret.Name}, }, }, }, @@ -616,7 +616,8 @@ func TestValidateConfigMapVolume(t *testing.T) { assert.NoError(t, err) - assert.Equal(t, got, []string{"ConfigMap 'configmap-name' not found for volume '{volume-name {nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil &ConfigMapVolumeSource{LocalObjectReference:LocalObjectReference{Name:configmap-name,},Items:[]KeyToPath{},DefaultMode:nil,Optional:*false,} nil nil nil nil nil nil nil nil nil nil}}'"}) + assert.Len(t, got, 1) + assert.Contains(t, got[0], "ConfigMap 'configmap-name' not found for volume") }) } @@ -689,8 +690,8 @@ func TestValidateSecretVolume(t *testing.T) { got, err := baseReconcileLoop.validateSecretVolume(volume) assert.NoError(t, err) - - assert.Equal(t, got, []string{"Secret 'secret-name' not found for volume '{volume-name {nil nil nil nil nil &SecretVolumeSource{SecretName:secret-name,Items:[]KeyToPath{},DefaultMode:nil,Optional:*false,} nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil}}'"}) + assert.Len(t, got, 1) + assert.Contains(t, got[0], "Secret 'secret-name' not found for volume") }) } diff --git a/pkg/configuration/configuration.go b/pkg/configuration/configuration.go index 63352405..3c5debad 100644 --- a/pkg/configuration/configuration.go +++ b/pkg/configuration/configuration.go @@ -83,7 +83,7 @@ func (c *Configuration) GetJenkinsDeployment() (*appsv1.Deployment, error) { // IsJenkinsTerminating returns true if the Jenkins pod is terminating. func (c *Configuration) IsJenkinsTerminating(pod corev1.Pod) bool { - return pod.ObjectMeta.DeletionTimestamp != nil + return pod.DeletionTimestamp != nil } // CreateResource is creating kubernetes resource and references it to Jenkins CR @@ -193,7 +193,7 @@ func (c *Configuration) getJenkinsAPIUrl() (string, error) { var service corev1.Service err := c.Client.Get(context.TODO(), types.NamespacedName{ - Namespace: c.Jenkins.ObjectMeta.Namespace, + Namespace: c.Jenkins.Namespace, Name: resources.GetJenkinsHTTPServiceName(c.Jenkins), }, &service) @@ -230,7 +230,7 @@ func (c *Configuration) GetJenkinsClientFromSecret() (jenkinsclient.Jenkins, err return nil, err } credentialsSecret := &corev1.Secret{} - err = c.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(c.Jenkins), Namespace: c.Jenkins.ObjectMeta.Namespace}, credentialsSecret) + err = c.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(c.Jenkins), Namespace: c.Jenkins.Namespace}, credentialsSecret) if err != nil { return nil, stackerr.WithStack(err) } diff --git a/pkg/configuration/user/reconcile.go b/pkg/configuration/user/reconcile.go index 3fdadf7b..2fe3ac90 100644 --- a/pkg/configuration/user/reconcile.go +++ b/pkg/configuration/user/reconcile.go @@ -2,6 +2,7 @@ package user import ( "strings" + "time" "github.com/jenkinsci/kubernetes-operator/api/v1alpha2" jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client" @@ -45,7 +46,7 @@ func (r *reconcileUserConfiguration) ReconcileCasc() (reconcile.Result, error) { if err != nil { return reconcile.Result{}, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, nil } @@ -72,7 +73,7 @@ func (r *reconcileUserConfiguration) ReconcileOthers() (reconcile.Result, error) if err != nil { return reconcile.Result{}, err } - if result.Requeue { + if result.RequeueAfter > 0 { return result, nil } @@ -81,19 +82,19 @@ func (r *reconcileUserConfiguration) ReconcileOthers() (reconcile.Result, error) func (r *reconcileUserConfiguration) ensureSeedJobs() (reconcile.Result, error) { seedJobs := seedjobs.New(r.jenkinsClient, r.Configuration) - done, err := seedJobs.EnsureSeedJobs(r.Configuration.Jenkins) + done, err := seedJobs.EnsureSeedJobs(r.Jenkins) if err != nil { return reconcile.Result{}, err } if !done { - return reconcile.Result{Requeue: true}, nil + return reconcile.Result{RequeueAfter: time.Second * 30}, nil } return reconcile.Result{}, nil } func (r *reconcileUserConfiguration) ensureCasc(jenkinsClient jenkinsclient.Jenkins) (reconcile.Result, error) { - configurationAsCodeClient := casc.New(jenkinsClient, r.Client, r.Configuration.Jenkins) - requeue, err := configurationAsCodeClient.Ensure(r.Configuration.Jenkins) + configurationAsCodeClient := casc.New(jenkinsClient, r.Client, r.Jenkins) + requeue, err := configurationAsCodeClient.Ensure(r.Jenkins) if err != nil { return reconcile.Result{}, err } @@ -101,7 +102,7 @@ func (r *reconcileUserConfiguration) ensureCasc(jenkinsClient jenkinsclient.Jenk return reconcile.Result{Requeue: true}, nil } - groovyClient := groovy.New(jenkinsClient, r.Client, r.Configuration.Jenkins, "user-groovy", r.Configuration.Jenkins.Spec.GroovyScripts.Customization) + groovyClient := groovy.New(jenkinsClient, r.Client, r.Jenkins, "user-groovy", r.Jenkins.Spec.GroovyScripts.Customization) requeue, err = groovyClient.WaitForSecretSynchronization(resources.GroovyScriptsSecretVolumePath) if err != nil { return reconcile.Result{}, err diff --git a/pkg/configuration/user/seedjobs/seedjobs.go b/pkg/configuration/user/seedjobs/seedjobs.go index b95ae9cf..b06f23c2 100644 --- a/pkg/configuration/user/seedjobs/seedjobs.go +++ b/pkg/configuration/user/seedjobs/seedjobs.go @@ -311,14 +311,14 @@ func (s *seedJobs) ensureLabelsForSecrets(jenkins v1alpha2.Jenkins) error { requiredLabels[JenkinsCredentialTypeLabelName] = string(seedJob.JenkinsCredentialType) secret := &corev1.Secret{} - namespaceName := types.NamespacedName{Namespace: jenkins.ObjectMeta.Namespace, Name: seedJob.CredentialID} + namespaceName := types.NamespacedName{Namespace: jenkins.Namespace, Name: seedJob.CredentialID} err := s.Client.Get(context.TODO(), namespaceName, secret) if err != nil { return stackerr.WithStack(err) } if !resources.VerifyIfLabelsAreSet(secret, requiredLabels) { - secret.ObjectMeta.Labels = requiredLabels + secret.Labels = requiredLabels if err = s.Client.Update(context.TODO(), secret); err != nil { return stackerr.WithStack(err) } diff --git a/pkg/configuration/user/seedjobs/validate.go b/pkg/configuration/user/seedjobs/validate.go index bd5839a7..6e7f2e9a 100644 --- a/pkg/configuration/user/seedjobs/validate.go +++ b/pkg/configuration/user/seedjobs/validate.go @@ -166,21 +166,21 @@ func validateBasicSSHSecret(secret v1.Secret) []string { var messages []string username, exists := secret.Data[UsernameSecretKey] if !exists { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", UsernameSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", UsernameSecretKey, secret.Name)) } if len(username) == 0 { - messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", UsernameSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", UsernameSecretKey, secret.Name)) } privateKey, exists := secret.Data[PrivateKeySecretKey] if !exists { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PrivateKeySecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PrivateKeySecretKey, secret.Name)) } if len(string(privateKey)) == 0 { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PrivateKeySecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PrivateKeySecretKey, secret.Name)) } if err := validatePrivateKey(string(privateKey)); err != nil { - messages = append(messages, fmt.Sprintf("private key '%s' invalid in secret '%s': %s", PrivateKeySecretKey, secret.ObjectMeta.Name, err)) + messages = append(messages, fmt.Sprintf("private key '%s' invalid in secret '%s': %s", PrivateKeySecretKey, secret.Name, err)) } return messages @@ -190,17 +190,17 @@ func validateUsernamePasswordSecret(secret v1.Secret) []string { var messages []string username, exists := secret.Data[UsernameSecretKey] if !exists { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", UsernameSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", UsernameSecretKey, secret.Name)) } if len(username) == 0 { - messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", UsernameSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", UsernameSecretKey, secret.Name)) } password, exists := secret.Data[PasswordSecretKey] if !exists { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PasswordSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PasswordSecretKey, secret.Name)) } if len(password) == 0 { - messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", PasswordSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", PasswordSecretKey, secret.Name)) } return messages @@ -210,17 +210,17 @@ func validateGithubAppSecret(secret v1.Secret) []string { var messages []string appid, exists := secret.Data[AppIDSecretKey] if !exists { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", AppIDSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", AppIDSecretKey, secret.Name)) } if len(appid) == 0 { - messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", AppIDSecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", AppIDSecretKey, secret.Name)) } pkey, exists := secret.Data[PrivateKeySecretKey] if !exists { - messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PrivateKeySecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' not found in secret '%s'", PrivateKeySecretKey, secret.Name)) } if len(pkey) == 0 { - messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", PrivateKeySecretKey, secret.ObjectMeta.Name)) + messages = append(messages, fmt.Sprintf("required data '%s' is empty in secret '%s'", PrivateKeySecretKey, secret.Name)) } return messages diff --git a/pkg/groovy/groovy.go b/pkg/groovy/groovy.go index aad3e934..a56c624c 100644 --- a/pkg/groovy/groovy.go +++ b/pkg/groovy/groovy.go @@ -87,7 +87,7 @@ func (g *Groovy) WaitForSecretSynchronization(secretsPath string) (requeue bool, } secret := &corev1.Secret{} - err = g.k8sClient.Get(context.TODO(), types.NamespacedName{Name: g.customization.Secret.Name, Namespace: g.jenkins.ObjectMeta.Namespace}, secret) + err = g.k8sClient.Get(context.TODO(), types.NamespacedName{Name: g.customization.Secret.Name, Namespace: g.jenkins.Namespace}, secret) if err != nil { return true, errors.WithStack(err) } @@ -116,7 +116,7 @@ func (g *Groovy) Ensure(filter func(name string) bool, updateGroovyScript func(g if len(g.customization.Secret.Name) > 0 { err := g.k8sClient.Get(context.TODO(), types.NamespacedName{ Name: g.customization.Secret.Name, - Namespace: g.jenkins.ObjectMeta.Namespace, + Namespace: g.jenkins.Namespace, }, secret) if err != nil { return true, err @@ -125,7 +125,7 @@ func (g *Groovy) Ensure(filter func(name string) bool, updateGroovyScript func(g for _, configMapRef := range g.customization.Configurations { configMap := &corev1.ConfigMap{} - err := g.k8sClient.Get(context.TODO(), types.NamespacedName{Name: configMapRef.Name, Namespace: g.jenkins.ObjectMeta.Namespace}, configMap) + err := g.k8sClient.Get(context.TODO(), types.NamespacedName{Name: configMapRef.Name, Namespace: g.jenkins.Namespace}, configMap) if err != nil { return true, errors.WithStack(err) } diff --git a/test/e2e/configuration_test.go b/test/e2e/configuration_test.go index 680fd299..857c9054 100644 --- a/test/e2e/configuration_test.go +++ b/test/e2e/configuration_test.go @@ -125,7 +125,7 @@ func verifyJenkinsMasterPodAttributes(jenkins *v1alpha2.Jenkins) { defaultGracePeriod := constants.DefaultTerminationGracePeriodSeconds - assertMapContainsElementsFromAnotherMap(jenkins.Spec.Master.Annotations, jenkinsPod.ObjectMeta.Annotations) + assertMapContainsElementsFromAnotherMap(jenkins.Spec.Master.Annotations, jenkinsPod.Annotations) Expect(jenkinsPod.Spec.NodeSelector).Should(Equal(jenkins.Spec.Master.NodeSelector)) Expect(jenkinsPod.Spec.Containers[0].Name).Should(Equal(resources.JenkinsMasterContainerName)) diff --git a/test/e2e/jenkins_test.go b/test/e2e/jenkins_test.go index 858c43ed..e76897f1 100644 --- a/test/e2e/jenkins_test.go +++ b/test/e2e/jenkins_test.go @@ -175,7 +175,7 @@ func createJenkinsAPIClientFromServiceAccount(jenkins *v1alpha2.Jenkins, jenkins config := configuration.Configuration{Jenkins: jenkins, ClientSet: *clientSet, Config: Cfg} r := base.New(config, jenkinsclient.JenkinsAPIConnectionSettings{}) - token, _, err := r.Configuration.Exec(podName, resources.JenkinsMasterContainerName, []string{"cat", "/var/run/secrets/kubernetes.io/serviceaccount/token"}) + token, _, err := r.Exec(podName, resources.JenkinsMasterContainerName, []string{"cat", "/var/run/secrets/kubernetes.io/serviceaccount/token"}) if err != nil { return nil, err } @@ -255,7 +255,7 @@ func restartJenkinsMasterPod(jenkins *v1alpha2.Jenkins) { func getJenkinsService(jenkins *v1alpha2.Jenkins, serviceKind string) *corev1.Service { service := &corev1.Service{} - serviceName := constants.OperatorName + "-" + serviceKind + "-" + jenkins.ObjectMeta.Name + serviceName := constants.OperatorName + "-" + serviceKind + "-" + jenkins.Name Expect(K8sClient.Get(context.TODO(), client.ObjectKey{Name: serviceName, Namespace: jenkins.Namespace}, service)).Should(Succeed()) return service diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go index ffaf7dfa..86829d7e 100644 --- a/test/e2e/suite_test.go +++ b/test/e2e/suite_test.go @@ -1,9 +1,11 @@ package e2e import ( + "context" "flag" "path/filepath" "testing" + "time" "github.com/jenkinsci/kubernetes-operator/api/v1alpha2" controllers "github.com/jenkinsci/kubernetes-operator/internal/controller" @@ -21,9 +23,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/envtest" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" // +kubebuilder:scaffold:imports ) +var managerCancel context.CancelFunc + func init() { hostname = flag.String("jenkins-api-hostname", "", "Hostname or IP of Jenkins API. It can be service name, node IP or localhost.") port = flag.Int("jenkins-api-port", 0, "The port on which Jenkins API is running. Note: If you want to use nodePort don't set this setting and --jenkins-api-use-nodeport must be true.") @@ -60,6 +65,9 @@ var _ = BeforeSuite(func(done Done) { // setup manager k8sManager, err := ctrl.NewManager(Cfg, ctrl.Options{ Scheme: scheme.Scheme, + Metrics: metricsserver.Options{ + BindAddress: "0", // Disable metrics server to avoid port conflicts + }, }) Expect(err).NotTo(HaveOccurred()) @@ -90,18 +98,32 @@ var _ = BeforeSuite(func(done Done) { }).SetupWithManager(k8sManager) Expect(err).NotTo(HaveOccurred()) + ctx, cancel := context.WithCancel(context.Background()) go func() { - err = k8sManager.Start(ctrl.SetupSignalHandler()) + defer GinkgoRecover() + err = k8sManager.Start(ctx) Expect(err).NotTo(HaveOccurred()) }() + // Give the manager time to start up + time.Sleep(2 * time.Second) + K8sClient = k8sManager.GetClient() Expect(K8sClient).NotTo(BeNil()) + + // Store cancel function for cleanup in AfterSuite + managerCancel = cancel + + // Store cancel function for cleanup in AfterSuite + // The cancel function will be called in AfterSuite close(done) }, 60) var _ = AfterSuite(func() { By("tearing down the test environment") + if managerCancel != nil { + managerCancel() + } err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) })