From 3278995f3786fb4728afdd637cc8175be2159de2 Mon Sep 17 00:00:00 2001 From: Jan Schoone <6106846+jschoone@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:08:49 +0200 Subject: [PATCH 1/2] :sparkles: update images and go version (#203) feat: update images and go version Signed-off-by: Jan Schoone <6106846+jschoone@users.noreply.github.com> --- .builder-image-version.txt | 2 +- .github/actions/setup-go/action.yaml | 1 + .github/renovate/golang.json5 | 2 +- .github/workflows/pr-lint.yaml | 4 ++- .github/workflows/release.yaml | 7 +---- .github/workflows/schedule-scan-image.yaml | 2 +- .gitignore | 2 ++ .golangci.yml | 27 ++++++++++++------- Makefile | 4 +-- ...-k8s.io_openstackclusterstackreleases.yaml | 2 +- ...openstackclusterstackreleasetemplates.yaml | 2 +- ...k.x-k8s.io_openstacknodeimagereleases.yaml | 2 +- docs/quickstart.md | 2 +- go.mod | 7 ++--- images/builder/Dockerfile | 4 +-- images/cspo/Dockerfile | 2 +- 16 files changed, 40 insertions(+), 32 deletions(-) diff --git a/.builder-image-version.txt b/.builder-image-version.txt index d917d3e2..b1e80bb2 100644 --- a/.builder-image-version.txt +++ b/.builder-image-version.txt @@ -1 +1 @@ -0.1.2 +0.1.3 diff --git a/.github/actions/setup-go/action.yaml b/.github/actions/setup-go/action.yaml index 2b590dbe..011e261c 100644 --- a/.github/actions/setup-go/action.yaml +++ b/.github/actions/setup-go/action.yaml @@ -6,6 +6,7 @@ runs: - name: Install go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: + go-version: "1.22" go-version-file: "go.mod" cache: true cache-dependency-path: go.sum diff --git a/.github/renovate/golang.json5 b/.github/renovate/golang.json5 index a47cf951..bc80bd49 100644 --- a/.github/renovate/golang.json5 +++ b/.github/renovate/golang.json5 @@ -4,7 +4,7 @@ }, // https://docs.renovatebot.com/configuration-options/#constraints "constraints": { - "go": "1.21" + "go": "1.22" }, packageRules: [ { diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index 1a1a2922..5cc5355b 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -22,7 +22,7 @@ jobs: if: github.event_name != 'pull_request' || !github.event.pull_request.draft runs-on: ubuntu-latest container: - image: ghcr.io/sovereigncloudstack/cspo-builder:0.1.2 + image: ghcr.io/sovereigncloudstack/cspo-builder:0.1.3 credentials: username: ${{ github.actor }} password: ${{ secrets.github_token }} @@ -32,6 +32,8 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} + - uses: ./.github/actions/setup-go + - name: Fixup git permissions # https://github.com/actions/checkout/issues/766 shell: bash diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 59d1fae9..e57d9602 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -75,7 +75,6 @@ jobs: cache-from: type=gha, scope=${{ github.workflow }} cache-to: type=gha, mode=max, scope=${{ github.workflow }} - - name: Sign Container Images run: | cosign sign --yes ghcr.io/sovereigncloudstack/cspo@${{ steps.docker_build_release_cspo.outputs.digest }} @@ -140,11 +139,7 @@ jobs: fetch-depth: 0 - name: Install go - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 - with: - go-version-file: "go.mod" - cache: true - cache-dependency-path: go.sum + uses: ./.github/actions/setup-go - name: install kustomize run: | diff --git a/.github/workflows/schedule-scan-image.yaml b/.github/workflows/schedule-scan-image.yaml index c16113e3..e63bac58 100644 --- a/.github/workflows/schedule-scan-image.yaml +++ b/.github/workflows/schedule-scan-image.yaml @@ -9,7 +9,7 @@ jobs: name: Trivy runs-on: ubuntu-latest container: - image: ghcr.io/sovereigncloudstack/cspo-builder:0.1.2 + image: ghcr.io/sovereigncloudstack/cspo-builder:0.1.3 credentials: username: ${{ github.actor }} password: ${{ secrets.github_token }} diff --git a/.gitignore b/.gitignore index 1c1fe519..8f38f1ea 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,5 @@ tmp_* .cspotemplate.yaml .secret.yaml .release + +.config diff --git a/.golangci.yml b/.golangci.yml index b10886a2..6d0ecfc3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -7,12 +7,12 @@ linters: - bodyclose - containedctx - contextcheck + - copyloopvar - durationcheck - errchkjson - errname - errorlint - exhaustive - - exportloopref - forcetypeassert - gci # - goconst @@ -86,10 +86,6 @@ linters-settings: allow-unused: false allow-leading-space: false require-specific: true - staticcheck: - go: "1.21" - stylecheck: - go: "1.21" checks: ["all", "-ST1006"] dot-import-whitelist: - "github.com/onsi/gomega" @@ -101,6 +97,9 @@ linters-settings: - performance - experimental - opinionated + settings: + hugeParam: + sizeThreshold: 120 revive: enable-all-rules: true rules: @@ -141,7 +140,14 @@ linters-settings: severity: warning disabled: false arguments: - - [ "call-chain", "loop", "method-call", "recover", "immediate-recover", "return"] # yamllint disable-line rule:line-length + - [ + "call-chain", + "loop", + "method-call", + "recover", + "immediate-recover", + "return", + ] # yamllint disable-line rule:line-length # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#exported - name: exported severity: warning @@ -224,7 +230,7 @@ linters-settings: - name: struct-tag disabled: true unused: - go: "1.21" + go: "1.22" usestdlibvars: # Suggest the use of http.MethodXX. # Default: true @@ -285,10 +291,11 @@ issues: - linters: - wrapcheck path: _test\.go + exclude-dirs: + - vendor$ + run: timeout: 10m - go: "1.21" + go: "1.22" allow-parallel-runners: true modules-download-mode: vendor - skip-dirs: - - vendor$ diff --git a/Makefile b/Makefile index d12fb23f..9996c32a 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.28.0 CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/controller-gen) controller-gen: $(CONTROLLER_GEN) ## Build a local copy of controller-gen $(CONTROLLER_GEN): # Build controller-gen from tools folder. - go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 + go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.16.2 KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/kustomize) kustomize: $(KUSTOMIZE) ## Build a local copy of kustomize @@ -338,7 +338,7 @@ ifeq ($(BUILD_IN_CONTAINER),true) else go version golangci-lint version - golangci-lint run -v --out-format=github-actions + golangci-lint run -v --out-format=colored-line-number endif .PHONY: lint-yaml diff --git a/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleases.yaml b/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleases.yaml index f47419ec..1462bf93 100644 --- a/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleases.yaml +++ b/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleases.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.16.2 name: openstackclusterstackreleases.infrastructure.clusterstack.x-k8s.io spec: group: infrastructure.clusterstack.x-k8s.io diff --git a/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleasetemplates.yaml b/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleasetemplates.yaml index 653e2108..5bb22e46 100644 --- a/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleasetemplates.yaml +++ b/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstackclusterstackreleasetemplates.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.16.2 name: openstackclusterstackreleasetemplates.infrastructure.clusterstack.x-k8s.io spec: group: infrastructure.clusterstack.x-k8s.io diff --git a/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstacknodeimagereleases.yaml b/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstacknodeimagereleases.yaml index d341dd72..e7e24989 100644 --- a/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstacknodeimagereleases.yaml +++ b/config/crd/bases/infrastructure.clusterstack.x-k8s.io_openstacknodeimagereleases.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.16.2 name: openstacknodeimagereleases.infrastructure.clusterstack.x-k8s.io spec: group: infrastructure.clusterstack.x-k8s.io diff --git a/docs/quickstart.md b/docs/quickstart.md index a7ccb276..56e52215 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -2,4 +2,4 @@ This document has been moved. -You can find the current version of the quickstart guide [here](https://github.com/SovereignCloudStack/cluster-stacks/blob/main/providers/openstack/README.md). +You can find the current version of the quickstart guide [here](https://docs.scs.community/docs/container/components/cluster-stacks/components/cluster-stack-provider-openstack/docs/quickstart). diff --git a/go.mod b/go.mod index 9c8e5bd8..825a2619 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,11 @@ module github.com/SovereignCloudStack/cluster-stack-provider-openstack -go 1.21.6 +go 1.22 -toolchain go1.22.1 +toolchain go1.23.0 require ( github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.5 - github.com/google/go-github/v52 v52.0.0 github.com/gophercloud/gophercloud/v2 v2.0.0-beta.2 github.com/gophercloud/utils/v2 v2.0.0-20240305212012-b57aefba4cdb github.com/onsi/ginkgo/v2 v2.17.1 @@ -22,6 +21,8 @@ require ( sigs.k8s.io/yaml v1.4.0 ) +require github.com/google/go-github/v52 v52.0.0 + require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/beorn7/perks v1.0.1 // indirect diff --git a/images/builder/Dockerfile b/images/builder/Dockerfile index ce39a1ca..fc6a1325 100644 --- a/images/builder/Dockerfile +++ b/images/builder/Dockerfile @@ -30,7 +30,7 @@ ENV GOLANGCI_VERSION="v1.59.1" # update: datasource=github-tags depName=kubernetes-sigs/kind ENV KIND_VERSION="v0.23.0" # update: datasource=github-tags depName=kubernetes/kubernetes -ARG KUBECTL_VERSION="v1.27.3" +ARG KUBECTL_VERSION="v1.31.0" # update: datasource=github-tags depName=kubernetes-sigs/kustomize extractVersion=^kustomize\/v(?.+)$ ENV KUSTOMIZE_VERSION="v5.3.0" # update: datasource=github-tags depName=aquasecurity/trivy @@ -54,7 +54,7 @@ RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/in ############################ # CSPO Build Image Base # ############################ -FROM docker.io/library/golang:1.21.8-bullseye +FROM docker.io/library/golang:1.23.0-bullseye # update: datasource=github-tags depName=adrienverge/yamllint versioning=semver ENV YAMLLINT_VERSION="v1.35.1" diff --git a/images/cspo/Dockerfile b/images/cspo/Dockerfile index 993a4b90..783e952f 100644 --- a/images/cspo/Dockerfile +++ b/images/cspo/Dockerfile @@ -13,7 +13,7 @@ # limitations under the License. # Build the manager binary -FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.21.8-bullseye as build +FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.23.0-bullseye as build ARG TARGETOS TARGETARCH COPY . /src/cluster-stack-provider-openstack From c7a92680580d34da0d1744d694d11d267a3681b4 Mon Sep 17 00:00:00 2001 From: Roman Hros Date: Tue, 10 Sep 2024 13:01:17 +0200 Subject: [PATCH 2/2] :sparkles: Add oci as assets client (#198) * Upgrade CSO dependency to v0.1.0-alpha.6 Signed-off-by: Roman Hros * Fix quickstart link Signed-off-by: Roman Hros * Add oci as assets client Signed-off-by: Roman Hros * Try registry.dnation.cloud to fix tests Signed-off-by: Roman Hros * fix(config): use cspo-cluster-stack-variables Signed-off-by: Jan Schoone <6106846+jschoone@users.noreply.github.com> * feat(envrc): add Resource Sets to sample environment Signed-off-by: Jan Schoone <6106846+jschoone@users.noreply.github.com> * Add oci username/password to the cspo config Signed-off-by: Roman Hros * feat(tilt): update CAPO version Signed-off-by: Jan Schoone <6106846+jschoone@users.noreply.github.com> * OCI_USERNAME and OCI_PASSWORD are not required Signed-off-by: Roman Hros * Upgrade CSO dependency to v0.1.0-alpha.7 Signed-off-by: Roman Hros * Disable oci integration tests for the GitHub CI Signed-off-by: Roman Hros --------- Signed-off-by: Roman Hros Signed-off-by: Jan Schoone <6106846+jschoone@users.noreply.github.com> Co-authored-by: Jan Schoone <6106846+jschoone@users.noreply.github.com> --- .envrc.sample | 2 + .github/workflows/test.yaml | 2 + Makefile | 14 +- Tiltfile | 4 +- api/v1alpha1/conditions_const.go | 8 +- cmd/main.go | 27 +- config/manager/credentials.yaml | 5 + config/manager/manager.yaml | 25 + config/rbac/role.yaml | 27 +- docs/develop.md | 2 +- ...ackclusterstackrelease-controller.plantuml | 2 +- ...penstackclusterstackrelease-controller.png | Bin 87002 -> 101057 bytes docs/quickstart.md | 2 +- go.mod | 95 +- go.sum | 289 +- ...openstackclusterstackrelease_controller.go | 38 +- ...tackclusterstackrelease_controller_test.go | 45 +- internal/test/helpers/envtest.go | 14 +- .../github/integration_suite_test.go | 4 +- .../integration/oci/integration_suite_test.go | 64 + .../test/integration/oci/integration_test.go | 109 + .../openstack/controller_suite_test.go | 3 +- local_cso.yaml | 612 +- tilt-settings.yaml.example | 4 +- .../pkg/assetsclient/client.go | 33 + .../pkg/assetsclient/fake/client.go | 60 + .../github/client.go} | 83 +- .../github}/credentials.go | 4 +- .../pkg/assetsclient/mocks/Client.go | 68 + .../client => assetsclient}/mocks/Factory.go | 12 +- .../pkg/assetsclient/mocks/assetsFactory.go | 37 + .../pkg/assetsclient/oci/client.go | 99 + .../pkg/assetsclient/oci/credentials.go | 68 + .../pkg/clusterstack/clusterstack.go | 7 + .../pkg/github/client/fake/github_client.go | 69 - .../pkg/github/client/mocks/Client.go | 113 - .../pkg/github/client/mocks/gfactory.go | 23 - .../pkg/release/release.go | 37 +- vendor/github.com/cespare/xxhash/v2/README.md | 2 + vendor/github.com/cespare/xxhash/v2/xxhash.go | 29 +- .../cespare/xxhash/v2/xxhash_asm.go | 2 +- .../cespare/xxhash/v2/xxhash_other.go | 2 +- .../cespare/xxhash/v2/xxhash_safe.go | 2 +- .../cespare/xxhash/v2/xxhash_unsafe.go | 2 +- .../cloudflare/circl/ecc/goldilocks/twist.go | 2 +- .../cloudflare/circl/internal/sha3/keccakf.go | 12 +- .../cloudflare/circl/internal/sha3/sha3.go | 11 +- .../cloudflare/circl/internal/sha3/shake.go | 40 + .../cloudflare/circl/math/primes.go | 34 + .../cloudflare/circl/sign/ed25519/ed25519.go | 2 +- .../emicklei/go-restful/v3/CHANGES.md | 20 +- .../emicklei/go-restful/v3/README.md | 4 +- .../emicklei/go-restful/v3/compress.go | 10 + .../emicklei/go-restful/v3/curly.go | 48 +- .../go-restful/v3/entity_accessors.go | 7 + .../github.com/emicklei/go-restful/v3/json.go | 11 - .../emicklei/go-restful/v3/jsoniter.go | 12 - .../emicklei/go-restful/v3/jsr311.go | 2 +- .../github.com/evanphx/json-patch/README.md | 4 +- vendor/github.com/evanphx/json-patch/patch.go | 46 +- .../json-patch/v5/internal/json/decode.go | 1385 +++ .../json-patch/v5/internal/json/encode.go | 1486 +++ .../json-patch/v5/internal/json/fold.go | 141 + .../json-patch/v5/internal/json/fuzz.go | 42 + .../json-patch/v5/internal/json/indent.go | 143 + .../json-patch/v5/internal/json/scanner.go | 610 ++ .../json-patch/v5/internal/json/stream.go | 495 + .../json-patch/v5/internal/json/tables.go | 218 + .../json-patch/v5/internal/json/tags.go | 38 + .../github.com/evanphx/json-patch/v5/merge.go | 110 +- .../github.com/evanphx/json-patch/v5/patch.go | 389 +- .../github.com/fsnotify/fsnotify/.cirrus.yml | 13 + .../github.com/fsnotify/fsnotify/.gitignore | 1 + .../github.com/fsnotify/fsnotify/CHANGELOG.md | 83 +- vendor/github.com/fsnotify/fsnotify/README.md | 81 +- .../fsnotify/fsnotify/backend_fen.go | 552 +- .../fsnotify/fsnotify/backend_inotify.go | 377 +- .../fsnotify/fsnotify/backend_kqueue.go | 295 +- .../fsnotify/fsnotify/backend_other.go | 205 +- .../fsnotify/fsnotify/backend_windows.go | 247 +- .../github.com/fsnotify/fsnotify/fsnotify.go | 91 +- vendor/github.com/fsnotify/fsnotify/mkdoc.zsh | 125 +- vendor/github.com/go-logr/logr/README.md | 1 + vendor/github.com/go-logr/logr/funcr/funcr.go | 169 +- vendor/github.com/go-logr/logr/slogr/slogr.go | 61 + vendor/github.com/go-logr/zapr/.golangci.yaml | 20 + vendor/github.com/go-logr/zapr/README.md | 39 +- vendor/github.com/go-logr/zapr/slogzapr.go | 183 + vendor/github.com/go-logr/zapr/zapr.go | 15 +- vendor/github.com/go-logr/zapr/zapr_noslog.go | 34 + vendor/github.com/go-logr/zapr/zapr_slog.go | 48 + vendor/github.com/go-openapi/swag/util.go | 16 +- .../go-task/slim-sprig/{ => v3}/.editorconfig | 0 .../slim-sprig/{ => v3}/.gitattributes | 0 .../go-task/slim-sprig/{ => v3}/.gitignore | 0 .../go-task/slim-sprig/{ => v3}/CHANGELOG.md | 19 + .../go-task/slim-sprig/{ => v3}/LICENSE.txt | 0 .../go-task/slim-sprig/{ => v3}/README.md | 2 +- .../go-task/slim-sprig/{ => v3}/Taskfile.yml | 2 +- .../go-task/slim-sprig/{ => v3}/crypto.go | 0 .../go-task/slim-sprig/{ => v3}/date.go | 0 .../go-task/slim-sprig/{ => v3}/defaults.go | 0 .../go-task/slim-sprig/{ => v3}/dict.go | 0 .../go-task/slim-sprig/{ => v3}/doc.go | 0 .../go-task/slim-sprig/{ => v3}/functions.go | 0 .../go-task/slim-sprig/{ => v3}/list.go | 0 .../go-task/slim-sprig/{ => v3}/network.go | 0 .../go-task/slim-sprig/{ => v3}/numeric.go | 0 .../go-task/slim-sprig/{ => v3}/reflect.go | 0 .../go-task/slim-sprig/{ => v3}/regex.go | 0 .../go-task/slim-sprig/{ => v3}/strings.go | 0 .../go-task/slim-sprig/{ => v3}/url.go | 0 .../github.com/golang/protobuf/ptypes/any.go | 7 +- .../github.com/google/pprof/profile/encode.go | 88 +- .../github.com/google/pprof/profile/filter.go | 4 + .../pprof/profile/legacy_java_profile.go | 4 +- .../google/pprof/profile/legacy_profile.go | 31 +- .../github.com/google/pprof/profile/merge.go | 282 +- .../google/pprof/profile/profile.go | 77 +- .../github.com/google/pprof/profile/proto.go | 19 +- .../github.com/google/pprof/profile/prune.go | 26 +- vendor/github.com/google/uuid/CHANGELOG.md | 31 + vendor/github.com/google/uuid/CONTRIBUTING.md | 2 +- vendor/github.com/google/uuid/hash.go | 6 + vendor/github.com/google/uuid/time.go | 21 +- vendor/github.com/google/uuid/uuid.go | 79 +- vendor/github.com/google/uuid/version6.go | 56 + vendor/github.com/google/uuid/version7.go | 104 + .../golang_protobuf_extensions/NOTICE | 1 - .../pbutil/.gitignore | 1 - .../pbutil/Makefile | 7 - .../pbutil/decode.go | 75 - .../pbutil/encode.go | 46 - vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md | 56 + .../github.com/onsi/ginkgo/v2/CONTRIBUTING.md | 10 +- vendor/github.com/onsi/ginkgo/v2/Makefile | 11 + .../ginkgo/v2/ginkgo/build/build_command.go | 15 +- .../v2/ginkgo/generators/bootstrap_command.go | 2 +- .../v2/ginkgo/generators/generate_command.go | 3 +- .../onsi/ginkgo/v2/ginkgo/internal/compile.go | 14 +- .../ginkgo/internal/profiles_and_reports.go | 2 + .../ginkgo/v2/ginkgo/watch/package_hash.go | 9 + .../onsi/ginkgo/v2/internal/suite.go | 7 +- .../ginkgo/v2/reporters/default_reporter.go | 16 +- .../onsi/ginkgo/v2/reporters/junit_report.go | 2 + vendor/github.com/onsi/ginkgo/v2/table_dsl.go | 8 +- .../github.com/onsi/ginkgo/v2/types/config.go | 18 +- .../onsi/ginkgo/v2/types/label_filter.go | 229 +- .../onsi/ginkgo/v2/types/version.go | 2 +- vendor/github.com/onsi/gomega/CHANGELOG.md | 36 + vendor/github.com/onsi/gomega/gomega_dsl.go | 6 +- vendor/github.com/onsi/gomega/matchers.go | 15 +- .../gomega/matchers/have_exact_elements.go | 7 +- .../onsi/gomega/matchers/receive_matcher.go | 70 +- .../bipartitegraph/bipartitegraphmatching.go | 7 + .../opencontainers/go-digest/.mailmap | 4 + .../opencontainers/go-digest/.pullapprove.yml | 28 + .../opencontainers/go-digest/.travis.yml | 5 + .../opencontainers/go-digest/CONTRIBUTING.md | 72 + .../opencontainers/go-digest}/LICENSE | 18 +- .../opencontainers/go-digest/LICENSE.docs | 425 + .../opencontainers/go-digest/MAINTAINERS | 5 + .../opencontainers/go-digest/README.md | 96 + .../opencontainers/go-digest/algorithm.go | 193 + .../opencontainers/go-digest/digest.go | 157 + .../opencontainers/go-digest/digester.go | 40 + .../opencontainers/go-digest/doc.go | 62 + .../opencontainers/go-digest/verifiers.go | 46 + .../image-spec}/LICENSE | 14 +- .../image-spec/specs-go/v1/annotations.go | 62 + .../image-spec/specs-go/v1/config.go | 111 + .../image-spec/specs-go/v1/descriptor.go | 80 + .../image-spec/specs-go/v1/index.go | 38 + .../image-spec/specs-go/v1/layout.go | 32 + .../image-spec/specs-go/v1/manifest.go | 41 + .../image-spec/specs-go/v1/mediatype.go | 85 + .../image-spec/specs-go/version.go | 32 + .../image-spec/specs-go/versioned.go | 23 + .../client_golang/prometheus/histogram.go | 56 +- .../client_golang/prometheus/labels.go | 2 + .../prometheus/process_collector_other.go | 4 +- .../prometheus/process_collector_wasip1.go} | 20 +- .../prometheus/client_model/go/metrics.pb.go | 198 +- .../prometheus/common/expfmt/decode.go | 31 +- .../prometheus/common/expfmt/encode.go | 87 +- .../prometheus/common/expfmt/expfmt.go | 154 +- .../common/expfmt/openmetrics_create.go | 283 +- .../prometheus/common/expfmt/text_create.go | 118 +- .../prometheus/common/expfmt/text_parse.go | 8 +- .../bitbucket.org/ww/goautoneg/README.txt | 67 - .../bitbucket.org/ww/goautoneg/autoneg.go | 160 - .../prometheus/common/model/alert.go | 31 +- .../prometheus/common/model/labels.go | 22 +- .../prometheus/common/model/labelset.go | 11 - .../common/model/labelset_string.go | 45 + .../common/model/labelset_string_go120.go | 39 + .../prometheus/common/model/metadata.go | 28 + .../prometheus/common/model/metric.go | 369 +- .../prometheus/common/model/signature.go | 6 +- .../prometheus/common/model/silence.go | 2 +- .../prometheus/common/model/value.go | 16 +- .../prometheus/common/model/value_float.go | 14 +- .../prometheus/procfs/.golangci.yml | 7 + .../prometheus/procfs/MAINTAINERS.md | 3 +- .../prometheus/procfs/Makefile.common | 26 +- vendor/github.com/prometheus/procfs/arp.go | 6 +- .../github.com/prometheus/procfs/buddyinfo.go | 6 +- .../github.com/prometheus/procfs/cpuinfo.go | 4 +- vendor/github.com/prometheus/procfs/crypto.go | 6 +- .../prometheus/procfs/fs_statfs_notype.go | 4 +- .../prometheus/procfs/fs_statfs_type.go | 4 +- .../github.com/prometheus/procfs/fscache.go | 4 +- vendor/github.com/prometheus/procfs/ipvs.go | 6 +- .../github.com/prometheus/procfs/loadavg.go | 2 +- vendor/github.com/prometheus/procfs/mdstat.go | 60 +- .../github.com/prometheus/procfs/meminfo.go | 220 +- .../github.com/prometheus/procfs/mountinfo.go | 2 +- .../prometheus/procfs/mountstats.go | 92 +- .../prometheus/procfs/net_conntrackstat.go | 4 +- .../prometheus/procfs/net_ip_socket.go | 46 +- .../prometheus/procfs/net_sockstat.go | 4 +- .../prometheus/procfs/net_softnet.go | 2 +- .../prometheus/procfs/net_tls_stat.go | 119 + .../github.com/prometheus/procfs/net_unix.go | 14 +- .../prometheus/procfs/net_wireless.go | 22 +- vendor/github.com/prometheus/procfs/proc.go | 8 +- .../prometheus/procfs/proc_fdinfo.go | 8 +- .../prometheus/procfs/proc_limits.go | 2 +- .../github.com/prometheus/procfs/proc_maps.go | 20 +- .../github.com/prometheus/procfs/proc_ns.go | 4 +- .../github.com/prometheus/procfs/proc_psi.go | 2 +- .../prometheus/procfs/proc_smaps.go | 2 +- .../github.com/prometheus/procfs/proc_stat.go | 7 + .../prometheus/procfs/proc_status.go | 50 +- .../github.com/prometheus/procfs/proc_sys.go | 2 +- .../github.com/prometheus/procfs/softirqs.go | 22 +- vendor/github.com/prometheus/procfs/stat.go | 22 +- vendor/github.com/prometheus/procfs/swaps.go | 6 +- vendor/github.com/prometheus/procfs/thread.go | 2 +- .../github.com/prometheus/procfs/zoneinfo.go | 4 +- vendor/go.uber.org/zap/.golangci.yml | 77 + vendor/go.uber.org/zap/.readme.tmpl | 10 +- vendor/go.uber.org/zap/CHANGELOG.md | 273 +- .../go.uber.org/zap/{LICENSE.txt => LICENSE} | 0 vendor/go.uber.org/zap/Makefile | 82 +- vendor/go.uber.org/zap/README.md | 66 +- vendor/go.uber.org/zap/array.go | 127 + vendor/go.uber.org/zap/array_go118.go | 156 - vendor/go.uber.org/zap/buffer/buffer.go | 5 + vendor/go.uber.org/zap/error.go | 5 +- vendor/go.uber.org/zap/field.go | 27 +- vendor/go.uber.org/zap/http_handler.go | 19 +- .../stacktrace/stack.go} | 71 +- vendor/go.uber.org/zap/logger.go | 81 +- vendor/go.uber.org/zap/options.go | 15 + vendor/go.uber.org/zap/sink.go | 5 +- vendor/go.uber.org/zap/sugar.go | 39 + vendor/go.uber.org/zap/writer.go | 12 +- .../zap/zapcore/console_encoder.go | 2 +- vendor/go.uber.org/zap/zapcore/core.go | 6 +- vendor/go.uber.org/zap/zapcore/encoder.go | 15 + vendor/go.uber.org/zap/zapcore/entry.go | 4 +- vendor/go.uber.org/zap/zapcore/error.go | 5 +- vendor/go.uber.org/zap/zapcore/field.go | 2 +- .../go.uber.org/zap/zapcore/json_encoder.go | 145 +- vendor/go.uber.org/zap/zapcore/lazy_with.go | 54 + vendor/golang.org/x/crypto/cast5/cast5.go | 2 +- vendor/golang.org/x/crypto/hkdf/hkdf.go | 2 +- vendor/golang.org/x/crypto/sha3/doc.go | 2 +- vendor/golang.org/x/crypto/sha3/hashes.go | 42 +- .../x/crypto/sha3/hashes_generic.go | 27 - .../golang.org/x/crypto/sha3/hashes_noasm.go | 23 + vendor/golang.org/x/crypto/sha3/register.go | 18 - vendor/golang.org/x/crypto/sha3/sha3.go | 62 +- vendor/golang.org/x/crypto/sha3/sha3_s390x.go | 67 +- vendor/golang.org/x/crypto/sha3/shake.go | 16 +- .../golang.org/x/crypto/sha3/shake_generic.go | 19 - .../golang.org/x/crypto/sha3/shake_noasm.go | 15 + vendor/golang.org/x/crypto/sha3/xor.go | 45 +- .../golang.org/x/crypto/sha3/xor_generic.go | 28 - .../golang.org/x/crypto/sha3/xor_unaligned.go | 66 - vendor/golang.org/x/mod/modfile/read.go | 2 +- vendor/golang.org/x/mod/modfile/rule.go | 113 +- vendor/golang.org/x/mod/modfile/work.go | 52 +- vendor/golang.org/x/mod/module/module.go | 2 + vendor/golang.org/x/net/html/doc.go | 2 +- .../golang.org/x/net/http/httpguts/httplex.go | 13 +- vendor/golang.org/x/net/http2/frame.go | 40 +- vendor/golang.org/x/net/http2/http2.go | 19 +- vendor/golang.org/x/net/http2/pipe.go | 11 +- vendor/golang.org/x/net/http2/server.go | 116 +- vendor/golang.org/x/net/http2/timer.go | 20 + vendor/golang.org/x/net/http2/transport.go | 234 +- .../x/net/http2/writesched_priority.go | 4 +- .../x/oauth2/internal/client_appengine.go | 13 - .../golang.org/x/oauth2/internal/transport.go | 5 - vendor/golang.org/x/oauth2/oauth2.go | 2 +- vendor/golang.org/x/sync/LICENSE | 27 + vendor/golang.org/x/sync/PATENTS | 22 + vendor/golang.org/x/sync/errgroup/errgroup.go | 135 + vendor/golang.org/x/sync/errgroup/go120.go | 13 + .../golang.org/x/sync/errgroup/pre_go120.go | 14 + .../golang.org/x/sync/semaphore/semaphore.go | 160 + vendor/golang.org/x/sys/cpu/cpu.go | 1 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 10 + vendor/golang.org/x/sys/cpu/cpu_arm64.s | 8 + vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go | 1 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 5 + vendor/golang.org/x/sys/unix/asm_zos_s390x.s | 665 +- vendor/golang.org/x/sys/unix/bpxsvc_zos.go | 657 ++ vendor/golang.org/x/sys/unix/bpxsvc_zos.s | 192 + vendor/golang.org/x/sys/unix/epoll_zos.go | 220 - vendor/golang.org/x/sys/unix/fstatfs_zos.go | 163 - vendor/golang.org/x/sys/unix/mkerrors.sh | 2 + vendor/golang.org/x/sys/unix/mmap_nomremap.go | 2 +- vendor/golang.org/x/sys/unix/mremap.go | 5 + vendor/golang.org/x/sys/unix/pagesize_unix.go | 2 +- .../x/sys/unix/readdirent_getdirentries.go | 2 +- vendor/golang.org/x/sys/unix/sockcmsg_zos.go | 58 + .../golang.org/x/sys/unix/symaddr_zos_s390x.s | 75 + .../golang.org/x/sys/unix/syscall_darwin.go | 12 + vendor/golang.org/x/sys/unix/syscall_unix.go | 9 + .../x/sys/unix/syscall_zos_s390x.go | 1509 ++- vendor/golang.org/x/sys/unix/sysvshm_unix.go | 2 +- .../x/sys/unix/sysvshm_unix_other.go | 2 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 29 +- .../x/sys/unix/zerrors_linux_386.go | 1 + .../x/sys/unix/zerrors_linux_amd64.go | 1 + .../x/sys/unix/zerrors_linux_arm64.go | 1 + .../x/sys/unix/zerrors_zos_s390x.go | 233 +- .../x/sys/unix/zsymaddr_zos_s390x.s | 364 + .../x/sys/unix/zsyscall_darwin_amd64.go | 33 + .../x/sys/unix/zsyscall_darwin_amd64.s | 10 + .../x/sys/unix/zsyscall_darwin_arm64.go | 33 + .../x/sys/unix/zsyscall_darwin_arm64.s | 10 + .../x/sys/unix/zsyscall_zos_s390x.go | 3113 +++++- .../x/sys/unix/zsysnum_linux_386.go | 5 + .../x/sys/unix/zsysnum_linux_amd64.go | 5 + .../x/sys/unix/zsysnum_linux_arm.go | 5 + .../x/sys/unix/zsysnum_linux_arm64.go | 5 + .../x/sys/unix/zsysnum_linux_loong64.go | 5 + .../x/sys/unix/zsysnum_linux_mips.go | 5 + .../x/sys/unix/zsysnum_linux_mips64.go | 5 + .../x/sys/unix/zsysnum_linux_mips64le.go | 5 + .../x/sys/unix/zsysnum_linux_mipsle.go | 5 + .../x/sys/unix/zsysnum_linux_ppc.go | 5 + .../x/sys/unix/zsysnum_linux_ppc64.go | 5 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 5 + .../x/sys/unix/zsysnum_linux_riscv64.go | 5 + .../x/sys/unix/zsysnum_linux_s390x.go | 5 + .../x/sys/unix/zsysnum_linux_sparc64.go | 5 + .../x/sys/unix/zsysnum_zos_s390x.go | 5507 +++++------ vendor/golang.org/x/sys/unix/ztypes_linux.go | 59 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 8 - .../x/sys/unix/ztypes_linux_amd64.go | 9 - .../golang.org/x/sys/unix/ztypes_linux_arm.go | 9 - .../x/sys/unix/ztypes_linux_arm64.go | 9 - .../x/sys/unix/ztypes_linux_loong64.go | 9 - .../x/sys/unix/ztypes_linux_mips.go | 9 - .../x/sys/unix/ztypes_linux_mips64.go | 9 - .../x/sys/unix/ztypes_linux_mips64le.go | 9 - .../x/sys/unix/ztypes_linux_mipsle.go | 9 - .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 9 - .../x/sys/unix/ztypes_linux_ppc64.go | 9 - .../x/sys/unix/ztypes_linux_ppc64le.go | 9 - .../x/sys/unix/ztypes_linux_riscv64.go | 9 - .../x/sys/unix/ztypes_linux_s390x.go | 9 - .../x/sys/unix/ztypes_linux_sparc64.go | 9 - .../golang.org/x/sys/unix/ztypes_zos_s390x.go | 146 +- vendor/golang.org/x/sys/windows/aliases.go | 2 +- vendor/golang.org/x/sys/windows/empty.s | 8 - .../x/sys/windows/security_windows.go | 25 +- .../x/sys/windows/syscall_windows.go | 82 + .../golang.org/x/sys/windows/types_windows.go | 24 + .../x/sys/windows/zsyscall_windows.go | 144 +- vendor/golang.org/x/time/rate/rate.go | 2 + .../appengine/internal/api.go | 678 -- .../appengine/internal/api_classic.go | 169 - .../appengine/internal/api_common.go | 123 - .../appengine/internal/app_id.go | 28 - .../appengine/internal/base/api_base.pb.go | 308 - .../appengine/internal/base/api_base.proto | 33 - .../internal/datastore/datastore_v3.pb.go | 4367 --------- .../internal/datastore/datastore_v3.proto | 551 -- .../appengine/internal/identity.go | 55 - .../appengine/internal/identity_classic.go | 61 - .../appengine/internal/identity_flex.go | 11 - .../appengine/internal/identity_vm.go | 134 - .../appengine/internal/internal.go | 110 - .../appengine/internal/log/log_service.pb.go | 1313 --- .../appengine/internal/log/log_service.proto | 150 - .../appengine/internal/main.go | 16 - .../appengine/internal/main_common.go | 7 - .../appengine/internal/main_vm.go | 69 - .../appengine/internal/metadata.go | 60 - .../appengine/internal/net.go | 56 - .../appengine/internal/regen.sh | 40 - .../internal/remote_api/remote_api.pb.go | 361 - .../internal/remote_api/remote_api.proto | 44 - .../appengine/internal/transaction.go | 115 - .../internal/urlfetch/urlfetch_service.pb.go | 527 -- .../internal/urlfetch/urlfetch_service.proto | 64 - .../appengine/urlfetch/urlfetch.go | 210 - .../encoding/protodelim/protodelim.go | 160 + .../protobuf/encoding/prototext/decode.go | 4 +- .../protobuf/encoding/prototext/encode.go | 20 +- .../protobuf/internal/descfmt/stringer.go | 1 + .../editiondefaults/editions_defaults.binpb | Bin 63 -> 93 bytes .../internal/editionssupport/editions.go | 13 + .../protobuf/internal/encoding/tag/tag.go | 4 +- .../protobuf/internal/encoding/text/decode.go | 2 +- .../protobuf/internal/errors/errors.go | 21 +- .../protobuf/internal/filedesc/desc.go | 88 +- .../protobuf/internal/filedesc/desc_init.go | 43 +- .../protobuf/internal/filedesc/desc_lazy.go | 49 +- .../internal/filedesc/desc_list_gen.go | 11 + .../protobuf/internal/filedesc/editions.go | 22 +- .../protobuf/internal/filedesc/placeholder.go | 1 + .../protobuf/internal/filetype/build.go | 4 +- .../protobuf/internal/genid/descriptor_gen.go | 49 +- .../internal/genid/go_features_gen.go | 2 +- .../protobuf/internal/impl/api_export.go | 6 +- .../protobuf/internal/impl/checkinit.go | 2 +- .../protobuf/internal/impl/codec_extension.go | 22 + .../protobuf/internal/impl/codec_field.go | 64 +- .../protobuf/internal/impl/codec_map.go | 15 +- .../internal/impl/codec_messageset.go | 22 + .../protobuf/internal/impl/convert.go | 2 +- .../protobuf/internal/impl/convert_list.go | 2 +- .../protobuf/internal/impl/convert_map.go | 2 +- .../protobuf/internal/impl/encode.go | 48 +- .../protobuf/internal/impl/extension.go | 8 +- .../protobuf/internal/impl/legacy_enum.go | 3 +- .../internal/impl/legacy_extension.go | 2 +- .../protobuf/internal/impl/legacy_file.go | 4 +- .../protobuf/internal/impl/legacy_message.go | 14 +- .../protobuf/internal/impl/message.go | 8 +- .../protobuf/internal/impl/message_reflect.go | 45 +- .../internal/impl/message_reflect_gen.go | 146 +- .../protobuf/internal/impl/pointer_reflect.go | 6 +- .../protobuf/internal/impl/pointer_unsafe.go | 4 +- .../protobuf/internal/order/range.go | 4 +- .../protobuf/internal/version/version.go | 4 +- .../protobuf/proto/decode.go | 2 + .../protobuf/proto/encode.go | 44 +- .../protobuf/proto/extension.go | 17 +- .../protobuf/proto/messageset.go | 7 +- .../google.golang.org/protobuf/proto/size.go | 2 + .../protobuf/reflect/protodesc/desc.go | 13 +- .../protobuf/reflect/protodesc/desc_init.go | 49 +- .../reflect/protodesc/desc_resolve.go | 5 + .../reflect/protodesc/desc_validate.go | 73 +- .../protobuf/reflect/protodesc/editions.go | 11 +- .../protobuf/reflect/protodesc/proto.go | 22 + .../protobuf/reflect/protoreflect/proto.go | 2 +- .../reflect/protoreflect/source_gen.go | 21 + .../protobuf/reflect/protoreflect/type.go | 12 +- .../reflect/protoreflect/value_pure.go | 14 +- .../reflect/protoreflect/value_union.go | 14 +- .../protoreflect/value_unsafe_go120.go | 6 +- .../protoreflect/value_unsafe_go121.go | 8 +- .../reflect/protoregistry/registry.go | 14 +- .../types/descriptorpb/descriptor.pb.go | 1141 ++- .../types/gofeaturespb/go_features.pb.go | 122 +- .../types/gofeaturespb/go_features.proto | 28 - .../protobuf/types/known/anypb/any.pb.go | 4 +- .../types/known/durationpb/duration.pb.go | 4 +- .../types/known/timestamppb/timestamp.pb.go | 4 +- .../k8s.io/api/admission/v1/generated.pb.go | 127 +- .../api/admission/v1beta1/generated.pb.go | 129 +- .../admissionregistration/v1/generated.pb.go | 6011 ++++++++++-- .../admissionregistration/v1/generated.proto | 574 +- .../api/admissionregistration/v1/register.go | 4 + .../api/admissionregistration/v1/types.go | 604 +- .../v1/types_swagger_doc_generated.go | 178 +- .../v1/zz_generated.deepcopy.go | 432 + .../v1alpha1/generated.pb.go | 235 +- .../admissionregistration/v1alpha1/types.go | 2 +- .../v1beta1/generated.pb.go | 309 +- .../v1beta1/generated.proto | 15 +- .../admissionregistration/v1beta1/types.go | 17 +- .../v1beta1/types_swagger_doc_generated.go | 4 +- .../v1alpha1 => api/apidiscovery/v2}/doc.go | 9 +- .../api/apidiscovery/v2/generated.pb.go | 1742 ++++ .../api/apidiscovery/v2/generated.proto | 156 + vendor/k8s.io/api/apidiscovery/v2/register.go | 56 + vendor/k8s.io/api/apidiscovery/v2/types.go | 155 + .../apidiscovery/v2/zz_generated.deepcopy.go | 190 + .../api/apidiscovery/v2beta1/generated.pb.go | 113 +- .../v1alpha1/generated.pb.go | 119 +- .../v1alpha1/generated.proto | 1 - .../api/apiserverinternal/v1alpha1/types.go | 1 - vendor/k8s.io/api/apps/v1/generated.pb.go | 341 +- vendor/k8s.io/api/apps/v1/generated.proto | 9 + vendor/k8s.io/api/apps/v1/types.go | 9 + .../k8s.io/api/apps/v1beta1/generated.pb.go | 299 +- .../k8s.io/api/apps/v1beta1/generated.proto | 5 + vendor/k8s.io/api/apps/v1beta1/types.go | 5 + .../k8s.io/api/apps/v1beta2/generated.pb.go | 365 +- .../k8s.io/api/apps/v1beta2/generated.proto | 9 + vendor/k8s.io/api/apps/v1beta2/types.go | 9 + .../api/authentication/v1/generated.pb.go | 154 +- .../api/authentication/v1/generated.proto | 4 + vendor/k8s.io/api/authentication/v1/types.go | 4 + .../authentication/v1alpha1/generated.pb.go | 59 +- .../authentication/v1beta1/generated.pb.go | 117 +- .../authentication/v1beta1/generated.proto | 3 + .../api/authentication/v1beta1/types.go | 3 + .../api/authorization/v1/generated.pb.go | 177 +- .../api/authorization/v1/generated.proto | 9 + vendor/k8s.io/api/authorization/v1/types.go | 9 + .../api/authorization/v1beta1/generated.pb.go | 183 +- .../api/authorization/v1beta1/generated.proto | 9 + .../k8s.io/api/authorization/v1beta1/types.go | 9 + .../k8s.io/api/autoscaling/v1/generated.pb.go | 255 +- .../k8s.io/api/autoscaling/v2/generated.pb.go | 243 +- .../api/autoscaling/v2beta1/generated.pb.go | 243 +- .../api/autoscaling/v2beta1/generated.proto | 3 + .../k8s.io/api/autoscaling/v2beta1/types.go | 3 + .../api/autoscaling/v2beta2/generated.pb.go | 255 +- .../api/autoscaling/v2beta2/generated.proto | 4 + .../k8s.io/api/autoscaling/v2beta2/types.go | 4 + vendor/k8s.io/api/batch/v1/generated.pb.go | 747 +- vendor/k8s.io/api/batch/v1/generated.proto | 122 +- vendor/k8s.io/api/batch/v1/types.go | 152 +- .../batch/v1/types_swagger_doc_generated.go | 49 +- .../api/batch/v1/zz_generated.deepcopy.go | 59 + .../k8s.io/api/batch/v1beta1/generated.pb.go | 115 +- .../api/certificates/v1/generated.pb.go | 133 +- .../api/certificates/v1alpha1/generated.pb.go | 74 +- .../api/certificates/v1beta1/generated.pb.go | 135 +- .../api/coordination/v1/generated.pb.go | 85 +- .../api/coordination/v1beta1/generated.pb.go | 85 +- .../api/core/v1/annotation_key_constants.go | 21 +- vendor/k8s.io/api/core/v1/generated.pb.go | 6565 +++++++++---- vendor/k8s.io/api/core/v1/generated.proto | 447 +- vendor/k8s.io/api/core/v1/types.go | 521 +- .../core/v1/types_swagger_doc_generated.go | 169 +- .../api/core/v1/zz_generated.deepcopy.go | 258 +- .../k8s.io/api/discovery/v1/generated.pb.go | 137 +- .../k8s.io/api/discovery/v1/generated.proto | 4 +- vendor/k8s.io/api/discovery/v1/types.go | 4 +- .../v1/types_swagger_doc_generated.go | 4 +- .../api/discovery/v1beta1/generated.pb.go | 135 +- .../api/discovery/v1beta1/generated.proto | 2 +- vendor/k8s.io/api/discovery/v1beta1/types.go | 2 +- .../v1beta1/types_swagger_doc_generated.go | 2 +- vendor/k8s.io/api/events/v1/generated.pb.go | 111 +- .../k8s.io/api/events/v1beta1/generated.pb.go | 111 +- .../api/extensions/v1beta1/generated.pb.go | 447 +- .../api/extensions/v1beta1/generated.proto | 19 + vendor/k8s.io/api/extensions/v1beta1/types.go | 19 + .../api/flowcontrol/{v1alpha1 => v1}/doc.go | 7 +- .../{v1alpha1 => v1}/generated.pb.go | 328 +- .../{v1alpha1 => v1}/generated.proto | 41 +- .../flowcontrol/{v1alpha1 => v1}/register.go | 6 +- .../api/flowcontrol/{v1alpha1 => v1}/types.go | 107 +- .../types_swagger_doc_generated.go | 4 +- .../{v1alpha1 => v1}/zz_generated.deepcopy.go | 7 +- .../zz_generated.prerelease-lifecycle.go | 122 - .../api/flowcontrol/v1beta1/generated.pb.go | 249 +- .../api/flowcontrol/v1beta1/generated.proto | 2 +- .../k8s.io/api/flowcontrol/v1beta1/types.go | 2 +- .../v1beta1/types_swagger_doc_generated.go | 2 +- .../api/flowcontrol/v1beta2/generated.pb.go | 261 +- .../api/flowcontrol/v1beta2/generated.proto | 2 +- .../k8s.io/api/flowcontrol/v1beta2/types.go | 2 +- .../v1beta2/types_swagger_doc_generated.go | 2 +- .../api/flowcontrol/v1beta3/generated.pb.go | 259 +- .../k8s.io/api/flowcontrol/v1beta3/types.go | 18 + .../zz_generated.prerelease-lifecycle.go | 28 + .../k8s.io/api/networking/v1/generated.pb.go | 275 +- .../k8s.io/api/networking/v1/generated.proto | 9 + vendor/k8s.io/api/networking/v1/types.go | 9 + .../api/networking/v1alpha1/generated.pb.go | 989 +- .../api/networking/v1alpha1/generated.proto | 116 +- .../api/networking/v1alpha1/register.go | 4 +- .../k8s.io/api/networking/v1alpha1/types.go | 148 +- .../v1alpha1/types_swagger_doc_generated.go | 72 +- .../v1alpha1/zz_generated.deepcopy.go | 110 +- .../zz_generated.prerelease-lifecycle.go | 36 +- .../api/networking/v1beta1/generated.pb.go | 202 +- .../api/networking/v1beta1/generated.proto | 5 + vendor/k8s.io/api/networking/v1beta1/types.go | 5 + vendor/k8s.io/api/node/v1/generated.pb.go | 99 +- .../k8s.io/api/node/v1alpha1/generated.pb.go | 103 +- .../k8s.io/api/node/v1beta1/generated.pb.go | 99 +- vendor/k8s.io/api/policy/v1/doc.go | 2 +- vendor/k8s.io/api/policy/v1/generated.pb.go | 125 +- vendor/k8s.io/api/policy/v1beta1/doc.go | 2 +- .../k8s.io/api/policy/v1beta1/generated.pb.go | 5003 ++-------- .../k8s.io/api/policy/v1beta1/generated.proto | 277 - vendor/k8s.io/api/policy/v1beta1/register.go | 2 - vendor/k8s.io/api/policy/v1beta1/types.go | 371 - .../v1beta1/types_swagger_doc_generated.go | 160 - .../policy/v1beta1/zz_generated.deepcopy.go | 367 - .../zz_generated.prerelease-lifecycle.go | 36 - vendor/k8s.io/api/rbac/v1/generated.pb.go | 137 +- vendor/k8s.io/api/rbac/v1/generated.proto | 10 + vendor/k8s.io/api/rbac/v1/types.go | 10 + .../k8s.io/api/rbac/v1alpha1/generated.pb.go | 141 +- .../k8s.io/api/rbac/v1alpha1/generated.proto | 10 + vendor/k8s.io/api/rbac/v1alpha1/types.go | 10 + .../k8s.io/api/rbac/v1beta1/generated.pb.go | 137 +- .../k8s.io/api/rbac/v1beta1/generated.proto | 10 + vendor/k8s.io/api/rbac/v1beta1/types.go | 10 + .../api/resource/v1alpha2/generated.pb.go | 8396 ++++++++++++++--- .../api/resource/v1alpha2/generated.proto | 353 +- .../api/resource/v1alpha2/namedresources.go | 127 + .../k8s.io/api/resource/v1alpha2/register.go | 6 + vendor/k8s.io/api/resource/v1alpha2/types.go | 281 +- .../v1alpha2/types_swagger_doc_generated.go | 179 +- .../v1alpha2/zz_generated.deepcopy.go | 630 +- .../k8s.io/api/scheduling/v1/generated.pb.go | 73 +- .../api/scheduling/v1alpha1/generated.pb.go | 71 +- .../api/scheduling/v1beta1/generated.pb.go | 73 +- vendor/k8s.io/api/storage/v1/generated.pb.go | 259 +- vendor/k8s.io/api/storage/v1/generated.proto | 12 +- vendor/k8s.io/api/storage/v1/types.go | 12 +- .../storage/v1/types_swagger_doc_generated.go | 4 +- .../api/storage/v1alpha1/generated.pb.go | 753 +- .../api/storage/v1alpha1/generated.proto | 42 +- .../k8s.io/api/storage/v1alpha1/register.go | 2 + vendor/k8s.io/api/storage/v1alpha1/types.go | 54 +- .../v1alpha1/types_swagger_doc_generated.go | 21 + .../storage/v1alpha1/zz_generated.deepcopy.go | 66 + .../zz_generated.prerelease-lifecycle.go | 36 + .../api/storage/v1beta1/generated.pb.go | 259 +- .../api/storage/v1beta1/generated.proto | 9 +- vendor/k8s.io/api/storage/v1beta1/types.go | 9 +- .../v1beta1/types_swagger_doc_generated.go | 2 +- .../api/storagemigration/v1alpha1/doc.go | 23 + .../storagemigration/v1alpha1/generated.pb.go | 1688 ++++ .../storagemigration/v1alpha1/generated.proto | 127 + .../api/storagemigration/v1alpha1/register.go | 58 + .../api/storagemigration/v1alpha1/types.go | 131 + .../v1alpha1/types_swagger_doc_generated.go | 95 + .../v1alpha1/zz_generated.deepcopy.go | 160 + .../zz_generated.prerelease-lifecycle.go | 58 + .../pkg/apis/apiextensions/types.go | 25 + .../apis/apiextensions/types_jsonschema.go | 31 + .../pkg/apis/apiextensions/v1/conversion.go | 26 +- .../pkg/apis/apiextensions/v1/generated.pb.go | 712 +- .../pkg/apis/apiextensions/v1/generated.proto | 68 + .../pkg/apis/apiextensions/v1/types.go | 30 + .../apis/apiextensions/v1/types_jsonschema.go | 83 +- .../v1/zz_generated.conversion.go | 35 + .../apiextensions/v1/zz_generated.deepcopy.go | 26 + .../apiextensions/v1beta1/generated.pb.go | 775 +- .../apiextensions/v1beta1/generated.proto | 76 + .../pkg/apis/apiextensions/v1beta1/types.go | 38 + .../apiextensions/v1beta1/types_jsonschema.go | 83 +- .../v1beta1/zz_generated.conversion.go | 36 + .../v1beta1/zz_generated.deepcopy.go | 31 + .../apiextensions/zz_generated.deepcopy.go | 31 + .../v1/customresourcedefinitionversion.go | 14 + .../apiextensions/v1/selectablefield.go | 39 + .../apiextensions/v1/validationrule.go | 9 + .../v1beta1/customresourcedefinitionspec.go | 14 + .../customresourcedefinitionversion.go | 14 + .../apiextensions/v1beta1/selectablefield.go} | 20 +- .../apiextensions/v1beta1/validationrule.go | 9 + .../apimachinery/pkg/api/meta/conditions.go | 37 +- .../apimachinery/pkg/api/resource/amount.go | 38 + .../pkg/api/resource/generated.pb.go | 43 +- .../apimachinery/pkg/api/resource/quantity.go | 10 + .../pkg/api/validation}/OWNERS | 2 - .../pkg/apis/meta/v1/generated.pb.go | 441 +- .../pkg/apis/meta/v1/generated.proto | 22 + .../apimachinery/pkg/apis/meta/v1/types.go | 35 + .../pkg/apis/meta/v1/unstructured/helpers.go | 2 +- .../pkg/apis/meta/v1beta1/generated.pb.go | 45 +- .../apimachinery/pkg/runtime/generated.pb.go | 65 +- .../k8s.io/apimachinery/pkg/runtime/helper.go | 35 +- .../pkg/runtime/schema/generated.pb.go | 31 +- .../runtime/serializer/streaming/streaming.go | 20 - .../pkg/util/cache/lruexpirecache.go | 13 + .../pkg/util/intstr/generated.pb.go | 47 +- .../apimachinery/pkg/util/intstr/intstr.go | 6 +- .../managedfields/internal/structuredmerge.go | 9 +- .../managedfields/internal/typeconverter.go | 14 +- .../pkg/util/managedfields/node.yaml | 2 +- .../k8s.io/apimachinery/pkg/util/sets/doc.go | 2 +- .../apimachinery/pkg/util/sets/ordered.go | 53 - .../k8s.io/apimachinery/pkg/util/sets/set.go | 9 +- .../pkg/util/strategicpatch/meta.go | 89 + .../apimachinery/pkg/util/validation/OWNERS | 11 + .../pkg/util/validation/field/errors.go | 4 +- .../pkg/util/validation/validation.go | 56 +- .../k8s.io/apimachinery/pkg/util/wait/loop.go | 38 +- .../v1/auditannotation.go | 48 + .../v1/expressionwarning.go | 48 + .../v1/matchresources.go | 90 + .../v1/namedrulewithoperations.go | 94 + .../admissionregistration/v1/paramkind.go | 48 + .../admissionregistration/v1/paramref.go | 71 + .../admissionregistration/v1/typechecking.go | 44 + .../v1/validatingadmissionpolicy.go | 256 + .../v1/validatingadmissionpolicybinding.go | 247 + .../validatingadmissionpolicybindingspec.go | 72 + .../v1/validatingadmissionpolicyspec.go | 117 + .../v1/validatingadmissionpolicystatus.go | 66 + .../admissionregistration/v1/validation.go | 70 + .../admissionregistration/v1/variable.go | 48 + .../applyconfigurations/batch/v1/jobspec.go | 18 + .../batch/v1/successpolicy.go | 44 + .../batch/v1/successpolicyrule.go | 48 + .../core/v1/apparmorprofile.go | 52 + .../core/v1/clustertrustbundleprojection.go | 79 + .../core/v1/containerstatus.go | 14 + .../core/v1/lifecyclehandler.go | 9 + .../core/v1/loadbalanceringress.go | 13 + .../core/v1/modifyvolumestatus.go | 52 + .../core/v1/noderuntimehandler.go | 48 + .../core/v1/noderuntimehandlerfeatures.go | 39 + .../applyconfigurations/core/v1/nodestatus.go | 14 + .../core/v1/persistentvolumeclaimspec.go | 27 +- .../core/v1/persistentvolumeclaimstatus.go | 30 +- .../core/v1/persistentvolumespec.go | 9 + .../core/v1/podaffinityterm.go | 22 + .../core/v1/podsecuritycontext.go | 9 + .../core/v1/securitycontext.go | 9 + .../core/v1/servicespec.go | 9 + .../core/v1/sleepaction.go | 39 + .../core/v1/volumemount.go | 21 +- .../core/v1/volumemountstatus.go | 70 + .../core/v1/volumeprojection.go | 9 + .../core/v1/volumeresourcerequirements.go | 52 + .../exemptprioritylevelconfiguration.go | 2 +- .../flowdistinguishermethod.go | 8 +- .../{v1alpha1 => v1}/flowschema.go | 16 +- .../{v1alpha1 => v1}/flowschemacondition.go | 22 +- .../{v1alpha1 => v1}/flowschemaspec.go | 2 +- .../{v1alpha1 => v1}/flowschemastatus.go | 2 +- .../{v1alpha1 => v1}/groupsubject.go | 2 +- .../limitedprioritylevelconfiguration.go | 12 +- .../{v1alpha1 => v1}/limitresponse.go | 8 +- .../{v1alpha1 => v1}/nonresourcepolicyrule.go | 2 +- .../policyruleswithsubjects.go | 2 +- .../prioritylevelconfiguration.go | 16 +- .../prioritylevelconfigurationcondition.go | 22 +- .../prioritylevelconfigurationreference.go | 2 +- .../prioritylevelconfigurationspec.go | 8 +- .../prioritylevelconfigurationstatus.go | 2 +- .../{v1alpha1 => v1}/queuingconfiguration.go | 2 +- .../{v1alpha1 => v1}/resourcepolicyrule.go | 2 +- .../{v1alpha1 => v1}/serviceaccountsubject.go | 2 +- .../flowcontrol/{v1alpha1 => v1}/subject.go | 8 +- .../{v1alpha1 => v1}/usersubject.go | 2 +- .../applyconfigurations/internal/internal.go | 1301 ++- .../meta/v1/unstructured.go | 2 +- .../networking/v1alpha1/clustercidrspec.go | 70 - .../networking/v1alpha1/parentreference.go | 21 +- .../{clustercidr.go => servicecidr.go} | 87 +- .../networking/v1alpha1/servicecidrspec.go | 41 + .../networking/v1alpha1/servicecidrstatus.go | 48 + .../policy/v1beta1/allowedhostpath.go | 48 - .../policy/v1beta1/fsgroupstrategyoptions.go | 57 - .../policy/v1beta1/hostportrange.go | 48 - .../policy/v1beta1/idrange.go | 48 - .../policy/v1beta1/podsecuritypolicyspec.go | 285 - .../v1beta1/runasgroupstrategyoptions.go | 57 - .../v1beta1/runasuserstrategyoptions.go | 57 - .../v1beta1/runtimeclassstrategyoptions.go | 50 - .../policy/v1beta1/selinuxstrategyoptions.go | 53 - .../supplementalgroupsstrategyoptions.go | 57 - .../v1alpha2/allocationresultmodel.go | 39 + .../v1alpha2/driverallocationresult.go | 52 + .../resource/v1alpha2/driverrequests.go | 66 + .../namedresourcesallocationresult.go} | 14 +- .../v1alpha2/namedresourcesattribute.go | 100 + .../v1alpha2/namedresourcesattributevalue.go | 97 + .../resource/v1alpha2/namedresourcesfilter.go | 39 + .../v1alpha2/namedresourcesinstance.go | 53 + .../v1alpha2/namedresourcesintslice.go | 41 + .../v1alpha2/namedresourcesrequest.go | 39 + .../v1alpha2/namedresourcesresources.go | 44 + .../v1alpha2/namedresourcesstringslice.go | 41 + .../v1alpha2/resourceclaimparameters.go | 272 + .../resource/v1alpha2/resourceclass.go | 9 + .../v1alpha2/resourceclassparameters.go | 277 + .../resource/v1alpha2/resourcefilter.go | 48 + .../resource/v1alpha2/resourcefiltermodel.go | 39 + .../resource/v1alpha2/resourcehandle.go | 13 +- .../resource/v1alpha2/resourcemodel.go | 39 + .../resource/v1alpha2/resourcerequest.go | 52 + .../resource/v1alpha2/resourcerequestmodel.go | 39 + .../v1alpha2/resourceslice.go} | 110 +- .../v1alpha2/structuredresourcehandle.go | 75 + .../resource/v1alpha2/vendorparameters.go | 52 + .../storage/v1alpha1/volumeattributesclass.go | 262 + .../v1alpha1/groupversionresource.go | 57 + .../v1alpha1/migrationcondition.go | 81 + .../v1alpha1/storageversionmigration.go | 256 + .../v1alpha1/storageversionmigrationspec.go | 48 + .../v1alpha1/storageversionmigrationstatus.go | 53 + .../discovery/aggregated_discovery.go | 124 +- .../client-go/discovery/discovery_client.go | 57 +- vendor/k8s.io/client-go/features/envvar.go | 138 + vendor/k8s.io/client-go/features/features.go | 143 + .../client-go/features/known_features.go | 54 + .../k8s.io/client-go/kubernetes/clientset.go | 29 +- vendor/k8s.io/client-go/kubernetes/doc.go | 2 +- .../client-go/kubernetes/scheme/register.go | 6 +- .../v1/admissionregistration_client.go | 10 + .../v1/generated_expansion.go | 4 + .../v1/validatingadmissionpolicy.go | 243 + .../v1/validatingadmissionpolicybinding.go | 197 + .../kubernetes/typed/flowcontrol/v1}/doc.go | 9 +- .../{v1alpha1 => v1}/flowcontrol_client.go | 38 +- .../{v1alpha1 => v1}/flowschema.go | 70 +- .../{v1alpha1 => v1}/generated_expansion.go | 2 +- .../prioritylevelconfiguration.go | 70 +- .../typed/networking/v1alpha1/clustercidr.go | 197 - .../v1alpha1/generated_expansion.go | 4 +- .../networking/v1alpha1/networking_client.go | 10 +- .../typed/networking/v1alpha1/servicecidr.go | 243 + .../policy/v1beta1/generated_expansion.go | 2 - .../typed/policy/v1beta1/podsecuritypolicy.go | 197 - .../typed/policy/v1beta1/policy_client.go | 5 - .../resource/v1alpha2/generated_expansion.go | 6 + .../resource/v1alpha2/resource_client.go | 15 + .../v1alpha2/resourceclaimparameters.go | 208 + .../v1alpha2/resourceclassparameters.go | 208 + .../typed/resource/v1alpha2/resourceslice.go | 197 + .../storage/v1alpha1/generated_expansion.go | 2 + .../typed/storage/v1alpha1/storage_client.go | 5 + .../storage/v1alpha1/volumeattributesclass.go | 197 + .../v1alpha1/doc.go | 0 .../v1alpha1/generated_expansion.go} | 8 +- .../v1alpha1/storagemigration_client.go | 107 + .../v1alpha1/storageversionmigration.go | 243 + vendor/k8s.io/client-go/metadata/metadata.go | 4 +- .../k8s.io/client-go/restmapper/shortcut.go | 36 +- .../client-go/tools/cache/controller.go | 10 + vendor/k8s.io/client-go/tools/cache/index.go | 3 +- .../k8s.io/client-go/tools/cache/reflector.go | 40 +- .../reflector_data_consistency_detector.go | 119 + .../client-go/tools/cache/shared_informer.go | 12 +- .../tools/cache/thread_safe_store.go | 92 +- .../client-go/tools/clientcmd/api/doc.go | 2 +- .../client-go/tools/clientcmd/api/v1/doc.go | 2 +- .../tools/clientcmd/client_config.go | 49 +- .../tools/clientcmd/merged_client_builder.go | 4 +- .../tools/internal/events/interfaces.go | 59 + .../tools/leaderelection/leaderelection.go | 30 +- .../client-go/tools/leaderelection/metrics.go | 30 +- vendor/k8s.io/client-go/tools/record/event.go | 197 +- vendor/k8s.io/client-go/tools/record/fake.go | 7 + .../k8s.io/client-go/transport/transport.go | 55 + .../client-go/util/flowcontrol/backoff.go | 3 +- .../k8s.io/client-go/util/workqueue/queue.go | 55 +- vendor/k8s.io/component-base/config/types.go | 80 - .../config/v1alpha1/conversion.go | 53 - .../config/v1alpha1/defaults.go | 98 - .../config/v1alpha1/register.go | 31 - .../component-base/config/v1alpha1/types.go | 82 - .../v1alpha1/zz_generated.conversion.go | 133 - .../config/v1alpha1/zz_generated.deepcopy.go | 88 - .../config/zz_generated.deepcopy.go | 73 - vendor/k8s.io/klog/v2/klog.go | 76 +- .../k8s.io/klog/v2/textlogger/textlogger.go | 2 +- .../kube-openapi/pkg/builder3/util/util.go | 51 - .../k8s.io/kube-openapi/pkg/cached/cache.go | 268 +- .../k8s.io/kube-openapi/pkg/common/common.go | 41 +- .../kube-openapi/pkg/handler3/handler.go | 77 +- .../k8s.io/kube-openapi/pkg/internal/flags.go | 1 + .../kube-openapi/pkg/openapiconv/convert.go | 322 - .../k8s.io/kube-openapi/pkg/schemaconv/smd.go | 3 - .../kube-openapi/pkg/schemamutation/walker.go | 519 - .../k8s.io/kube-openapi/pkg/spec3/encoding.go | 21 + .../k8s.io/kube-openapi/pkg/spec3/example.go | 14 + .../pkg/spec3/external_documentation.go | 13 + vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go | 27 + .../k8s.io/kube-openapi/pkg/spec3/header.go | 31 + .../kube-openapi/pkg/spec3/media_type.go | 20 + .../kube-openapi/pkg/spec3/operation.go | 27 + .../kube-openapi/pkg/spec3/parameter.go | 31 + vendor/k8s.io/kube-openapi/pkg/spec3/path.go | 47 +- .../kube-openapi/pkg/spec3/request_body.go | 21 + .../k8s.io/kube-openapi/pkg/spec3/response.go | 52 + .../kube-openapi/pkg/spec3/security_scheme.go | 17 + .../k8s.io/kube-openapi/pkg/spec3/server.go | 26 + vendor/k8s.io/kube-openapi/pkg/spec3/spec.go | 25 + .../kube-openapi/pkg/validation/spec/fuzz.go | 502 - vendor/k8s.io/utils/integer/integer.go | 73 - vendor/k8s.io/utils/net/multi_listen.go | 195 + vendor/k8s.io/utils/pointer/pointer.go | 283 +- vendor/k8s.io/utils/ptr/OWNERS | 10 + vendor/k8s.io/utils/ptr/README.md | 3 + vendor/k8s.io/utils/ptr/ptr.go | 73 + vendor/k8s.io/utils/trace/trace.go | 2 +- vendor/modules.txt | 217 +- vendor/oras.land/oras-go/v2/.gitignore | 41 + vendor/oras.land/oras-go/v2/CODEOWNERS | 2 + .../oras.land/oras-go/v2/CODE_OF_CONDUCT.md | 3 + .../oras-go/v2}/LICENSE | 3 +- .../oras.land/oras-go/v2/MIGRATION_GUIDE.md | 45 + vendor/oras.land/oras-go/v2/Makefile | 38 + vendor/oras.land/oras-go/v2/OWNERS.md | 11 + vendor/oras.land/oras-go/v2/README.md | 58 + vendor/oras.land/oras-go/v2/SECURITY.md | 3 + vendor/oras.land/oras-go/v2/content.go | 411 + .../oras-go/v2/content/descriptor.go | 40 + .../oras-go/v2/content/file/errors.go | 28 + .../oras.land/oras-go/v2/content/file/file.go | 684 ++ .../oras-go/v2/content/file/utils.go | 261 + vendor/oras.land/oras-go/v2/content/graph.go | 122 + .../oras-go/v2/content/limitedstorage.go | 50 + vendor/oras.land/oras-go/v2/content/reader.go | 144 + .../oras.land/oras-go/v2/content/resolver.go | 47 + .../oras.land/oras-go/v2/content/storage.go | 80 + vendor/oras.land/oras-go/v2/copy.go | 516 + vendor/oras.land/oras-go/v2/errdef/errors.go | 31 + vendor/oras.land/oras-go/v2/extendedcopy.go | 389 + .../oras-go/v2/internal/cas/memory.go | 88 + .../oras-go/v2/internal/cas/proxy.go | 125 + .../oras-go/v2/internal/container/set/set.go | 40 + .../oras-go/v2/internal/copyutil/stack.go | 55 + .../v2/internal/descriptor/descriptor.go | 89 + .../oras-go/v2/internal/docker/mediatype.go | 24 + .../oras-go/v2/internal/graph/memory.go | 201 + .../oras-go/v2/internal/httputil/seek.go | 116 + .../v2/internal/interfaces/registry.go | 24 + .../oras-go/v2/internal/ioutil/io.go | 66 + .../v2/internal/manifestutil/parser.go | 84 + .../oras-go/v2/internal/platform/platform.go | 145 + .../oras-go/v2/internal/registryutil/proxy.go | 102 + .../oras-go/v2/internal/resolver/memory.go | 104 + .../oras-go/v2/internal/spec/artifact.go | 57 + .../oras-go/v2/internal/status/tracker.go | 43 + .../oras-go/v2/internal/syncutil/limit.go | 84 + .../v2/internal/syncutil/limitgroup.go | 67 + .../oras-go/v2/internal/syncutil/merge.go | 140 + .../oras-go/v2/internal/syncutil/once.go | 102 + .../oras-go/v2/internal/syncutil/pool.go | 64 + vendor/oras.land/oras-go/v2/pack.go | 439 + .../oras-go/v2/registry/reference.go | 276 + .../oras.land/oras-go/v2/registry/registry.go | 52 + .../oras-go/v2/registry/remote/auth/cache.go | 232 + .../v2/registry/remote/auth/challenge.go | 167 + .../oras-go/v2/registry/remote/auth/client.go | 430 + .../v2/registry/remote/auth/credential.go | 40 + .../oras-go/v2/registry/remote/auth/scope.go | 325 + .../v2/registry/remote/errcode/errors.go | 128 + .../remote/internal/errutil/errutil.go | 54 + .../oras-go/v2/registry/remote/manifest.go | 59 + .../oras-go/v2/registry/remote/referrers.go | 221 + .../oras-go/v2/registry/remote/registry.go | 190 + .../oras-go/v2/registry/remote/repository.go | 1667 ++++ .../v2/registry/remote/retry/client.go | 114 + .../v2/registry/remote/retry/policy.go | 154 + .../oras-go/v2/registry/remote/url.go | 119 + .../oras-go/v2/registry/remote/utils.go | 94 + .../oras-go/v2/registry/remote/warning.go | 100 + .../oras-go/v2/registry/repository.go | 226 + vendor/oras.land/oras-go/v2/target.go | 43 + .../api/v1beta1/cluster_phase_types.go | 9 +- .../cluster-api/api/v1beta1/cluster_types.go | 55 +- .../api/v1beta1/clusterclass_types.go | 203 +- .../cluster-api/api/v1beta1/common_types.go | 17 +- .../api/v1beta1/condition_consts.go | 17 + .../api/v1beta1/machinedeployment_types.go | 35 + .../api/v1beta1/machinehealthcheck_types.go | 24 +- .../api/v1beta1/machineset_types.go | 17 +- .../api/v1beta1/zz_generated.deepcopy.go | 147 + .../api/v1beta1/zz_generated.openapi.go | 368 +- .../cluster-api/cmd/clusterctl/log/logger.go | 2 +- .../sigs.k8s.io/cluster-api/errors/pointer.go | 6 + .../cluster-api/util/annotations/helpers.go | 5 + .../cluster-api/util/conditions/getter.go | 14 + .../cluster-api/util/conditions/merge.go | 44 +- .../util/conditions/merge_strategies.go | 9 + .../cluster-api/util/conditions/setter.go | 29 + .../cluster-api/util/labels/format/helpers.go | 52 + .../cluster-api/util/patch/patch.go | 83 +- .../cluster-api/util/patch/utils.go | 32 +- vendor/sigs.k8s.io/cluster-api/util/util.go | 132 +- .../controller-runtime/.golangci.yml | 16 +- vendor/sigs.k8s.io/controller-runtime/FAQ.md | 4 +- .../sigs.k8s.io/controller-runtime/Makefile | 49 +- vendor/sigs.k8s.io/controller-runtime/OWNERS | 3 +- .../controller-runtime/OWNERS_ALIASES | 6 - .../sigs.k8s.io/controller-runtime/RELEASE.md | 14 +- .../sigs.k8s.io/controller-runtime/alias.go | 8 - .../pkg/builder/controller.go | 60 +- .../controller-runtime/pkg/builder/webhook.go | 6 +- .../controller-runtime/pkg/cache/cache.go | 98 +- .../pkg/cache/delegating_by_gvk_cache.go | 8 + .../pkg/cache/informer_cache.go | 11 + .../pkg/cache/internal/cache_reader.go | 57 +- .../pkg/cache/internal/informers.go | 70 +- .../pkg/cache/multi_namespace_cache.go | 45 +- .../pkg/certwatcher/certwatcher.go | 10 +- .../pkg/client/apiutil/apimachinery.go | 21 - .../pkg/client/apiutil/restmapper.go | 50 +- .../controller-runtime/pkg/client/client.go | 44 +- .../pkg/client/fake/client.go | 118 +- .../pkg/client/fieldowner.go | 106 + .../controller-runtime/pkg/client/options.go | 2 +- .../controller-runtime/pkg/config/config.go | 112 - .../pkg/config/v1alpha1/doc.go | 22 - .../pkg/config/v1alpha1/register.go | 43 - .../pkg/config/v1alpha1/types.go | 179 - .../config/v1alpha1/zz_generated.deepcopy.go | 157 - .../pkg/controller/controller.go | 40 +- .../controllerutil/controllerutil.go | 114 +- .../controller-runtime/pkg/envtest/crd.go | 23 +- .../controller-runtime/pkg/envtest/server.go | 25 + .../controller-runtime/pkg/envtest/webhook.go | 10 +- .../controller-runtime/pkg/event/event.go | 51 +- .../controller-runtime/pkg/handler/enqueue.go | 43 +- .../pkg/handler/enqueue_mapped.go | 42 +- .../pkg/handler/enqueue_owner.go | 48 +- .../pkg/handler/eventhandler.go | 62 +- .../pkg/internal/controller/controller.go | 35 +- .../pkg/internal/field/selector/utils.go | 16 +- .../pkg/internal/source/event_handler.go | 32 +- .../pkg/internal/source/kind.go | 58 +- .../pkg/internal/syncs/syncs.go | 38 + .../internal/testing/controlplane/kubectl.go | 1 + .../testing/process/procattr_other.go | 28 + .../internal/testing/process/procattr_unix.go | 33 + .../pkg/internal/testing/process/process.go | 4 + .../pkg/manager/internal.go | 55 +- .../controller-runtime/pkg/manager/manager.go | 138 +- .../pkg/manager/runnable_group.go | 20 +- .../controller-runtime/pkg/manager/server.go | 74 +- .../pkg/metrics/leaderelection.go | 23 +- .../pkg/metrics/server/server.go | 32 +- .../pkg/metrics/workqueue.go | 4 +- .../pkg/predicate/predicate.go | 179 +- .../pkg/reconcile/reconcile.go | 34 +- .../controller-runtime/pkg/source/source.go | 124 +- .../pkg/webhook/admission/decode.go | 25 +- .../pkg/webhook/admission/defaulter.go | 4 +- .../pkg/webhook/admission/defaulter_custom.go | 2 +- .../pkg/webhook/admission/http.go | 52 +- .../pkg/webhook/admission/validator.go | 4 +- .../pkg/webhook/admission/validator_custom.go | 3 +- .../controller-runtime/pkg/webhook/alias.go | 2 + .../v4/fieldpath/pathelementmap.go | 45 +- .../v4/merge/conflict.go | 2 +- .../structured-merge-diff/v4/merge/update.go | 72 +- .../v4/schema/elements.go | 3 +- .../v4/schema/schemaschema.go | 3 +- .../structured-merge-diff/v4/typed/compare.go | 460 + .../structured-merge-diff/v4/typed/helpers.go | 21 +- .../structured-merge-diff/v4/typed/merge.go | 61 +- .../structured-merge-diff/v4/typed/parser.go | 12 +- .../structured-merge-diff/v4/typed/remove.go | 4 +- .../v4/typed/tofieldset.go | 24 +- .../structured-merge-diff/v4/typed/typed.go | 187 +- .../structured-merge-diff/v4/typed/union.go | 276 - .../v4/typed/validate.go | 14 +- .../v4/value/mapreflect.go | 2 +- .../v4/value/mapunstructured.go | 8 +- .../v4/value/reflectcache.go | 4 +- 1058 files changed, 85491 insertions(+), 41571 deletions(-) create mode 100644 internal/test/integration/oci/integration_suite_test.go create mode 100644 internal/test/integration/oci/integration_test.go create mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/client.go create mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/fake/client.go rename vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/{github/client/github_client.go => assetsclient/github/client.go} (75%) rename vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/{github/client => assetsclient/github}/credentials.go (96%) create mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Client.go rename vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/{github/client => assetsclient}/mocks/Factory.go (70%) create mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/assetsFactory.go create mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/client.go create mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/credentials.go delete mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/fake/github_client.go delete mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Client.go delete mode 100644 vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/gfactory.go create mode 100644 vendor/github.com/cloudflare/circl/math/primes.go delete mode 100644 vendor/github.com/emicklei/go-restful/v3/json.go delete mode 100644 vendor/github.com/emicklei/go-restful/v3/jsoniter.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/fold.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/fuzz.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/indent.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/scanner.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/stream.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/tables.go create mode 100644 vendor/github.com/evanphx/json-patch/v5/internal/json/tags.go create mode 100644 vendor/github.com/fsnotify/fsnotify/.cirrus.yml create mode 100644 vendor/github.com/go-logr/logr/slogr/slogr.go create mode 100644 vendor/github.com/go-logr/zapr/.golangci.yaml create mode 100644 vendor/github.com/go-logr/zapr/slogzapr.go create mode 100644 vendor/github.com/go-logr/zapr/zapr_noslog.go create mode 100644 vendor/github.com/go-logr/zapr/zapr_slog.go rename vendor/github.com/go-task/slim-sprig/{ => v3}/.editorconfig (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/.gitattributes (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/.gitignore (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/CHANGELOG.md (95%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/LICENSE.txt (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/README.md (88%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/Taskfile.yml (89%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/crypto.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/date.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/defaults.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/dict.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/doc.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/functions.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/list.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/network.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/numeric.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/reflect.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/regex.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/strings.go (100%) rename vendor/github.com/go-task/slim-sprig/{ => v3}/url.go (100%) create mode 100644 vendor/github.com/google/uuid/version6.go create mode 100644 vendor/github.com/google/uuid/version7.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/NOTICE delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/decode.go delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/encode.go create mode 100644 vendor/github.com/onsi/ginkgo/v2/Makefile create mode 100644 vendor/github.com/opencontainers/go-digest/.mailmap create mode 100644 vendor/github.com/opencontainers/go-digest/.pullapprove.yml create mode 100644 vendor/github.com/opencontainers/go-digest/.travis.yml create mode 100644 vendor/github.com/opencontainers/go-digest/CONTRIBUTING.md rename vendor/{google.golang.org/appengine => github.com/opencontainers/go-digest}/LICENSE (93%) create mode 100644 vendor/github.com/opencontainers/go-digest/LICENSE.docs create mode 100644 vendor/github.com/opencontainers/go-digest/MAINTAINERS create mode 100644 vendor/github.com/opencontainers/go-digest/README.md create mode 100644 vendor/github.com/opencontainers/go-digest/algorithm.go create mode 100644 vendor/github.com/opencontainers/go-digest/digest.go create mode 100644 vendor/github.com/opencontainers/go-digest/digester.go create mode 100644 vendor/github.com/opencontainers/go-digest/doc.go create mode 100644 vendor/github.com/opencontainers/go-digest/verifiers.go rename vendor/github.com/{matttproud/golang_protobuf_extensions => opencontainers/image-spec}/LICENSE (94%) create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/config.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/index.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/layout.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/version.go create mode 100644 vendor/github.com/opencontainers/image-spec/specs-go/versioned.go rename vendor/github.com/{matttproud/golang_protobuf_extensions/pbutil/doc.go => prometheus/client_golang/prometheus/process_collector_wasip1.go} (63%) delete mode 100644 vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/README.txt delete mode 100644 vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go create mode 100644 vendor/github.com/prometheus/common/model/labelset_string.go create mode 100644 vendor/github.com/prometheus/common/model/labelset_string_go120.go create mode 100644 vendor/github.com/prometheus/common/model/metadata.go create mode 100644 vendor/github.com/prometheus/procfs/net_tls_stat.go create mode 100644 vendor/go.uber.org/zap/.golangci.yml rename vendor/go.uber.org/zap/{LICENSE.txt => LICENSE} (100%) delete mode 100644 vendor/go.uber.org/zap/array_go118.go rename vendor/go.uber.org/zap/{stacktrace.go => internal/stacktrace/stack.go} (75%) create mode 100644 vendor/go.uber.org/zap/zapcore/lazy_with.go delete mode 100644 vendor/golang.org/x/crypto/sha3/hashes_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/hashes_noasm.go delete mode 100644 vendor/golang.org/x/crypto/sha3/register.go delete mode 100644 vendor/golang.org/x/crypto/sha3/shake_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/shake_noasm.go delete mode 100644 vendor/golang.org/x/crypto/sha3/xor_generic.go delete mode 100644 vendor/golang.org/x/crypto/sha3/xor_unaligned.go create mode 100644 vendor/golang.org/x/net/http2/timer.go delete mode 100644 vendor/golang.org/x/oauth2/internal/client_appengine.go create mode 100644 vendor/golang.org/x/sync/LICENSE create mode 100644 vendor/golang.org/x/sync/PATENTS create mode 100644 vendor/golang.org/x/sync/errgroup/errgroup.go create mode 100644 vendor/golang.org/x/sync/errgroup/go120.go create mode 100644 vendor/golang.org/x/sync/errgroup/pre_go120.go create mode 100644 vendor/golang.org/x/sync/semaphore/semaphore.go create mode 100644 vendor/golang.org/x/sys/unix/bpxsvc_zos.go create mode 100644 vendor/golang.org/x/sys/unix/bpxsvc_zos.s delete mode 100644 vendor/golang.org/x/sys/unix/epoll_zos.go delete mode 100644 vendor/golang.org/x/sys/unix/fstatfs_zos.go create mode 100644 vendor/golang.org/x/sys/unix/sockcmsg_zos.go create mode 100644 vendor/golang.org/x/sys/unix/symaddr_zos_s390x.s create mode 100644 vendor/golang.org/x/sys/unix/zsymaddr_zos_s390x.s delete mode 100644 vendor/golang.org/x/sys/windows/empty.s delete mode 100644 vendor/google.golang.org/appengine/internal/api.go delete mode 100644 vendor/google.golang.org/appengine/internal/api_classic.go delete mode 100644 vendor/google.golang.org/appengine/internal/api_common.go delete mode 100644 vendor/google.golang.org/appengine/internal/app_id.go delete mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.pb.go delete mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.proto delete mode 100644 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.pb.go delete mode 100644 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto delete mode 100644 vendor/google.golang.org/appengine/internal/identity.go delete mode 100644 vendor/google.golang.org/appengine/internal/identity_classic.go delete mode 100644 vendor/google.golang.org/appengine/internal/identity_flex.go delete mode 100644 vendor/google.golang.org/appengine/internal/identity_vm.go delete mode 100644 vendor/google.golang.org/appengine/internal/internal.go delete mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.pb.go delete mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.proto delete mode 100644 vendor/google.golang.org/appengine/internal/main.go delete mode 100644 vendor/google.golang.org/appengine/internal/main_common.go delete mode 100644 vendor/google.golang.org/appengine/internal/main_vm.go delete mode 100644 vendor/google.golang.org/appengine/internal/metadata.go delete mode 100644 vendor/google.golang.org/appengine/internal/net.go delete mode 100644 vendor/google.golang.org/appengine/internal/regen.sh delete mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.pb.go delete mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto delete mode 100644 vendor/google.golang.org/appengine/internal/transaction.go delete mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.pb.go delete mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto delete mode 100644 vendor/google.golang.org/appengine/urlfetch/urlfetch.go create mode 100644 vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go create mode 100644 vendor/google.golang.org/protobuf/internal/editionssupport/editions.go delete mode 100644 vendor/google.golang.org/protobuf/types/gofeaturespb/go_features.proto rename vendor/k8s.io/{component-base/config/v1alpha1 => api/apidiscovery/v2}/doc.go (75%) create mode 100644 vendor/k8s.io/api/apidiscovery/v2/generated.pb.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/generated.proto create mode 100644 vendor/k8s.io/api/apidiscovery/v2/register.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/types.go create mode 100644 vendor/k8s.io/api/apidiscovery/v2/zz_generated.deepcopy.go rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/doc.go (73%) rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/generated.pb.go (91%) rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/generated.proto (94%) rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/register.go (95%) rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/types.go (88%) rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/types_swagger_doc_generated.go (95%) rename vendor/k8s.io/api/flowcontrol/{v1alpha1 => v1}/zz_generated.deepcopy.go (99%) delete mode 100644 vendor/k8s.io/api/flowcontrol/v1alpha1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/api/resource/v1alpha2/namedresources.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/doc.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/generated.pb.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/generated.proto create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/register.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/types.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/types_swagger_doc_generated.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/k8s.io/api/storagemigration/v1alpha1/zz_generated.prerelease-lifecycle.go create mode 100644 vendor/k8s.io/apiextensions-apiserver/pkg/client/applyconfiguration/apiextensions/v1/selectablefield.go rename vendor/k8s.io/{client-go/applyconfigurations/policy/v1beta1/allowedflexvolume.go => apiextensions-apiserver/pkg/client/applyconfiguration/apiextensions/v1beta1/selectablefield.go} (51%) rename vendor/k8s.io/{component-base/config => apimachinery/pkg/api/validation}/OWNERS (84%) delete mode 100644 vendor/k8s.io/apimachinery/pkg/util/sets/ordered.go create mode 100644 vendor/k8s.io/apimachinery/pkg/util/validation/OWNERS create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/auditannotation.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/expressionwarning.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/matchresources.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/namedrulewithoperations.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/paramkind.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/paramref.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/typechecking.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicybinding.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicybindingspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicyspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validatingadmissionpolicystatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/validation.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/admissionregistration/v1/variable.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/batch/v1/successpolicy.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/batch/v1/successpolicyrule.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/apparmorprofile.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/clustertrustbundleprojection.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/modifyvolumestatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/noderuntimehandler.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/noderuntimehandlerfeatures.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/sleepaction.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/volumemountstatus.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/core/v1/volumeresourcerequirements.go rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/exemptprioritylevelconfiguration.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/flowdistinguishermethod.go (87%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/flowschema.go (94%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/flowschemacondition.go (81%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/flowschemaspec.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/flowschemastatus.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/groupsubject.go (98%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/limitedprioritylevelconfiguration.go (90%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/limitresponse.go (88%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/nonresourcepolicyrule.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/policyruleswithsubjects.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/prioritylevelconfiguration.go (94%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/prioritylevelconfigurationcondition.go (81%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/prioritylevelconfigurationreference.go (98%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/prioritylevelconfigurationspec.go (92%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/prioritylevelconfigurationstatus.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/queuingconfiguration.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/resourcepolicyrule.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/serviceaccountsubject.go (99%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/subject.go (92%) rename vendor/k8s.io/client-go/applyconfigurations/flowcontrol/{v1alpha1 => v1}/usersubject.go (98%) delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1alpha1/clustercidrspec.go rename vendor/k8s.io/client-go/applyconfigurations/networking/v1alpha1/{clustercidr.go => servicecidr.go} (68%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1alpha1/servicecidrspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/networking/v1alpha1/servicecidrstatus.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/allowedhostpath.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/fsgroupstrategyoptions.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/hostportrange.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/idrange.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/podsecuritypolicyspec.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/runasgroupstrategyoptions.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/runasuserstrategyoptions.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/runtimeclassstrategyoptions.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/selinuxstrategyoptions.go delete mode 100644 vendor/k8s.io/client-go/applyconfigurations/policy/v1beta1/supplementalgroupsstrategyoptions.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/allocationresultmodel.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/driverallocationresult.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/driverrequests.go rename vendor/k8s.io/client-go/applyconfigurations/{policy/v1beta1/allowedcsidriver.go => resource/v1alpha2/namedresourcesallocationresult.go} (60%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesattribute.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesattributevalue.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesfilter.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesinstance.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesintslice.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesrequest.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesresources.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/namedresourcesstringslice.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourceclaimparameters.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourceclassparameters.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourcefilter.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourcefiltermodel.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourcemodel.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourcerequest.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/resourcerequestmodel.go rename vendor/k8s.io/client-go/applyconfigurations/{policy/v1beta1/podsecuritypolicy.go => resource/v1alpha2/resourceslice.go} (61%) create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/structuredresourcehandle.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/resource/v1alpha2/vendorparameters.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storage/v1alpha1/volumeattributesclass.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/groupversionresource.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/migrationcondition.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/storageversionmigrationspec.go create mode 100644 vendor/k8s.io/client-go/applyconfigurations/storagemigration/v1alpha1/storageversionmigrationstatus.go create mode 100644 vendor/k8s.io/client-go/features/envvar.go create mode 100644 vendor/k8s.io/client-go/features/features.go create mode 100644 vendor/k8s.io/client-go/features/known_features.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/validatingadmissionpolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/admissionregistration/v1/validatingadmissionpolicybinding.go rename vendor/{sigs.k8s.io/controller-runtime/pkg/config => k8s.io/client-go/kubernetes/typed/flowcontrol/v1}/doc.go (76%) rename vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/{v1alpha1 => v1}/flowcontrol_client.go (64%) rename vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/{v1alpha1 => v1}/flowschema.go (69%) rename vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/{v1alpha1 => v1}/generated_expansion.go (97%) rename vendor/k8s.io/client-go/kubernetes/typed/flowcontrol/{v1alpha1 => v1}/prioritylevelconfiguration.go (69%) delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/clustercidr.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/networking/v1alpha1/servicecidr.go delete mode 100644 vendor/k8s.io/client-go/kubernetes/typed/policy/v1beta1/podsecuritypolicy.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/resourceclaimparameters.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/resourceclassparameters.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/resource/v1alpha2/resourceslice.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storage/v1alpha1/volumeattributesclass.go rename vendor/k8s.io/client-go/kubernetes/typed/{flowcontrol => storagemigration}/v1alpha1/doc.go (100%) rename vendor/k8s.io/{component-base/config/doc.go => client-go/kubernetes/typed/storagemigration/v1alpha1/generated_expansion.go} (78%) create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/storagemigration_client.go create mode 100644 vendor/k8s.io/client-go/kubernetes/typed/storagemigration/v1alpha1/storageversionmigration.go create mode 100644 vendor/k8s.io/client-go/tools/cache/reflector_data_consistency_detector.go create mode 100644 vendor/k8s.io/client-go/tools/internal/events/interfaces.go delete mode 100644 vendor/k8s.io/component-base/config/types.go delete mode 100644 vendor/k8s.io/component-base/config/v1alpha1/conversion.go delete mode 100644 vendor/k8s.io/component-base/config/v1alpha1/defaults.go delete mode 100644 vendor/k8s.io/component-base/config/v1alpha1/register.go delete mode 100644 vendor/k8s.io/component-base/config/v1alpha1/types.go delete mode 100644 vendor/k8s.io/component-base/config/v1alpha1/zz_generated.conversion.go delete mode 100644 vendor/k8s.io/component-base/config/v1alpha1/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/component-base/config/zz_generated.deepcopy.go delete mode 100644 vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go delete mode 100644 vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go delete mode 100644 vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go delete mode 100644 vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go delete mode 100644 vendor/k8s.io/utils/integer/integer.go create mode 100644 vendor/k8s.io/utils/net/multi_listen.go create mode 100644 vendor/k8s.io/utils/ptr/OWNERS create mode 100644 vendor/k8s.io/utils/ptr/README.md create mode 100644 vendor/k8s.io/utils/ptr/ptr.go create mode 100644 vendor/oras.land/oras-go/v2/.gitignore create mode 100644 vendor/oras.land/oras-go/v2/CODEOWNERS create mode 100644 vendor/oras.land/oras-go/v2/CODE_OF_CONDUCT.md rename vendor/{k8s.io/component-base => oras.land/oras-go/v2}/LICENSE (99%) create mode 100644 vendor/oras.land/oras-go/v2/MIGRATION_GUIDE.md create mode 100644 vendor/oras.land/oras-go/v2/Makefile create mode 100644 vendor/oras.land/oras-go/v2/OWNERS.md create mode 100644 vendor/oras.land/oras-go/v2/README.md create mode 100644 vendor/oras.land/oras-go/v2/SECURITY.md create mode 100644 vendor/oras.land/oras-go/v2/content.go create mode 100644 vendor/oras.land/oras-go/v2/content/descriptor.go create mode 100644 vendor/oras.land/oras-go/v2/content/file/errors.go create mode 100644 vendor/oras.land/oras-go/v2/content/file/file.go create mode 100644 vendor/oras.land/oras-go/v2/content/file/utils.go create mode 100644 vendor/oras.land/oras-go/v2/content/graph.go create mode 100644 vendor/oras.land/oras-go/v2/content/limitedstorage.go create mode 100644 vendor/oras.land/oras-go/v2/content/reader.go create mode 100644 vendor/oras.land/oras-go/v2/content/resolver.go create mode 100644 vendor/oras.land/oras-go/v2/content/storage.go create mode 100644 vendor/oras.land/oras-go/v2/copy.go create mode 100644 vendor/oras.land/oras-go/v2/errdef/errors.go create mode 100644 vendor/oras.land/oras-go/v2/extendedcopy.go create mode 100644 vendor/oras.land/oras-go/v2/internal/cas/memory.go create mode 100644 vendor/oras.land/oras-go/v2/internal/cas/proxy.go create mode 100644 vendor/oras.land/oras-go/v2/internal/container/set/set.go create mode 100644 vendor/oras.land/oras-go/v2/internal/copyutil/stack.go create mode 100644 vendor/oras.land/oras-go/v2/internal/descriptor/descriptor.go create mode 100644 vendor/oras.land/oras-go/v2/internal/docker/mediatype.go create mode 100644 vendor/oras.land/oras-go/v2/internal/graph/memory.go create mode 100644 vendor/oras.land/oras-go/v2/internal/httputil/seek.go create mode 100644 vendor/oras.land/oras-go/v2/internal/interfaces/registry.go create mode 100644 vendor/oras.land/oras-go/v2/internal/ioutil/io.go create mode 100644 vendor/oras.land/oras-go/v2/internal/manifestutil/parser.go create mode 100644 vendor/oras.land/oras-go/v2/internal/platform/platform.go create mode 100644 vendor/oras.land/oras-go/v2/internal/registryutil/proxy.go create mode 100644 vendor/oras.land/oras-go/v2/internal/resolver/memory.go create mode 100644 vendor/oras.land/oras-go/v2/internal/spec/artifact.go create mode 100644 vendor/oras.land/oras-go/v2/internal/status/tracker.go create mode 100644 vendor/oras.land/oras-go/v2/internal/syncutil/limit.go create mode 100644 vendor/oras.land/oras-go/v2/internal/syncutil/limitgroup.go create mode 100644 vendor/oras.land/oras-go/v2/internal/syncutil/merge.go create mode 100644 vendor/oras.land/oras-go/v2/internal/syncutil/once.go create mode 100644 vendor/oras.land/oras-go/v2/internal/syncutil/pool.go create mode 100644 vendor/oras.land/oras-go/v2/pack.go create mode 100644 vendor/oras.land/oras-go/v2/registry/reference.go create mode 100644 vendor/oras.land/oras-go/v2/registry/registry.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/auth/cache.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/auth/challenge.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/auth/client.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/auth/credential.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/auth/scope.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/errcode/errors.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/internal/errutil/errutil.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/manifest.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/referrers.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/registry.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/repository.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/retry/client.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/retry/policy.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/url.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/utils.go create mode 100644 vendor/oras.land/oras-go/v2/registry/remote/warning.go create mode 100644 vendor/oras.land/oras-go/v2/registry/repository.go create mode 100644 vendor/oras.land/oras-go/v2/target.go create mode 100644 vendor/sigs.k8s.io/cluster-api/util/labels/format/helpers.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/client/fieldowner.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go delete mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/syncs/syncs.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/procattr_other.go create mode 100644 vendor/sigs.k8s.io/controller-runtime/pkg/internal/testing/process/procattr_unix.go create mode 100644 vendor/sigs.k8s.io/structured-merge-diff/v4/typed/compare.go delete mode 100644 vendor/sigs.k8s.io/structured-merge-diff/v4/typed/union.go diff --git a/.envrc.sample b/.envrc.sample index c616ae41..15330753 100644 --- a/.envrc.sample +++ b/.envrc.sample @@ -1,6 +1,8 @@ export PATH="$(pwd)/hack/tools/bin/:$PATH" export KUBECONFIG=$PWD/.mgt-cluster-kubeconfig.yaml export CLUSTER_TOPOLOGY=true +export EXP_RUNTIME_SDK=true +export EXP_CLUSTER_RESOURCE_SET=true export CLUSTER_NAME=test-dfkhje export SECRET_NAME=supersecret export CLOUD_NAME=test diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ac2ff6ae..cd20114f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -62,6 +62,8 @@ jobs: GIT_REPOSITORY_NAME: cluster-stacks GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }} ENCODED_CLOUDS_YAML: ${{ secrets.ENCODED_CLOUDS_YAML }} + # OCI_REGISTRY: registry.scs.community + # OCI_REPOSITORY: registry.scs.community/csctl-oci/openstack run: make test-integration # - name: Create Report diff --git a/Makefile b/Makefile index 9996c32a..971bd2ab 100644 --- a/Makefile +++ b/Makefile @@ -144,11 +144,11 @@ all-tools: get-dependencies $(GOTESTSUM) $(go-cover-treemap) $(go-binsize-treema env-vars-for-wl-cluster: ifeq ($(wildcard tilt-settings.yaml),) - @./hack/ensure-env-variables.sh GIT_PROVIDER_B64 GIT_ACCESS_TOKEN_B64 GIT_ORG_NAME_B64 GIT_REPOSITORY_NAME_B64 CLUSTER_TOPOLOGY CLUSTER_NAME SECRET_NAME CLOUD_NAME ENCODED_CLOUDS_YAML + @./hack/ensure-env-variables.sh GIT_PROVIDER_B64 GIT_ACCESS_TOKEN_B64 GIT_ORG_NAME_B64 GIT_REPOSITORY_NAME_B64 CLUSTER_TOPOLOGY EXP_RUNTIME_SDK CLUSTER_NAME SECRET_NAME CLOUD_NAME ENCODED_CLOUDS_YAML else ifeq ($(shell awk '/local_mode:/ {print tolower($$2)}' tilt-settings.yaml),true) - @./hack/ensure-env-variables.sh CLUSTER_TOPOLOGY CLUSTER_NAME SECRET_NAME CLOUD_NAME ENCODED_CLOUDS_YAML + @./hack/ensure-env-variables.sh CLUSTER_TOPOLOGY EXP_RUNTIME_SDK CLUSTER_NAME SECRET_NAME CLOUD_NAME ENCODED_CLOUDS_YAML else - @./hack/ensure-env-variables.sh GIT_PROVIDER_B64 GIT_ACCESS_TOKEN_B64 GIT_ORG_NAME_B64 GIT_REPOSITORY_NAME_B64 CLUSTER_TOPOLOGY CLUSTER_NAME SECRET_NAME CLOUD_NAME ENCODED_CLOUDS_YAML + @./hack/ensure-env-variables.sh GIT_PROVIDER_B64 GIT_ACCESS_TOKEN_B64 GIT_ORG_NAME_B64 GIT_REPOSITORY_NAME_B64 CLUSTER_TOPOLOGY EXP_RUNTIME_SDK CLUSTER_NAME SECRET_NAME CLOUD_NAME ENCODED_CLOUDS_YAML endif .PHONY: cluster @@ -494,7 +494,7 @@ generate-modules-ci: generate-modules KUBEBUILDER_ASSETS ?= $(shell $(SETUP_ENVTEST) use --use-env --bin-dir $(abspath $(TOOLS_BIN_DIR)) -p path $(KUBEBUILDER_ENVTEST_KUBERNETES_VERSION)) .PHONY: test-integration ## Run integration tests -test-integration: test-integration-github test-integration-openstack +test-integration: test-integration-openstack test-integration-github #test-integration-oci echo done .PHONY: test-unit @@ -513,6 +513,12 @@ test-integration-github: $(SETUP_ENVTEST) $(GOTESTSUM) KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GOTESTSUM) --junitfile=.coverage/junit.xml --format testname -- -mod=vendor \ -covermode=atomic -coverprofile=.coverage/cover.out -p=1 ./internal/test/integration/github/... +.PHONY: test-integration-oci +test-integration-oci: $(SETUP_ENVTEST) $(GOTESTSUM) + @mkdir -p $(shell pwd)/.coverage + KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" $(GOTESTSUM) --junitfile=.coverage/junit.xml --format testname -- -mod=vendor \ + -covermode=atomic -coverprofile=.coverage/cover.out -p=1 ./internal/test/integration/oci/... + .PHONY: test-integration-openstack test-integration-openstack: $(SETUP_ENVTEST) $(GOTESTSUM) @mkdir -p $(shell pwd)/.coverage diff --git a/Tiltfile b/Tiltfile index 4adcf976..f0df8870 100644 --- a/Tiltfile +++ b/Tiltfile @@ -22,8 +22,8 @@ settings = { "preload_images_for_kind": True, "kind_cluster_name": "cspo", "capi_version": "v1.6.0", - "cso_version": "v0.1.0-alpha.5", - "capo_version": "v0.9.0", + "cso_version": "v0.1.0-alpha.7", + "capo_version": "v0.10.4", "cert_manager_version": "v1.13.2", "kustomize_substitutions": { }, diff --git a/api/v1alpha1/conditions_const.go b/api/v1alpha1/conditions_const.go index d2d0a5bb..cbe25343 100644 --- a/api/v1alpha1/conditions_const.go +++ b/api/v1alpha1/conditions_const.go @@ -40,11 +40,11 @@ const ( ) const ( - // GitAPIAvailableCondition is used when Git API is available. - GitAPIAvailableCondition = "GitAPIAvailable" + // AssetsClientAPIAvailableCondition is used when AssetsClient API is available. + AssetsClientAPIAvailableCondition = "AssetsClientAPIAvailable" - // GitTokenOrEnvVariableNotSetReason is used when user don't specify the token or environment variable. - GitTokenOrEnvVariableNotSetReason = "GitTokenOrEnvVariableNotSet" //#nosec + // FailedCreateAssetsClientReason is used when user don't specify the token or environment variable required for initializing the assets client. + FailedCreateAssetsClientReason = "FailedCreateAssetsClient" //#nosec ) const ( diff --git a/cmd/main.go b/cmd/main.go index 83b9cf2b..01d74470 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,12 +19,15 @@ package main // Import packages including all Kubernetes client auth plugins: k8s.io/client-go/plugin/pkg/client/auth. import ( + "errors" "flag" "os" "time" - githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" - "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/fake" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/fake" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci" apiv1alpha1 "github.com/SovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1" "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/controller" "k8s.io/apimachinery/pkg/runtime" @@ -53,6 +56,7 @@ var ( releaseDir string imageImportTimeout int localMode bool + source string metricsAddr string enableLeaderElection bool probeAddr string @@ -69,7 +73,8 @@ func main() { ) flag.StringVar(&releaseDir, "release-dir", "/tmp/downloads/", "Specify release directory for cluster-stack releases") flag.IntVar(&imageImportTimeout, "image-import-timeout", 0, "Maximum time in minutes that you allow cspo to import image. If image-import-timeout <= 0, cspo waits forever.") - flag.BoolVar(&localMode, "local", false, "Enable local mode where no release assets will be downloaded from a remote Git repository. Useful for implementing cluster stacks.") + flag.BoolVar(&localMode, "local", false, "Enable local mode where no release assets will be downloaded from a remote repository. Useful for implementing cluster stacks.") + flag.StringVar(&source, "source", "github", "Specifies the source from which release assets would be downloaded. Allowed sources are 'github' and 'oci'") opts := zap.Options{ Development: true, @@ -100,18 +105,26 @@ func main() { // Initialize event recorder. record.InitFromRecorder(mgr.GetEventRecorderFor("cspo-controller")) - var gitFactory githubclient.Factory + var assetsClientFactory assetsclient.Factory if localMode { - gitFactory = fake.NewFactory() + assetsClientFactory = fake.NewFactory() } else { - gitFactory = githubclient.NewFactory() + switch source { + case "oci": + assetsClientFactory = oci.NewFactory() + case "github": + assetsClientFactory = github.NewFactory() + default: + setupLog.Error(errors.New("invalid asset source"), "no valid source specified, allowed sources are 'github' and 'oci'") + os.Exit(1) + } } if err = (&controller.OpenStackClusterStackReleaseReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), ReleaseDirectory: releaseDir, - GitHubClientFactory: gitFactory, + AssetsClientFactory: assetsClientFactory, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "OpenStackClusterStackRelease") os.Exit(1) diff --git a/config/manager/credentials.yaml b/config/manager/credentials.yaml index c8211f0a..10388eba 100644 --- a/config/manager/credentials.yaml +++ b/config/manager/credentials.yaml @@ -9,3 +9,8 @@ data: git-org-name: ${GIT_ORG_NAME_B64:=""} git-repo-name: ${GIT_REPOSITORY_NAME_B64:=""} git-access-token: ${GIT_ACCESS_TOKEN_B64:=""} + oci-registry: ${OCI_REGISTRY_B64:=""} + oci-repository: ${OCI_REPOSITORY_B64:=""} + oci-access-token: ${OCI_ACCESS_TOKEN_B64:=""} + oci-username: ${OCI_USERNAME_B64:=""} + oci-password: ${OCI_PASSWORD_B64:=""} diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index fc2e8f5b..2bd9fc5a 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -62,6 +62,31 @@ spec: secretKeyRef: name: cspo-cluster-stack-variables key: git-access-token + - name: OCI_REGISTRY + valueFrom: + secretKeyRef: + name: cspo-cluster-stack-variables + key: oci-registry + - name: OCI_REPOSITORY + valueFrom: + secretKeyRef: + name: cspo-cluster-stack-variables + key: oci-repository + - name: OCI_ACCESS_TOKEN + valueFrom: + secretKeyRef: + name: cspo-cluster-stack-variables + key: oci-access-token + - name: OCI_USERNAME + valueFrom: + secretKeyRef: + name: cspo-cluster-stack-variables + key: oci-username + - name: OCI_PASSWORD + valueFrom: + secretKeyRef: + name: cspo-cluster-stack-variables + key: oci-password image: controller:latest name: manager securityContext: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index c58cca2a..0cd91ea3 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -24,31 +24,6 @@ rules: - infrastructure.clusterstack.x-k8s.io resources: - openstackclusterstackreleases - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - infrastructure.clusterstack.x-k8s.io - resources: - - openstackclusterstackreleases/finalizers - verbs: - - update -- apiGroups: - - infrastructure.clusterstack.x-k8s.io - resources: - - openstackclusterstackreleases/status - verbs: - - get - - patch - - update -- apiGroups: - - infrastructure.clusterstack.x-k8s.io - resources: - openstacknodeimagereleases verbs: - create @@ -61,12 +36,14 @@ rules: - apiGroups: - infrastructure.clusterstack.x-k8s.io resources: + - openstackclusterstackreleases/finalizers - openstacknodeimagereleases/finalizers verbs: - update - apiGroups: - infrastructure.clusterstack.x-k8s.io resources: + - openstackclusterstackreleases/status - openstacknodeimagereleases/status verbs: - get diff --git a/docs/develop.md b/docs/develop.md index e3c6d0ef..55abb64e 100644 --- a/docs/develop.md +++ b/docs/develop.md @@ -60,7 +60,7 @@ If you have any trouble finding the right command, then you can use `make help` ## Toggle between local_mode and remote mode -We can retrieve cluster-stacks in two modes. One way is to let the controller fetch it from GitHub which is remote mode and other is we mount the cluster-stacks inside the container at `/tmp/downloads/cluster-stacks` directory. +We can retrieve cluster-stacks in two modes. One way is to let the controller fetch it from repository which is remote mode and other is we mount the cluster-stacks inside the container at `/tmp/downloads/cluster-stacks` directory. > [!NOTE] > Using remote mode is the default behavior. diff --git a/docs/images/openstackclusterstackrelease-controller.plantuml b/docs/images/openstackclusterstackrelease-controller.plantuml index a00eb33a..2d932340 100644 --- a/docs/images/openstackclusterstackrelease-controller.plantuml +++ b/docs/images/openstackclusterstackrelease-controller.plantuml @@ -6,7 +6,7 @@ start; repeat :OpenStackClusterStackRelease controller enqueues a Reconcile call; if (Release assets have been download into the CSPO container) then (no) - :Create GitHub client; + :Create assets client; #LightBlue:Download Release assets; #Pink:Return RequeueError; note left: make sure that Release can be accessed diff --git a/docs/images/openstackclusterstackrelease-controller.png b/docs/images/openstackclusterstackrelease-controller.png index 0240212309917f656679633d3e057f41caae4b45..da868279bd74d4e9c6442b6e21814dca0f3c18f8 100644 GIT binary patch literal 101057 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 R2!BMoD{=o$uGqup{|hf8xDNmT literal 87002 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 ($NfTV%$0hGRz(cDwz}7kR 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μa4qK|V(zOpd$2S{pUcn5M5%0r4n!O`5#I0jP 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 diff --git a/docs/quickstart.md b/docs/quickstart.md index 56e52215..435eb531 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -2,4 +2,4 @@ This document has been moved. -You can find the current version of the quickstart guide [here](https://docs.scs.community/docs/container/components/cluster-stacks/components/cluster-stack-provider-openstack/docs/quickstart). +You can find the current version of the quickstart guide [here](https://docs.scs.community/docs/container/components/cluster-stacks/components/cluster-stacks/providers/openstack/quickstart). diff --git a/go.mod b/go.mod index 825a2619..6f0e50e2 100644 --- a/go.mod +++ b/go.mod @@ -1,96 +1,97 @@ module github.com/SovereignCloudStack/cluster-stack-provider-openstack -go 1.22 +go 1.22.0 toolchain go1.23.0 require ( - github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.5 + github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.7 github.com/gophercloud/gophercloud/v2 v2.0.0-beta.2 github.com/gophercloud/utils/v2 v2.0.0-20240305212012-b57aefba4cdb - github.com/onsi/ginkgo/v2 v2.17.1 - github.com/onsi/gomega v1.32.0 + github.com/onsi/ginkgo/v2 v2.19.1 + github.com/onsi/gomega v1.34.0 github.com/stretchr/testify v1.9.0 - k8s.io/api v0.28.4 - k8s.io/apimachinery v0.28.4 - k8s.io/client-go v0.28.4 - k8s.io/klog/v2 v2.120.1 - sigs.k8s.io/cluster-api v1.6.0 + k8s.io/api v0.30.3 + k8s.io/apimachinery v0.30.3 + k8s.io/client-go v0.30.3 + k8s.io/klog/v2 v2.130.1 + sigs.k8s.io/cluster-api v1.8.1 sigs.k8s.io/cluster-api-provider-openstack v0.9.0 - sigs.k8s.io/controller-runtime v0.16.5 + sigs.k8s.io/controller-runtime v0.18.5 sigs.k8s.io/yaml v1.4.0 ) -require github.com/google/go-github/v52 v52.0.0 +require github.com/google/go-github/v52 v52.0.0 // indirect require ( github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/circl v1.3.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/evanphx/json-patch/v5 v5.7.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect - github.com/go-logr/zapr v1.2.4 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect + github.com/evanphx/json-patch v5.7.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gobuffalo/flect v1.0.2 // 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.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gophercloud/gophercloud v1.11.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/imdario/mergo v0.3.15 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.17.0 // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // 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_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.25.0 // indirect - golang.org/x/crypto v0.20.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/oauth2 v0.14.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.17.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.28.4 // indirect - k8s.io/component-base v0.28.4 // indirect - k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect - k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect + k8s.io/apiextensions-apiserver v0.30.3 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + oras.land/oras-go/v2 v2.5.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index 0a656162..db02691a 100644 --- a/go.sum +++ b/go.sum @@ -8,77 +8,73 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= -github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.5 h1:jONI0j2BVpL6ubQt9nT8LxWwtHQ1kyrvt1X/1+Hrea8= -github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.5/go.mod h1:zrwUudq/JQae24/yzS5exA1ZwaXxIL2ZtKIQVrYuPqY= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1 h1:X8MJ0fnN5FPdcGF5Ij2/OW+HgiJrRg3AfHAx1PJtIzM= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230321174746-8dcc6526cfb1/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.7 h1:Kuu+fBAs190SSthXR+jDMMU/I58zDLNfkYMwvmWnXys= +github.com/SovereignCloudStack/cluster-stack-operator v0.1.0-alpha.7/go.mod h1:jYNYO65Y9ncoZFhB87yh/Ig1tGugYzFFj7aj3NGM0g4= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= -github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/coredns/caddy v1.1.0 h1:ezvsPrT/tA/7pYDBZxu0cT0VmWk75AfIaf6GSYCNMf0= -github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= -github.com/coredns/corefile-migration v1.0.21 h1:W/DCETrHDiFo0Wj03EyMkaQ9fwsmSgqTCQDHpceaSsE= -github.com/coredns/corefile-migration v1.0.21/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= +github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= +github.com/coredns/corefile-migration v1.0.23 h1:Fp4FETmk8sT/IRgnKX2xstC2dL7+QdcU+BL5AYIN3Jw= +github.com/coredns/corefile-migration v1.0.23/go.mod h1:8HyMhuyzx9RLZp8cRc9Uf3ECpEAafHOFxQWUPqktMQI= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= -github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= -github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= +github.com/evanphx/json-patch v5.7.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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +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/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.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.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= 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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo= -github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= 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/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -89,21 +85,23 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 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-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +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/gophercloud/gophercloud v1.11.0 h1:ls0O747DIq1D8SUHc7r2vI8BFbMLeLFuENaAIfEx7OM= github.com/gophercloud/gophercloud v1.11.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gophercloud/gophercloud/v2 v2.0.0-beta.2 h1:JWv6L7eg3+aIS57n11YlVvtn1pVCKpVlMo24ANj/OVc= github.com/gophercloud/gophercloud/v2 v2.0.0-beta.2/go.mod h1:Sy5GHwY4iazyaRf94rzL/VxJToVWn8WnIH+1cXqoAks= github.com/gophercloud/utils/v2 v2.0.0-20240305212012-b57aefba4cdb h1:Mh5JdhNBmS9UPOsZdB3Vf09McFVumONpQzNGTXfKDxs= github.com/gophercloud/utils/v2 v2.0.0-20240305212012-b57aefba4cdb/go.mod h1:lnmaqFj6tCRbGAvvda4DIs6Aryii/1ETsDTOi+1hAs8= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -112,7 +110,6 @@ 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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -122,8 +119,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -137,31 +132,33 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= -github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= -github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= -github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= 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/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +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_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/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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= @@ -172,8 +169,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE 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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -181,103 +176,97 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 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.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= +go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 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.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 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.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= -go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 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.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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/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.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.62.2 h1:iEIj1U5qjyBjzkM5nk3Fq+S1IbjbXSyqeULZ1Nfo4AA= +google.golang.org/grpc v1.62.2/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -288,35 +277,39 @@ 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.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY= -k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0= -k8s.io/apiextensions-apiserver v0.28.4 h1:AZpKY/7wQ8n+ZYDtNHbAJBb+N4AXXJvyZx6ww6yAJvU= -k8s.io/apiextensions-apiserver v0.28.4/go.mod h1:pgQIZ1U8eJSMQcENew/0ShUTlePcSGFq6dxSxf2mwPM= -k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8= -k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg= -k8s.io/apiserver v0.28.4 h1:BJXlaQbAU/RXYX2lRz+E1oPe3G3TKlozMMCZWu5GMgg= -k8s.io/apiserver v0.28.4/go.mod h1:Idq71oXugKZoVGUUL2wgBCTHbUR+FYTWa4rq9j4n23w= -k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY= -k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4= -k8s.io/cluster-bootstrap v0.28.4 h1:4MKNy1Qd9QY7pl47rSMGIORF+tm3CUaqC1M8U9bjn4Q= -k8s.io/cluster-bootstrap v0.28.4/go.mod h1:/c4ro/R4yf4EtJgFgFtvnHkbDOHwubeKJXh5R1c89Bc= -k8s.io/component-base v0.28.4 h1:c/iQLWPdUgI90O+T9TeECg8o7N3YJTiuz2sKxILYcYo= -k8s.io/component-base v0.28.4/go.mod h1:m9hR0uvqXDybiGL2nf/3Lf0MerAfQXzkfWhUY58JUbU= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= -k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= -k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU= -k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/cluster-api v1.6.0 h1:2bhVSnUbtWI8taCjd9lGiHExsRUpKf7Z1fXqi/IwYx4= -sigs.k8s.io/cluster-api v1.6.0/go.mod h1:LB7u/WxiWj4/bbpHNOa1oQ8nq0MQ5iYlD0pGfRSBGLI= +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/apiserver v0.30.3 h1:QZJndA9k2MjFqpnyYv/PH+9PE0SHhx3hBho4X0vE65g= +k8s.io/apiserver v0.30.3/go.mod h1:6Oa88y1CZqnzetd2JdepO0UXzQX4ZnOekx2/PtEjrOg= +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/cluster-bootstrap v0.30.3 h1:MgxyxMkpaC6mu0BKWJ8985XCOnKU+eH3Iy+biwtDXRk= +k8s.io/cluster-bootstrap v0.30.3/go.mod h1:h8BoLDfdD7XEEIXy7Bx9FcMzxHwz29jsYYi34bM5DKU= +k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= +k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= +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-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= +oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.0 h1:Tc9rS7JJoZ9sl3OpL4842oIk6lH7gWBb0JOmJ0ute7M= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.0/go.mod h1:1ewhL9l1gkPcU/IU/6rFYfikf+7Y5imWv7ARVbBOzNs= +sigs.k8s.io/cluster-api v1.8.1 h1:OA3w1CjCmXXXDL7aY3WDe+seL0mdFVJX1K5mZwqKbDE= +sigs.k8s.io/cluster-api v1.8.1/go.mod h1:pXv5LqLxuIbhGIXykyNKiJh+KrLweSBajVHHitPLyoY= sigs.k8s.io/cluster-api-provider-openstack v0.9.0 h1:ScwZIfT1kI88+qMzeO7ppMP9DvEzrfLHuYPg2p1mcho= sigs.k8s.io/cluster-api-provider-openstack v0.9.0/go.mod h1:ecR9lx4XbOr3Gg2CGNgM3wguuV6l31Nd5rUccE+xjKs= -sigs.k8s.io/controller-runtime v0.16.5 h1:yr1cEJbX08xsTW6XEIzT13KHHmIyX8Umvme2cULvFZw= -sigs.k8s.io/controller-runtime v0.16.5/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= +sigs.k8s.io/controller-runtime v0.18.5 h1:nTHio/W+Q4aBlQMgbnC5hZb4IjIidyrizMai9P6n4Rk= +sigs.k8s.io/controller-runtime v0.18.5/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/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/controller/openstackclusterstackrelease_controller.go b/internal/controller/openstackclusterstackrelease_controller.go index 8c995145..f00d8d22 100644 --- a/internal/controller/openstackclusterstackrelease_controller.go +++ b/internal/controller/openstackclusterstackrelease_controller.go @@ -19,14 +19,13 @@ package controller import ( "context" "fmt" - "net/http" "os" "path/filepath" "strings" "sync" "time" - githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" "github.com/SovereignCloudStack/cluster-stack-operator/pkg/release" apiv1alpha1 "github.com/SovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -49,7 +48,7 @@ import ( type OpenStackClusterStackReleaseReconciler struct { client.Client Scheme *runtime.Scheme - GitHubClientFactory githubclient.Factory + AssetsClientFactory assetsclient.Factory ReleaseDirectory string openStackClusterStackRelDownloadDirectoryMutex sync.Mutex } @@ -60,7 +59,6 @@ type NodeImages struct { } const ( - metadataFileName = "metadata.yaml" nodeImagesFileName = "node-images.yaml" waitForOpenStackNodeImageReleasesBecomeReady = 30 * time.Second ) @@ -123,28 +121,28 @@ func (r *OpenStackClusterStackReleaseReconciler) Reconcile(ctx context.Context, if download { conditions.MarkFalse(openstackclusterstackrelease, apiv1alpha1.ClusterStackReleaseAssetsReadyCondition, apiv1alpha1.ReleaseAssetsNotDownloadedYetReason, clusterv1beta1.ConditionSeverityInfo, "assets not downloaded yet") - gc, err := r.GitHubClientFactory.NewClient(ctx) + ac, err := r.AssetsClientFactory.NewClient(ctx) if err != nil { conditions.MarkFalse(openstackclusterstackrelease, - apiv1alpha1.GitAPIAvailableCondition, - apiv1alpha1.GitTokenOrEnvVariableNotSetReason, + apiv1alpha1.AssetsClientAPIAvailableCondition, + apiv1alpha1.FailedCreateAssetsClientReason, clusterv1beta1.ConditionSeverityError, err.Error(), ) - record.Warnf(openstackclusterstackrelease, "GitTokenOrEnvVariableNotSet", err.Error()) - logger.Error(err, "failed to create Github client") + record.Warnf(openstackclusterstackrelease, "FailedCreateAssetsClient", err.Error()) + logger.Error(err, "failed to create assets client") return ctrl.Result{}, nil } - conditions.MarkTrue(openstackclusterstackrelease, apiv1alpha1.GitAPIAvailableCondition) + conditions.MarkTrue(openstackclusterstackrelease, apiv1alpha1.AssetsClientAPIAvailableCondition) - // this is the point where we download the release from github + // this is the point where we download the release from repository // acquire lock so that only one reconcile loop can download the release r.openStackClusterStackRelDownloadDirectoryMutex.Lock() defer r.openStackClusterStackRelDownloadDirectoryMutex.Unlock() - if err := downloadReleaseAssets(ctx, releaseTag, releaseAssets.LocalDownloadPath, gc); err != nil { + if err := downloadReleaseAssets(ctx, releaseTag, releaseAssets.LocalDownloadPath, ac); err != nil { logger.Error(err, "failed to download release assets") return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil } @@ -237,7 +235,7 @@ func (r *OpenStackClusterStackReleaseReconciler) createOrUpdateOpenStackNodeImag } // Unexpected error - if err != nil && !apierrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return fmt.Errorf("failed to get OpenStackNodeImageRelease: %w", err) } @@ -283,18 +281,8 @@ func (r *OpenStackClusterStackReleaseReconciler) getOwnedOpenStackNodeImageRelea return ownedOpenStackNodeImageReleases, nil } -func downloadReleaseAssets(ctx context.Context, releaseTag, downloadPath string, gc githubclient.Client) error { - repoRelease, resp, err := gc.GetReleaseByTag(ctx, releaseTag) - if err != nil { - return fmt.Errorf("failed to fetch release tag %q: %w", releaseTag, err) - } - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("failed to fetch release tag %s with status code %d", releaseTag, resp.StatusCode) - } - - assetlist := []string{metadataFileName, nodeImagesFileName} - - if err := gc.DownloadReleaseAssets(ctx, repoRelease, downloadPath, assetlist); err != nil { +func downloadReleaseAssets(ctx context.Context, releaseTag, downloadPath string, ac assetsclient.Client) error { + if err := ac.DownloadReleaseAssets(ctx, releaseTag, downloadPath); err != nil { // if download failed for some reason, delete the release directory so that it can be retried in the next reconciliation if err := os.RemoveAll(downloadPath); err != nil { return fmt.Errorf("failed to remove release: %w", err) diff --git a/internal/controller/openstackclusterstackrelease_controller_test.go b/internal/controller/openstackclusterstackrelease_controller_test.go index 34dbf996..475cabd1 100644 --- a/internal/controller/openstackclusterstackrelease_controller_test.go +++ b/internal/controller/openstackclusterstackrelease_controller_test.go @@ -20,13 +20,11 @@ import ( "context" "errors" "fmt" - "net/http" "testing" "time" - githubmocks "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks" + assetsclientmocks "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks" apiv1alpha1 "github.com/SovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1" - "github.com/google/go-github/v52/github" "github.com/gophercloud/gophercloud/v2/openstack/imageservice/v2/images" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -203,26 +201,11 @@ func TestDownloadReleaseAssets(t *testing.T) { ctx := context.TODO() releaseTag := "v1.0.0" downloadPath := "/tmp/download" - assetlist := []string{metadataFileName, nodeImagesFileName} - mockGitHubClient := githubmocks.NewClient(t) - mockHTTPResponse := &http.Response{ - StatusCode: http.StatusOK, - } - mockResponse := &github.Response{ - Response: mockHTTPResponse, - } - mockRepoRelease := &github.RepositoryRelease{ - Name: github.String("test-release-name"), - } - - mockGitHubClient.On("GetReleaseByTag", ctx, releaseTag).Return(mockRepoRelease, mockResponse, nil) - repoRelease, resp, err := mockGitHubClient.GetReleaseByTag(ctx, releaseTag) - assert.NoError(t, err) - assert.Equal(t, resp.StatusCode, http.StatusOK) + mockAssetsClient := assetsclientmocks.NewClient(t) - mockGitHubClient.On("DownloadReleaseAssets", ctx, repoRelease, downloadPath, assetlist).Return(nil) + mockAssetsClient.On("DownloadReleaseAssets", ctx, releaseTag, downloadPath).Return(nil) - err = downloadReleaseAssets(ctx, releaseTag, downloadPath, mockGitHubClient) + err := downloadReleaseAssets(ctx, releaseTag, downloadPath, mockAssetsClient) assert.NoError(t, err) } @@ -230,26 +213,12 @@ func TestDownloadReleaseAssets(t *testing.T) { func TestDownloadReleaseAssetsFailedToDownload(t *testing.T) { ctx := context.TODO() releaseTag := "v1.0.0" - mockGitHubClient := githubmocks.NewClient(t) downloadPath := "/tmp/download" - assetlist := []string{metadataFileName, nodeImagesFileName} - mockHTTPResponse := &http.Response{ - StatusCode: http.StatusOK, - } - mockResponse := &github.Response{ - Response: mockHTTPResponse, - } - mockRepoRelease := &github.RepositoryRelease{ - Name: github.String("test-release-name"), - } + mockAssetsClient := assetsclientmocks.NewClient(t) - mockGitHubClient.On("GetReleaseByTag", ctx, releaseTag).Return(mockRepoRelease, mockResponse, nil) - repoRelease, resp, err := mockGitHubClient.GetReleaseByTag(ctx, releaseTag) - assert.NoError(t, err) - assert.Equal(t, resp.StatusCode, http.StatusOK) + mockAssetsClient.On("DownloadReleaseAssets", ctx, releaseTag, downloadPath).Return(errors.New("failed to download release assets")) - mockGitHubClient.On("DownloadReleaseAssets", ctx, repoRelease, downloadPath, assetlist).Return(errors.New("failed to download release assets")) - err = downloadReleaseAssets(ctx, releaseTag, downloadPath, mockGitHubClient) + err := downloadReleaseAssets(ctx, releaseTag, downloadPath, mockAssetsClient) assert.ErrorContains(t, err, "failed to download release assets") } diff --git a/internal/test/helpers/envtest.go b/internal/test/helpers/envtest.go index 121af0f7..afdcb1b7 100644 --- a/internal/test/helpers/envtest.go +++ b/internal/test/helpers/envtest.go @@ -24,8 +24,8 @@ import ( "path/filepath" goruntime "runtime" - githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" - githubmocks "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" + assetsclientmocks "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks" cspov1alpha1 "github.com/SovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1" g "github.com/onsi/ginkgo/v2" corev1 "k8s.io/api/core/v1" @@ -95,8 +95,8 @@ type ( client.Client Config *rest.Config cancel context.CancelFunc - GitHubClientFactory githubclient.Factory - GitHubClient *githubmocks.Client + AssetsClientFactory assetsclient.Factory + AssetsClient *assetsclientmocks.Client } ) @@ -127,14 +127,14 @@ func NewTestEnvironment() *TestEnvironment { klog.Fatalf("unable to create manager pod namespace: %s", err) } - githubClient := &githubmocks.Client{} + assetsClient := &assetsclientmocks.Client{} testEnv := &TestEnvironment{ Manager: mgr, Client: mgr.GetClient(), Config: mgr.GetConfig(), - GitHubClientFactory: githubmocks.NewGitHubFactory(githubClient), - GitHubClient: githubClient, + AssetsClientFactory: assetsclientmocks.NewAssetsClientFactory(assetsClient), + AssetsClient: assetsClient, } return testEnv diff --git a/internal/test/integration/github/integration_suite_test.go b/internal/test/integration/github/integration_suite_test.go index 0baf1719..b92baef6 100644 --- a/internal/test/integration/github/integration_suite_test.go +++ b/internal/test/integration/github/integration_suite_test.go @@ -20,7 +20,7 @@ import ( "testing" "time" - githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" + githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github" "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/controller" "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/test/helpers" . "github.com/onsi/ginkgo/v2" @@ -47,7 +47,7 @@ var _ = BeforeSuite(func() { testEnv = helpers.NewTestEnvironment() Expect((&controller.OpenStackClusterStackReleaseReconciler{ Client: testEnv.Manager.GetClient(), - GitHubClientFactory: githubclient.NewFactory(), + AssetsClientFactory: githubclient.NewFactory(), ReleaseDirectory: "/tmp/downloads", }).SetupWithManager(testEnv.Manager)).To(Succeed()) diff --git a/internal/test/integration/oci/integration_suite_test.go b/internal/test/integration/oci/integration_suite_test.go new file mode 100644 index 00000000..a3e85850 --- /dev/null +++ b/internal/test/integration/oci/integration_suite_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oci + +import ( + "testing" + "time" + + ociclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci" + "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/controller" + "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/test/helpers" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + ctrl "sigs.k8s.io/controller-runtime" +) + +const ( + timeout = time.Second * 10 + interval = 1000 * time.Millisecond + releaseDir = "/tmp/downloads" +) + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Controller Suite") +} + +var ( + ctx = ctrl.SetupSignalHandler() + testEnv *helpers.TestEnvironment +) + +var _ = BeforeSuite(func() { + testEnv = helpers.NewTestEnvironment() + Expect((&controller.OpenStackClusterStackReleaseReconciler{ + Client: testEnv.Manager.GetClient(), + AssetsClientFactory: ociclient.NewFactory(), + ReleaseDirectory: releaseDir, + }).SetupWithManager(testEnv.Manager)).To(Succeed()) + + go func() { + defer GinkgoRecover() + Expect(testEnv.StartManager(ctx)).To(Succeed()) + }() + <-testEnv.Manager.Elected() +}) + +var _ = AfterSuite(func() { + Expect(testEnv.Stop()).To(Succeed()) +}) diff --git a/internal/test/integration/oci/integration_test.go b/internal/test/integration/oci/integration_test.go new file mode 100644 index 00000000..8bf73560 --- /dev/null +++ b/internal/test/integration/oci/integration_test.go @@ -0,0 +1,109 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oci + +import ( + "encoding/base64" + "os" + + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/test/utils" + cspov1alpha1 "github.com/SovereignCloudStack/cluster-stack-provider-openstack/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + apiv1alpha7 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7" + clusterv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1" +) + +var _ = Describe("OpenStackClusterStackReleaseReconciler", func() { + Context("test", func() { + var ( + openStackClusterStackRelease *cspov1alpha1.OpenStackClusterStackRelease + testNs *corev1.Namespace + openstackClusterStackReleaseKey types.NamespacedName + ) + + BeforeEach(func() { + var err error + testNs, err = testEnv.CreateNamespace(ctx, "oscsr-integration") + Expect(err).NotTo(HaveOccurred()) + + openstackClusterStackReleaseKey = types.NamespacedName{Name: "openstack-scs-1-28-v0-sha-umng5ie", Namespace: testNs.Name} + + cloudsYAMLBase64 := os.Getenv("ENCODED_CLOUDS_YAML") + cloudsYAMLData, err := base64.StdEncoding.DecodeString(cloudsYAMLBase64) + Expect(err).NotTo(HaveOccurred()) + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "supersecret", + Namespace: testNs.Name, + }, + Data: map[string][]byte{ + "clouds.yaml": cloudsYAMLData, + }, + } + Expect(testEnv.Create(ctx, secret)).To(Succeed()) + + openStackClusterStackRelease = &cspov1alpha1.OpenStackClusterStackRelease{ + TypeMeta: metav1.TypeMeta{ + Kind: "OpenStackClusterStackRelease", + APIVersion: "infrastructure.clusterstack.x-k8s.io", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "openstack-scs-1-28-v0-sha-umng5ie", + Namespace: testNs.Name, + }, + Spec: cspov1alpha1.OpenStackClusterStackReleaseSpec{ + IdentityRef: &apiv1alpha7.OpenStackIdentityReference{ + Kind: "Secret", + Name: "supersecret", + }, + }, + Status: cspov1alpha1.OpenStackClusterStackReleaseStatus{ + Ready: false, + Conditions: clusterv1beta1.Conditions{}, + }, + } + Expect(testEnv.Create(ctx, openStackClusterStackRelease)).To(Succeed()) + }) + + AfterEach(func() { + Expect(os.RemoveAll(releaseDir)).To(Succeed()) + Eventually(func() error { + return testEnv.Cleanup(ctx, testNs, openStackClusterStackRelease) + }, timeout, interval).Should(BeNil()) + }) + + It("creates the OpenStackNodeImageRelease object", func() { + openstackNodeImageReleaseName := types.NamespacedName{Name: "openstack-scs-1-28-ubuntu-capi-image-v1.28.11-v0-sha-umng5ie", Namespace: testNs.Name} + Eventually(func() error { + var openStackNodeImageRelease cspov1alpha1.OpenStackNodeImageRelease + return testEnv.Get(ctx, openstackNodeImageReleaseName, &openStackNodeImageRelease) + }, timeout, interval).Should(BeNil()) + }) + + It("sets ClusterStackReleaseAssetsReadyCondition condition once OpenStackClusterStackRelease object is created", func() { + Eventually(func() bool { + var openStackClusterStackRelease cspov1alpha1.OpenStackClusterStackRelease + return utils.IsPresentAndTrue(ctx, testEnv.Client, openstackClusterStackReleaseKey, &openStackClusterStackRelease, cspov1alpha1.ClusterStackReleaseAssetsReadyCondition) + }, timeout, interval).Should(BeTrue()) + }) + }) +}) diff --git a/internal/test/integration/openstack/controller_suite_test.go b/internal/test/integration/openstack/controller_suite_test.go index 46d28bc1..5524664e 100644 --- a/internal/test/integration/openstack/controller_suite_test.go +++ b/internal/test/integration/openstack/controller_suite_test.go @@ -20,7 +20,6 @@ import ( "testing" "time" - githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/controller" "github.com/SovereignCloudStack/cluster-stack-provider-openstack/internal/test/helpers" . "github.com/onsi/ginkgo/v2" @@ -50,7 +49,7 @@ var _ = BeforeSuite(func() { Expect((&controller.OpenStackClusterStackReleaseReconciler{ Client: testEnv.Manager.GetClient(), - GitHubClientFactory: githubclient.NewFactory(), + AssetsClientFactory: testEnv.AssetsClientFactory, ReleaseDirectory: "./../../../../test/releases", }).SetupWithManager(testEnv.Manager)).To(Succeed()) diff --git a/local_cso.yaml b/local_cso.yaml index bf3c6a5c..39b6d817 100644 --- a/local_cso.yaml +++ b/local_cso.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Namespace metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator control-plane: cso-controller-manager name: cso-system --- @@ -10,9 +10,9 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.16.2 labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator cluster.x-k8s.io/v1beta1: v1beta1 name: clusteraddons.clusterstack.x-k8s.io spec: @@ -21,6 +21,8 @@ spec: kind: ClusterAddon listKind: ClusterAddonList plural: clusteraddons + shortNames: + - caddon singular: clusteraddon scope: Namespaced versions: @@ -28,6 +30,10 @@ spec: - jsonPath: .metadata.ownerReferences[?(@.kind=="Cluster")].name name: Cluster type: string + - description: Present running hook + jsonPath: .spec.hook + name: Hook + type: string - jsonPath: .status.ready name: Ready type: boolean @@ -47,14 +53,19 @@ spec: description: ClusterAddon is the schema for the clusteraddons API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -63,49 +74,57 @@ spec: object. properties: clusterRef: - description: ClusterRef is the reference to the clusterv1.Cluster - object that corresponds to the workload cluster where this controller - applies the cluster addons. + description: |- + ClusterRef is the reference to the clusterv1.Cluster object that corresponds to the workload cluster where this + controller applies the cluster addons. properties: apiVersion: description: API version of the referent. type: string fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. type: string kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ type: string resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency type: string uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids type: string type: object x-kubernetes-map-type: atomic clusterStack: - description: ClusterStack is the full string --- that will be filled with the cluster stack that - the respective cluster uses currently. It always matches cluster.spec.topology.class - if the work of this controller is done. + description: |- + ClusterStack is the full string --- that will be filled with the cluster stack that + the respective cluster uses currently. It always matches cluster.spec.topology.class if the work of this controller is done. + type: string + hook: + description: Hook specifies the runtime hook for the Cluster event. type: string version: description: Version is the version of the cluster addons that have @@ -124,37 +143,37 @@ spec: operational state. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: - description: A human readable message indicating details about - the transition. This field may be empty. + description: |- + A human readable message indicating details about the transition. + This field may be empty. type: string reason: - description: The reason for the condition's last transition - in CamelCase. The specific API may choose whether or not this - field is considered a guaranteed API. This field may not be - empty. + description: |- + The reason for the condition's last transition in CamelCase. + The specific API may choose whether or not this field is considered a guaranteed API. + This field may not be empty. type: string severity: - description: Severity provides an explicit classification of - Reason code, so the users or machines can immediately understand - the current situation and act accordingly. The Severity field - MUST be set only when Status=False. + description: |- + Severity provides an explicit classification of Reason code, so the users or machines can immediately + understand the current situation and act accordingly. + The Severity field MUST be set only when Status=False. type: string status: description: Status of the condition, one of True, False, Unknown. type: string type: - description: Type of condition in CamelCase or in foo.example.com/CamelCase. - Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. + description: |- + Type of condition in CamelCase or in foo.example.com/CamelCase. + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability to deconflict is important. type: string required: - lastTransitionTime @@ -196,6 +215,25 @@ spec: type: string type: object type: array + stages: + description: Stages shows the state of all stages in the current running + hook. + items: + description: StageStatus represents the helm charts of the hook + and it's phases. + properties: + action: + description: Action is the action of the helm chart. e.g. - + apply and delete. + type: string + name: + description: Name represent name of the helm chart + type: string + phase: + description: Phase is the current phase of the helm chart. + type: string + type: object + type: array type: object type: object served: true @@ -207,9 +245,9 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.16.2 labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator cluster.x-k8s.io/v1beta1: v1beta1 name: clusterstackreleases.clusterstack.x-k8s.io spec: @@ -218,6 +256,8 @@ spec: kind: ClusterStackRelease listKind: ClusterStackReleaseList plural: clusterstackreleases + shortNames: + - cskr singular: clusterstackrelease scope: Namespaced versions: @@ -245,14 +285,19 @@ spec: API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -260,41 +305,47 @@ spec: description: ClusterStackReleaseSpec defines the desired state of ClusterStackRelease. properties: providerRef: - description: ProviderRef specifies the reference to the ProviderClusterStackRelease - object. It has to be set only if the object exists, i.e. if the - noProvider mode is turned off. + description: |- + ProviderRef specifies the reference to the ProviderClusterStackRelease object. + It has to be set only if the object exists, i.e. if the noProvider mode is turned off. properties: apiVersion: description: API version of the referent. type: string fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. type: string kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ type: string resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency type: string uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids type: string type: object x-kubernetes-map-type: atomic @@ -309,37 +360,37 @@ spec: operational state. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: - description: A human readable message indicating details about - the transition. This field may be empty. + description: |- + A human readable message indicating details about the transition. + This field may be empty. type: string reason: - description: The reason for the condition's last transition - in CamelCase. The specific API may choose whether or not this - field is considered a guaranteed API. This field may not be - empty. + description: |- + The reason for the condition's last transition in CamelCase. + The specific API may choose whether or not this field is considered a guaranteed API. + This field may not be empty. type: string severity: - description: Severity provides an explicit classification of - Reason code, so the users or machines can immediately understand - the current situation and act accordingly. The Severity field - MUST be set only when Status=False. + description: |- + Severity provides an explicit classification of Reason code, so the users or machines can immediately + understand the current situation and act accordingly. + The Severity field MUST be set only when Status=False. type: string status: description: Status of the condition, one of True, False, Unknown. type: string type: - description: Type of condition in CamelCase or in foo.example.com/CamelCase. - Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. + description: |- + Type of condition in CamelCase or in foo.example.com/CamelCase. + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability to deconflict is important. type: string required: - lastTransitionTime @@ -348,9 +399,9 @@ spec: type: object type: array kubernetesVersion: - description: KubernetesVersion is the Kubernetes version incl. patch - version, e.g. 1.26.6. The controller fetches the version from the - release assets of the cluster stack. + description: |- + KubernetesVersion is the Kubernetes version incl. patch version, e.g. 1.26.6. + The controller fetches the version from the release assets of the cluster stack. type: string ready: default: false @@ -397,9 +448,9 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.12.0 + controller-gen.kubebuilder.io/version: v0.16.2 labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator cluster.x-k8s.io/v1beta1: v1beta1 name: clusterstacks.clusterstack.x-k8s.io spec: @@ -408,6 +459,8 @@ spec: kind: ClusterStack listKind: ClusterStackList plural: clusterstacks + shortNames: + - csk singular: clusterstack scope: Namespaced versions: @@ -449,14 +502,19 @@ spec: description: ClusterStack is the Schema for the clusterstacks API. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -502,42 +560,47 @@ spec: description: API version of the referent. type: string fieldPath: - description: 'If referring to a piece of an object instead of - an entire object, this string should contain a valid JSON/Go - field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part of - an object. TODO: this design is not final and this field is - subject to change in the future.' + description: |- + If referring to a piece of an object instead of an entire object, this string + should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within a pod, this would take on a value like: + "spec.containers{name}" (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to have some well-defined way of + referencing a part of an object. type: string kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind of the referent. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ type: string resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + description: |- + Specific resourceVersion to which this reference is made, if any. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency type: string uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids type: string type: object x-kubernetes-map-type: atomic versions: - description: Versions is a list of version of the cluster stack that - should be available in the management cluster. A version has to - have the format 'v', e.g. v1 for stable channel or, - v1-alpha.1 for alpha channel. The versions have to correspond to - the channel property. + description: |- + Versions is a list of version of the cluster stack that should be available in the management cluster. + A version has to have the format 'v', e.g. v1 for stable channel or, v1-alpha.1 for alpha channel. + The versions have to correspond to the channel property. items: type: string type: array @@ -557,37 +620,37 @@ spec: operational state. properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. This should be when the underlying condition changed. - If that is not known, then using the time when the API field - changed is acceptable. + description: |- + Last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when + the API field changed is acceptable. format: date-time type: string message: - description: A human readable message indicating details about - the transition. This field may be empty. + description: |- + A human readable message indicating details about the transition. + This field may be empty. type: string reason: - description: The reason for the condition's last transition - in CamelCase. The specific API may choose whether or not this - field is considered a guaranteed API. This field may not be - empty. + description: |- + The reason for the condition's last transition in CamelCase. + The specific API may choose whether or not this field is considered a guaranteed API. + This field may not be empty. type: string severity: - description: Severity provides an explicit classification of - Reason code, so the users or machines can immediately understand - the current situation and act accordingly. The Severity field - MUST be set only when Status=False. + description: |- + Severity provides an explicit classification of Reason code, so the users or machines can immediately + understand the current situation and act accordingly. + The Severity field MUST be set only when Status=False. type: string status: description: Status of the condition, one of True, False, Unknown. type: string type: - description: Type of condition in CamelCase or in foo.example.com/CamelCase. - Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. + description: |- + Type of condition in CamelCase or in foo.example.com/CamelCase. + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability to deconflict is important. type: string required: - lastTransitionTime @@ -631,7 +694,7 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-controller-manager namespace: cso-system --- @@ -639,7 +702,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-leader-election-role namespace: cso-system rules: @@ -679,7 +742,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-manager-role rules: - apiGroups: @@ -707,6 +770,7 @@ rules: - cluster.x-k8s.io - controlplane.cluster.x-k8s.io - infrastructure.cluster.x-k8s.io + - infrastructure.clusterstack.x-k8s.io resources: - '*' verbs: @@ -739,12 +803,15 @@ rules: - clusterstack.x-k8s.io resources: - clusteraddons/finalizers + - clusterstackreleases/finalizers verbs: - update - apiGroups: - clusterstack.x-k8s.io resources: - clusteraddons/status + - clusterstackreleases/status + - clusterstacks/status verbs: - get - patch @@ -760,20 +827,6 @@ rules: - list - patch - watch -- apiGroups: - - clusterstack.x-k8s.io - resources: - - clusterstackreleases/finalizers - verbs: - - update -- apiGroups: - - clusterstack.x-k8s.io - resources: - - clusterstackreleases/status - verbs: - - get - - patch - - update - apiGroups: - clusterstack.x-k8s.io resources: @@ -791,32 +844,12 @@ rules: verbs: - delete - update -- apiGroups: - - clusterstack.x-k8s.io - resources: - - clusterstacks/status - verbs: - - get - - patch - - update -- apiGroups: - - infrastructure.clusterstack.x-k8s.io - resources: - - '*' - verbs: - - create - - delete - - get - - list - - patch - - update - - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-leader-election-rolebinding namespace: cso-system roleRef: @@ -832,7 +865,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-manager-rolebinding roleRef: apiGroup: rbac.authorization.k8s.io @@ -843,11 +876,41 @@ subjects: name: cso-controller-manager namespace: cso-system --- +apiVersion: v1 +kind: Service +metadata: + labels: + cluster.x-k8s.io/provider: cluster-stack-operator + name: cso-hook-server-svc + namespace: cso-system +spec: + ports: + - port: 443 + targetPort: 9442 + selector: + cluster.x-k8s.io/provider: cluster-stack-operator + control-plane: cso-controller-manager +--- +apiVersion: v1 +kind: Service +metadata: + labels: + cluster.x-k8s.io/provider: cluster-stack-operator + name: cso-webhook-service + namespace: cso-system +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + cluster.x-k8s.io/provider: cluster-stack-operator + control-plane: cso-controller-manager +--- apiVersion: apps/v1 kind: Deployment metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator control-plane: cso-controller-manager name: cso-controller-manager namespace: cso-system @@ -855,23 +918,24 @@ spec: replicas: 1 selector: matchLabels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator control-plane: cso-controller-manager template: metadata: annotations: kubectl.kubernetes.io/default-container: manager labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator control-plane: cso-controller-manager spec: containers: - args: - --leader-elect=true + - --log-level=info - --local=true command: - /manager - image: ghcr.io/sovereigncloudstack/cso-test:v0.1.0-alpha.5 + image: ghcr.io/sovereigncloudstack/cso-test:v0.1.0-alpha.7 imagePullPolicy: Always livenessProbe: failureThreshold: 3 @@ -884,6 +948,12 @@ spec: timeoutSeconds: 1 name: manager ports: + - containerPort: 9442 + name: hook-server-svc + protocol: TCP + - containerPort: 9443 + name: webhook-server + protocol: TCP - containerPort: 9440 name: healthz protocol: TCP @@ -903,23 +973,58 @@ spec: requests: cpu: 200m memory: 250Mi + volumeMounts: + - mountPath: /tmp/k8s-hook-server/serving-certs + name: hook-server-cert + readOnly: true + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true serviceAccountName: cso-controller-manager terminationGracePeriodSeconds: 10 tolerations: - effect: NoSchedule key: node-role.kubernetes.io/control-plane + volumes: + - name: hook-server-cert + secret: + defaultMode: 420 + secretName: cso-hook-server-server-cert + - name: cert + secret: + defaultMode: 420 + secretName: cso-webhook-server-cert --- apiVersion: cert-manager.io/v1 kind: Certificate metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator + name: cso-hook-server-server-cert + namespace: cso-system +spec: + dnsNames: + - cso-hook-server-svc.cso-system.svc + - cso-hook-server-svc.cso-system.svc.cluster.local + issuerRef: + kind: Issuer + name: cso-selfsigned-issuer + secretName: cso-hook-server-server-cert + subject: + organizations: + - k8s-sig-cluster-lifecycle +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + labels: + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-serving-cert namespace: cso-system spec: dnsNames: - - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc - - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local + - cso-webhook-service.cso-system.svc + - cso-webhook-service.cso-system.svc.cluster.local issuerRef: kind: Issuer name: cso-selfsigned-issuer @@ -932,8 +1037,119 @@ apiVersion: cert-manager.io/v1 kind: Issuer metadata: labels: - cluster.x-k8s.io/provider: infrastructure-cluster-stack-operator + cluster.x-k8s.io/provider: cluster-stack-operator name: cso-selfsigned-issuer namespace: cso-system spec: selfSigned: {} +--- +apiVersion: runtime.cluster.x-k8s.io/v1alpha1 +kind: ExtensionConfig +metadata: + annotations: + runtime.cluster.x-k8s.io/inject-ca-from-secret: cso-system/cso-hook-server-server-cert + labels: + cluster.x-k8s.io/provider: cluster-stack-operator + name: cso-hook-server-extensionconfig + namespace: cso-system +spec: + clientConfig: + service: + name: cso-hook-server-svc + namespace: cso-system + port: 443 + namespaceSelector: {} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + annotations: + cert-manager.io/inject-ca-from: cso-system/cso-serving-cert + labels: + cluster.x-k8s.io/provider: cluster-stack-operator + name: cso-validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: cso-webhook-service + namespace: cso-system + path: /validate-cluster-x-k8s-io-v1beta1-cluster + failurePolicy: Fail + name: validation.cluster.cluster.x-k8s.io + rules: + - apiGroups: + - cluster.x-k8s.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - clusters + sideEffects: None +- admissionReviewVersions: + - v1 + - v1alpha1 + clientConfig: + service: + name: cso-webhook-service + namespace: cso-system + path: /validate-clusterstack-x-k8s-io-v1alpha1-clusteraddon + failurePolicy: Fail + name: validation.clusteraddon.clusterstack.x-k8s.io + rules: + - apiGroups: + - clusterstack.x-k8s.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - clusteraddons + sideEffects: None +- admissionReviewVersions: + - v1 + - v1alpha1 + clientConfig: + service: + name: cso-webhook-service + namespace: cso-system + path: /validate-clusterstack-x-k8s-io-v1alpha1-clusterstack + failurePolicy: Fail + name: validation.clusterstack.clusterstack.x-k8s.io + rules: + - apiGroups: + - clusterstack.x-k8s.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - clusterstacks + sideEffects: None +- admissionReviewVersions: + - v1 + - v1alpha1 + clientConfig: + service: + name: cso-webhook-service + namespace: cso-system + path: /validate-clusterstack-x-k8s-io-v1alpha1-clusterstackrelease + failurePolicy: Fail + name: validation.clusterstackrelease.clusterstack.x-k8s.io + rules: + - apiGroups: + - clusterstack.x-k8s.io + apiVersions: + - v1alpha1 + operations: + - DELETE + resources: + - clusterstackreleases + sideEffects: None diff --git a/tilt-settings.yaml.example b/tilt-settings.yaml.example index ab602ad8..bb089542 100644 --- a/tilt-settings.yaml.example +++ b/tilt-settings.yaml.example @@ -6,6 +6,6 @@ deploy_cert_manager: true preload_images_for_kind: true kind_cluster_name: cspo capi_version: v1.6.0 -cso_version: v0.1.0-alpha.5 -capo_version: v0.9.0 +cso_version: v0.1.0-alpha.7 +capo_version: v0.10.4 cert_manager_version: v1.13.2 diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/client.go new file mode 100644 index 00000000..1d545837 --- /dev/null +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/client.go @@ -0,0 +1,33 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package assetsclient contains interface for talking to assets repositories. +package assetsclient + +import ( + "context" +) + +// Client contains functions to talk to list and download assets. +type Client interface { + DownloadReleaseAssets(ctx context.Context, tag, path string) error + ListRelease(ctx context.Context) ([]string, error) +} + +// Factory is a factory to generate assets clients. +type Factory interface { + NewClient(ctx context.Context) (Client, error) +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/fake/client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/fake/client.go new file mode 100644 index 00000000..953ab854 --- /dev/null +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/fake/client.go @@ -0,0 +1,60 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package fake defines a fake Gitub client. +package fake + +import ( + "context" + + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" + "github.com/go-logr/logr" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +type fakeClient struct { + log logr.Logger +} + +type factory struct{} + +var _ = assetsclient.Client(&fakeClient{}) + +var _ = assetsclient.Factory(&factory{}) + +// NewFactory returns a new factory for assets clients. +func NewFactory() assetsclient.Factory { + return &factory{} +} + +func (*factory) NewClient(ctx context.Context) (assetsclient.Client, error) { + logger := log.FromContext(ctx) + + return &fakeClient{ + log: logger, + }, nil +} + +func (c *fakeClient) ListRelease(_ context.Context) ([]string, error) { + c.log.Info("WARNING: called ListRelease of fake assets client") + return nil, nil +} + +// DownloadReleaseAssets downloads a list of release assets. +func (c *fakeClient) DownloadReleaseAssets(_ context.Context, _, _ string) error { + c.log.Info("WARNING: called DownloadReleaseAssets of fake assets client") + return nil +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/github_client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github/client.go similarity index 75% rename from vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/github_client.go rename to vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github/client.go index 9f26800e..4a7e88c5 100644 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/github_client.go +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github/client.go @@ -1,5 +1,5 @@ /* -Copyright 2023 The Kubernetes Authors. +Copyright 2024 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package client +package github import ( "context" @@ -23,24 +23,12 @@ import ( "net/http" "os" "path/filepath" - "strings" + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" "github.com/google/go-github/v52/github" "golang.org/x/oauth2" ) -// Client contains all functions to talk to Github API. -type Client interface { - DownloadReleaseAssets(ctx context.Context, release *github.RepositoryRelease, path string, assetlist []string) error - GetReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error) - ListRelease(ctx context.Context) ([]*github.RepositoryRelease, *github.Response, error) -} - -// Factory is a factory to generate Github clients. -type Factory interface { - NewClient(ctx context.Context) (Client, error) -} - type realGhClient struct { client *github.Client httpclient *http.Client @@ -50,18 +38,18 @@ type realGhClient struct { type factory struct{} -var _ = Client(&realGhClient{}) +var _ = assetsclient.Client(&realGhClient{}) -var _ = Factory(&factory{}) +var _ = assetsclient.Factory(&factory{}) // NewFactory returns a new factory for Github clients. -func NewFactory() Factory { +func NewFactory() assetsclient.Factory { return &factory{} } -var _ = Client(&realGhClient{}) +var _ = assetsclient.Client(&realGhClient{}) -func (*factory) NewClient(ctx context.Context) (Client, error) { +func (*factory) NewClient(ctx context.Context) (assetsclient.Client, error) { creds, err := NewGitConfig() if err != nil { return nil, fmt.Errorf("failed to create git config: %w", err) @@ -83,16 +71,26 @@ func (*factory) NewClient(ctx context.Context) (Client, error) { }, nil } -func (c *realGhClient) ListRelease(ctx context.Context) ([]*github.RepositoryRelease, *github.Response, error) { +func (c *realGhClient) ListRelease(ctx context.Context) ([]string, error) { repoRelease, response, err := c.client.Repositories.ListReleases(ctx, c.orgName, c.repoName, &github.ListOptions{}) if err != nil { - return nil, nil, fmt.Errorf("failed to list releases: %w", err) + return nil, fmt.Errorf("failed to list releases: %w", err) } - return repoRelease, response, nil + if response != nil && response.StatusCode != http.StatusOK { + return nil, fmt.Errorf("got unexpected status from call to remote repository: %s", response.Status) + } + + releases := []string{} + + for _, release := range repoRelease { + releases = append(releases, *release.Name) + } + + return releases, nil } -func (c *realGhClient) GetReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error) { +func (c *realGhClient) getReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error) { repoRelease, response, err := c.client.Repositories.GetReleaseByTag(ctx, c.orgName, c.repoName, tag) if err != nil { return nil, nil, fmt.Errorf("failed to get release tag: %w", err) @@ -102,15 +100,21 @@ func (c *realGhClient) GetReleaseByTag(ctx context.Context, tag string) (*github } // DownloadReleaseAssets downloads a list of release assets. -func (c *realGhClient) DownloadReleaseAssets(ctx context.Context, release *github.RepositoryRelease, path string, assetlist []string) error { - if err := os.MkdirAll(path, os.ModePerm); err != nil { +func (c *realGhClient) DownloadReleaseAssets(ctx context.Context, tag, path string) error { + release, response, err := c.getReleaseByTag(ctx, tag) + if err != nil { + return fmt.Errorf("failed to fetch release tag %s: %w", tag, err) + } + + if response.StatusCode != http.StatusOK { + return fmt.Errorf("failed to fetch release tag %s with status code %d: %w", tag, response.StatusCode, err) + } + + if err := os.MkdirAll(path, os.ModePerm); err != nil { //nolint:gosec //nolint:ignore return fmt.Errorf("failed to create destination directory: %w", err) } // Extract the release assets for _, asset := range release.Assets { - if !contains(assetlist, asset.GetName()) { - continue - } assetPath := filepath.Join(path, asset.GetName()) // Create a temporary file (inside the dest dir) to save the downloaded asset file assetFile, err := os.Create(filepath.Clean(assetPath)) @@ -145,7 +149,7 @@ func (c *realGhClient) DownloadReleaseAssets(ctx context.Context, release *githu return nil } -func (c *realGhClient) handleRedirect(ctx context.Context, url string, assetFile *os.File) error { +func (c *realGhClient) handleRedirect(ctx context.Context, url string, assetFile *os.File) (reterr error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, http.NoBody) if err != nil { return fmt.Errorf("failed to define http get request: %w", err) @@ -156,6 +160,13 @@ func (c *realGhClient) handleRedirect(ctx context.Context, url string, assetFile return fmt.Errorf("failed to get URL %q: %w", url, err) } + defer func() { + err := resp.Body.Close() + if reterr == nil { + reterr = err + } + }() + if resp.StatusCode != http.StatusOK { return fmt.Errorf("failed to download asset, HTTP status code: %d", resp.StatusCode) } @@ -164,9 +175,6 @@ func (c *realGhClient) handleRedirect(ctx context.Context, url string, assetFile return fmt.Errorf("failed to copy http response in file: %w", err) } - if err := resp.Body.Close(); err != nil { - return fmt.Errorf("failed to close body of response: %w", err) - } return nil } @@ -196,12 +204,3 @@ func verifyAccess(ctx context.Context, client *github.Client, creds GitConfig) e } return nil } - -func contains(source []string, ghAsset string) bool { - for _, a := range source { - if a == ghAsset || strings.Contains(ghAsset, a) { - return true - } - } - return false -} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/credentials.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github/credentials.go similarity index 96% rename from vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/credentials.go rename to vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github/credentials.go index 542f4e42..6845bccb 100644 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/credentials.go +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/github/credentials.go @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package client contains interface for github client. -package client +// Package github provides utilities for talking to github API. +package github import ( "fmt" diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Client.go new file mode 100644 index 00000000..227e2c67 --- /dev/null +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Client.go @@ -0,0 +1,68 @@ +// Code generated by mockery v2.32.4. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// Client is an autogenerated mock type for the Client type +type Client struct { + mock.Mock +} + +// DownloadReleaseAssets provides a mock function with given fields: ctx, tag, path +func (_m *Client) DownloadReleaseAssets(ctx context.Context, tag string, path string) error { + ret := _m.Called(ctx, tag, path) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, tag, path) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ListRelease provides a mock function with given fields: ctx +func (_m *Client) ListRelease(ctx context.Context) ([]string, error) { + ret := _m.Called(ctx) + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) ([]string, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) []string); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewClient(t interface { + mock.TestingT + Cleanup(func()) +}) *Client { + mock := &Client{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Factory.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Factory.go similarity index 70% rename from vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Factory.go rename to vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Factory.go index f7046f9f..a57ed99f 100644 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Factory.go +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/Factory.go @@ -5,7 +5,7 @@ package mocks import ( context "context" - client "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" + assetsclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" mock "github.com/stretchr/testify/mock" ) @@ -16,19 +16,19 @@ type Factory struct { } // NewClient provides a mock function with given fields: ctx -func (_m *Factory) NewClient(ctx context.Context) (client.Client, error) { +func (_m *Factory) NewClient(ctx context.Context) (assetsclient.Client, error) { ret := _m.Called(ctx) - var r0 client.Client + var r0 assetsclient.Client var r1 error - if rf, ok := ret.Get(0).(func(context.Context) (client.Client, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context) (assetsclient.Client, error)); ok { return rf(ctx) } - if rf, ok := ret.Get(0).(func(context.Context) client.Client); ok { + if rf, ok := ret.Get(0).(func(context.Context) assetsclient.Client); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(client.Client) + r0 = ret.Get(0).(assetsclient.Client) } } diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/assetsFactory.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/assetsFactory.go new file mode 100644 index 00000000..46fc102b --- /dev/null +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/mocks/assetsFactory.go @@ -0,0 +1,37 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package mocks implement important mocking interface of packer. +package mocks + +import ( + "context" + + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" +) + +type assetsClientFactory struct { + client *Client +} + +// NewAssetsClientFactory returns a mocked assets client factory. +func NewAssetsClientFactory(client *Client) assetsclient.Factory { + return &assetsClientFactory{client: client} +} + +func (f *assetsClientFactory) NewClient(_ context.Context) (assetsclient.Client, error) { + return f.client, nil +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/client.go new file mode 100644 index 00000000..d7218d63 --- /dev/null +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/client.go @@ -0,0 +1,99 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package oci + +import ( + "context" + "errors" + "fmt" + + "github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient" + "oras.land/oras-go/v2" + "oras.land/oras-go/v2/content/file" + "oras.land/oras-go/v2/registry" + "oras.land/oras-go/v2/registry/remote" + "oras.land/oras-go/v2/registry/remote/auth" +) + +type ociClient struct { + repository *remote.Repository +} + +type factory struct{} + +// NewFactory returns a new factory for OCI clients. +func NewFactory() assetsclient.Factory { + return &factory{} +} + +var _ = assetsclient.Factory(&factory{}) + +var _ = assetsclient.Client(&ociClient{}) + +func (*factory) NewClient(ctx context.Context) (assetsclient.Client, error) { + _ = ctx + config, err := newOCIConfig() + if err != nil { + return nil, fmt.Errorf("failed to create OCI config: %w", err) + } + + client := auth.Client{ + Credential: auth.StaticCredential(config.registry, auth.Credential{ + AccessToken: config.accessToken, + Username: config.username, + Password: config.password, + }), + } + + repository, err := remote.NewRepository(config.repository) + if err != nil { + return nil, fmt.Errorf("failed to create OCI client to remote repository %s: %w", config.repository, err) + } + + repository.Client = &client + return &ociClient{repository: repository}, nil +} + +func (c *ociClient) ListRelease(ctx context.Context) ([]string, error) { + tags, err := registry.Tags(ctx, c.repository) + if err != nil { + return nil, fmt.Errorf("failed to list tags: %w", err) + } + + return tags, nil +} + +func (c *ociClient) DownloadReleaseAssets(ctx context.Context, tag, path string) (reterr error) { + dest, err := file.New(path) + if err != nil { + return fmt.Errorf("failed to create file store: %w", err) + } + + defer func() { + err := dest.Close() + if err != nil { + reterr = errors.Join(reterr, err) + } + }() + + _, err = oras.Copy(ctx, c.repository, tag, dest, tag, oras.DefaultCopyOptions) + if err != nil { + return fmt.Errorf("failed to copy repository artifacts to path %s: %w", path, err) + } + + return nil +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/credentials.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/credentials.go new file mode 100644 index 00000000..9c7d84e8 --- /dev/null +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/assetsclient/oci/credentials.go @@ -0,0 +1,68 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package oci provides utilities for comunicating with the OCI registry. +package oci + +import ( + "encoding/base64" + "fmt" + "os" +) + +const ( + envOCIRegistry = "OCI_REGISTRY" + envOCIRepository = "OCI_REPOSITORY" + envOCIAccessToken = "OCI_ACCESS_TOKEN" + envOCIUsername = "OCI_USERNAME" + envOCIPassword = "OCI_PASSWORD" +) + +type ociConfig struct { + registry string + repository string + accessToken string + username string + password string +} + +func newOCIConfig() (ociConfig, error) { + var config ociConfig + + val := os.Getenv(envOCIRegistry) + if val == "" { + return ociConfig{}, fmt.Errorf("environment variable %s is not set", envOCIRegistry) + } + config.registry = val + + val = os.Getenv(envOCIRepository) + if val == "" { + return ociConfig{}, fmt.Errorf("environment variable %s is not set", envOCIRepository) + } + config.repository = val + + val = os.Getenv(envOCIAccessToken) + base64AccessToken := base64.StdEncoding.EncodeToString([]byte(val)) + config.accessToken = base64AccessToken + + val = os.Getenv(envOCIUsername) + config.username = val + + val = os.Getenv(envOCIPassword) + config.password = val + + return config, nil +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/clusterstack/clusterstack.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/clusterstack/clusterstack.go index 37cead13..47f5b99e 100644 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/clusterstack/clusterstack.go +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/clusterstack/clusterstack.go @@ -198,7 +198,14 @@ func (cs *ClusterStack) Validate() error { return nil } +// String returns cluster stack with "-" notation. func (cs *ClusterStack) String() string { // release tag: myprovider-myclusterstack-1-26-v1 return strings.Join([]string{cs.Provider, cs.Name, cs.KubernetesVersion.String(), cs.Version.String()}, Separator) } + +// StringWithDot returns cluster stack with semver "." notation. +func (cs *ClusterStack) StringWithDot() string { + // release tag: myprovider-myclusterstack-1-26-v0-sha.hd237u2 + return strings.Join([]string{cs.Provider, cs.Name, cs.KubernetesVersion.String(), cs.Version.StringWithDot()}, Separator) +} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/fake/github_client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/fake/github_client.go deleted file mode 100644 index 90e0bd09..00000000 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/fake/github_client.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2023 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package fake defines a fake Gitub client. -package fake - -import ( - "context" - "net/http" - - "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" - "github.com/go-logr/logr" - "github.com/google/go-github/v52/github" - "sigs.k8s.io/controller-runtime/pkg/log" -) - -type fakeClient struct { - log logr.Logger -} - -type factory struct{} - -var _ = client.Client(&fakeClient{}) - -var _ = client.Factory(&factory{}) - -// NewFactory returns a new factory for Github clients. -func NewFactory() client.Factory { - return &factory{} -} - -func (*factory) NewClient(ctx context.Context) (client.Client, error) { - logger := log.FromContext(ctx) - - return &fakeClient{ - log: logger, - }, nil -} - -func (c *fakeClient) ListRelease(_ context.Context) ([]*github.RepositoryRelease, *github.Response, error) { - c.log.Info("WARNING: called ListRelease of fake Github client") - resp := &github.Response{Response: &http.Response{StatusCode: http.StatusOK}} - return nil, resp, nil -} - -func (c *fakeClient) GetReleaseByTag(_ context.Context, _ string) (*github.RepositoryRelease, *github.Response, error) { - c.log.Info("WARNING: called GetReleaseByTag of fake Github client") - resp := &github.Response{Response: &http.Response{StatusCode: http.StatusOK}} - return nil, resp, nil -} - -// DownloadReleaseAssets downloads a list of release assets. -func (c *fakeClient) DownloadReleaseAssets(_ context.Context, _ *github.RepositoryRelease, _ string, _ []string) error { - c.log.Info("WARNING: called DownloadReleaseAssets of fake Github client") - return nil -} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Client.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Client.go deleted file mode 100644 index 279ba3df..00000000 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/Client.go +++ /dev/null @@ -1,113 +0,0 @@ -// Code generated by mockery v2.32.4. DO NOT EDIT. - -package mocks - -import ( - context "context" - - github "github.com/google/go-github/v52/github" - mock "github.com/stretchr/testify/mock" -) - -// Client is an autogenerated mock type for the Client type -type Client struct { - mock.Mock -} - -// DownloadReleaseAssets provides a mock function with given fields: ctx, release, path, assetlist -func (_m *Client) DownloadReleaseAssets(ctx context.Context, release *github.RepositoryRelease, path string, assetlist []string) error { - ret := _m.Called(ctx, release, path, assetlist) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *github.RepositoryRelease, string, []string) error); ok { - r0 = rf(ctx, release, path, assetlist) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// GetReleaseByTag provides a mock function with given fields: ctx, tag -func (_m *Client) GetReleaseByTag(ctx context.Context, tag string) (*github.RepositoryRelease, *github.Response, error) { - ret := _m.Called(ctx, tag) - - var r0 *github.RepositoryRelease - var r1 *github.Response - var r2 error - if rf, ok := ret.Get(0).(func(context.Context, string) (*github.RepositoryRelease, *github.Response, error)); ok { - return rf(ctx, tag) - } - if rf, ok := ret.Get(0).(func(context.Context, string) *github.RepositoryRelease); ok { - r0 = rf(ctx, tag) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*github.RepositoryRelease) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, string) *github.Response); ok { - r1 = rf(ctx, tag) - } else { - if ret.Get(1) != nil { - r1 = ret.Get(1).(*github.Response) - } - } - - if rf, ok := ret.Get(2).(func(context.Context, string) error); ok { - r2 = rf(ctx, tag) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// ListRelease provides a mock function with given fields: ctx -func (_m *Client) ListRelease(ctx context.Context) ([]*github.RepositoryRelease, *github.Response, error) { - ret := _m.Called(ctx) - - var r0 []*github.RepositoryRelease - var r1 *github.Response - var r2 error - if rf, ok := ret.Get(0).(func(context.Context) ([]*github.RepositoryRelease, *github.Response, error)); ok { - return rf(ctx) - } - if rf, ok := ret.Get(0).(func(context.Context) []*github.RepositoryRelease); ok { - r0 = rf(ctx) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]*github.RepositoryRelease) - } - } - - if rf, ok := ret.Get(1).(func(context.Context) *github.Response); ok { - r1 = rf(ctx) - } else { - if ret.Get(1) != nil { - r1 = ret.Get(1).(*github.Response) - } - } - - if rf, ok := ret.Get(2).(func(context.Context) error); ok { - r2 = rf(ctx) - } else { - r2 = ret.Error(2) - } - - return r0, r1, r2 -} - -// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewClient(t interface { - mock.TestingT - Cleanup(func()) -}) *Client { - mock := &Client{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/gfactory.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/gfactory.go deleted file mode 100644 index b6e0e986..00000000 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client/mocks/gfactory.go +++ /dev/null @@ -1,23 +0,0 @@ -// Package mocks implement important mocking interface of packer. -package mocks - -import ( - "context" - - githubclient "github.com/SovereignCloudStack/cluster-stack-operator/pkg/github/client" -) - -type githubFactory struct { - client *Client -} - -// NewGitHubFactory returns a mocked Github client. -func NewGitHubFactory(client *Client) githubclient.Factory { - return &githubFactory{client: client} -} - -var _ = githubclient.Factory(&githubFactory{}) - -func (f *githubFactory) NewClient(_ context.Context) (githubclient.Client, error) { - return f.client, nil -} diff --git a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/release/release.go b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/release/release.go index 473f668f..218c77a0 100644 --- a/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/release/release.go +++ b/vendor/github.com/SovereignCloudStack/cluster-stack-operator/pkg/release/release.go @@ -46,9 +46,19 @@ var ( ) const ( - clusterStackSuffix = "cluster-stacks" - metadataFileName = "metadata.yaml" - clusterAddonValuesName = "cluster-addon-values.yaml" + // ClusterStackSuffix is the directory name where cluster stacks are there. + ClusterStackSuffix = "cluster-stacks" + + // ClusterAddonYamlName is the file name where clusteraddon config is there. + ClusterAddonYamlName = "clusteraddon.yaml" + + metadataFileName = "metadata.yaml" + + // ClusterAddonValuesName constant for the file cluster-addon-values.yaml. + ClusterAddonValuesName = "cluster-addon-values.yaml" + + // OverwriteYaml is the new cluster stack overwrite yaml. + OverwriteYaml = "overwrite.yaml" ) // New returns a new release. @@ -59,7 +69,7 @@ func New(tag, downloadPath string) (Release, bool, error) { // downloadPath is the path where the release is downloaded. // The path is of the form: /// // For example: /tmp/downloads/cluster-stacks/docker-ferrol-1-26-v2/ - downloadPath = filepath.Join(downloadPath, clusterStackSuffix, tag) + downloadPath = filepath.Join(downloadPath, ClusterStackSuffix, tag) cs, err := clusterstack.NewFromClusterStackReleaseProperties(tag) if err != nil { return Release{}, false, fmt.Errorf("failed to parse cluster stack release: %w", err) @@ -157,13 +167,20 @@ func (r *Release) CheckHelmCharts() error { return fmt.Errorf("failed to verify the cluster addon chart path %s with error: %w", clusterClassChartPath, err) } - // check if the cluster addon values file is present. - valuesPath := filepath.Join(r.LocalDownloadPath, clusterAddonValuesName) - if _, err := os.Stat(valuesPath); err != nil { - return fmt.Errorf("failed to verify the cluster addon values path %s with error: %w", valuesPath, err) + clusterAddonPath := filepath.Join(r.LocalDownloadPath, ClusterAddonYamlName) + if _, err := os.Stat(clusterAddonPath); err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("failed to verify the clusteraddon.yaml path %s with error: %w", clusterAddonPath, err) + } + + // check if the cluster addon values file is present. + valuesPath := filepath.Join(r.LocalDownloadPath, ClusterAddonValuesName) + if _, err := os.Stat(valuesPath); err != nil { + return fmt.Errorf("failed to verify the cluster addon values path %s with error: %w", valuesPath, err) + } } - // check if the cluster class chart is present. + // check if the cluster addon chart is present. clusterAddonChartName := r.clusterAddonChartName() clusterAddonChartPath, err := r.helmChartNamePath(clusterAddonChartName) if err != nil { @@ -212,7 +229,7 @@ func (r *Release) ClusterAddonChartPath() string { // ClusterAddonValuesPath returns the path to the cluster addon values file. func (r *Release) ClusterAddonValuesPath() string { - return filepath.Join(r.LocalDownloadPath, clusterAddonValuesName) + return filepath.Join(r.LocalDownloadPath, ClusterAddonValuesName) } // clusterClassChartName returns the helm chart name for cluster class. diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md index 8bf0e5b7..33c88305 100644 --- a/vendor/github.com/cespare/xxhash/v2/README.md +++ b/vendor/github.com/cespare/xxhash/v2/README.md @@ -70,3 +70,5 @@ benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$') - [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) - [FreeCache](https://github.com/coocood/freecache) - [FastCache](https://github.com/VictoriaMetrics/fastcache) +- [Ristretto](https://github.com/dgraph-io/ristretto) +- [Badger](https://github.com/dgraph-io/badger) diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go index a9e0d45c..78bddf1c 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash.go @@ -19,10 +19,13 @@ const ( // Store the primes in an array as well. // // The consts are used when possible in Go code to avoid MOVs but we need a -// contiguous array of the assembly code. +// contiguous array for the assembly code. var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} // Digest implements hash.Hash64. +// +// Note that a zero-valued Digest is not ready to receive writes. +// Call Reset or create a Digest using New before calling other methods. type Digest struct { v1 uint64 v2 uint64 @@ -33,19 +36,31 @@ type Digest struct { n int // how much of mem is used } -// New creates a new Digest that computes the 64-bit xxHash algorithm. +// New creates a new Digest with a zero seed. func New() *Digest { + return NewWithSeed(0) +} + +// NewWithSeed creates a new Digest with the given seed. +func NewWithSeed(seed uint64) *Digest { var d Digest - d.Reset() + d.ResetWithSeed(seed) return &d } // Reset clears the Digest's state so that it can be reused. +// It uses a seed value of zero. func (d *Digest) Reset() { - d.v1 = primes[0] + prime2 - d.v2 = prime2 - d.v3 = 0 - d.v4 = -primes[0] + d.ResetWithSeed(0) +} + +// ResetWithSeed clears the Digest's state so that it can be reused. +// It uses the given seed to initialize the state. +func (d *Digest) ResetWithSeed(seed uint64) { + d.v1 = seed + prime1 + prime2 + d.v2 = seed + prime2 + d.v3 = seed + d.v4 = seed - prime1 d.total = 0 d.n = 0 } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go index 9216e0a4..78f95f25 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go @@ -6,7 +6,7 @@ package xxhash -// Sum64 computes the 64-bit xxHash digest of b. +// Sum64 computes the 64-bit xxHash digest of b with a zero seed. // //go:noescape func Sum64(b []byte) uint64 diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go index 26df13bb..118e49e8 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go @@ -3,7 +3,7 @@ package xxhash -// Sum64 computes the 64-bit xxHash digest of b. +// Sum64 computes the 64-bit xxHash digest of b with a zero seed. func Sum64(b []byte) uint64 { // A simpler version would be // d := New() diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go index e86f1b5f..05f5e7df 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go @@ -5,7 +5,7 @@ package xxhash -// Sum64String computes the 64-bit xxHash digest of s. +// Sum64String computes the 64-bit xxHash digest of s with a zero seed. func Sum64String(s string) uint64 { return Sum64([]byte(s)) } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go index 1c1638fd..cf9d42ae 100644 --- a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go @@ -33,7 +33,7 @@ import ( // // See https://github.com/golang/go/issues/42739 for discussion. -// Sum64String computes the 64-bit xxHash digest of s. +// Sum64String computes the 64-bit xxHash digest of s with a zero seed. // It may be faster than Sum64([]byte(s)) by avoiding a copy. func Sum64String(s string) uint64 { b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) diff --git a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go index 8cd4e333..83d7cdad 100644 --- a/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go +++ b/vendor/github.com/cloudflare/circl/ecc/goldilocks/twist.go @@ -9,7 +9,7 @@ import ( fp "github.com/cloudflare/circl/math/fp448" ) -// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogeneous to Goldilocks. +// twistCurve is -x^2+y^2=1-39082x^2y^2 and is 4-isogenous to Goldilocks. type twistCurve struct{} // Identity returns the identity point. diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go b/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go index ab19d0ad..1755fd1e 100644 --- a/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go +++ b/vendor/github.com/cloudflare/circl/internal/sha3/keccakf.go @@ -6,13 +6,21 @@ package sha3 // KeccakF1600 applies the Keccak permutation to a 1600b-wide // state represented as a slice of 25 uint64s. +// If turbo is true, applies the 12-round variant instead of the +// regular 24-round variant. // nolint:funlen -func KeccakF1600(a *[25]uint64) { +func KeccakF1600(a *[25]uint64, turbo bool) { // Implementation translated from Keccak-inplace.c // in the keccak reference code. var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 - for i := 0; i < 24; i += 4 { + i := 0 + + if turbo { + i = 12 + } + + for ; i < 24; i += 4 { // Combines the 5 steps in each round into 2 steps. // Unrolls 4 rounds per loop and spreads some steps across rounds. diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go b/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go index b35cd006..a0df5aa6 100644 --- a/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go +++ b/vendor/github.com/cloudflare/circl/internal/sha3/sha3.go @@ -51,6 +51,7 @@ type State struct { // Specific to SHA-3 and SHAKE. outputLen int // the default output size in bytes state spongeDirection // whether the sponge is absorbing or squeezing + turbo bool // Whether we're using 12 rounds instead of 24 } // BlockSize returns the rate of sponge underlying this hash function. @@ -86,11 +87,11 @@ func (d *State) permute() { xorIn(d, d.buf()) d.bufe = 0 d.bufo = 0 - KeccakF1600(&d.a) + KeccakF1600(&d.a, d.turbo) case spongeSqueezing: // If we're squeezing, we need to apply the permutation before // copying more output. - KeccakF1600(&d.a) + KeccakF1600(&d.a, d.turbo) d.bufe = d.rate d.bufo = 0 copyOut(d, d.buf()) @@ -136,7 +137,7 @@ func (d *State) Write(p []byte) (written int, err error) { // The fast path; absorb a full "rate" bytes of input and apply the permutation. xorIn(d, p[:d.rate]) p = p[d.rate:] - KeccakF1600(&d.a) + KeccakF1600(&d.a, d.turbo) } else { // The slow path; buffer the input until we can fill the sponge, and then xor it in. todo := d.rate - bufl @@ -193,3 +194,7 @@ func (d *State) Sum(in []byte) []byte { _, _ = dup.Read(hash) return append(in, hash...) } + +func (d *State) IsAbsorbing() bool { + return d.state == spongeAbsorbing +} diff --git a/vendor/github.com/cloudflare/circl/internal/sha3/shake.go b/vendor/github.com/cloudflare/circl/internal/sha3/shake.go index b92c5b7d..77817f75 100644 --- a/vendor/github.com/cloudflare/circl/internal/sha3/shake.go +++ b/vendor/github.com/cloudflare/circl/internal/sha3/shake.go @@ -57,6 +57,17 @@ func NewShake128() State { return State{rate: rate128, dsbyte: dsbyteShake} } +// NewTurboShake128 creates a new TurboSHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +// D is the domain separation byte and must be between 0x01 and 0x7f inclusive. +func NewTurboShake128(D byte) State { + if D == 0 || D > 0x7f { + panic("turboshake: D out of range") + } + return State{rate: rate128, dsbyte: D, turbo: true} +} + // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // Its generic security strength is 256 bits against all attacks if // at least 64 bytes of its output are used. @@ -64,6 +75,17 @@ func NewShake256() State { return State{rate: rate256, dsbyte: dsbyteShake} } +// NewTurboShake256 creates a new TurboSHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +// D is the domain separation byte and must be between 0x01 and 0x7f inclusive. +func NewTurboShake256(D byte) State { + if D == 0 || D > 0x7f { + panic("turboshake: D out of range") + } + return State{rate: rate256, dsbyte: D, turbo: true} +} + // ShakeSum128 writes an arbitrary-length digest of data into hash. func ShakeSum128(hash, data []byte) { h := NewShake128() @@ -77,3 +99,21 @@ func ShakeSum256(hash, data []byte) { _, _ = h.Write(data) _, _ = h.Read(hash) } + +// TurboShakeSum128 writes an arbitrary-length digest of data into hash. +func TurboShakeSum128(hash, data []byte, D byte) { + h := NewTurboShake128(D) + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +// TurboShakeSum256 writes an arbitrary-length digest of data into hash. +func TurboShakeSum256(hash, data []byte, D byte) { + h := NewTurboShake256(D) + _, _ = h.Write(data) + _, _ = h.Read(hash) +} + +func (d *State) SwitchDS(D byte) { + d.dsbyte = D +} diff --git a/vendor/github.com/cloudflare/circl/math/primes.go b/vendor/github.com/cloudflare/circl/math/primes.go new file mode 100644 index 00000000..158fd83a --- /dev/null +++ b/vendor/github.com/cloudflare/circl/math/primes.go @@ -0,0 +1,34 @@ +package math + +import ( + "crypto/rand" + "io" + "math/big" +) + +// IsSafePrime reports whether p is (probably) a safe prime. +// The prime p=2*q+1 is safe prime if both p and q are primes. +// Note that ProbablyPrime is not suitable for judging primes +// that an adversary may have crafted to fool the test. +func IsSafePrime(p *big.Int) bool { + pdiv2 := new(big.Int).Rsh(p, 1) + return p.ProbablyPrime(20) && pdiv2.ProbablyPrime(20) +} + +// SafePrime returns a number of the given bit length that is a safe prime with high probability. +// The number returned p=2*q+1 is a safe prime if both p and q are primes. +// SafePrime will return error for any error returned by rand.Read or if bits < 2. +func SafePrime(random io.Reader, bits int) (*big.Int, error) { + one := big.NewInt(1) + p := new(big.Int) + for { + q, err := rand.Prime(random, bits-1) + if err != nil { + return nil, err + } + p.Lsh(q, 1).Add(p, one) + if p.ProbablyPrime(20) { + return p, nil + } + } +} diff --git a/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go index 08ca65d7..2c73c26f 100644 --- a/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go +++ b/vendor/github.com/cloudflare/circl/sign/ed25519/ed25519.go @@ -1,7 +1,7 @@ // Package ed25519 implements Ed25519 signature scheme as described in RFC-8032. // // This package provides optimized implementations of the three signature -// variants and maintaining closer compatiblilty with crypto/ed25519. +// variants and maintaining closer compatibility with crypto/ed25519. // // | Scheme Name | Sign Function | Verification | Context | // |-------------|-------------------|---------------|-------------------| diff --git a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md index 5edd5a7c..92b78048 100644 --- a/vendor/github.com/emicklei/go-restful/v3/CHANGES.md +++ b/vendor/github.com/emicklei/go-restful/v3/CHANGES.md @@ -1,6 +1,24 @@ # Change history of go-restful -## [v3.11.0] - 2023-08-19 + +## [v3.12.1] - 2024-05-28 + +- fix misroute when dealing multiple webservice with regex (#549) (thanks Haitao Chen) + +## [v3.12.0] - 2024-03-11 + +- add Flush method #529 (#538) +- fix: Improper handling of empty POST requests (#543) + +## [v3.11.3] - 2024-01-09 + +- better not have 2 tags on one commit + +## [v3.11.1, v3.11.2] - 2024-01-09 + +- fix by restoring custom JSON handler functions (Mike Beaumont #540) + +## [v3.12.0] - 2023-08-19 - restored behavior as <= v3.9.0 with option to change path strategy using TrimRightSlashEnabled. diff --git a/vendor/github.com/emicklei/go-restful/v3/README.md b/vendor/github.com/emicklei/go-restful/v3/README.md index e3e30080..7234604e 100644 --- a/vendor/github.com/emicklei/go-restful/v3/README.md +++ b/vendor/github.com/emicklei/go-restful/v3/README.md @@ -2,7 +2,6 @@ go-restful ========== package for building REST-style Web Services using Google Go -[![Build Status](https://travis-ci.org/emicklei/go-restful.png)](https://travis-ci.org/emicklei/go-restful) [![Go Report Card](https://goreportcard.com/badge/github.com/emicklei/go-restful)](https://goreportcard.com/report/github.com/emicklei/go-restful) [![GoDoc](https://godoc.org/github.com/emicklei/go-restful?status.svg)](https://pkg.go.dev/github.com/emicklei/go-restful) [![codecov](https://codecov.io/gh/emicklei/go-restful/branch/master/graph/badge.svg)](https://codecov.io/gh/emicklei/go-restful) @@ -95,8 +94,7 @@ There are several hooks to customize the behavior of the go-restful package. - Trace logging - Compression - Encoders for other serializers -- Use [jsoniter](https://github.com/json-iterator/go) by building this package using a build tag, e.g. `go build -tags=jsoniter .` -- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/` +- Use the package variable `TrimRightSlashEnabled` (default true) to control the behavior of matching routes that end with a slash `/` ## Resources diff --git a/vendor/github.com/emicklei/go-restful/v3/compress.go b/vendor/github.com/emicklei/go-restful/v3/compress.go index 1ff239f9..80adf55f 100644 --- a/vendor/github.com/emicklei/go-restful/v3/compress.go +++ b/vendor/github.com/emicklei/go-restful/v3/compress.go @@ -49,6 +49,16 @@ func (c *CompressingResponseWriter) CloseNotify() <-chan bool { return c.writer.(http.CloseNotifier).CloseNotify() } +// Flush is part of http.Flusher interface. Noop if the underlying writer doesn't support it. +func (c *CompressingResponseWriter) Flush() { + flusher, ok := c.writer.(http.Flusher) + if !ok { + // writer doesn't support http.Flusher interface + return + } + flusher.Flush() +} + // Close the underlying compressor func (c *CompressingResponseWriter) Close() error { if c.isCompressorClosed() { diff --git a/vendor/github.com/emicklei/go-restful/v3/curly.go b/vendor/github.com/emicklei/go-restful/v3/curly.go index ba1fc5d5..6fd2bcd5 100644 --- a/vendor/github.com/emicklei/go-restful/v3/curly.go +++ b/vendor/github.com/emicklei/go-restful/v3/curly.go @@ -46,10 +46,10 @@ func (c CurlyRouter) SelectRoute( // selectRoutes return a collection of Route from a WebService that matches the path tokens from the request. func (c CurlyRouter) selectRoutes(ws *WebService, requestTokens []string) sortableCurlyRoutes { candidates := make(sortableCurlyRoutes, 0, 8) - for _, each := range ws.routes { - matches, paramCount, staticCount := c.matchesRouteByPathTokens(each.pathParts, requestTokens, each.hasCustomVerb) + for _, eachRoute := range ws.routes { + matches, paramCount, staticCount := c.matchesRouteByPathTokens(eachRoute.pathParts, requestTokens, eachRoute.hasCustomVerb) if matches { - candidates.add(curlyRoute{each, paramCount, staticCount}) // TODO make sure Routes() return pointers? + candidates.add(curlyRoute{eachRoute, paramCount, staticCount}) // TODO make sure Routes() return pointers? } } sort.Sort(candidates) @@ -72,7 +72,7 @@ func (c CurlyRouter) matchesRouteByPathTokens(routeTokens, requestTokens []strin return false, 0, 0 } requestToken := requestTokens[i] - if routeHasCustomVerb && hasCustomVerb(routeToken){ + if routeHasCustomVerb && hasCustomVerb(routeToken) { if !isMatchCustomVerb(routeToken, requestToken) { return false, 0, 0 } @@ -129,44 +129,52 @@ func (c CurlyRouter) detectRoute(candidateRoutes sortableCurlyRoutes, httpReques // detectWebService returns the best matching webService given the list of path tokens. // see also computeWebserviceScore func (c CurlyRouter) detectWebService(requestTokens []string, webServices []*WebService) *WebService { - var best *WebService + var bestWs *WebService score := -1 - for _, each := range webServices { - matches, eachScore := c.computeWebserviceScore(requestTokens, each.pathExpr.tokens) + for _, eachWS := range webServices { + matches, eachScore := c.computeWebserviceScore(requestTokens, eachWS.pathExpr.tokens) if matches && (eachScore > score) { - best = each + bestWs = eachWS score = eachScore } } - return best + return bestWs } // computeWebserviceScore returns whether tokens match and // the weighted score of the longest matching consecutive tokens from the beginning. -func (c CurlyRouter) computeWebserviceScore(requestTokens []string, tokens []string) (bool, int) { - if len(tokens) > len(requestTokens) { +func (c CurlyRouter) computeWebserviceScore(requestTokens []string, routeTokens []string) (bool, int) { + if len(routeTokens) > len(requestTokens) { return false, 0 } score := 0 - for i := 0; i < len(tokens); i++ { - each := requestTokens[i] - other := tokens[i] - if len(each) == 0 && len(other) == 0 { + for i := 0; i < len(routeTokens); i++ { + eachRequestToken := requestTokens[i] + eachRouteToken := routeTokens[i] + if len(eachRequestToken) == 0 && len(eachRouteToken) == 0 { score++ continue } - if len(other) > 0 && strings.HasPrefix(other, "{") { + if len(eachRouteToken) > 0 && strings.HasPrefix(eachRouteToken, "{") { // no empty match - if len(each) == 0 { + if len(eachRequestToken) == 0 { return false, score } - score += 1 + score++ + + if colon := strings.Index(eachRouteToken, ":"); colon != -1 { + // match by regex + matchesToken, _ := c.regularMatchesPathToken(eachRouteToken, colon, eachRequestToken) + if matchesToken { + score++ // extra score for regex match + } + } } else { // not a parameter - if each != other { + if eachRequestToken != eachRouteToken { return false, score } - score += (len(tokens) - i) * 10 //fuzzy + score += (len(routeTokens) - i) * 10 //fuzzy } } return true, score diff --git a/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go b/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go index 66dfc824..9808752a 100644 --- a/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go +++ b/vendor/github.com/emicklei/go-restful/v3/entity_accessors.go @@ -5,11 +5,18 @@ package restful // that can be found in the LICENSE file. import ( + "encoding/json" "encoding/xml" "strings" "sync" ) +var ( + MarshalIndent = json.MarshalIndent + NewDecoder = json.NewDecoder + NewEncoder = json.NewEncoder +) + // EntityReaderWriter can read and write values using an encoding such as JSON,XML. type EntityReaderWriter interface { // Read a serialized version of the value from the request. diff --git a/vendor/github.com/emicklei/go-restful/v3/json.go b/vendor/github.com/emicklei/go-restful/v3/json.go deleted file mode 100644 index 87116516..00000000 --- a/vendor/github.com/emicklei/go-restful/v3/json.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !jsoniter - -package restful - -import "encoding/json" - -var ( - MarshalIndent = json.MarshalIndent - NewDecoder = json.NewDecoder - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/emicklei/go-restful/v3/jsoniter.go b/vendor/github.com/emicklei/go-restful/v3/jsoniter.go deleted file mode 100644 index 11b8f8ae..00000000 --- a/vendor/github.com/emicklei/go-restful/v3/jsoniter.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build jsoniter - -package restful - -import "github.com/json-iterator/go" - -var ( - json = jsoniter.ConfigCompatibleWithStandardLibrary - MarshalIndent = json.MarshalIndent - NewDecoder = json.NewDecoder - NewEncoder = json.NewEncoder -) diff --git a/vendor/github.com/emicklei/go-restful/v3/jsr311.go b/vendor/github.com/emicklei/go-restful/v3/jsr311.go index 07a0c91e..a9b3faaa 100644 --- a/vendor/github.com/emicklei/go-restful/v3/jsr311.go +++ b/vendor/github.com/emicklei/go-restful/v3/jsr311.go @@ -155,7 +155,7 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R method, length := httpRequest.Method, httpRequest.Header.Get("Content-Length") if (method == http.MethodPost || method == http.MethodPut || - method == http.MethodPatch) && length == "" { + method == http.MethodPatch) && (length == "" || length == "0") { return nil, NewError( http.StatusUnsupportedMediaType, fmt.Sprintf("415: Unsupported Media Type\n\nAvailable representations: %s", strings.Join(available, ", ")), diff --git a/vendor/github.com/evanphx/json-patch/README.md b/vendor/github.com/evanphx/json-patch/README.md index 28e35169..97e319b2 100644 --- a/vendor/github.com/evanphx/json-patch/README.md +++ b/vendor/github.com/evanphx/json-patch/README.md @@ -4,7 +4,7 @@ well as for calculating & applying [RFC7396 JSON merge patches](https://tools.ietf.org/html/rfc7396). [![GoDoc](https://godoc.org/github.com/evanphx/json-patch?status.svg)](http://godoc.org/github.com/evanphx/json-patch) -[![Build Status](https://travis-ci.org/evanphx/json-patch.svg?branch=master)](https://travis-ci.org/evanphx/json-patch) +[![Build Status](https://github.com/evanphx/json-patch/actions/workflows/go.yml/badge.svg)](https://github.com/evanphx/json-patch/actions/workflows/go.yml) [![Report Card](https://goreportcard.com/badge/github.com/evanphx/json-patch)](https://goreportcard.com/report/github.com/evanphx/json-patch) # Get It! @@ -314,4 +314,4 @@ go test -cover ./... ``` Builds for pull requests are tested automatically -using [TravisCI](https://travis-ci.org/evanphx/json-patch). +using [GitHub Actions](https://github.com/evanphx/json-patch/actions/workflows/go.yml). diff --git a/vendor/github.com/evanphx/json-patch/patch.go b/vendor/github.com/evanphx/json-patch/patch.go index 4bce5936..cd0274e1 100644 --- a/vendor/github.com/evanphx/json-patch/patch.go +++ b/vendor/github.com/evanphx/json-patch/patch.go @@ -359,7 +359,7 @@ func findObject(pd *container, path string) (container, string) { next, ok := doc.get(decodePatchKey(part)) - if next == nil || ok != nil { + if next == nil || ok != nil || next.raw == nil { return nil, "" } @@ -568,6 +568,29 @@ func (p Patch) replace(doc *container, op Operation) error { return errors.Wrapf(err, "replace operation failed to decode path") } + if path == "" { + val := op.value() + + if val.which == eRaw { + if !val.tryDoc() { + if !val.tryAry() { + return errors.Wrapf(err, "replace operation value must be object or array") + } + } + } + + switch val.which { + case eAry: + *doc = &val.ary + case eDoc: + *doc = &val.doc + case eRaw: + return errors.Wrapf(err, "replace operation hit impossible case") + } + + return nil + } + con, key := findObject(doc, path) if con == nil { @@ -634,6 +657,25 @@ func (p Patch) test(doc *container, op Operation) error { return errors.Wrapf(err, "test operation failed to decode path") } + if path == "" { + var self lazyNode + + switch sv := (*doc).(type) { + case *partialDoc: + self.doc = *sv + self.which = eDoc + case *partialArray: + self.ary = *sv + self.which = eAry + } + + if self.equal(op.value()) { + return nil + } + + return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) + } + con, key := findObject(doc, path) if con == nil { @@ -646,7 +688,7 @@ func (p Patch) test(doc *container, op Operation) error { } if val == nil { - if op.value().raw == nil { + if op.value() == nil || op.value().raw == nil { return nil } return errors.Wrapf(ErrTestFailed, "testing value %s failed", path) diff --git a/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go b/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go new file mode 100644 index 00000000..e9bb0efe --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/internal/json/decode.go @@ -0,0 +1,1385 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Represents JSON data structure using native Go types: booleans, floats, +// strings, arrays, and maps. + +package json + +import ( + "encoding" + "encoding/base64" + "fmt" + "reflect" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an InvalidUnmarshalError. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing the Unmarshaler interface, +// Unmarshal calls that value's UnmarshalJSON method, including +// when the input is a JSON null. +// Otherwise, if the value implements encoding.TextUnmarshaler +// and the input is a JSON quoted string, Unmarshal calls that value's +// UnmarshalText method with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, implement json.Unmarshaler, or +// implement encoding.TextUnmarshaler. +// +// If the JSON-encoded data contain a syntax error, Unmarshal returns a SyntaxError. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// “not present,” unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +func Unmarshal(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + err := checkValid(data, &d.scan) + if err != nil { + return err + } + + d.init(data) + return d.unmarshal(v) +} + +var ds = sync.Pool{ + New: func() any { + return new(decodeState) + }, +} + +func UnmarshalWithKeys(data []byte, v any) ([]string, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + err := checkValid(data, &d.scan) + if err != nil { + return nil, err + } + + d.init(data) + err = d.unmarshal(v) + if err != nil { + return nil, err + } + + return d.lastKeys, nil +} + +func UnmarshalValid(data []byte, v any) error { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + + d.init(data) + return d.unmarshal(v) +} + +func UnmarshalValidWithKeys(data []byte, v any) ([]string, error) { + // Check for well-formedness. + // Avoids filling out half a data structure + // before discovering a JSON syntax error. + + d := ds.Get().(*decodeState) + defer ds.Put(d) + //var d decodeState + d.useNumber = true + + d.init(data) + err := d.unmarshal(v) + if err != nil { + return nil, err + } + + return d.lastKeys, nil +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of Unmarshal itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() + } + return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() +} + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() +} + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Pointer { + return "json: Unmarshal(non-pointer " + e.Type.String() + ")" + } + return "json: Unmarshal(nil " + e.Type.String() + ")" +} + +func (d *decodeState) unmarshal(v any) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Pointer || rv.IsNil() { + return &InvalidUnmarshalError{reflect.TypeOf(v)} + } + + d.scan.reset() + d.scanWhile(scanSkipSpace) + // We decode rv not rv.Elem because the Unmarshaler interface + // test must be applied at the top level of the value. + err := d.value(rv) + if err != nil { + return d.addErrorContext(err) + } + return d.savedError +} + +// A Number represents a JSON number literal. +type Number string + +// String returns the literal text of the number. +func (n Number) String() string { return string(n) } + +// Float64 returns the number as a float64. +func (n Number) Float64() (float64, error) { + return strconv.ParseFloat(string(n), 64) +} + +// Int64 returns the number as an int64. +func (n Number) Int64() (int64, error) { + return strconv.ParseInt(string(n), 10, 64) +} + +// An errorContext provides context for type errors during decoding. +type errorContext struct { + Struct reflect.Type + FieldStack []string +} + +// decodeState represents the state while decoding a JSON value. +type decodeState struct { + data []byte + off int // next read offset in data + opcode int // last read result + scan scanner + errorContext *errorContext + savedError error + useNumber bool + disallowUnknownFields bool + lastKeys []string +} + +// readIndex returns the position of the last byte read. +func (d *decodeState) readIndex() int { + return d.off - 1 +} + +// phasePanicMsg is used as a panic message when we end up with something that +// shouldn't happen. It can indicate a bug in the JSON decoder, or that +// something is editing the data slice while the decoder executes. +const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" + +func (d *decodeState) init(data []byte) *decodeState { + d.data = data + d.off = 0 + d.savedError = nil + if d.errorContext != nil { + d.errorContext.Struct = nil + // Reuse the allocated space for the FieldStack slice. + d.errorContext.FieldStack = d.errorContext.FieldStack[:0] + } + return d +} + +// saveError saves the first err it is called with, +// for reporting at the end of the unmarshal. +func (d *decodeState) saveError(err error) { + if d.savedError == nil { + d.savedError = d.addErrorContext(err) + } +} + +// addErrorContext returns a new error enhanced with information from d.errorContext +func (d *decodeState) addErrorContext(err error) error { + if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { + switch err := err.(type) { + case *UnmarshalTypeError: + err.Struct = d.errorContext.Struct.Name() + err.Field = strings.Join(d.errorContext.FieldStack, ".") + } + } + return err +} + +// skip scans to the end of what was started. +func (d *decodeState) skip() { + s, data, i := &d.scan, d.data, d.off + depth := len(s.parseState) + for { + op := s.step(s, data[i]) + i++ + if len(s.parseState) < depth { + d.off = i + d.opcode = op + return + } + } +} + +// scanNext processes the byte at d.data[d.off]. +func (d *decodeState) scanNext() { + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ + } else { + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 + } +} + +// scanWhile processes bytes in d.data[d.off:] until it +// receives a scan code not equal to op. +func (d *decodeState) scanWhile(op int) { + s, data, i := &d.scan, d.data, d.off + for i < len(data) { + newOp := s.step(s, data[i]) + i++ + if newOp != op { + d.opcode = newOp + d.off = i + return + } + } + + d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() +} + +// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the +// common case where we're decoding a literal. The decoder scans the input +// twice, once for syntax errors and to check the length of the value, and the +// second to perform the decoding. +// +// Only in the second step do we use decodeState to tokenize literals, so we +// know there aren't any syntax errors. We can take advantage of that knowledge, +// and scan a literal's bytes much more quickly. +func (d *decodeState) rescanLiteral() { + data, i := d.data, d.off +Switch: + switch data[i-1] { + case '"': // string + for ; i < len(data); i++ { + switch data[i] { + case '\\': + i++ // escaped char + case '"': + i++ // tokenize the closing quote too + break Switch + } + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number + for ; i < len(data); i++ { + switch data[i] { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '.', 'e', 'E', '+', '-': + default: + break Switch + } + } + case 't': // true + i += len("rue") + case 'f': // false + i += len("alse") + case 'n': // null + i += len("ull") + } + if i < len(data) { + d.opcode = stateEndValue(&d.scan, data[i]) + } else { + d.opcode = scanEnd + } + d.off = i + 1 +} + +// value consumes a JSON value from d.data[d.off-1:], decoding into v, and +// reads the following byte ahead. If v is invalid, the value is discarded. +// The first byte of the value has been read already. +func (d *decodeState) value(v reflect.Value) error { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray: + if v.IsValid() { + if err := d.array(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginObject: + if v.IsValid() { + if err := d.object(v); err != nil { + return err + } + } else { + d.skip() + } + d.scanNext() + + case scanBeginLiteral: + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + if v.IsValid() { + if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { + return err + } + } + } + return nil +} + +type unquotedValue struct{} + +// valueQuoted is like value but decodes a +// quoted string literal or literal null into an interface value. +// If it finds anything other than a quoted string literal or null, +// valueQuoted returns unquotedValue{}. +func (d *decodeState) valueQuoted() any { + switch d.opcode { + default: + panic(phasePanicMsg) + + case scanBeginArray, scanBeginObject: + d.skip() + d.scanNext() + + case scanBeginLiteral: + v := d.literalInterface() + switch v.(type) { + case nil, string: + return v + } + } + return unquotedValue{} +} + +// indirect walks down v allocating pointers as needed, +// until it gets to a non-pointer. +// If it encounters an Unmarshaler, indirect stops and returns that. +// If decodingNull is true, indirect stops at the first settable pointer so it +// can be set to nil. +func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { + // Issue #24153 indicates that it is generally not a guaranteed property + // that you may round-trip a reflect.Value by calling Value.Addr().Elem() + // and expect the value to still be settable for values derived from + // unexported embedded struct fields. + // + // The logic below effectively does this when it first addresses the value + // (to satisfy possible pointer methods) and continues to dereference + // subsequent pointers as necessary. + // + // After the first round-trip, we set v back to the original value to + // preserve the original RW flags contained in reflect.Value. + v0 := v + haveAddr := false + + // If v is a named type and is addressable, + // start with its address, so that if the type has pointer methods, + // we find them. + if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { + haveAddr = true + v = v.Addr() + } + for { + // Load value from interface, but only if the result will be + // usefully addressable. + if v.Kind() == reflect.Interface && !v.IsNil() { + e := v.Elem() + if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { + haveAddr = false + v = e + continue + } + } + + if v.Kind() != reflect.Pointer { + break + } + + if decodingNull && v.CanSet() { + break + } + + // Prevent infinite loop if v is an interface pointing to its own address: + // var v interface{} + // v = &v + if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { + v = v.Elem() + break + } + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + if v.Type().NumMethod() > 0 && v.CanInterface() { + if u, ok := v.Interface().(Unmarshaler); ok { + return u, nil, reflect.Value{} + } + if !decodingNull { + if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { + return nil, u, reflect.Value{} + } + } + } + + if haveAddr { + v = v0 // restore original value after round-trip Value.Addr().Elem() + haveAddr = false + } else { + v = v.Elem() + } + } + return nil, nil, v +} + +// array consumes an array from d.data[d.off-1:], decoding into v. +// The first byte of the array ('[') has been read already. +func (d *decodeState) array(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + + // Check type of target. + switch v.Kind() { + case reflect.Interface: + if v.NumMethod() == 0 { + // Decoding into nil interface? Switch to non-reflect code. + ai := d.arrayInterface() + v.Set(reflect.ValueOf(ai)) + return nil + } + // Otherwise it's invalid. + fallthrough + default: + d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + case reflect.Array, reflect.Slice: + break + } + + i := 0 + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + // Get element of array, growing if necessary. + if v.Kind() == reflect.Slice { + // Grow slice if necessary + if i >= v.Cap() { + newcap := v.Cap() + v.Cap()/2 + if newcap < 4 { + newcap = 4 + } + newv := reflect.MakeSlice(v.Type(), v.Len(), newcap) + reflect.Copy(newv, v) + v.Set(newv) + } + if i >= v.Len() { + v.SetLen(i + 1) + } + } + + if i < v.Len() { + // Decode into element. + if err := d.value(v.Index(i)); err != nil { + return err + } + } else { + // Ran out of fixed array: skip. + if err := d.value(reflect.Value{}); err != nil { + return err + } + } + i++ + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + + if i < v.Len() { + if v.Kind() == reflect.Array { + // Array. Zero the rest. + z := reflect.Zero(v.Type().Elem()) + for ; i < v.Len(); i++ { + v.Index(i).Set(z) + } + } else { + v.SetLen(i) + } + } + if i == 0 && v.Kind() == reflect.Slice { + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) + } + return nil +} + +var nullLiteral = []byte("null") +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + +// object consumes an object from d.data[d.off-1:], decoding into v. +// The first byte ('{') of the object has been read already. +func (d *decodeState) object(v reflect.Value) error { + // Check for unmarshaler. + u, ut, pv := indirect(v, false) + if u != nil { + start := d.readIndex() + d.skip() + return u.UnmarshalJSON(d.data[start:d.off]) + } + if ut != nil { + d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.skip() + return nil + } + v = pv + t := v.Type() + + // Decoding into nil interface? Switch to non-reflect code. + if v.Kind() == reflect.Interface && v.NumMethod() == 0 { + oi := d.objectInterface() + v.Set(reflect.ValueOf(oi)) + return nil + } + + var fields structFields + + // Check type of target: + // struct or + // map[T1]T2 where T1 is string, an integer type, + // or an encoding.TextUnmarshaler + switch v.Kind() { + case reflect.Map: + // Map key must either have string kind, have an integer kind, + // or be an encoding.TextUnmarshaler. + switch t.Key().Kind() { + case reflect.String, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + default: + if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) { + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + } + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + case reflect.Struct: + fields = cachedTypeFields(t) + // ok + default: + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) + d.skip() + return nil + } + + var mapElem reflect.Value + var origErrorContext errorContext + if d.errorContext != nil { + origErrorContext = *d.errorContext + } + + var keys []string + + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquoteBytes(item) + if !ok { + panic(phasePanicMsg) + } + + keys = append(keys, string(key)) + + // Figure out field corresponding to key. + var subv reflect.Value + destring := false // whether the value is wrapped in a string to be decoded first + + if v.Kind() == reflect.Map { + elemType := t.Elem() + if !mapElem.IsValid() { + mapElem = reflect.New(elemType).Elem() + } else { + mapElem.Set(reflect.Zero(elemType)) + } + subv = mapElem + } else { + var f *field + if i, ok := fields.nameIndex[string(key)]; ok { + // Found an exact name match. + f = &fields.list[i] + } else { + // Fall back to the expensive case-insensitive + // linear search. + for i := range fields.list { + ff := &fields.list[i] + if ff.equalFold(ff.nameBytes, key) { + f = ff + break + } + } + } + if f != nil { + subv = v + destring = f.quoted + for _, i := range f.index { + if subv.Kind() == reflect.Pointer { + if subv.IsNil() { + // If a struct embeds a pointer to an unexported type, + // it is not possible to set a newly allocated value + // since the field is unexported. + // + // See https://golang.org/issue/21357 + if !subv.CanSet() { + d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) + // Invalidate subv to ensure d.value(subv) skips over + // the JSON value without assigning it to subv. + subv = reflect.Value{} + destring = false + break + } + subv.Set(reflect.New(subv.Type().Elem())) + } + subv = subv.Elem() + } + subv = subv.Field(i) + } + if d.errorContext == nil { + d.errorContext = new(errorContext) + } + d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) + d.errorContext.Struct = t + } else if d.disallowUnknownFields { + d.saveError(fmt.Errorf("json: unknown field %q", key)) + } + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + if destring { + switch qv := d.valueQuoted().(type) { + case nil: + if err := d.literalStore(nullLiteral, subv, false); err != nil { + return err + } + case string: + if err := d.literalStore([]byte(qv), subv, true); err != nil { + return err + } + default: + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) + } + } else { + if err := d.value(subv); err != nil { + return err + } + } + + // Write value back to map; + // if using struct, subv points into struct already. + if v.Kind() == reflect.Map { + kt := t.Key() + var kv reflect.Value + switch { + case reflect.PointerTo(kt).Implements(textUnmarshalerType): + kv = reflect.New(kt) + if err := d.literalStore(item, kv, true); err != nil { + return err + } + kv = kv.Elem() + case kt.Kind() == reflect.String: + kv = reflect.ValueOf(key).Convert(kt) + default: + switch kt.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := string(key) + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + s := string(key) + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || reflect.Zero(kt).OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) + break + } + kv = reflect.ValueOf(n).Convert(kt) + default: + panic("json: Unexpected key type") // should never occur + } + } + if kv.IsValid() { + v.SetMapIndex(kv, subv) + } + } + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.errorContext != nil { + // Reset errorContext to its original state. + // Keep the same underlying array for FieldStack, to reuse the + // space and avoid unnecessary allocs. + d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] + d.errorContext.Struct = origErrorContext.Struct + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + + if v.Kind() == reflect.Map { + d.lastKeys = keys + } + return nil +} + +// convertNumber converts the number literal s to a float64 or a Number +// depending on the setting of d.useNumber. +func (d *decodeState) convertNumber(s string) (any, error) { + if d.useNumber { + return Number(s), nil + } + f, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)} + } + return f, nil +} + +var numberType = reflect.TypeOf(Number("")) + +// literalStore decodes a literal stored in item into v. +// +// fromQuoted indicates whether this literal came from unwrapping a +// string from the ",string" struct tag option. this is used only to +// produce more helpful error messages. +func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { + // Check for unmarshaler. + if len(item) == 0 { + //Empty string given + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + isNull := item[0] == 'n' // null + u, ut, pv := indirect(v, isNull) + if u != nil { + return u.UnmarshalJSON(item) + } + if ut != nil { + if item[0] != '"' { + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + return nil + } + val := "number" + switch item[0] { + case 'n': + val = "null" + case 't', 'f': + val = "bool" + } + d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) + return nil + } + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + return ut.UnmarshalText(s) + } + + v = pv + + switch c := item[0]; c { + case 'n': // null + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "null" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice: + v.Set(reflect.Zero(v.Type())) + // otherwise, ignore null for primitives/string + } + case 't', 'f': // true, false + value := item[0] == 't' + // The main parser checks that only true and false can reach here, + // but if this was a quoted string input, it could be anything. + if fromQuoted && string(item) != "true" && string(item) != "false" { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + break + } + switch v.Kind() { + default: + if fromQuoted { + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + case reflect.Bool: + v.SetBool(value) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(value)) + } else { + d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + case '"': // string + s, ok := unquoteBytes(item) + if !ok { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + switch v.Kind() { + default: + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Slice: + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) + n, err := base64.StdEncoding.Decode(b, s) + if err != nil { + d.saveError(err) + break + } + v.SetBytes(b[:n]) + case reflect.String: + if v.Type() == numberType && !isValidNumber(string(s)) { + return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) + } + v.SetString(string(s)) + case reflect.Interface: + if v.NumMethod() == 0 { + v.Set(reflect.ValueOf(string(s))) + } else { + d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) + } + } + + default: // number + if c != '-' && (c < '0' || c > '9') { + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + panic(phasePanicMsg) + } + s := string(item) + switch v.Kind() { + default: + if v.Kind() == reflect.String && v.Type() == numberType { + // s must be a valid number, because it's + // already been tokenized. + v.SetString(s) + break + } + if fromQuoted { + return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) + } + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + case reflect.Interface: + n, err := d.convertNumber(s) + if err != nil { + d.saveError(err) + break + } + if v.NumMethod() != 0 { + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.Set(reflect.ValueOf(n)) + + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n, err := strconv.ParseInt(s, 10, 64) + if err != nil || v.OverflowInt(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetInt(n) + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n, err := strconv.ParseUint(s, 10, 64) + if err != nil || v.OverflowUint(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetUint(n) + + case reflect.Float32, reflect.Float64: + n, err := strconv.ParseFloat(s, v.Type().Bits()) + if err != nil || v.OverflowFloat(n) { + d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())}) + break + } + v.SetFloat(n) + } + } + return nil +} + +// The xxxInterface routines build up a value to be stored +// in an empty interface. They are not strictly necessary, +// but they avoid the weight of reflection in this common case. + +// valueInterface is like value but returns interface{} +func (d *decodeState) valueInterface() (val any) { + switch d.opcode { + default: + panic(phasePanicMsg) + case scanBeginArray: + val = d.arrayInterface() + d.scanNext() + case scanBeginObject: + val = d.objectInterface() + d.scanNext() + case scanBeginLiteral: + val = d.literalInterface() + } + return +} + +// arrayInterface is like array but returns []interface{}. +func (d *decodeState) arrayInterface() []any { + var v = make([]any, 0) + for { + // Look ahead for ] - can only happen on first iteration. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndArray { + break + } + + v = append(v, d.valueInterface()) + + // Next token must be , or ]. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndArray { + break + } + if d.opcode != scanArrayValue { + panic(phasePanicMsg) + } + } + return v +} + +// objectInterface is like object but returns map[string]interface{}. +func (d *decodeState) objectInterface() map[string]any { + m := make(map[string]any) + for { + // Read opening " of string key or closing }. + d.scanWhile(scanSkipSpace) + if d.opcode == scanEndObject { + // closing } - can only happen on first iteration. + break + } + if d.opcode != scanBeginLiteral { + panic(phasePanicMsg) + } + + // Read string key. + start := d.readIndex() + d.rescanLiteral() + item := d.data[start:d.readIndex()] + key, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + + // Read : before value. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode != scanObjectKey { + panic(phasePanicMsg) + } + d.scanWhile(scanSkipSpace) + + // Read value. + m[key] = d.valueInterface() + + // Next token must be , or }. + if d.opcode == scanSkipSpace { + d.scanWhile(scanSkipSpace) + } + if d.opcode == scanEndObject { + break + } + if d.opcode != scanObjectValue { + panic(phasePanicMsg) + } + } + return m +} + +// literalInterface consumes and returns a literal from d.data[d.off-1:] and +// it reads the following byte ahead. The first byte of the literal has been +// read already (that's how the caller knows it's a literal). +func (d *decodeState) literalInterface() any { + // All bytes inside literal return scanContinue op code. + start := d.readIndex() + d.rescanLiteral() + + item := d.data[start:d.readIndex()] + + switch c := item[0]; c { + case 'n': // null + return nil + + case 't', 'f': // true, false + return c == 't' + + case '"': // string + s, ok := unquote(item) + if !ok { + panic(phasePanicMsg) + } + return s + + default: // number + if c != '-' && (c < '0' || c > '9') { + panic(phasePanicMsg) + } + n, err := d.convertNumber(string(item)) + if err != nil { + d.saveError(err) + } + return n + } +} + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} diff --git a/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go b/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go new file mode 100644 index 00000000..2e6eca44 --- /dev/null +++ b/vendor/github.com/evanphx/json-patch/v5/internal/json/encode.go @@ -0,0 +1,1486 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package json implements encoding and decoding of JSON as defined in +// RFC 7159. The mapping between JSON and Go values is described +// in the documentation for the Marshal and Unmarshal functions. +// +// See "JSON and Go" for an introduction to this package: +// https://golang.org/doc/articles/json_and_go.html +package json + +import ( + "bytes" + "encoding" + "encoding/base64" + "fmt" + "math" + "reflect" + "sort" + "strconv" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// So that the JSON will be safe to embed inside HTML