diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index bb76406eff..50c1c21f96 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -16,14 +16,14 @@ jobs: if: github.repository_owner == 'akuity' && github.event.pull_request.merged && (github.event_name != 'labeled' || startsWith('backport/', github.event.label.name)) steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Create backport PRs - uses: korthout/backport-action@4aaf0e03a94ff0a619c9a511b61aeb42adea5b02 # v4.2.0 + uses: korthout/backport-action@3c06f323a58619da1e8522229ebc8d5de2633e46 # v4.3.0 # xref: https://github.com/korthout/backport-action#inputs with: # Use token to allow workflows to be triggered for the created PR diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 12c0377d07..53125c2617 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,7 +24,7 @@ jobs: # "stable" is updated to >= 2.42.0 (which supports `--orphan` for `git # worktree add`). - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -50,7 +50,7 @@ jobs: mv $tmp_file $report done - name: Upload coverage reports - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 + uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -58,7 +58,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -94,7 +94,7 @@ jobs: image: *golangImage steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -122,7 +122,7 @@ jobs: image: *golangImage steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -152,7 +152,7 @@ jobs: image: *golangImage steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -180,7 +180,7 @@ jobs: image: *golangImage steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -232,7 +232,7 @@ jobs: - 5000:5000 steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -266,7 +266,7 @@ jobs: image: *golangImage steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit diff --git a/.github/workflows/governance.yaml b/.github/workflows/governance.yaml index bc4aa926f8..370c872e45 100644 --- a/.github/workflows/governance.yaml +++ b/.github/workflows/governance.yaml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit diff --git a/.github/workflows/lint-pr.yaml b/.github/workflows/lint-pr.yaml index c6ab4ad38f..2a16a0984c 100644 --- a/.github/workflows/lint-pr.yaml +++ b/.github/workflows/lint-pr.yaml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 238f85985b..7c88a86d25 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -29,7 +29,7 @@ jobs: unstable-version: ${{ steps.unstable-version.outputs.unstable-version }} steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -44,7 +44,7 @@ jobs: echo "Repository is set to: $REPO" echo "repo=$REPO" >> $GITHUB_OUTPUT - name: Setup Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version: '1.26.0' - name: Set version for unstable builds @@ -62,11 +62,11 @@ jobs: with: driver-opts: network=host - name: Install Cosign - uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 + uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1 with: cosign-release: 'v2.2.1' # optional - name: Login to GHCR - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -141,7 +141,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -166,11 +166,11 @@ jobs: echo "VERSION is set to: $VERSION" echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Set up Helm - uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 + uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 with: version: '3.19.4' - name: Login to GHCR - uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -193,7 +193,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -245,7 +245,7 @@ jobs: hash-windows-arm64: ${{ steps.hash.outputs.hash-windows-arm64 }} steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -283,7 +283,7 @@ jobs: run: | make sign-and-notarize-cli - name: Publish CLI - uses: svenstaro/upload-release-action@b98a3b12e86552593f3e4e577ca8a62aa2f3f22b # v2.11.4 + uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2.11.5 with: file: bin/* file_glob: true @@ -308,7 +308,7 @@ jobs: arch: [amd64, arm64] steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -375,7 +375,7 @@ jobs: HASHES: ${{ toJSON(needs.publish-cli.outputs) }} steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -413,7 +413,7 @@ jobs: image: *golangImage steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit @@ -424,11 +424,11 @@ jobs: mkdir _site go run ./hack/best-releases > _site/best-releases.json - name: Configure Pages - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - name: Upload Pages artifact uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 with: path: _site - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index b1b6f50836..dc87cddd3d 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -12,7 +12,7 @@ jobs: timeout-minutes: 30 # Don't wait 6 hours to cancel workflow if it hangs. steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 + uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit diff --git a/.gitignore b/.gitignore index 45cd0b693b..49466ad20f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,3 @@ vendor/ internal/server/ui/ .DS_Store docs/static/swagger.json -docs/static/swagger.yaml diff --git a/.swaggo b/.swaggo new file mode 100644 index 0000000000..9bc8d3d478 --- /dev/null +++ b/.swaggo @@ -0,0 +1,65 @@ +// Override type aliases that go-swagger mishandles. Go-swagger wraps referenced +// types in anonymous structs, which breaks JSON deserialization when the wire +// format is a bare string or integer. Replacing them with primitives here +// prevents that. + +replace k8s.io/apimachinery/pkg/apis/meta/v1.Duration string +replace k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON object +replace k8s.io/apimachinery/pkg/apis/meta/v1.ConditionStatus string +replace k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorOperator string +replace k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsOperationType string +replace k8s.io/apimachinery/pkg/util/intstr.Type integer + +replace k8s.io/api/core/v1.AppArmorProfileType string +replace k8s.io/api/core/v1.AzureDataDiskCachingMode string +replace k8s.io/api/core/v1.AzureDataDiskKind string +replace k8s.io/api/core/v1.CompletionMode string +replace k8s.io/api/core/v1.ConditionStatus string +replace k8s.io/api/core/v1.ContainerRestartPolicy string +replace k8s.io/api/core/v1.ContainerRestartRuleAction string +replace k8s.io/api/core/v1.ContainerRestartRuleOnExitCodesOperator string +replace k8s.io/api/core/v1.DNSPolicy string +replace k8s.io/api/core/v1.HostPathType string +replace k8s.io/api/core/v1.MountPropagationMode string +replace k8s.io/api/core/v1.NodeInclusionPolicy string +replace k8s.io/api/core/v1.NodeSelectorOperator string +replace k8s.io/api/core/v1.OSName string +replace k8s.io/api/core/v1.PersistentVolumeAccessMode string +replace k8s.io/api/core/v1.PersistentVolumeMode string +replace k8s.io/api/core/v1.PodConditionType string +replace k8s.io/api/core/v1.PodFSGroupChangePolicy string +replace k8s.io/api/core/v1.PodFailurePolicyAction string +replace k8s.io/api/core/v1.PodFailurePolicyOnExitCodesOperator string +replace k8s.io/api/core/v1.PodReplacementPolicy string +replace k8s.io/api/core/v1.PodSELinuxChangePolicy string +replace k8s.io/api/core/v1.PreemptionPolicy string +replace k8s.io/api/core/v1.ProcMountType string +replace k8s.io/api/core/v1.Protocol string +replace k8s.io/api/core/v1.PullPolicy string +replace k8s.io/api/core/v1.RecursiveReadOnlyMode string +replace k8s.io/api/core/v1.ResourceName string +replace k8s.io/api/core/v1.ResourceResizeRestartPolicy string +replace k8s.io/api/core/v1.RestartPolicy string +replace k8s.io/api/core/v1.SeccompProfileType string +replace k8s.io/api/core/v1.SecretType string +replace k8s.io/api/core/v1.Signal string +replace k8s.io/api/core/v1.StorageMedium string +replace k8s.io/api/core/v1.SupplementalGroupsPolicy string +replace k8s.io/api/core/v1.TaintEffect string +replace k8s.io/api/core/v1.TerminationMessagePolicy string +replace k8s.io/api/core/v1.TolerationOperator string +replace k8s.io/api/core/v1.URIScheme string +replace k8s.io/api/core/v1.UnsatisfiableConstraintAction string + +replace github.com/akuity/kargo/api/v1alpha1.AutoPromotionSelectionPolicy string +replace github.com/akuity/kargo/api/v1alpha1.FreightAvailabilityStrategy string +replace github.com/akuity/kargo/api/v1alpha1.FreightCreationPolicy string +replace github.com/akuity/kargo/api/v1alpha1.FreightOriginKind string +replace github.com/akuity/kargo/api/v1alpha1.GenericWebhookActionType string +replace github.com/akuity/kargo/api/v1alpha1.GenericWebhookTargetKind string +replace github.com/akuity/kargo/api/v1alpha1.HealthState string +replace github.com/akuity/kargo/api/v1alpha1.IndexSelectorOperator string +replace github.com/akuity/kargo/api/v1alpha1.PromotionPhase string +replace github.com/akuity/kargo/api/v1alpha1.PromotionStepStatus string +replace github.com/akuity/kargo/api/v1alpha1.VerificationPhase string +replace github.com/akuity/kargo/api/stubs/rollouts/v1alpha1.AnalysisPhase string diff --git a/Dockerfile b/Dockerfile index 515b24303c..f67514b943 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,11 +11,11 @@ RUN npm install --global pnpm@${PNPM_VERSION} WORKDIR /ui COPY ["ui/package.json", "ui/pnpm-lock.yaml", "./"] -RUN pnpm install +RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install COPY ["ui/", "."] ARG VERSION -RUN NODE_ENV='production' VERSION=${VERSION} pnpm run build +RUN --mount=type=cache,target=/root/.local/share/pnpm/store NODE_ENV='production' VERSION=${VERSION} pnpm run build #################################################################################################### # back-end-builder @@ -31,8 +31,9 @@ ARG CGO_ENABLED=0 WORKDIR /kargo COPY ["api/go.mod", "api/go.sum", "api/"] +COPY ["pkg/client/generated/go.mod", "pkg/client/generated/go.sum", "pkg/client/generated/"] COPY ["go.mod", "go.sum", "./"] -RUN go mod download +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build go mod download COPY api/ api/ COPY pkg/ pkg/ COPY cmd/ cmd/ @@ -42,13 +43,15 @@ ARG VERSION ARG GIT_COMMIT ARG GIT_TREE_STATE -RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ + GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ -trimpath \ -ldflags "-w -s" \ -o bin/credential-helper \ ./cmd/credential-helper -RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ + GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \ -trimpath \ -ldflags "-w -X ${VERSION_PACKAGE}.version=${VERSION} -X ${VERSION_PACKAGE}.buildDate=$(date -u +'%Y-%m-%dT%H:%M:%SZ') -X ${VERSION_PACKAGE}.gitCommit=${GIT_COMMIT} -X ${VERSION_PACKAGE}.gitTreeState=${GIT_TREE_STATE}" \ -o bin/kargo \ @@ -107,7 +110,7 @@ RUN npm install --global pnpm@${PNPM_VERSION} WORKDIR /ui COPY ["ui/package.json", "ui/pnpm-lock.yaml", "./"] -RUN pnpm install +RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install COPY ["ui/", "."] diff --git a/Makefile b/Makefile index 23aaf5a012..ff40607378 100644 --- a/Makefile +++ b/Makefile @@ -216,12 +216,12 @@ build-cli-with-ui: build-ui build-cli ################################################################################ .PHONY: codegen -codegen: codegen-openapi codegen-schema-to-go codegen-proto codegen-controller codegen-ui codegen-docs +codegen: codegen-openapi codegen-proto codegen-controller codegen-schema-to-go codegen-ui codegen-docs .PHONY: codegen-openapi -codegen-openapi: install-swag install-go-swagger - rm -f swagger.yaml swagger.json - rm -rf pkg/client/generated +codegen-openapi: install-swag install-go-swagger install-jq + rm -f swagger.json + find pkg/client/generated -mindepth 1 ! -name go.mod ! -name go.sum -exec rm -rf {} + rm -rf /tmp/swagger-build mkdir -p /tmp/swagger-build $(SWAG_LINK) init \ @@ -229,10 +229,10 @@ codegen-openapi: install-swag install-go-swagger --output /tmp/swagger-build \ --parseDependency \ --parseInternal \ - --outputTypes yaml,json - mv /tmp/swagger-build/swagger.yaml . + --outputTypes json mv /tmp/swagger-build/swagger.json . rm -rf /tmp/swagger-build + hack/codegen/fix-swagger-spec.sh swagger.json mkdir -p pkg/client/generated $(GO_SWAGGER_LINK) generate client \ -f swagger.json \ @@ -260,7 +260,7 @@ codegen-controller: install-controller-gen paths=./... .PHONY: codegen-schema-to-go -codegen-schema-to-go: +codegen-schema-to-go: install-goimports npm install -g quicktype@23.0.176 ./hack/codegen/promotion-step-configs.sh ./hack/codegen/subscriptions.sh diff --git a/api/v1alpha1/generated.pb.go b/api/v1alpha1/generated.pb.go index 8283c253af..165952cd14 100644 --- a/api/v1alpha1/generated.pb.go +++ b/api/v1alpha1/generated.pb.go @@ -2891,365 +2891,366 @@ func init() { } var fileDescriptor_e26b7f7bbc391025 = []byte{ - // 5725 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x6b, 0x6c, 0x23, 0xc7, - 0x79, 0xb7, 0xa4, 0x9e, 0x1f, 0xf5, 0x9c, 0xd3, 0xf9, 0x64, 0xd9, 0x3e, 0x5d, 0x37, 0x8e, 0x61, - 0xd7, 0x36, 0x55, 0x9f, 0x7d, 0xbe, 0xf3, 0xeb, 0x62, 0x52, 0xba, 0x87, 0x6c, 0xd9, 0xa7, 0x0c, - 0xe5, 0xbb, 0xf8, 0x6c, 0xc3, 0x19, 0x91, 0x23, 0x72, 0x23, 0x92, 0x4b, 0xef, 0x2e, 0x75, 0x47, - 0xbb, 0x48, 0x1d, 0xbb, 0x0d, 0x5c, 0xa0, 0x28, 0xfc, 0xc3, 0x85, 0x8b, 0x02, 0x05, 0x8a, 0x06, - 0x05, 0x5a, 0x04, 0x48, 0xfe, 0xb7, 0x40, 0x53, 0xa0, 0x28, 0xe0, 0xa4, 0x49, 0x11, 0xb8, 0x3f, - 0xea, 0x02, 0x81, 0x1a, 0x2b, 0x40, 0xfe, 0x14, 0x05, 0xfa, 0xfb, 0xd0, 0x16, 0xc5, 0x3c, 0x76, - 0x67, 0x76, 0xb9, 0x94, 0x76, 0xa9, 0xc7, 0x5d, 0x81, 0xfe, 0x23, 0xe7, 0x9b, 0xf9, 0xbe, 0x79, - 0x7e, 0xef, 0x99, 0x85, 0xa7, 0xaa, 0x96, 0x57, 0x6b, 0xaf, 0xe7, 0xcb, 0x76, 0x63, 0x81, 0x6c, - 0xb6, 0x2d, 0xaf, 0xb3, 0xb0, 0x49, 0x9c, 0xaa, 0xbd, 0x40, 0x5a, 0xd6, 0xc2, 0xd6, 0x13, 0xa4, - 0xde, 0xaa, 0x91, 0x27, 0x16, 0xaa, 0xb4, 0x49, 0x1d, 0xe2, 0xd1, 0x4a, 0xbe, 0xe5, 0xd8, 0x9e, - 0x8d, 0x1e, 0x54, 0xad, 0xf2, 0xa2, 0x55, 0x9e, 0xb7, 0xca, 0x93, 0x96, 0x95, 0xf7, 0x5b, 0xcd, - 0x3d, 0xae, 0xe1, 0xae, 0xda, 0x55, 0x7b, 0x81, 0x37, 0x5e, 0x6f, 0x6f, 0xf0, 0x7f, 0xfc, 0x0f, - 0xff, 0x25, 0x90, 0xce, 0x99, 0x9b, 0xe7, 0xdd, 0xbc, 0x25, 0x28, 0x97, 0x6d, 0x87, 0x2e, 0x6c, - 0x75, 0x11, 0x9e, 0xbb, 0xa2, 0xea, 0xd0, 0x5b, 0x1e, 0x6d, 0xba, 0x96, 0xdd, 0x74, 0x1f, 0x27, - 0x2d, 0xcb, 0xa5, 0xce, 0x16, 0x75, 0x16, 0x5a, 0x9b, 0x55, 0x06, 0x73, 0xc3, 0x15, 0xe2, 0x30, - 0x3d, 0xa5, 0x30, 0x35, 0x48, 0xb9, 0x66, 0x35, 0xa9, 0xd3, 0x51, 0xcd, 0x1b, 0xd4, 0x23, 0x71, - 0xad, 0x16, 0x7a, 0xb5, 0x72, 0xda, 0x4d, 0xcf, 0x6a, 0xd0, 0xae, 0x06, 0x4f, 0xef, 0xd5, 0xc0, - 0x2d, 0xd7, 0x68, 0x83, 0x44, 0xdb, 0x99, 0x6f, 0xc2, 0xf1, 0x42, 0x93, 0xd4, 0x3b, 0xae, 0xe5, - 0xe2, 0x76, 0xb3, 0xe0, 0x54, 0xdb, 0x0d, 0xda, 0xf4, 0xd0, 0x69, 0x18, 0x68, 0x92, 0x06, 0x9d, - 0x35, 0x4e, 0x1b, 0x0f, 0x8f, 0x16, 0xc7, 0x3e, 0xdb, 0x9e, 0x3f, 0xb6, 0xb3, 0x3d, 0x3f, 0xf0, - 0x2a, 0x69, 0x50, 0xcc, 0x21, 0xe8, 0x2b, 0x30, 0xb8, 0x45, 0xea, 0x6d, 0x3a, 0x9b, 0xe1, 0x55, - 0xc6, 0x65, 0x95, 0xc1, 0x6b, 0xac, 0x10, 0x0b, 0x98, 0xf9, 0x61, 0x36, 0x84, 0xfe, 0x15, 0xea, - 0x91, 0x0a, 0xf1, 0x08, 0x6a, 0xc0, 0x50, 0x9d, 0xac, 0xd3, 0xba, 0x3b, 0x6b, 0x9c, 0xce, 0x3e, - 0x9c, 0x3b, 0x73, 0x31, 0x9f, 0x64, 0xa1, 0xf3, 0x31, 0xa8, 0xf2, 0x2b, 0x1c, 0xcf, 0xc5, 0xa6, - 0xe7, 0x74, 0x8a, 0x13, 0xb2, 0x13, 0x43, 0xa2, 0x10, 0x4b, 0x22, 0xe8, 0x3b, 0x06, 0xe4, 0x48, - 0xb3, 0x69, 0x7b, 0xc4, 0x63, 0xcb, 0x34, 0x9b, 0xe1, 0x44, 0x5f, 0xea, 0x9f, 0x68, 0x41, 0x21, - 0x13, 0x94, 0x8f, 0x4b, 0xca, 0x39, 0x0d, 0x82, 0x75, 0x9a, 0x73, 0xcf, 0x40, 0x4e, 0xeb, 0x2a, - 0x9a, 0x82, 0xec, 0x26, 0xed, 0x88, 0xf9, 0xc5, 0xec, 0x27, 0x9a, 0x09, 0x4d, 0xa8, 0x9c, 0xc1, - 0x67, 0x33, 0xe7, 0x8d, 0xb9, 0x0b, 0x30, 0x15, 0x25, 0x98, 0xa6, 0xbd, 0xf9, 0x87, 0x06, 0xcc, - 0x68, 0xa3, 0xc0, 0x74, 0x83, 0x3a, 0xb4, 0x59, 0xa6, 0x68, 0x01, 0x46, 0xd9, 0x5a, 0xba, 0x2d, - 0x52, 0xf6, 0x97, 0x7a, 0x5a, 0x0e, 0x64, 0xf4, 0x55, 0x1f, 0x80, 0x55, 0x9d, 0x60, 0x5b, 0x64, - 0x76, 0xdb, 0x16, 0xad, 0x1a, 0x71, 0xe9, 0x6c, 0x36, 0xbc, 0x2d, 0x56, 0x59, 0x21, 0x16, 0x30, - 0xf3, 0x6d, 0xb8, 0xd7, 0xef, 0xcf, 0x1a, 0x6d, 0xb4, 0xea, 0xc4, 0xa3, 0xaa, 0x53, 0x7b, 0x6f, - 0xbd, 0xd3, 0x30, 0xb0, 0x69, 0x35, 0x2b, 0xd1, 0x5e, 0xbc, 0x6c, 0x35, 0x2b, 0x98, 0x43, 0xcc, - 0x4d, 0x18, 0x2f, 0xb4, 0x5a, 0x8e, 0xbd, 0x45, 0x2b, 0x25, 0x8f, 0x54, 0x29, 0xba, 0x01, 0x40, - 0x64, 0x41, 0xc1, 0xe3, 0xa8, 0x73, 0x67, 0x7e, 0x33, 0x2f, 0xce, 0x4c, 0x5e, 0x3f, 0x33, 0xf9, - 0xd6, 0x66, 0x95, 0x15, 0xb8, 0x79, 0x76, 0x34, 0xf3, 0x5b, 0x4f, 0xe4, 0xd7, 0xac, 0x06, 0x2d, - 0x4e, 0xec, 0x6c, 0xcf, 0x43, 0x21, 0xc0, 0x80, 0x35, 0x6c, 0xe6, 0x07, 0x06, 0x9c, 0x28, 0x38, - 0x55, 0x7b, 0x71, 0xa9, 0xd0, 0x6a, 0x5d, 0xa1, 0xa4, 0xee, 0xd5, 0x4a, 0x1e, 0xf1, 0xda, 0x2e, - 0xba, 0x00, 0x43, 0x2e, 0xff, 0x25, 0x07, 0xf3, 0x90, 0xbf, 0x3f, 0x05, 0xfc, 0xf6, 0xf6, 0xfc, - 0x4c, 0x4c, 0x43, 0x8a, 0x65, 0x2b, 0xf4, 0x08, 0x0c, 0x37, 0xa8, 0xeb, 0x92, 0xaa, 0x3f, 0xe3, - 0x93, 0x12, 0xc1, 0xf0, 0x2b, 0xa2, 0x18, 0xfb, 0x70, 0xf3, 0x27, 0x19, 0x98, 0x0c, 0x70, 0x49, - 0xf2, 0x87, 0xb0, 0xbc, 0x6d, 0x18, 0xab, 0x69, 0x23, 0xe4, 0xab, 0x9c, 0x3b, 0xf3, 0x5c, 0xc2, - 0x93, 0x14, 0x37, 0x49, 0xc5, 0x19, 0x49, 0x66, 0x4c, 0x2f, 0xc5, 0x21, 0x32, 0xa8, 0x01, 0xe0, - 0x76, 0x9a, 0x65, 0x49, 0x74, 0x80, 0x13, 0x7d, 0x26, 0x25, 0xd1, 0x52, 0x80, 0xa0, 0x88, 0x24, - 0x49, 0x50, 0x65, 0x58, 0x23, 0x60, 0xfe, 0xc0, 0x80, 0xe3, 0x31, 0xed, 0xd0, 0xf3, 0x91, 0xf5, - 0x7c, 0xb0, 0x6b, 0x3d, 0x51, 0x57, 0x33, 0xb5, 0x9a, 0x8f, 0xc1, 0x88, 0x43, 0xb7, 0x2c, 0x26, - 0x29, 0xe4, 0x0c, 0x4f, 0xc9, 0xf6, 0x23, 0x58, 0x96, 0xe3, 0xa0, 0x06, 0x7a, 0x14, 0x46, 0xfd, - 0xdf, 0x6c, 0x9a, 0xb3, 0xec, 0x30, 0xb1, 0x85, 0xf3, 0xab, 0xba, 0x58, 0xc1, 0xcd, 0xbf, 0xcc, - 0xc0, 0x74, 0xc1, 0xf1, 0xac, 0x0d, 0x52, 0xf6, 0xd4, 0x49, 0x3a, 0x0f, 0x63, 0x44, 0x16, 0xae, - 0x75, 0x5a, 0xfe, 0x16, 0x08, 0xe6, 0xbb, 0xa0, 0xc1, 0x70, 0xa8, 0x26, 0x5a, 0x82, 0x29, 0xb7, - 0xbd, 0xee, 0x96, 0x1d, 0xab, 0xc5, 0x78, 0xce, 0xab, 0x6a, 0x53, 0xcc, 0xca, 0xd6, 0x53, 0xa5, - 0x08, 0x1c, 0x77, 0xb5, 0x60, 0xdb, 0x77, 0x8b, 0x3a, 0x7c, 0xbc, 0xd9, 0xf0, 0xf6, 0xbd, 0x26, - 0x8a, 0xb1, 0x0f, 0x47, 0x35, 0x18, 0x69, 0x48, 0xe6, 0x2a, 0x97, 0xf7, 0x82, 0x76, 0x3a, 0x95, - 0x84, 0x7d, 0x3b, 0x10, 0xc1, 0xea, 0xa0, 0x86, 0x2a, 0xb0, 0x13, 0xfb, 0x52, 0xe9, 0xea, 0xab, - 0xc5, 0x31, 0x36, 0xaf, 0x3e, 0xc3, 0xc6, 0x01, 0x76, 0xf3, 0xef, 0x0c, 0x38, 0xed, 0x8f, 0xdc, - 0x76, 0x3a, 0xd7, 0xe9, 0x7a, 0xcd, 0xb6, 0x37, 0x31, 0x2d, 0x53, 0x6b, 0x8b, 0x3a, 0x8b, 0x76, - 0x73, 0xc3, 0xaa, 0xa2, 0xd7, 0x61, 0xd4, 0xa5, 0x65, 0x87, 0xb2, 0xc9, 0x94, 0xdc, 0xe2, 0x61, - 0xad, 0x3f, 0x79, 0xa6, 0x36, 0x30, 0x4a, 0x2b, 0x76, 0x99, 0xd4, 0xaf, 0xae, 0x7f, 0x8b, 0x6a, - 0xd3, 0xae, 0xce, 0x58, 0xc9, 0x47, 0x81, 0x15, 0x36, 0x54, 0x80, 0xc9, 0x2d, 0xcb, 0xf1, 0xda, - 0xa4, 0x8e, 0x69, 0xcb, 0xd6, 0x66, 0xf6, 0xa4, 0x6c, 0x36, 0x79, 0x2d, 0x0c, 0xc6, 0xd1, 0xfa, - 0x66, 0x07, 0x66, 0x0a, 0x6d, 0xcf, 0x5e, 0x75, 0xec, 0x86, 0xcd, 0x26, 0xfb, 0x2a, 0x9f, 0x72, - 0x17, 0x11, 0x98, 0x74, 0x69, 0x9d, 0x96, 0xd9, 0xbf, 0x55, 0xbb, 0x6e, 0x95, 0xa5, 0x7c, 0x28, - 0x9e, 0xf3, 0x51, 0x97, 0xc2, 0xe0, 0xdb, 0xdb, 0xf3, 0xf7, 0x87, 0x30, 0x45, 0xe0, 0x38, 0x8a, - 0xcf, 0xbc, 0x09, 0x73, 0x85, 0x77, 0xdb, 0x0e, 0x3d, 0xea, 0x69, 0x33, 0xdf, 0x83, 0x53, 0x45, - 0xcb, 0x5b, 0x6f, 0x97, 0x37, 0xa9, 0x77, 0xe4, 0xc4, 0x7f, 0x07, 0x06, 0x17, 0x6b, 0xc4, 0xf1, - 0xd8, 0x8e, 0x76, 0x68, 0xcb, 0x7e, 0x0d, 0xaf, 0xc8, 0x99, 0x0d, 0x76, 0x34, 0x16, 0xc5, 0xd8, - 0x87, 0x27, 0xe0, 0xa5, 0xc9, 0x8f, 0x87, 0xf9, 0xcf, 0x06, 0xcc, 0xf0, 0x1e, 0x2c, 0x59, 0x6e, - 0xd9, 0xde, 0xa2, 0x4e, 0x07, 0x53, 0xb7, 0x5d, 0x3f, 0xe0, 0x0e, 0xb1, 0x53, 0x4f, 0x1b, 0x62, - 0x46, 0x5d, 0xcf, 0x21, 0x56, 0xd3, 0x93, 0x3d, 0x53, 0xa7, 0x3e, 0x02, 0xc7, 0x5d, 0x2d, 0xd0, - 0xc3, 0x30, 0x22, 0xbb, 0xcd, 0x38, 0x35, 0xe3, 0x5b, 0xfc, 0x28, 0xca, 0x31, 0xb9, 0x38, 0x80, - 0x9a, 0xbf, 0x36, 0x60, 0x9a, 0x8f, 0x4a, 0xe7, 0x25, 0xe8, 0x02, 0x4c, 0x54, 0xfc, 0x51, 0xae, + // 5743 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x6b, 0x88, 0x24, 0xc7, + 0x79, 0xd7, 0x33, 0xfb, 0xfc, 0x66, 0x9f, 0x75, 0x7b, 0xba, 0xd5, 0x4a, 0xba, 0xbd, 0xb4, 0x65, + 0x21, 0x45, 0xd2, 0x6c, 0x74, 0xd2, 0xe9, 0x4e, 0xaf, 0xb3, 0x66, 0x76, 0xef, 0xb1, 0xd2, 0x4a, + 0xb7, 0xae, 0x59, 0xdd, 0x59, 0x27, 0x09, 0xb9, 0x76, 0xa6, 0x76, 0xa6, 0xbd, 0x33, 0xd3, 0xa3, + 0xee, 0x9e, 0xbd, 0x1b, 0x29, 0x38, 0xb2, 0x94, 0x18, 0x07, 0x42, 0xd0, 0x0f, 0x05, 0x85, 0x40, + 0x20, 0xc4, 0x04, 0x12, 0x0c, 0xf6, 0xff, 0x18, 0xe2, 0x40, 0x08, 0xc8, 0x8e, 0x1d, 0x8c, 0x42, + 0x88, 0x02, 0x66, 0x63, 0xad, 0x21, 0x7f, 0x42, 0x20, 0xbf, 0x8f, 0x24, 0x84, 0x7a, 0x74, 0x57, + 0x75, 0x4f, 0xcf, 0x6e, 0xf7, 0xec, 0xe3, 0x2e, 0xe0, 0x7f, 0x33, 0xf5, 0x55, 0x7d, 0x5f, 0x3d, + 0xbf, 0x77, 0x55, 0xc3, 0x53, 0x55, 0xcb, 0xab, 0xb5, 0xd7, 0xf3, 0x65, 0xbb, 0xb1, 0x40, 0x36, + 0xdb, 0x96, 0xd7, 0x59, 0xd8, 0x24, 0x4e, 0xd5, 0x5e, 0x20, 0x2d, 0x6b, 0x61, 0xeb, 0x09, 0x52, + 0x6f, 0xd5, 0xc8, 0x13, 0x0b, 0x55, 0xda, 0xa4, 0x0e, 0xf1, 0x68, 0x25, 0xdf, 0x72, 0x6c, 0xcf, + 0x46, 0x0f, 0xaa, 0x56, 0x79, 0xd1, 0x2a, 0xcf, 0x5b, 0xe5, 0x49, 0xcb, 0xca, 0xfb, 0xad, 0xe6, + 0x1e, 0xd7, 0x70, 0x57, 0xed, 0xaa, 0xbd, 0xc0, 0x1b, 0xaf, 0xb7, 0x37, 0xf8, 0x3f, 0xfe, 0x87, + 0xff, 0x12, 0x48, 0xe7, 0xcc, 0xcd, 0xf3, 0x6e, 0xde, 0x12, 0x94, 0xcb, 0xb6, 0x43, 0x17, 0xb6, + 0xba, 0x08, 0xcf, 0x5d, 0x51, 0x75, 0xe8, 0x2d, 0x8f, 0x36, 0x5d, 0xcb, 0x6e, 0xba, 0x8f, 0x93, + 0x96, 0xe5, 0x52, 0x67, 0x8b, 0x3a, 0x0b, 0xad, 0xcd, 0x2a, 0x83, 0xb9, 0xe1, 0x0a, 0x71, 0x98, + 0x9e, 0x52, 0x98, 0x1a, 0xa4, 0x5c, 0xb3, 0x9a, 0xd4, 0xe9, 0xa8, 0xe6, 0x0d, 0xea, 0x91, 0xb8, + 0x56, 0x0b, 0xbd, 0x5a, 0x39, 0xed, 0xa6, 0x67, 0x35, 0x68, 0x57, 0x83, 0xa7, 0xf7, 0x6a, 0xe0, + 0x96, 0x6b, 0xb4, 0x41, 0xa2, 0xed, 0xcc, 0x37, 0xe1, 0x78, 0xa1, 0x49, 0xea, 0x1d, 0xd7, 0x72, + 0x71, 0xbb, 0x59, 0x70, 0xaa, 0xed, 0x06, 0x6d, 0x7a, 0xe8, 0x34, 0x0c, 0x34, 0x49, 0x83, 0xce, + 0x1a, 0xa7, 0x8d, 0x87, 0x47, 0x8b, 0x63, 0x9f, 0x6e, 0xcf, 0x1f, 0xdb, 0xd9, 0x9e, 0x1f, 0x78, + 0x95, 0x34, 0x28, 0xe6, 0x10, 0xf4, 0x25, 0x18, 0xdc, 0x22, 0xf5, 0x36, 0x9d, 0xcd, 0xf0, 0x2a, + 0xe3, 0xb2, 0xca, 0xe0, 0x35, 0x56, 0x88, 0x05, 0xcc, 0xfc, 0x30, 0x1b, 0x42, 0xff, 0x0a, 0xf5, + 0x48, 0x85, 0x78, 0x04, 0x35, 0x60, 0xa8, 0x4e, 0xd6, 0x69, 0xdd, 0x9d, 0x35, 0x4e, 0x67, 0x1f, + 0xce, 0x9d, 0xb9, 0x98, 0x4f, 0xb2, 0xd0, 0xf9, 0x18, 0x54, 0xf9, 0x15, 0x8e, 0xe7, 0x62, 0xd3, + 0x73, 0x3a, 0xc5, 0x09, 0xd9, 0x89, 0x21, 0x51, 0x88, 0x25, 0x11, 0xf4, 0x2d, 0x03, 0x72, 0xa4, + 0xd9, 0xb4, 0x3d, 0xe2, 0xb1, 0x65, 0x9a, 0xcd, 0x70, 0xa2, 0x2f, 0xf5, 0x4f, 0xb4, 0xa0, 0x90, + 0x09, 0xca, 0xc7, 0x25, 0xe5, 0x9c, 0x06, 0xc1, 0x3a, 0xcd, 0xb9, 0x67, 0x20, 0xa7, 0x75, 0x15, + 0x4d, 0x41, 0x76, 0x93, 0x76, 0xc4, 0xfc, 0x62, 0xf6, 0x13, 0xcd, 0x84, 0x26, 0x54, 0xce, 0xe0, + 0xb3, 0x99, 0xf3, 0xc6, 0xdc, 0x05, 0x98, 0x8a, 0x12, 0x4c, 0xd3, 0xde, 0xfc, 0x43, 0x03, 0x66, + 0xb4, 0x51, 0x60, 0xba, 0x41, 0x1d, 0xda, 0x2c, 0x53, 0xb4, 0x00, 0xa3, 0x6c, 0x2d, 0xdd, 0x16, + 0x29, 0xfb, 0x4b, 0x3d, 0x2d, 0x07, 0x32, 0xfa, 0xaa, 0x0f, 0xc0, 0xaa, 0x4e, 0xb0, 0x2d, 0x32, + 0xbb, 0x6d, 0x8b, 0x56, 0x8d, 0xb8, 0x74, 0x36, 0x1b, 0xde, 0x16, 0xab, 0xac, 0x10, 0x0b, 0x98, + 0xf9, 0x36, 0xdc, 0xeb, 0xf7, 0x67, 0x8d, 0x36, 0x5a, 0x75, 0xe2, 0x51, 0xd5, 0xa9, 0xbd, 0xb7, + 0xde, 0x69, 0x18, 0xd8, 0xb4, 0x9a, 0x95, 0x68, 0x2f, 0x5e, 0xb6, 0x9a, 0x15, 0xcc, 0x21, 0xe6, + 0x26, 0x8c, 0x17, 0x5a, 0x2d, 0xc7, 0xde, 0xa2, 0x95, 0x92, 0x47, 0xaa, 0x14, 0xdd, 0x00, 0x20, + 0xb2, 0xa0, 0xe0, 0x71, 0xd4, 0xb9, 0x33, 0xbf, 0x99, 0x17, 0x67, 0x26, 0xaf, 0x9f, 0x99, 0x7c, + 0x6b, 0xb3, 0xca, 0x0a, 0xdc, 0x3c, 0x3b, 0x9a, 0xf9, 0xad, 0x27, 0xf2, 0x6b, 0x56, 0x83, 0x16, + 0x27, 0x76, 0xb6, 0xe7, 0xa1, 0x10, 0x60, 0xc0, 0x1a, 0x36, 0xf3, 0x03, 0x03, 0x4e, 0x14, 0x9c, + 0xaa, 0xbd, 0xb8, 0x54, 0x68, 0xb5, 0xae, 0x50, 0x52, 0xf7, 0x6a, 0x25, 0x8f, 0x78, 0x6d, 0x17, + 0x5d, 0x80, 0x21, 0x97, 0xff, 0x92, 0x83, 0x79, 0xc8, 0xdf, 0x9f, 0x02, 0x7e, 0x7b, 0x7b, 0x7e, + 0x26, 0xa6, 0x21, 0xc5, 0xb2, 0x15, 0x7a, 0x04, 0x86, 0x1b, 0xd4, 0x75, 0x49, 0xd5, 0x9f, 0xf1, + 0x49, 0x89, 0x60, 0xf8, 0x15, 0x51, 0x8c, 0x7d, 0xb8, 0xf9, 0x93, 0x0c, 0x4c, 0x06, 0xb8, 0x24, + 0xf9, 0x43, 0x58, 0xde, 0x36, 0x8c, 0xd5, 0xb4, 0x11, 0xf2, 0x55, 0xce, 0x9d, 0x79, 0x2e, 0xe1, + 0x49, 0x8a, 0x9b, 0xa4, 0xe2, 0x8c, 0x24, 0x33, 0xa6, 0x97, 0xe2, 0x10, 0x19, 0xd4, 0x00, 0x70, + 0x3b, 0xcd, 0xb2, 0x24, 0x3a, 0xc0, 0x89, 0x3e, 0x93, 0x92, 0x68, 0x29, 0x40, 0x50, 0x44, 0x92, + 0x24, 0xa8, 0x32, 0xac, 0x11, 0x30, 0xbf, 0x6f, 0xc0, 0xf1, 0x98, 0x76, 0xe8, 0xf9, 0xc8, 0x7a, + 0x3e, 0xd8, 0xb5, 0x9e, 0xa8, 0xab, 0x99, 0x5a, 0xcd, 0xc7, 0x60, 0xc4, 0xa1, 0x5b, 0x16, 0x93, + 0x14, 0x72, 0x86, 0xa7, 0x64, 0xfb, 0x11, 0x2c, 0xcb, 0x71, 0x50, 0x03, 0x3d, 0x0a, 0xa3, 0xfe, + 0x6f, 0x36, 0xcd, 0x59, 0x76, 0x98, 0xd8, 0xc2, 0xf9, 0x55, 0x5d, 0xac, 0xe0, 0xe6, 0x5f, 0x66, + 0x60, 0xba, 0xe0, 0x78, 0xd6, 0x06, 0x29, 0x7b, 0xea, 0x24, 0x9d, 0x87, 0x31, 0x22, 0x0b, 0xd7, + 0x3a, 0x2d, 0x7f, 0x0b, 0x04, 0xf3, 0x5d, 0xd0, 0x60, 0x38, 0x54, 0x13, 0x2d, 0xc1, 0x94, 0xdb, + 0x5e, 0x77, 0xcb, 0x8e, 0xd5, 0x62, 0x3c, 0xe7, 0x55, 0xb5, 0x29, 0x66, 0x65, 0xeb, 0xa9, 0x52, + 0x04, 0x8e, 0xbb, 0x5a, 0xb0, 0xed, 0xbb, 0x45, 0x1d, 0x3e, 0xde, 0x6c, 0x78, 0xfb, 0x5e, 0x13, + 0xc5, 0xd8, 0x87, 0xa3, 0x1a, 0x8c, 0x34, 0x24, 0x73, 0x95, 0xcb, 0x7b, 0x41, 0x3b, 0x9d, 0x4a, + 0xc2, 0xbe, 0x1d, 0x88, 0x60, 0x75, 0x50, 0x43, 0x15, 0xd8, 0x89, 0x7d, 0xa9, 0x74, 0xf5, 0xd5, + 0xe2, 0x18, 0x9b, 0x57, 0x9f, 0x61, 0xe3, 0x00, 0xbb, 0xf9, 0xb7, 0x06, 0x9c, 0xf6, 0x47, 0x6e, + 0x3b, 0x9d, 0xeb, 0x74, 0xbd, 0x66, 0xdb, 0x9b, 0x98, 0x96, 0xa9, 0xb5, 0x45, 0x9d, 0x45, 0xbb, + 0xb9, 0x61, 0x55, 0xd1, 0xeb, 0x30, 0xea, 0xd2, 0xb2, 0x43, 0xd9, 0x64, 0x4a, 0x6e, 0xf1, 0xb0, + 0xd6, 0x9f, 0x3c, 0x53, 0x1b, 0x18, 0xa5, 0x15, 0xbb, 0x4c, 0xea, 0x57, 0xd7, 0xbf, 0x41, 0xb5, + 0x69, 0x57, 0x67, 0xac, 0xe4, 0xa3, 0xc0, 0x0a, 0x1b, 0x2a, 0xc0, 0xe4, 0x96, 0xe5, 0x78, 0x6d, + 0x52, 0xc7, 0xb4, 0x65, 0x6b, 0x33, 0x7b, 0x52, 0x36, 0x9b, 0xbc, 0x16, 0x06, 0xe3, 0x68, 0x7d, + 0xb3, 0x03, 0x33, 0x85, 0xb6, 0x67, 0xaf, 0x3a, 0x76, 0xc3, 0x66, 0x93, 0x7d, 0x95, 0x4f, 0xb9, + 0x8b, 0x08, 0x4c, 0xba, 0xb4, 0x4e, 0xcb, 0xec, 0xdf, 0xaa, 0x5d, 0xb7, 0xca, 0x52, 0x3e, 0x14, + 0xcf, 0xf9, 0xa8, 0x4b, 0x61, 0xf0, 0xed, 0xed, 0xf9, 0xfb, 0x43, 0x98, 0x22, 0x70, 0x1c, 0xc5, + 0x67, 0xde, 0x84, 0xb9, 0xc2, 0xbb, 0x6d, 0x87, 0x1e, 0xf5, 0xb4, 0x99, 0xef, 0xc1, 0xa9, 0xa2, + 0xe5, 0xad, 0xb7, 0xcb, 0x9b, 0xd4, 0x3b, 0x72, 0xe2, 0xbf, 0x03, 0x83, 0x8b, 0x35, 0xe2, 0x78, + 0x6c, 0x47, 0x3b, 0xb4, 0x65, 0xbf, 0x86, 0x57, 0xe4, 0xcc, 0x06, 0x3b, 0x1a, 0x8b, 0x62, 0xec, + 0xc3, 0x13, 0xf0, 0xd2, 0xe4, 0xc7, 0xc3, 0xfc, 0x27, 0x03, 0x66, 0x78, 0x0f, 0x96, 0x2c, 0xb7, + 0x6c, 0x6f, 0x51, 0xa7, 0x83, 0xa9, 0xdb, 0xae, 0x1f, 0x70, 0x87, 0xd8, 0xa9, 0xa7, 0x0d, 0x31, + 0xa3, 0xae, 0xe7, 0x10, 0xab, 0xe9, 0xc9, 0x9e, 0xa9, 0x53, 0x1f, 0x81, 0xe3, 0xae, 0x16, 0xe8, + 0x61, 0x18, 0x91, 0xdd, 0x66, 0x9c, 0x9a, 0xf1, 0x2d, 0x7e, 0x14, 0xe5, 0x98, 0x5c, 0x1c, 0x40, + 0xcd, 0x1f, 0x66, 0x60, 0x9a, 0x8f, 0x4a, 0xe7, 0x25, 0xe8, 0x02, 0x4c, 0x54, 0xfc, 0x51, 0xae, 0x58, 0x0d, 0x4b, 0x88, 0xeb, 0x6c, 0xf1, 0x1e, 0xd9, 0x87, 0x89, 0xa5, 0x10, 0x14, 0x47, 0x6a, - 0x27, 0x9b, 0x78, 0x7f, 0xd2, 0xb2, 0x7b, 0x4c, 0x5a, 0xdc, 0x94, 0x0c, 0xa4, 0x9d, 0x12, 0xf3, - 0x87, 0x19, 0x18, 0x5f, 0xac, 0xb7, 0x5d, 0x2f, 0xd8, 0xac, 0xdf, 0xd4, 0xf8, 0x9d, 0xd8, 0xab, - 0xbf, 0x95, 0x4c, 0x1b, 0x11, 0x1b, 0x97, 0xf1, 0x35, 0x25, 0xc5, 0x54, 0x99, 0xe2, 0x73, 0xe8, - 0x75, 0x18, 0x70, 0x5b, 0xb4, 0xcc, 0xa7, 0x21, 0x77, 0xe6, 0x5c, 0x32, 0x61, 0x19, 0xea, 0x64, - 0xa9, 0x45, 0xcb, 0x6a, 0xfe, 0xd8, 0x3f, 0xcc, 0x51, 0x22, 0x12, 0x88, 0xc1, 0x6c, 0x1a, 0x49, - 0x1c, 0x46, 0x2e, 0x24, 0xf1, 0x44, 0x58, 0x82, 0xfa, 0xb2, 0xd2, 0xfc, 0x47, 0xb6, 0x35, 0xf4, - 0xfa, 0x2b, 0x96, 0xeb, 0xa1, 0x37, 0xbb, 0x66, 0x2d, 0x9f, 0x6c, 0xd6, 0x58, 0x6b, 0x3e, 0x67, - 0x81, 0xc4, 0xf5, 0x4b, 0xb4, 0x19, 0xfb, 0x06, 0x0c, 0x5a, 0x1e, 0x6d, 0xf8, 0xe6, 0xc1, 0x93, - 0x7d, 0x8c, 0x4a, 0xe9, 0xbb, 0xcb, 0x0c, 0x13, 0x16, 0x08, 0xcd, 0x4f, 0xa3, 0xa3, 0x61, 0x93, - 0xc9, 0xac, 0x92, 0xa9, 0x9b, 0x61, 0x56, 0xe6, 0xdb, 0x43, 0x09, 0x15, 0xaa, 0x58, 0x46, 0xa8, - 0x76, 0x66, 0x04, 0xec, 0xe2, 0x2e, 0x72, 0xe6, 0xa7, 0x59, 0x38, 0x1e, 0xb3, 0x2e, 0xa8, 0x0c, - 0x50, 0xb6, 0x9b, 0x15, 0x4b, 0xd8, 0x4b, 0xa2, 0x53, 0x0b, 0xc9, 0xe6, 0x7a, 0xd1, 0x6f, 0xa7, - 0x36, 0x68, 0x50, 0xe4, 0x62, 0x0d, 0x2d, 0x7a, 0x09, 0x90, 0xbd, 0xce, 0xa5, 0x79, 0xe5, 0xb2, - 0x30, 0x4b, 0x7d, 0x5e, 0x98, 0x2d, 0xce, 0xc9, 0xb6, 0xe8, 0x6a, 0x57, 0x0d, 0x1c, 0xd3, 0x8a, - 0xe1, 0xaa, 0x13, 0xd7, 0xbb, 0x42, 0x9a, 0x95, 0x3a, 0xad, 0x60, 0xba, 0xe1, 0x50, 0xb7, 0x26, - 0x8f, 0x6a, 0x80, 0x6b, 0xa5, 0xab, 0x06, 0x8e, 0x69, 0x85, 0x3e, 0x88, 0x5b, 0x18, 0xb1, 0x29, - 0x9e, 0xef, 0x6b, 0x61, 0x96, 0xa8, 0x47, 0xac, 0xba, 0x9b, 0x6a, 0x65, 0x38, 0xcb, 0x17, 0x2b, - 0x13, 0x88, 0xe7, 0x35, 0xe2, 0x6e, 0xde, 0xad, 0xac, 0x23, 0xd4, 0xc9, 0x5e, 0xac, 0xc3, 0xfc, - 0x57, 0x03, 0x66, 0xe3, 0x46, 0x75, 0x04, 0xc7, 0xfb, 0xed, 0xf0, 0xf1, 0x7e, 0x36, 0xd5, 0xf1, - 0x0e, 0x75, 0xb6, 0xc7, 0x29, 0x7f, 0x03, 0xc6, 0x16, 0xdb, 0x8e, 0x43, 0x9b, 0x9e, 0xb0, 0x39, - 0x5f, 0x86, 0x41, 0xd7, 0x6a, 0x4a, 0xd3, 0x2b, 0x9d, 0xb9, 0x39, 0xca, 0x90, 0x97, 0x58, 0x63, - 0x2c, 0x70, 0x98, 0xff, 0x93, 0x85, 0xe3, 0xbe, 0xe0, 0xa3, 0x15, 0x5f, 0x81, 0x75, 0x51, 0x05, - 0xc6, 0x2a, 0xaa, 0xd8, 0x93, 0xca, 0x73, 0x1a, 0x5a, 0x81, 0x3d, 0xa0, 0xa1, 0xf7, 0x70, 0x08, - 0x2b, 0xba, 0x0e, 0xd9, 0x2a, 0x17, 0xc4, 0x6c, 0xe6, 0xce, 0x27, 0x9b, 0xb9, 0xcb, 0x56, 0x54, - 0x5b, 0x29, 0xe6, 0x24, 0xa9, 0xec, 0x65, 0xcb, 0xc3, 0x0c, 0x23, 0x5a, 0x87, 0x21, 0xab, 0x41, - 0xaa, 0x34, 0xe5, 0xaa, 0x2c, 0xb3, 0x36, 0x51, 0xec, 0x81, 0x2c, 0xe1, 0x50, 0x17, 0x4b, 0xcc, - 0x8c, 0x46, 0x99, 0x69, 0x19, 0xc2, 0x8c, 0x4a, 0xbe, 0xf2, 0x31, 0xfa, 0x96, 0xa2, 0xc1, 0xa1, - 0x2e, 0x96, 0x98, 0xd1, 0x37, 0x99, 0x4a, 0xc1, 0x6a, 0xb8, 0xb3, 0x83, 0x9c, 0xc8, 0xd9, 0x64, - 0x44, 0xa2, 0xf8, 0x35, 0x4d, 0x84, 0x63, 0xc3, 0x3e, 0x5a, 0xf3, 0x8b, 0x0c, 0x4c, 0xa9, 0x15, - 0x5a, 0xb4, 0x1b, 0x4c, 0xd7, 0x99, 0x83, 0x8c, 0x55, 0x91, 0x9a, 0x1f, 0xc8, 0xa6, 0x99, 0xe5, - 0x25, 0x9c, 0xb1, 0x2a, 0xe8, 0x21, 0x18, 0x5a, 0x77, 0x48, 0xb3, 0x5c, 0x93, 0x9a, 0x50, 0xd0, - 0xf5, 0x22, 0x2f, 0xc5, 0x12, 0x8a, 0x1e, 0x80, 0xac, 0x47, 0xaa, 0x52, 0x13, 0x0a, 0x56, 0x68, - 0x8d, 0x54, 0x31, 0x2b, 0x67, 0xca, 0x92, 0xdb, 0xe6, 0x5c, 0x42, 0x72, 0xd3, 0xa0, 0x8b, 0x25, - 0x51, 0x8c, 0x7d, 0x38, 0xa3, 0x48, 0xda, 0x5e, 0xcd, 0x76, 0x66, 0x07, 0xc3, 0x14, 0x0b, 0xbc, - 0x14, 0x4b, 0x28, 0x5a, 0x80, 0xd1, 0x32, 0xef, 0xbf, 0x47, 0x9d, 0xd9, 0xa1, 0xb0, 0x5f, 0x62, - 0xd1, 0x07, 0x60, 0x55, 0x07, 0xbd, 0x05, 0xb9, 0xb2, 0x43, 0x89, 0x67, 0x3b, 0x4b, 0xc4, 0xa3, - 0xb3, 0xc3, 0xa9, 0xf7, 0xf8, 0xe4, 0xce, 0xf6, 0x7c, 0x6e, 0x51, 0xa1, 0xc0, 0x3a, 0x3e, 0xf3, - 0xc3, 0x2c, 0xcc, 0xaa, 0xa9, 0xe5, 0xbb, 0x47, 0x19, 0xd1, 0x72, 0x7a, 0x8c, 0x1e, 0xd3, 0xf3, - 0x10, 0x0c, 0x55, 0xac, 0x2a, 0x75, 0xbd, 0xe8, 0x2c, 0x2f, 0xf1, 0x52, 0x2c, 0xa1, 0xe8, 0xbb, - 0x11, 0x17, 0xa4, 0xd8, 0x25, 0x57, 0xd3, 0xed, 0x92, 0x68, 0xe7, 0xfa, 0xf0, 0x43, 0xa2, 0xeb, - 0x30, 0xca, 0xc7, 0xde, 0x27, 0xb7, 0xe0, 0x3e, 0x88, 0x45, 0x1f, 0x01, 0x56, 0xb8, 0xf6, 0xed, - 0xa5, 0xfc, 0x07, 0x03, 0x26, 0xa3, 0xe6, 0xcd, 0x63, 0x52, 0x97, 0xcf, 0xee, 0xe1, 0x7b, 0x10, - 0x7a, 0xfd, 0x87, 0x06, 0x20, 0x12, 0xf5, 0x82, 0xf8, 0x9c, 0xe5, 0x5c, 0x52, 0x77, 0x51, 0xa4, - 0xbd, 0xd2, 0x1e, 0xba, 0x40, 0x2e, 0x8e, 0x21, 0xc7, 0x2c, 0xd5, 0x25, 0xbb, 0xbc, 0x49, 0x9d, - 0x2b, 0xed, 0xf5, 0x23, 0xb7, 0x54, 0xdf, 0x00, 0x74, 0xf1, 0x56, 0xcb, 0xa1, 0x2e, 0xb3, 0xb0, - 0xae, 0x11, 0xc7, 0x22, 0xeb, 0x75, 0x7a, 0x50, 0xde, 0xfc, 0xbf, 0x1e, 0x84, 0xe1, 0x4b, 0x0e, - 0xb5, 0xaa, 0x35, 0xef, 0x08, 0xb4, 0x90, 0xaf, 0xc0, 0x20, 0xa9, 0x5b, 0xc4, 0xe5, 0xc7, 0x5d, - 0xeb, 0x52, 0x81, 0x15, 0x62, 0x01, 0x43, 0x6f, 0xc0, 0x90, 0xed, 0x58, 0x55, 0xab, 0x39, 0x3b, - 0xca, 0x3b, 0x91, 0x50, 0x69, 0x97, 0xa3, 0xb8, 0xca, 0x9b, 0xaa, 0x33, 0x2b, 0xfe, 0x63, 0x89, - 0x12, 0xdd, 0x80, 0x61, 0xc1, 0x83, 0x7c, 0xc9, 0xb1, 0x90, 0x58, 0xf2, 0x09, 0x36, 0xa6, 0x78, - 0xa5, 0xf8, 0xef, 0x62, 0x1f, 0x21, 0x2a, 0x05, 0x82, 0x6f, 0x80, 0xa3, 0x7e, 0x34, 0x85, 0xe0, - 0xeb, 0x29, 0xe9, 0x4a, 0x81, 0xa4, 0x1b, 0x4c, 0x83, 0x94, 0xcb, 0xb2, 0x9e, 0xa2, 0xad, 0x06, - 0xa3, 0xfe, 0x2e, 0x77, 0x67, 0x61, 0x7f, 0x67, 0x29, 0xd8, 0xbc, 0x81, 0x02, 0x83, 0x15, 0x72, - 0xb6, 0x98, 0xd2, 0xae, 0x1c, 0xea, 0x63, 0x31, 0xf7, 0xb0, 0x28, 0x3f, 0xc9, 0xc2, 0xb4, 0xac, - 0xb9, 0x68, 0xd7, 0xa5, 0x57, 0x4b, 0x0a, 0xd0, 0x6c, 0xac, 0x00, 0xb5, 0x7c, 0x85, 0x51, 0xa8, - 0x3d, 0xc5, 0x54, 0xbd, 0x51, 0x34, 0xf2, 0x5c, 0x49, 0x14, 0xec, 0x39, 0xd8, 0x0f, 0xb2, 0x96, - 0x54, 0x1d, 0xd1, 0xef, 0x19, 0x70, 0x7c, 0x8b, 0x3a, 0xd6, 0x86, 0x55, 0xe6, 0xec, 0xf3, 0x8a, - 0xe5, 0x7a, 0xb6, 0xd3, 0x91, 0xac, 0xeb, 0xe9, 0x64, 0x94, 0xaf, 0x69, 0x08, 0x96, 0x9b, 0x1b, - 0x76, 0xf1, 0x3e, 0x49, 0xed, 0xf8, 0xb5, 0x6e, 0xd4, 0x38, 0x8e, 0xde, 0x5c, 0x0b, 0x40, 0xf5, - 0x36, 0x86, 0x7b, 0xaf, 0xe8, 0x6c, 0x22, 0x71, 0xc7, 0xfc, 0xc1, 0xfa, 0xdb, 0x40, 0xe7, 0xfa, - 0xaf, 0xc0, 0x49, 0x7f, 0xc6, 0x98, 0x24, 0xb1, 0xec, 0xe6, 0xa2, 0x63, 0x79, 0xd4, 0xb1, 0x08, - 0x3a, 0x03, 0x40, 0x03, 0x5e, 0x26, 0x79, 0x57, 0xc0, 0x32, 0x14, 0x97, 0xc3, 0x5a, 0x2d, 0xf3, - 0x47, 0x06, 0xe4, 0x24, 0xbe, 0x23, 0x30, 0x29, 0x70, 0xd8, 0xa4, 0x78, 0x3c, 0xd5, 0x74, 0xf4, - 0xb0, 0x22, 0x1c, 0x18, 0x0f, 0x71, 0x27, 0x74, 0x56, 0x46, 0xbb, 0xc4, 0x04, 0xfc, 0x86, 0x1e, - 0xed, 0xba, 0xbd, 0x3d, 0x3f, 0x1d, 0xaa, 0xac, 0x42, 0x60, 0x7b, 0xbb, 0xc1, 0x9e, 0x1d, 0xf9, - 0xe3, 0x3f, 0x9b, 0x3f, 0xf6, 0xfe, 0x2f, 0x4e, 0x1f, 0x33, 0xbf, 0x33, 0x00, 0x53, 0xd1, 0x45, - 0x4a, 0x20, 0x34, 0x14, 0xf3, 0x1d, 0x39, 0x54, 0xe6, 0x9b, 0x39, 0x3c, 0xe6, 0x9b, 0x3d, 0x0c, - 0xe6, 0x3b, 0x70, 0x48, 0xcc, 0x77, 0xf4, 0x10, 0x99, 0xaf, 0xf9, 0x4f, 0x06, 0x4c, 0x04, 0x7b, - 0xe0, 0x9d, 0x36, 0xd3, 0x59, 0xd5, 0xfa, 0x1a, 0x07, 0xbf, 0xbe, 0x6f, 0xc3, 0xb0, 0x6b, 0xb7, - 0x1d, 0xa1, 0xa0, 0x31, 0xec, 0x4f, 0xa5, 0xe3, 0xf6, 0xa2, 0xad, 0x66, 0x8d, 0x88, 0x02, 0xec, - 0x63, 0x35, 0x7f, 0x92, 0x0d, 0x06, 0x24, 0x61, 0x42, 0x59, 0x77, 0x98, 0x29, 0xc3, 0x06, 0x34, - 0xa2, 0x2b, 0xeb, 0xac, 0x14, 0x4b, 0x28, 0x32, 0xb9, 0x20, 0xf2, 0xad, 0xd2, 0xd1, 0x22, 0x48, - 0x79, 0xc2, 0x97, 0x5b, 0x40, 0x50, 0x0b, 0xa6, 0x1c, 0xfa, 0x4e, 0xdb, 0x72, 0x68, 0xa5, 0x64, - 0x93, 0x4d, 0xa6, 0x1c, 0x4b, 0x77, 0x68, 0x42, 0x0e, 0xb3, 0xd4, 0x16, 0xae, 0xab, 0xe2, 0x0c, - 0x53, 0x69, 0x71, 0x04, 0x17, 0xee, 0xc2, 0x8e, 0x6c, 0x98, 0x21, 0x5b, 0xc4, 0xaa, 0x93, 0x75, - 0xab, 0x6e, 0x79, 0x9d, 0x92, 0xe7, 0x10, 0x8f, 0x56, 0x3b, 0xd2, 0x2c, 0x7b, 0x4e, 0x8e, 0x65, - 0xa6, 0x10, 0x53, 0xe7, 0xf6, 0xf6, 0xfc, 0x7d, 0x72, 0x2e, 0xe2, 0xc0, 0x38, 0x16, 0x31, 0xfa, - 0xc8, 0x80, 0x19, 0x12, 0x13, 0x68, 0xe2, 0xe6, 0x5d, 0x62, 0x3b, 0x3a, 0x2e, 0x54, 0x55, 0x9c, - 0xe5, 0x3d, 0x8d, 0x81, 0xe0, 0x58, 0x8a, 0xe6, 0xcf, 0x86, 0x03, 0xb6, 0x28, 0x3d, 0x94, 0xef, - 0x41, 0xae, 0x2c, 0xbc, 0x2d, 0xf5, 0xce, 0x72, 0x53, 0x1e, 0xe4, 0xa5, 0x3e, 0x34, 0x86, 0xfc, - 0xa2, 0x42, 0x13, 0x31, 0xa2, 0x34, 0x08, 0xd6, 0xa9, 0xa1, 0x9b, 0x00, 0x42, 0x7c, 0xd2, 0xca, - 0x72, 0x53, 0xea, 0x07, 0x8b, 0xfd, 0xd0, 0xbe, 0x16, 0x60, 0x11, 0xa4, 0x03, 0xf9, 0xa6, 0x00, - 0x58, 0x23, 0xc5, 0x46, 0xed, 0x67, 0x1e, 0x5c, 0xb2, 0x1d, 0xc9, 0x19, 0xfb, 0x1a, 0x75, 0x41, - 0xa1, 0x89, 0x9a, 0x8e, 0x0a, 0x82, 0x75, 0x6a, 0xc8, 0x0e, 0x05, 0x69, 0x19, 0xe5, 0x42, 0x3f, - 0x94, 0xfd, 0xa0, 0xac, 0x20, 0x1b, 0xc8, 0xd7, 0xee, 0x58, 0xed, 0x9c, 0x03, 0x53, 0xd1, 0xc5, - 0x89, 0x51, 0x4a, 0xae, 0x84, 0x95, 0x92, 0x33, 0x09, 0xf9, 0xae, 0xe6, 0xaa, 0xd3, 0x93, 0x6d, - 0x1c, 0x98, 0x8c, 0x2c, 0x4a, 0x0c, 0xc9, 0xe5, 0x30, 0xc9, 0x27, 0xd3, 0x28, 0x68, 0x32, 0x25, - 0x45, 0xa7, 0xe9, 0xc2, 0x54, 0x74, 0x39, 0x0e, 0x8c, 0x68, 0x28, 0x0f, 0x46, 0x27, 0xfa, 0x1e, - 0x8c, 0x87, 0x56, 0x22, 0x86, 0xe2, 0x5a, 0x98, 0xe2, 0x3e, 0x43, 0xf2, 0xba, 0xda, 0xf7, 0xeb, - 0x2c, 0xcc, 0x70, 0xef, 0xbd, 0x55, 0x96, 0x36, 0x72, 0x41, 0x28, 0xe4, 0x97, 0x60, 0x88, 0xf0, - 0x5f, 0x52, 0xef, 0xc8, 0xfb, 0x07, 0x42, 0xc0, 0xd7, 0x3a, 0x2d, 0x7a, 0x7b, 0x7b, 0x7e, 0x36, - 0xae, 0x2d, 0xcf, 0x63, 0x90, 0xad, 0xd1, 0x05, 0x98, 0xb8, 0x59, 0xa3, 0x4d, 0xa5, 0x26, 0x4a, - 0x45, 0x28, 0x88, 0x22, 0x5e, 0x0f, 0x41, 0x71, 0xa4, 0x36, 0xfa, 0x36, 0x40, 0x8b, 0x38, 0xa4, - 0x41, 0x3d, 0xea, 0xf8, 0x6a, 0x42, 0xc2, 0x84, 0xb1, 0xb8, 0xbe, 0xe5, 0x57, 0x03, 0x64, 0x91, - 0x83, 0xae, 0x00, 0x58, 0xa3, 0x88, 0xbe, 0x6b, 0xc0, 0xb0, 0x47, 0x9c, 0x2a, 0x0d, 0xf4, 0x89, - 0x97, 0xfb, 0xa1, 0xbe, 0xc6, 0x51, 0x04, 0x61, 0x7d, 0x5f, 0xb7, 0x2e, 0xce, 0x4b, 0xf2, 0x27, - 0x7b, 0x54, 0xc0, 0x3e, 0xf1, 0xb9, 0x17, 0x60, 0x32, 0xd2, 0xf7, 0x54, 0x5e, 0x9d, 0x5f, 0x1a, - 0x70, 0x7f, 0xb8, 0x4b, 0x47, 0x97, 0x6a, 0x41, 0x61, 0x58, 0xec, 0x86, 0x94, 0xde, 0xe5, 0xb8, - 0x05, 0x54, 0x8a, 0x86, 0xf8, 0xef, 0x62, 0x1f, 0xb7, 0xf9, 0xef, 0x19, 0xf8, 0x6a, 0xa2, 0x59, - 0x47, 0xcf, 0x87, 0x54, 0xf9, 0x87, 0x23, 0xaa, 0xfc, 0x6c, 0x1c, 0x92, 0x34, 0x1a, 0x3d, 0x6a, - 0xc1, 0x38, 0xcf, 0x78, 0x14, 0x94, 0x6d, 0x47, 0x2a, 0x24, 0x4f, 0x26, 0x34, 0x79, 0xf4, 0xa6, - 0xc5, 0x13, 0x12, 0xff, 0x78, 0xa8, 0x18, 0x87, 0x09, 0x30, 0x8a, 0x56, 0xb3, 0x42, 0x6f, 0x05, - 0x14, 0x07, 0xd2, 0xf0, 0xa6, 0x65, 0xbd, 0xa9, 0xa2, 0x18, 0x2a, 0xc6, 0x61, 0x02, 0xe6, 0x9f, - 0x66, 0x60, 0x34, 0xd0, 0xf1, 0xd3, 0xe4, 0x3f, 0x08, 0x53, 0x3f, 0xb3, 0x87, 0xaf, 0x3c, 0x9b, - 0xc4, 0x57, 0x3e, 0xd0, 0xdb, 0x57, 0xee, 0xe7, 0xeb, 0x0d, 0xed, 0x9e, 0xaf, 0xa7, 0xf9, 0xca, - 0x87, 0x93, 0xfb, 0xca, 0x47, 0xf6, 0xf6, 0x95, 0x9b, 0x7f, 0x6e, 0x00, 0xea, 0x0e, 0xbd, 0xa4, - 0x99, 0x28, 0x12, 0xb5, 0xbc, 0x9e, 0x4e, 0xeb, 0xa5, 0xde, 0xcb, 0x00, 0x33, 0x6f, 0xc1, 0x7d, - 0x97, 0x2d, 0xef, 0x4e, 0x38, 0x48, 0x05, 0xe5, 0x15, 0x72, 0xf4, 0x94, 0x3f, 0x1a, 0x86, 0xc9, - 0xcb, 0x56, 0x38, 0xd7, 0x65, 0x01, 0x46, 0x49, 0xbd, 0x6e, 0xdf, 0x5c, 0x23, 0x55, 0x37, 0x9a, - 0xa1, 0x59, 0xf0, 0x01, 0x58, 0xd5, 0x41, 0x2f, 0xc2, 0x54, 0xf0, 0x07, 0xd3, 0x2a, 0xbd, 0x15, - 0xd8, 0x28, 0xdc, 0x8a, 0x28, 0x44, 0x60, 0xb8, 0xab, 0x76, 0xe2, 0xad, 0xee, 0xc1, 0x49, 0xb1, - 0x5a, 0x01, 0x1b, 0x8b, 0x18, 0x1c, 0xcf, 0xfa, 0x22, 0x64, 0x31, 0xbe, 0xda, 0xed, 0xde, 0x20, - 0xdc, 0x0b, 0x75, 0x4c, 0xf2, 0xcf, 0x60, 0xaa, 0xe4, 0x9f, 0xa7, 0x60, 0x8c, 0xde, 0x2a, 0xd7, - 0xdb, 0x15, 0xba, 0x4a, 0xbc, 0x9a, 0x3b, 0x3b, 0xc4, 0xe7, 0x66, 0x6a, 0x67, 0x7b, 0x7e, 0xec, - 0xa2, 0x56, 0x8e, 0x43, 0xb5, 0xd0, 0x12, 0x4c, 0x29, 0x1f, 0xd2, 0x25, 0xab, 0xce, 0xce, 0xda, - 0x70, 0x38, 0xe4, 0x70, 0x31, 0x02, 0xc7, 0x5d, 0x2d, 0x50, 0x1e, 0xc0, 0xaa, 0x36, 0x6d, 0x87, - 0xf2, 0xd5, 0x1c, 0xe1, 0x94, 0x79, 0xde, 0xf0, 0x72, 0x50, 0x8a, 0xb5, 0x1a, 0x68, 0x11, 0xa6, - 0xd5, 0x3f, 0x7f, 0x31, 0x47, 0x79, 0xb3, 0x13, 0x3b, 0xdb, 0xf3, 0xd3, 0xcb, 0x51, 0x20, 0xee, - 0xae, 0xcf, 0x06, 0x6c, 0x35, 0xb5, 0x01, 0x83, 0x1a, 0xf0, 0x72, 0x53, 0x1f, 0xb0, 0x5e, 0x0b, - 0x95, 0xe0, 0x84, 0xd5, 0x74, 0x69, 0xb9, 0xed, 0xd0, 0xd2, 0xa6, 0xd5, 0x5a, 0x5b, 0x29, 0x71, - 0xdd, 0xb4, 0x33, 0x9b, 0xe3, 0x76, 0xf1, 0x03, 0x72, 0xd4, 0x27, 0x96, 0xe3, 0x2a, 0xe1, 0xf8, - 0xb6, 0x3a, 0x8b, 0x19, 0xeb, 0x23, 0xad, 0x6a, 0x3c, 0x75, 0xa6, 0xd9, 0x39, 0x18, 0x77, 0x3d, - 0xc7, 0x2a, 0x7b, 0xa2, 0xae, 0x3b, 0x3b, 0xc1, 0x7b, 0x3f, 0xcd, 0x64, 0x48, 0x49, 0x07, 0xe0, - 0x70, 0x3d, 0xf3, 0x26, 0xcc, 0x5d, 0xb6, 0x3c, 0x4a, 0xee, 0x04, 0xf7, 0xb9, 0x42, 0x9c, 0x75, - 0xdb, 0x39, 0x72, 0xca, 0xdf, 0xcf, 0xc0, 0x90, 0x48, 0xb0, 0x46, 0x67, 0x23, 0x59, 0xcc, 0x0f, - 0x74, 0x65, 0x31, 0xe7, 0xe2, 0x92, 0xd1, 0x4d, 0x18, 0xb2, 0x5c, 0xb7, 0x1d, 0x76, 0x8a, 0x2c, - 0xf3, 0x12, 0x2c, 0x21, 0x3c, 0xd4, 0xce, 0x87, 0x72, 0x40, 0x49, 0xbc, 0x9c, 0x86, 0x98, 0x1c, - 0x2c, 0x31, 0x33, 0x1a, 0x76, 0xdb, 0x6b, 0xb5, 0x3d, 0xe9, 0x86, 0x38, 0x10, 0x1a, 0x57, 0x39, - 0x46, 0x2c, 0x31, 0x9b, 0x9f, 0x1a, 0x30, 0x29, 0xe6, 0x60, 0xb1, 0x46, 0xcb, 0x9b, 0x25, 0x8f, - 0xb6, 0x98, 0xfa, 0xd5, 0x76, 0xa9, 0x1b, 0xf5, 0x87, 0xbe, 0xe6, 0x52, 0x17, 0x73, 0x88, 0x36, - 0xfa, 0xcc, 0x61, 0x8d, 0xde, 0x3c, 0x0f, 0xda, 0xe2, 0xf0, 0x1b, 0x02, 0x22, 0x51, 0xbe, 0x23, - 0xb3, 0x24, 0x83, 0x33, 0x27, 0x6a, 0x75, 0xb0, 0x0f, 0x37, 0x7f, 0x90, 0x81, 0x41, 0xee, 0xb2, - 0x4c, 0xa3, 0x0b, 0xec, 0x91, 0x1c, 0xa0, 0xa2, 0xdf, 0x03, 0xbb, 0x46, 0xbf, 0xdd, 0xb8, 0xe0, - 0xf7, 0xf3, 0x29, 0xbc, 0xae, 0xfd, 0xdc, 0xb8, 0xd9, 0x6f, 0x40, 0xfa, 0x57, 0x06, 0xcc, 0xc4, - 0x25, 0x9a, 0xa4, 0x99, 0xbf, 0xc7, 0x60, 0xa4, 0x55, 0x27, 0xde, 0x86, 0xed, 0x34, 0xa2, 0x39, - 0xff, 0xab, 0xb2, 0x1c, 0x07, 0x35, 0x90, 0x03, 0xe0, 0xa8, 0xb8, 0xb5, 0x30, 0x3a, 0x2f, 0xec, - 0x2f, 0x45, 0x40, 0x19, 0x9a, 0x5a, 0xd8, 0x5a, 0xa3, 0x62, 0xfe, 0xd7, 0x20, 0x4c, 0xf3, 0x26, - 0x77, 0x5a, 0x31, 0x39, 0x03, 0x50, 0x26, 0xe5, 0x1a, 0x2d, 0x76, 0xd6, 0xe4, 0x8e, 0x1b, 0xd1, - 0x32, 0x08, 0x03, 0x08, 0xd6, 0x6a, 0xf1, 0x36, 0xd1, 0xc4, 0x5c, 0x3d, 0xeb, 0xd0, 0x97, 0x1d, - 0x5a, 0xad, 0x7d, 0xab, 0x18, 0x61, 0x31, 0x3f, 0xd4, 0x9f, 0x98, 0x1f, 0x4e, 0x29, 0xe6, 0x5b, - 0x70, 0x0f, 0x0f, 0x33, 0x74, 0x2b, 0x63, 0xc2, 0x26, 0x38, 0x2f, 0x3b, 0x7f, 0xcf, 0x72, 0x6c, - 0xad, 0xdb, 0x3d, 0x21, 0xb8, 0x07, 0xde, 0xde, 0x2a, 0xc2, 0xe8, 0x3e, 0x54, 0x04, 0xfd, 0x38, - 0xc0, 0x9e, 0xc7, 0x41, 0x3b, 0x67, 0xb9, 0x3d, 0xce, 0x59, 0x97, 0x2a, 0x30, 0x96, 0x50, 0x15, - 0xf8, 0x7d, 0x03, 0xc2, 0xf6, 0x26, 0xba, 0x05, 0x63, 0x0d, 0xe2, 0x95, 0x6b, 0xcb, 0xcd, 0x8a, - 0x55, 0xa6, 0x7e, 0xf4, 0xf7, 0x42, 0x1f, 0x16, 0xad, 0xf4, 0xe9, 0x37, 0x68, 0xd3, 0x53, 0x59, - 0x76, 0xaf, 0x68, 0xb8, 0x71, 0x88, 0x92, 0xf9, 0x17, 0x06, 0xcc, 0xf6, 0x42, 0xc0, 0x38, 0x71, - 0xc0, 0xb9, 0x14, 0x27, 0x7e, 0x99, 0x76, 0x04, 0x1b, 0xbb, 0x08, 0x23, 0x76, 0x8b, 0x3a, 0xc4, - 0xe3, 0x5e, 0x61, 0x56, 0xe7, 0x11, 0x7f, 0x66, 0xaf, 0xca, 0xf2, 0xdb, 0x7c, 0xb5, 0x34, 0xf4, - 0x3e, 0x00, 0x07, 0x4d, 0x55, 0x1e, 0x48, 0x76, 0x97, 0x3c, 0x90, 0xcf, 0x0c, 0x18, 0x5e, 0x75, - 0x6c, 0x9e, 0xf3, 0x75, 0xf8, 0x79, 0x20, 0x6f, 0x44, 0xb2, 0xcd, 0x9f, 0x4c, 0x9c, 0x8f, 0xca, - 0x90, 0xed, 0x91, 0x15, 0xf0, 0xc3, 0x0c, 0x8c, 0xcb, 0x9a, 0x77, 0x77, 0x66, 0x7e, 0xa8, 0x93, - 0x07, 0x9d, 0x99, 0x1f, 0x46, 0xbe, 0x77, 0x66, 0x7e, 0xa8, 0xfe, 0x5d, 0x9b, 0x99, 0x1f, 0xea, - 0x65, 0xaf, 0xcc, 0xfc, 0x4c, 0x64, 0x34, 0x3c, 0x33, 0xff, 0xdb, 0x30, 0xdd, 0xf2, 0x23, 0x50, - 0xfc, 0xe2, 0x93, 0x15, 0xf0, 0x81, 0xb3, 0x29, 0xb3, 0xa1, 0xc5, 0xbd, 0xa9, 0xe2, 0xbd, 0x92, - 0xfa, 0xf4, 0x6a, 0x14, 0x2f, 0xee, 0x26, 0x15, 0x7f, 0x33, 0x20, 0x73, 0xf4, 0x37, 0x03, 0x62, - 0xf6, 0xc5, 0xff, 0xdf, 0x0c, 0xb8, 0xe3, 0x37, 0x03, 0x7e, 0x64, 0x40, 0x4e, 0xae, 0xcc, 0x5d, - 0x9b, 0xe3, 0x22, 0xfb, 0xd7, 0xe3, 0xd4, 0x7d, 0x6e, 0xc0, 0x98, 0xc6, 0x9f, 0x5d, 0x54, 0x03, - 0xb8, 0x49, 0x1c, 0x5a, 0xb3, 0x03, 0x0b, 0x2b, 0x71, 0x3e, 0xc0, 0x75, 0xbf, 0x1d, 0xc7, 0xa4, - 0x76, 0x56, 0x50, 0xee, 0x62, 0x0d, 0x37, 0xfa, 0x86, 0x16, 0xda, 0x17, 0xcc, 0x3d, 0x11, 0x15, - 0x1e, 0x3d, 0x13, 0x14, 0x74, 0xc6, 0xa8, 0x25, 0x04, 0x98, 0x3f, 0x36, 0x02, 0x51, 0x12, 0x7b, - 0x54, 0xb2, 0x87, 0x73, 0x54, 0x4a, 0x30, 0xc8, 0x38, 0xb3, 0x7f, 0x2b, 0xfa, 0x4c, 0x6a, 0xe9, - 0xe8, 0xca, 0xdb, 0x06, 0xec, 0x27, 0x16, 0xb8, 0xcc, 0xef, 0x65, 0x60, 0x34, 0xe0, 0x54, 0x47, - 0x20, 0x12, 0x5f, 0x0b, 0x89, 0xc4, 0x27, 0x53, 0xf2, 0xd8, 0x9e, 0xe2, 0xf0, 0xad, 0x88, 0x38, - 0x4c, 0xcb, 0xbc, 0xf7, 0x10, 0x85, 0x7f, 0x2f, 0x56, 0x5c, 0xd4, 0x3d, 0x82, 0xa3, 0xb8, 0x16, - 0x3e, 0x8a, 0x0b, 0x29, 0x47, 0xd3, 0xe3, 0x30, 0xbe, 0x9f, 0x81, 0xc9, 0x88, 0xb8, 0x62, 0x6a, - 0x20, 0xdf, 0xd5, 0x52, 0xdd, 0x0c, 0x1a, 0xca, 0x20, 0x32, 0x87, 0xa1, 0x2d, 0xa6, 0x73, 0x07, - 0xb6, 0x43, 0x10, 0x6d, 0x7a, 0xa1, 0x2f, 0x09, 0x19, 0x44, 0x81, 0xa4, 0xca, 0xae, 0xe1, 0xc5, - 0x61, 0x32, 0x68, 0x35, 0x92, 0x95, 0x72, 0xb1, 0x49, 0xd6, 0xeb, 0x54, 0x84, 0x76, 0x46, 0x8a, - 0xf7, 0x07, 0x79, 0x30, 0x31, 0x75, 0x70, 0x6c, 0x4b, 0xf3, 0xaf, 0x0c, 0x38, 0xd9, 0xa3, 0x3f, - 0x09, 0xd2, 0xe0, 0xea, 0xd1, 0xa8, 0x5b, 0xa6, 0xff, 0xa8, 0xdb, 0xf4, 0x5e, 0x11, 0x37, 0xf3, - 0xa7, 0x19, 0x40, 0x41, 0x5f, 0xd3, 0x64, 0xeb, 0xbd, 0x05, 0xc3, 0x1b, 0x22, 0x0f, 0x63, 0x7f, - 0xd9, 0x9b, 0xc5, 0x9c, 0x9e, 0xc0, 0xea, 0xe3, 0x44, 0xaf, 0x1f, 0xcc, 0x59, 0x83, 0xee, 0x73, - 0x86, 0x6e, 0x00, 0x6c, 0x58, 0x4d, 0xcb, 0xad, 0xf5, 0x79, 0x67, 0x81, 0x5b, 0xe7, 0x97, 0x02, - 0x0c, 0x58, 0xc3, 0x66, 0xfe, 0x51, 0x46, 0x3b, 0xc3, 0x5c, 0xf9, 0x4b, 0xb4, 0xf7, 0x1f, 0x09, - 0x4f, 0xe6, 0x68, 0x77, 0x66, 0x6f, 0x30, 0x31, 0x37, 0x60, 0x60, 0x8b, 0x38, 0x7e, 0x14, 0x3f, - 0xe1, 0xe5, 0xa9, 0xee, 0x24, 0x7e, 0xb5, 0xa6, 0xd7, 0x88, 0xe3, 0x62, 0x8e, 0x93, 0x29, 0xc6, - 0xae, 0x47, 0x5b, 0xbe, 0x70, 0x49, 0xcd, 0x38, 0x3d, 0xda, 0xd2, 0x07, 0x48, 0x5b, 0x5c, 0x02, - 0xd0, 0x96, 0x6b, 0xfe, 0xc7, 0xb0, 0xc6, 0x15, 0xa4, 0x3c, 0x3b, 0x48, 0x4d, 0xea, 0xac, 0xff, - 0x4e, 0x8c, 0x98, 0xe5, 0xf9, 0xd0, 0x3b, 0x31, 0xb7, 0xb7, 0xe7, 0x27, 0xd4, 0x79, 0xd4, 0x5e, - 0x8e, 0x49, 0xf1, 0x22, 0x8a, 0xbe, 0xdf, 0x07, 0x0f, 0x61, 0xbf, 0xff, 0x36, 0x4c, 0x6f, 0x44, - 0x53, 0xbd, 0xe5, 0xcd, 0xa4, 0x73, 0x7d, 0x66, 0x8a, 0x0b, 0x7f, 0x50, 0x57, 0x31, 0xee, 0x26, - 0x84, 0x6c, 0xff, 0x1d, 0x16, 0xee, 0x9f, 0x16, 0xd1, 0xa6, 0xc4, 0x67, 0x2e, 0xe2, 0xd9, 0x8e, - 0xbe, 0xc0, 0x22, 0x50, 0xe2, 0x10, 0x01, 0x74, 0x1d, 0x46, 0x5d, 0x8f, 0x38, 0xe2, 0xda, 0xd0, - 0x58, 0x7f, 0xd7, 0x86, 0x4a, 0x3e, 0x02, 0xac, 0x70, 0x45, 0x0e, 0xf7, 0xd0, 0x41, 0x1e, 0x6e, - 0x74, 0x36, 0xc8, 0x11, 0x64, 0xe3, 0xe4, 0x9e, 0xab, 0x6c, 0x57, 0x76, 0x1f, 0x03, 0x61, 0xbd, - 0x1e, 0xfa, 0xd8, 0x80, 0x13, 0xec, 0x14, 0x5c, 0xbc, 0x45, 0xcb, 0x6d, 0x36, 0xdd, 0x7e, 0x9e, - 0xd4, 0x6c, 0x2e, 0x8d, 0x0d, 0x56, 0x8a, 0x43, 0xa1, 0x1c, 0x67, 0xb1, 0x60, 0x1c, 0x4f, 0x18, - 0xbd, 0x2d, 0xb4, 0x3c, 0xca, 0xbd, 0x66, 0xfb, 0x8f, 0x2c, 0x04, 0x1a, 0x9f, 0x60, 0x68, 0x1e, - 0x35, 0xbf, 0x37, 0xa0, 0xf3, 0xc1, 0x64, 0xf1, 0x8e, 0x1b, 0x30, 0xe0, 0x11, 0x77, 0x53, 0x1e, - 0xaf, 0xe7, 0xfb, 0xb8, 0x27, 0xac, 0x0e, 0xd9, 0x08, 0xc3, 0xcd, 0x8b, 0x38, 0x4e, 0x34, 0x07, - 0x19, 0xe2, 0x46, 0xb3, 0x35, 0x0a, 0x2e, 0xce, 0x10, 0x97, 0x67, 0x72, 0x6c, 0xc8, 0x00, 0xad, - 0xca, 0xe4, 0xd8, 0xc0, 0x19, 0x8b, 0x3f, 0xaf, 0x52, 0xb6, 0x9b, 0x9e, 0xd5, 0x6c, 0xd3, 0xab, - 0xcd, 0x8b, 0x8e, 0x63, 0x8b, 0xac, 0x89, 0x11, 0xf5, 0xbc, 0xca, 0x62, 0x18, 0x8c, 0xa3, 0xf5, - 0xd1, 0xeb, 0x30, 0xe8, 0x50, 0xcf, 0xe9, 0x48, 0x49, 0x73, 0xbe, 0x0f, 0xa6, 0x8a, 0x59, 0x7b, - 0x31, 0xcb, 0xfc, 0x27, 0x16, 0x18, 0x03, 0x59, 0x30, 0x74, 0x08, 0xb2, 0x40, 0x45, 0x9f, 0xb2, - 0x87, 0x16, 0x7d, 0xfa, 0xbe, 0xa1, 0x29, 0x1f, 0xc1, 0x40, 0xd1, 0x6b, 0x30, 0xec, 0x59, 0x0d, - 0x6a, 0xb7, 0xbd, 0x74, 0x5a, 0x6f, 0x90, 0x02, 0xcd, 0x59, 0xec, 0x9a, 0x40, 0x81, 0x7d, 0x5c, - 0xe8, 0x02, 0x4c, 0x50, 0xb6, 0x22, 0x6b, 0x35, 0x26, 0x32, 0xec, 0xba, 0x50, 0xf1, 0xc6, 0x95, - 0xa7, 0xfe, 0x62, 0x08, 0x8a, 0x23, 0xb5, 0xcd, 0x9f, 0xea, 0xfa, 0xf9, 0xff, 0xfd, 0xbb, 0xf3, - 0xd2, 0xf3, 0x76, 0xa4, 0x97, 0xe6, 0xfb, 0xf6, 0xbc, 0xed, 0x79, 0x5b, 0xfe, 0x4d, 0xb8, 0x27, - 0x9e, 0x15, 0x1c, 0xc8, 0x03, 0x70, 0x3f, 0x8e, 0xce, 0x15, 0x57, 0xed, 0xfc, 0xe3, 0x67, 0x1c, - 0xa6, 0x2a, 0x96, 0x39, 0x68, 0x55, 0xcc, 0xd1, 0x87, 0x22, 0x9f, 0xcb, 0x43, 0x6f, 0xc9, 0x7d, - 0x66, 0xa4, 0x79, 0x80, 0xad, 0x0b, 0x4d, 0xcf, 0xbd, 0xf6, 0x33, 0x03, 0x4e, 0xc4, 0xd6, 0x0e, - 0xe6, 0x30, 0x73, 0x98, 0x73, 0x68, 0x1c, 0xf4, 0x1c, 0x6e, 0xc1, 0xbd, 0x5f, 0x6f, 0x93, 0x23, - 0x7f, 0xed, 0xcb, 0xfc, 0x20, 0x0b, 0x53, 0x98, 0xb6, 0xec, 0x50, 0x70, 0x75, 0xd5, 0x7f, 0x4d, - 0x21, 0x85, 0x9d, 0x14, 0xc9, 0x1c, 0x2b, 0x0e, 0x87, 0x9e, 0x51, 0x60, 0xc7, 0xb4, 0xe1, 0x2b, - 0xc5, 0x89, 0xd9, 0x4e, 0x57, 0xd8, 0x57, 0x48, 0x2c, 0x11, 0x40, 0x16, 0x08, 0x19, 0x66, 0x7e, - 0x15, 0x49, 0x0a, 0x95, 0x73, 0x29, 0x2e, 0x35, 0x75, 0x63, 0xe6, 0xc5, 0x58, 0x20, 0x44, 0x35, - 0x18, 0xd3, 0x5f, 0x8c, 0x4b, 0xe7, 0xbf, 0x0a, 0xe1, 0xe6, 0xd9, 0x4e, 0x7a, 0x09, 0x0e, 0x61, - 0x36, 0x3f, 0xcd, 0x80, 0xb0, 0xde, 0x8e, 0x80, 0xff, 0x7f, 0x3d, 0xc4, 0xff, 0x17, 0xd2, 0x78, - 0x17, 0x7b, 0x79, 0xb1, 0xa2, 0x96, 0xf5, 0x13, 0x29, 0x5d, 0x96, 0xbb, 0x78, 0xb0, 0xfe, 0xc6, - 0x80, 0x51, 0x5e, 0xef, 0x08, 0x44, 0xc9, 0x6a, 0x58, 0x94, 0x3c, 0x9a, 0x62, 0x14, 0x3d, 0x44, - 0xc8, 0x7f, 0x66, 0x65, 0xef, 0x03, 0xbb, 0xbd, 0x46, 0x9c, 0x8a, 0x34, 0x48, 0x15, 0x1f, 0x60, - 0x85, 0x58, 0xc0, 0x02, 0xee, 0x35, 0x7c, 0x08, 0xdc, 0xeb, 0x5d, 0x71, 0x23, 0x8c, 0xba, 0x1e, - 0xad, 0x5c, 0x0a, 0x2c, 0xcf, 0x6c, 0xea, 0xab, 0x6d, 0xf2, 0xfa, 0x9d, 0x8a, 0x09, 0xe0, 0x08, - 0x56, 0xdc, 0x45, 0x87, 0x59, 0xa3, 0xad, 0x28, 0xbb, 0x96, 0xc6, 0xd4, 0xb9, 0x3e, 0x65, 0x83, - 0xb0, 0x46, 0xbb, 0x8a, 0x71, 0x37, 0x21, 0x76, 0x94, 0xf5, 0xdb, 0xc4, 0x72, 0x9f, 0x9e, 0x49, - 0x7f, 0x6d, 0x59, 0x1c, 0x65, 0xbd, 0x04, 0x87, 0x30, 0x9b, 0x7f, 0x60, 0x00, 0x28, 0x5f, 0x3c, - 0x5b, 0xf3, 0xb2, 0xdd, 0x6e, 0x0a, 0x27, 0x4c, 0x56, 0xad, 0xf9, 0x22, 0x2b, 0xc4, 0x02, 0xc6, - 0xce, 0x8f, 0x30, 0x65, 0xe5, 0xa6, 0x7e, 0x22, 0x8d, 0x95, 0x1c, 0xf1, 0xf9, 0x8b, 0x42, 0x2c, - 0x11, 0x9a, 0x7f, 0x3b, 0x02, 0x39, 0xed, 0x9c, 0x45, 0x3c, 0xfe, 0xe3, 0x87, 0x16, 0x1c, 0x8b, - 0x71, 0xc3, 0xe4, 0xfa, 0x72, 0xc3, 0xb8, 0x30, 0x21, 0x9d, 0x0b, 0xfe, 0x95, 0xf3, 0x81, 0x34, - 0x97, 0x4c, 0xbb, 0x5d, 0x18, 0x88, 0xe9, 0xe5, 0x97, 0x42, 0x28, 0x71, 0x84, 0x04, 0xd3, 0xeb, - 0x65, 0x49, 0xa9, 0xdd, 0x68, 0x10, 0xa7, 0x23, 0xf3, 0x45, 0x03, 0xbd, 0xfe, 0x52, 0x08, 0x8a, - 0x23, 0xb5, 0xd1, 0x6a, 0xb0, 0xa0, 0xe2, 0xde, 0xf1, 0x63, 0x69, 0x16, 0x54, 0xd8, 0x35, 0xe1, - 0x75, 0xec, 0x11, 0x6f, 0x1c, 0xea, 0x2b, 0xde, 0xf8, 0x2e, 0x4c, 0x49, 0x67, 0x42, 0x70, 0x76, - 0xa4, 0x5f, 0x28, 0xad, 0x25, 0xa9, 0x94, 0x0c, 0x9e, 0x43, 0xb5, 0x18, 0xc1, 0x8a, 0xbb, 0xe8, - 0xa0, 0x77, 0x60, 0x9c, 0x2d, 0xb2, 0x22, 0x0c, 0xfb, 0x24, 0x2c, 0xfd, 0xd1, 0x1a, 0x4a, 0x1c, - 0xa6, 0xd0, 0xd3, 0x1b, 0x3f, 0xd1, 0xaf, 0x37, 0x1e, 0x35, 0x34, 0x31, 0x34, 0xc9, 0x77, 0xe3, - 0xd7, 0x52, 0x4b, 0xbc, 0x14, 0x97, 0x0c, 0xef, 0xe8, 0x3d, 0xb8, 0xcf, 0xb3, 0x10, 0xef, 0x08, - 0x52, 0xcf, 0x9f, 0x18, 0xbb, 0x3c, 0x7f, 0x12, 0xf2, 0xca, 0x65, 0x0e, 0xcd, 0x2b, 0x97, 0x3d, - 0x50, 0xaf, 0xdc, 0x19, 0x00, 0x6e, 0xa8, 0x73, 0x26, 0xcd, 0xa5, 0xf5, 0xb8, 0xf6, 0xae, 0x43, - 0x00, 0xc1, 0x5a, 0x2d, 0xf4, 0x42, 0xa0, 0x03, 0x89, 0xa7, 0xa5, 0xbe, 0xda, 0x95, 0xb3, 0x7c, - 0x3c, 0x64, 0x06, 0x44, 0x22, 0x08, 0x29, 0x2e, 0xe6, 0xc4, 0x38, 0x90, 0x86, 0xd3, 0x39, 0x90, - 0xcc, 0x3f, 0xc9, 0x40, 0x48, 0x1d, 0x8d, 0x3e, 0xa7, 0xac, 0x3d, 0xc6, 0x1c, 0xfb, 0xa4, 0x11, - 0xbf, 0xc8, 0xd8, 0xd5, 0x22, 0xc1, 0xfd, 0xaf, 0x23, 0x70, 0x01, 0xc5, 0xa4, 0x4f, 0xb2, 0x15, - 0x1c, 0x4c, 0x9a, 0x3e, 0x69, 0xfe, 0x77, 0x06, 0x42, 0x02, 0x1e, 0x7d, 0x64, 0xc0, 0x34, 0x89, - 0xbc, 0x06, 0xef, 0x5b, 0x80, 0x5f, 0x4b, 0xf7, 0x44, 0x7f, 0xd7, 0x63, 0xf2, 0x2a, 0xef, 0x26, - 0x5a, 0xc5, 0xc5, 0xdd, 0x44, 0xd1, 0xef, 0x1a, 0x70, 0x9c, 0x74, 0x3f, 0xf7, 0x2f, 0x4f, 0xd6, - 0x33, 0x7d, 0x7f, 0x2f, 0xa0, 0x78, 0x72, 0x67, 0x7b, 0x3e, 0xee, 0x43, 0x08, 0x38, 0x8e, 0x1c, - 0x7a, 0x03, 0x06, 0x88, 0x53, 0xf5, 0x83, 0x3a, 0xe9, 0xc9, 0xfa, 0x5f, 0x71, 0x50, 0x7b, 0xa4, - 0xe0, 0x54, 0x5d, 0xcc, 0x91, 0x9a, 0xbf, 0xc8, 0xc2, 0x54, 0xf4, 0xa5, 0x18, 0x79, 0x37, 0x6e, - 0x20, 0xf6, 0x6e, 0x1c, 0x63, 0x44, 0x3c, 0xac, 0x19, 0x7d, 0x87, 0x89, 0x47, 0x27, 0x05, 0x2c, - 0x60, 0x44, 0xfc, 0x19, 0x84, 0xc1, 0x7d, 0x30, 0x22, 0xfe, 0xf6, 0x81, 0xc2, 0x85, 0xce, 0x87, - 0xe3, 0x44, 0x66, 0x34, 0x4e, 0x34, 0xad, 0x8f, 0xa5, 0xdf, 0x50, 0x51, 0x03, 0x72, 0xda, 0x3a, - 0xc8, 0xc3, 0xf3, 0x6c, 0xea, 0x79, 0x57, 0xdb, 0x6e, 0x52, 0x24, 0xa6, 0x2b, 0x88, 0x8e, 0x5f, - 0x31, 0x57, 0x3e, 0x5b, 0xfb, 0x0a, 0x79, 0xf0, 0xe9, 0xd2, 0xb0, 0x99, 0xff, 0x62, 0xc0, 0x78, - 0xe8, 0x9e, 0x39, 0xa3, 0xe6, 0x3f, 0x20, 0xd0, 0xff, 0xa7, 0x0f, 0xae, 0x05, 0x18, 0xb0, 0x86, - 0x0d, 0x7d, 0x0b, 0x72, 0x75, 0xbb, 0x59, 0xa5, 0xae, 0x57, 0xb2, 0xc9, 0xa6, 0x3c, 0x27, 0x69, - 0x9d, 0xbf, 0xfc, 0x2d, 0x88, 0x15, 0x81, 0x66, 0xd1, 0x6e, 0xb4, 0xea, 0xd4, 0x13, 0xaf, 0x5e, - 0x60, 0x1d, 0x39, 0xcf, 0x49, 0x09, 0x92, 0x7a, 0xee, 0xd6, 0x9c, 0x14, 0x95, 0x8d, 0x74, 0xc0, - 0x39, 0x29, 0xa1, 0x34, 0xa7, 0x3d, 0x72, 0x52, 0x82, 0xba, 0x77, 0x6d, 0x4e, 0x4a, 0xd0, 0xc3, - 0x1e, 0x96, 0xfd, 0x27, 0x03, 0xda, 0x28, 0xc2, 0xd6, 0x7d, 0x66, 0x17, 0xeb, 0xfe, 0x4d, 0x18, - 0xb1, 0x9a, 0x1e, 0x75, 0xb6, 0x48, 0x5d, 0xba, 0x93, 0xd2, 0xee, 0xc5, 0x60, 0xa8, 0xcb, 0x12, - 0x0f, 0x0e, 0x30, 0xa2, 0x3a, 0x9c, 0xd8, 0x08, 0x3f, 0x55, 0x25, 0x1f, 0xd9, 0x17, 0xb9, 0xd2, - 0x4f, 0xfb, 0x81, 0xbd, 0x4b, 0x71, 0x95, 0x6e, 0xf7, 0x02, 0xe0, 0x78, 0xa4, 0xe8, 0x3d, 0x18, - 0xd7, 0x35, 0x00, 0x95, 0x87, 0xbe, 0x3f, 0x91, 0x1e, 0x5c, 0xb2, 0xd6, 0x15, 0x0e, 0x17, 0x87, - 0x69, 0xa1, 0x4f, 0x0c, 0x38, 0xb9, 0x11, 0xff, 0x2c, 0x97, 0xe4, 0xee, 0x2f, 0xa4, 0x33, 0x10, - 0x23, 0x48, 0x8a, 0xf7, 0xed, 0x6c, 0xcf, 0xf7, 0x7a, 0xf8, 0x0b, 0xf7, 0x22, 0x6d, 0x7e, 0x6c, - 0xc0, 0x44, 0x38, 0xdf, 0xef, 0x8e, 0x7b, 0x00, 0x3e, 0xcf, 0xc2, 0x64, 0xe4, 0x6c, 0x46, 0xbc, - 0x00, 0xa3, 0x47, 0xe9, 0x05, 0x18, 0xea, 0xcb, 0x0b, 0x10, 0x6f, 0xfe, 0x0e, 0xf4, 0x65, 0xfe, - 0x3e, 0x27, 0x4c, 0x50, 0xb9, 0xb6, 0xcb, 0x4b, 0xf2, 0x82, 0x8a, 0xf6, 0x9c, 0x80, 0x06, 0xc4, - 0xe1, 0xba, 0x5c, 0x01, 0xab, 0x74, 0xbf, 0x72, 0x2c, 0xed, 0xe7, 0x67, 0xd2, 0x5e, 0x85, 0x0a, - 0x10, 0x08, 0x05, 0x2c, 0x06, 0x80, 0xe3, 0xc8, 0x99, 0xff, 0x36, 0x02, 0x27, 0xe2, 0x43, 0x05, - 0x7b, 0xc7, 0xa6, 0xde, 0x81, 0xd1, 0x75, 0xff, 0x43, 0x15, 0xf2, 0xac, 0x24, 0x7c, 0x9f, 0x67, - 0xf7, 0xef, 0x5b, 0x08, 0x1d, 0x29, 0xa8, 0x83, 0x15, 0x15, 0x46, 0xb2, 0xc2, 0x5f, 0x1c, 0xad, - 0xb5, 0xd7, 0xa5, 0x3a, 0x91, 0x90, 0xe4, 0xee, 0x0f, 0x95, 0x0a, 0x92, 0x41, 0x1d, 0xac, 0xa8, - 0x20, 0x0a, 0x43, 0x82, 0x80, 0x14, 0x8f, 0x85, 0xc4, 0x51, 0x8c, 0x9e, 0xc4, 0xb8, 0xb1, 0x21, - 0x2a, 0x60, 0x89, 0x5c, 0x92, 0xa9, 0x93, 0x75, 0x29, 0x2c, 0x93, 0x93, 0xe9, 0x75, 0xc3, 0x3f, - 0x20, 0xb3, 0x42, 0x04, 0x99, 0x3a, 0xe1, 0x64, 0x6a, 0xfc, 0x5a, 0xae, 0xf4, 0x97, 0x24, 0x24, - 0xb3, 0xcb, 0x55, 0x5e, 0xe9, 0x65, 0xe2, 0x15, 0xb0, 0x44, 0x8e, 0xde, 0x82, 0x81, 0x77, 0xda, - 0xc4, 0xcf, 0x2b, 0x48, 0x68, 0xdb, 0xf4, 0x0c, 0x5b, 0x89, 0x94, 0x09, 0x06, 0xc6, 0x1c, 0x2d, - 0xea, 0x40, 0x8e, 0xa8, 0x0f, 0xdb, 0xc8, 0x07, 0x51, 0x2f, 0xa5, 0x7b, 0x2d, 0xae, 0xd7, 0x17, - 0x71, 0xa4, 0x46, 0xab, 0x6a, 0x61, 0x9d, 0x16, 0x22, 0x30, 0x48, 0xde, 0x6d, 0x3b, 0x54, 0x3a, - 0xe4, 0x5e, 0x4c, 0x48, 0xb4, 0xe7, 0x97, 0x64, 0x44, 0xb8, 0x88, 0xc3, 0xb1, 0xc0, 0xcc, 0x48, - 0x54, 0x2d, 0x8f, 0x12, 0xc9, 0x0b, 0x5e, 0x4c, 0xbc, 0x13, 0x7a, 0x5c, 0xf3, 0x16, 0x24, 0x38, - 0x1c, 0x0b, 0xcc, 0xc8, 0x82, 0xe1, 0xaa, 0x78, 0x82, 0x85, 0x7b, 0x53, 0x13, 0x3f, 0xf9, 0xb9, - 0xdb, 0xfb, 0x36, 0x22, 0xb5, 0x41, 0xd6, 0xc0, 0x3e, 0x7e, 0xf3, 0x3d, 0xb8, 0x27, 0xfe, 0x26, - 0x40, 0xb2, 0xe8, 0x77, 0x8b, 0x78, 0xfe, 0xfb, 0x0d, 0x41, 0x8d, 0x55, 0xe2, 0xd5, 0x30, 0x87, - 0xa0, 0x07, 0x20, 0xdb, 0x76, 0xea, 0xd1, 0x67, 0x4a, 0x5e, 0xc3, 0x2b, 0x98, 0x95, 0x17, 0x5f, - 0xfa, 0xec, 0xcb, 0x53, 0xc7, 0x7e, 0xfe, 0xe5, 0xa9, 0x63, 0x5f, 0x7c, 0x79, 0xea, 0xd8, 0xfb, - 0x3b, 0xa7, 0x8c, 0xcf, 0x76, 0x4e, 0x19, 0x3f, 0xdf, 0x39, 0x65, 0x7c, 0xb1, 0x73, 0xca, 0xf8, - 0xe5, 0xce, 0x29, 0xe3, 0xe3, 0x5f, 0x9d, 0x3a, 0x76, 0xe3, 0xc1, 0x24, 0x5f, 0x6c, 0xfc, 0xdf, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x61, 0x5e, 0x30, 0xb8, 0xd8, 0x71, 0x00, 0x00, + 0xa3, 0x12, 0x9c, 0xb0, 0x9a, 0x2e, 0x2d, 0xb7, 0x1d, 0x5a, 0xda, 0xb4, 0x5a, 0x6b, 0x2b, 0xa5, + 0x6b, 0xd4, 0xb1, 0x36, 0x3a, 0x7c, 0xe0, 0x23, 0xc5, 0x07, 0x24, 0x9a, 0x13, 0xcb, 0x71, 0x95, + 0x70, 0x7c, 0xdb, 0x60, 0xf2, 0xb2, 0xbb, 0xad, 0xa6, 0xbf, 0x12, 0x03, 0x7b, 0xac, 0x44, 0xdc, + 0x3c, 0x0f, 0xa6, 0x9d, 0x67, 0xf3, 0x07, 0x19, 0x18, 0x5f, 0xac, 0xb7, 0x5d, 0x2f, 0x38, 0x01, + 0x5f, 0xd7, 0x98, 0xa8, 0x38, 0x00, 0xbf, 0x95, 0x4c, 0xc5, 0x11, 0xa7, 0x81, 0x31, 0x4b, 0x25, + 0x1a, 0x55, 0x99, 0x62, 0x9e, 0xe8, 0x75, 0x18, 0x70, 0x5b, 0xb4, 0xcc, 0xa7, 0x32, 0x77, 0xe6, + 0x5c, 0x32, 0x09, 0x1c, 0xea, 0x64, 0xa9, 0x45, 0xcb, 0x6a, 0xfe, 0xd8, 0x3f, 0xcc, 0x51, 0x22, + 0x12, 0xc8, 0xd6, 0x6c, 0x1a, 0xf1, 0x1e, 0x46, 0x2e, 0xc4, 0xfb, 0x44, 0x58, 0x2c, 0xfb, 0x02, + 0xd8, 0xfc, 0x07, 0x03, 0xa6, 0x43, 0xf5, 0x57, 0x2c, 0xd7, 0x43, 0x6f, 0x76, 0xcd, 0x5a, 0x3e, + 0xd9, 0xac, 0xb1, 0xd6, 0x7c, 0xce, 0x02, 0x31, 0xee, 0x97, 0x68, 0x33, 0xf6, 0x35, 0x18, 0xb4, + 0x3c, 0xda, 0xf0, 0x6d, 0x8e, 0x27, 0xfb, 0x18, 0x95, 0x52, 0xa2, 0x97, 0x19, 0x26, 0x2c, 0x10, + 0x9a, 0x9f, 0x44, 0x47, 0xc3, 0x26, 0x93, 0x99, 0x3a, 0x53, 0x37, 0xc3, 0xfc, 0xd1, 0x37, 0xb2, + 0x12, 0x6a, 0x69, 0xb1, 0xdc, 0x55, 0xed, 0xcc, 0x08, 0xd8, 0xc5, 0x5d, 0xe4, 0xcc, 0x4f, 0xb2, + 0x70, 0x3c, 0x66, 0x5d, 0x50, 0x19, 0xa0, 0x6c, 0x37, 0x2b, 0x96, 0x30, 0xc2, 0x44, 0xa7, 0x16, + 0x92, 0xcd, 0xf5, 0xa2, 0xdf, 0x4e, 0x6d, 0xd0, 0xa0, 0xc8, 0xc5, 0x1a, 0x5a, 0xf4, 0x12, 0x20, + 0x7b, 0x9d, 0xab, 0x08, 0x95, 0xcb, 0xc2, 0xd6, 0xf5, 0x19, 0x6c, 0xb6, 0x38, 0x27, 0xdb, 0xa2, + 0xab, 0x5d, 0x35, 0x70, 0x4c, 0x2b, 0x86, 0xab, 0x4e, 0x5c, 0xef, 0x0a, 0x69, 0x56, 0xea, 0xb4, + 0x82, 0xe9, 0x86, 0x43, 0xdd, 0x9a, 0x3c, 0xde, 0x01, 0xae, 0x95, 0xae, 0x1a, 0x38, 0xa6, 0x15, + 0xfa, 0x20, 0x6e, 0x61, 0xc4, 0xa6, 0x78, 0xbe, 0xaf, 0x85, 0x59, 0xa2, 0x1e, 0xb1, 0xea, 0x6e, + 0xaa, 0x95, 0xe1, 0x72, 0x44, 0xac, 0x4c, 0x20, 0xf3, 0xd7, 0x88, 0xbb, 0x79, 0xb7, 0xb2, 0x8e, + 0x50, 0x27, 0x7b, 0xb1, 0x0e, 0xf3, 0x5f, 0x0d, 0x98, 0x8d, 0x1b, 0xd5, 0x11, 0x1c, 0xef, 0xb7, + 0xc3, 0xc7, 0xfb, 0xd9, 0x54, 0xc7, 0x3b, 0xd4, 0xd9, 0x1e, 0xa7, 0xfc, 0x0d, 0x18, 0x5b, 0x6c, + 0x3b, 0x0e, 0x6d, 0x7a, 0xc2, 0x90, 0x7d, 0x19, 0x06, 0x5d, 0xab, 0x29, 0xed, 0xb9, 0x74, 0x36, + 0xec, 0x28, 0x43, 0x5e, 0x62, 0x8d, 0xb1, 0xc0, 0x61, 0xfe, 0x6f, 0x16, 0x8e, 0xfb, 0xd2, 0x94, + 0x56, 0x7c, 0xad, 0xd8, 0x45, 0x15, 0x18, 0xab, 0xa8, 0x62, 0x4f, 0x6a, 0xe4, 0x69, 0x68, 0x05, + 0x46, 0x86, 0x86, 0xde, 0xc3, 0x21, 0xac, 0xe8, 0x3a, 0x64, 0xab, 0x5c, 0xba, 0xb3, 0x99, 0x3b, + 0x9f, 0x6c, 0xe6, 0x2e, 0x5b, 0x51, 0x15, 0xa8, 0x98, 0x93, 0xa4, 0xb2, 0x97, 0x2d, 0x0f, 0x33, + 0x8c, 0x68, 0x1d, 0x86, 0xac, 0x06, 0xa9, 0xd2, 0x94, 0xab, 0xb2, 0xcc, 0xda, 0x44, 0xb1, 0x07, + 0xb2, 0x84, 0x43, 0x5d, 0x2c, 0x31, 0x33, 0x1a, 0x65, 0xa6, 0xba, 0x08, 0xdb, 0x2c, 0xf9, 0xca, + 0xc7, 0x28, 0x71, 0x8a, 0x06, 0x87, 0xba, 0x58, 0x62, 0x46, 0x5f, 0x67, 0x2a, 0x05, 0xab, 0xe1, + 0xce, 0x0e, 0x72, 0x22, 0x67, 0x93, 0x11, 0x89, 0xe2, 0xd7, 0x34, 0x11, 0x8e, 0x0d, 0xfb, 0x68, + 0xcd, 0xcf, 0x33, 0x30, 0xa5, 0x56, 0x68, 0xd1, 0x6e, 0x30, 0x05, 0x6a, 0x0e, 0x32, 0x56, 0x45, + 0xaa, 0x93, 0x20, 0x9b, 0x66, 0x96, 0x97, 0x70, 0xc6, 0xaa, 0xa0, 0x87, 0x60, 0x68, 0xdd, 0x21, + 0xcd, 0x72, 0x4d, 0xaa, 0x91, 0x41, 0xd7, 0x8b, 0xbc, 0x14, 0x4b, 0x28, 0x7a, 0x00, 0xb2, 0x1e, + 0xa9, 0x4a, 0x75, 0x29, 0x58, 0xa1, 0x35, 0x52, 0xc5, 0xac, 0x9c, 0x29, 0x4b, 0x6e, 0x9b, 0x73, + 0x89, 0xa8, 0xb2, 0x54, 0x12, 0xc5, 0xd8, 0x87, 0x33, 0x8a, 0xa4, 0xed, 0xd5, 0x6c, 0x47, 0xaa, + 0x48, 0x01, 0xc5, 0x02, 0x2f, 0xc5, 0x12, 0x8a, 0x16, 0x60, 0xb4, 0xcc, 0xfb, 0xef, 0x51, 0x67, + 0x76, 0x28, 0xec, 0xec, 0x58, 0xf4, 0x01, 0x58, 0xd5, 0x41, 0x6f, 0x41, 0xae, 0xec, 0x50, 0xe2, + 0xd9, 0xce, 0x12, 0xf1, 0xe8, 0xec, 0x70, 0xea, 0x3d, 0x3e, 0xb9, 0xb3, 0x3d, 0x9f, 0x5b, 0x54, + 0x28, 0xb0, 0x8e, 0xcf, 0xfc, 0x30, 0x0b, 0xb3, 0x6a, 0x6a, 0xf9, 0xee, 0x51, 0x96, 0xb9, 0x9c, + 0x1e, 0xa3, 0xc7, 0xf4, 0x3c, 0x04, 0x43, 0x15, 0xab, 0x4a, 0x5d, 0x2f, 0x3a, 0xcb, 0x4b, 0xbc, + 0x14, 0x4b, 0x28, 0xfa, 0x76, 0xc4, 0xaf, 0x29, 0x76, 0xc9, 0xd5, 0x74, 0xbb, 0x24, 0xda, 0xb9, + 0x3e, 0x9c, 0x9b, 0xe8, 0x3a, 0x8c, 0xf2, 0xb1, 0xf7, 0xc9, 0x2d, 0xb8, 0x63, 0x63, 0xd1, 0x47, + 0x80, 0x15, 0xae, 0x7d, 0xbb, 0x3e, 0xff, 0xde, 0x80, 0xc9, 0xa8, 0xcd, 0xf4, 0x58, 0x48, 0x97, + 0xef, 0xed, 0xd0, 0x10, 0x7a, 0xfd, 0x87, 0x06, 0x20, 0x12, 0x75, 0xad, 0xf8, 0x9c, 0xe5, 0x5c, + 0x52, 0x1f, 0x54, 0xa4, 0xbd, 0xd2, 0x1e, 0xba, 0x40, 0x2e, 0x8e, 0x21, 0xc7, 0xcc, 0xdf, 0x25, + 0xbb, 0xbc, 0x49, 0x9d, 0x2b, 0xed, 0xf5, 0x23, 0x37, 0x7f, 0xdf, 0x00, 0x74, 0xf1, 0x56, 0xcb, + 0xa1, 0x2e, 0x33, 0xdb, 0xae, 0x11, 0xc7, 0x22, 0xeb, 0x75, 0x7a, 0x50, 0x21, 0x82, 0xbf, 0x1e, + 0x84, 0xe1, 0x4b, 0x0e, 0xb5, 0xaa, 0x35, 0xef, 0x08, 0xb4, 0x90, 0x2f, 0xc1, 0x20, 0xa9, 0x5b, + 0xc4, 0xe5, 0xc7, 0x5d, 0xeb, 0x52, 0x81, 0x15, 0x62, 0x01, 0x43, 0x6f, 0xc0, 0x90, 0xed, 0x58, + 0x55, 0xab, 0x39, 0x3b, 0xca, 0x3b, 0x91, 0x50, 0x69, 0x97, 0xa3, 0xb8, 0xca, 0x9b, 0xaa, 0x33, + 0x2b, 0xfe, 0x63, 0x89, 0x12, 0xdd, 0x80, 0x61, 0xc1, 0x83, 0x7c, 0xc9, 0xb1, 0x90, 0x58, 0xf2, + 0x09, 0x36, 0xa6, 0x78, 0xa5, 0xf8, 0xef, 0x62, 0x1f, 0x21, 0x2a, 0x05, 0x82, 0x6f, 0x80, 0xa3, + 0x7e, 0x34, 0x85, 0xe0, 0xeb, 0x29, 0xe9, 0x4a, 0x81, 0xa4, 0x1b, 0x4c, 0x83, 0x94, 0xcb, 0xb2, + 0x9e, 0xa2, 0xad, 0x06, 0xa3, 0xfe, 0x2e, 0x77, 0x67, 0x61, 0x7f, 0x67, 0x29, 0xd8, 0xbc, 0x81, + 0x02, 0x83, 0x15, 0x72, 0xb6, 0x98, 0xd2, 0xae, 0x1c, 0xea, 0x63, 0x31, 0xf7, 0xb0, 0x28, 0x3f, + 0xce, 0xc2, 0xb4, 0xac, 0xb9, 0x68, 0xd7, 0xa5, 0xab, 0x4c, 0x0a, 0xd0, 0x6c, 0xac, 0x00, 0xb5, + 0x7c, 0x85, 0x51, 0xa8, 0x3d, 0xc5, 0x54, 0xbd, 0x51, 0x34, 0xf2, 0x5c, 0x49, 0x14, 0xec, 0x39, + 0xd8, 0x0f, 0xb2, 0x96, 0x54, 0x1d, 0xd1, 0xef, 0x19, 0x70, 0x7c, 0x8b, 0x3a, 0xd6, 0x86, 0x55, + 0xe6, 0xec, 0xf3, 0x8a, 0xe5, 0x7a, 0xb6, 0xd3, 0x91, 0xac, 0xeb, 0xe9, 0x64, 0x94, 0xaf, 0x69, + 0x08, 0x96, 0x9b, 0x1b, 0x76, 0xf1, 0x3e, 0x49, 0xed, 0xf8, 0xb5, 0x6e, 0xd4, 0x38, 0x8e, 0xde, + 0x5c, 0x0b, 0x40, 0xf5, 0x36, 0x86, 0x7b, 0xaf, 0xe8, 0x6c, 0x22, 0x71, 0xc7, 0xfc, 0xc1, 0xfa, + 0xdb, 0x40, 0xe7, 0xfa, 0xaf, 0xc0, 0x49, 0x7f, 0xc6, 0x98, 0x24, 0xb1, 0xec, 0xe6, 0xa2, 0x63, + 0x79, 0xd4, 0xb1, 0x08, 0x3a, 0x03, 0x40, 0x03, 0x5e, 0x26, 0x79, 0x57, 0xc0, 0x32, 0x14, 0x97, + 0xc3, 0x5a, 0x2d, 0xf3, 0x47, 0x06, 0xe4, 0x24, 0xbe, 0x23, 0x30, 0x29, 0x70, 0xd8, 0xa4, 0x78, + 0x3c, 0xd5, 0x74, 0xf4, 0xb0, 0x22, 0x1c, 0x18, 0x0f, 0x71, 0x27, 0x74, 0x56, 0x86, 0xd0, 0xc4, + 0x04, 0xfc, 0x86, 0x1e, 0x42, 0xbb, 0xbd, 0x3d, 0x3f, 0x1d, 0xaa, 0xac, 0xe2, 0x6a, 0x7b, 0xfb, + 0x10, 0x9f, 0x1d, 0xf9, 0xe3, 0x3f, 0x9b, 0x3f, 0xf6, 0xfe, 0x2f, 0x4e, 0x1f, 0x33, 0xbf, 0x35, + 0x00, 0x53, 0xd1, 0x45, 0x4a, 0x20, 0x34, 0x14, 0xf3, 0x1d, 0x39, 0x54, 0xe6, 0x9b, 0x39, 0x3c, + 0xe6, 0x9b, 0x3d, 0x0c, 0xe6, 0x3b, 0x70, 0x48, 0xcc, 0x77, 0xf4, 0x10, 0x99, 0xaf, 0xf9, 0x8f, + 0x06, 0x4c, 0x04, 0x7b, 0xe0, 0x9d, 0x36, 0xd3, 0x59, 0xd5, 0xfa, 0x1a, 0x07, 0xbf, 0xbe, 0x6f, + 0xc3, 0xb0, 0x6b, 0xb7, 0x1d, 0xa1, 0xa0, 0x31, 0xec, 0x4f, 0xa5, 0xe3, 0xf6, 0xa2, 0xad, 0x66, + 0x8d, 0x88, 0x02, 0xec, 0x63, 0x35, 0x7f, 0x92, 0x0d, 0x06, 0x24, 0x61, 0x42, 0x59, 0x77, 0x98, + 0x29, 0x63, 0x70, 0x07, 0xb3, 0xa6, 0xac, 0xb3, 0x52, 0x2c, 0xa1, 0xc8, 0xe4, 0x82, 0xc8, 0xb7, + 0x4a, 0x47, 0x8b, 0x20, 0xe5, 0x09, 0x5f, 0x6e, 0x01, 0x41, 0x2d, 0x98, 0x72, 0xe8, 0x3b, 0x6d, + 0xcb, 0xa1, 0x95, 0x92, 0x4d, 0x36, 0x99, 0x72, 0x2c, 0xdd, 0xa1, 0x09, 0x39, 0xcc, 0x52, 0x5b, + 0xb8, 0xae, 0x8a, 0x33, 0x4c, 0xa5, 0xc5, 0x11, 0x5c, 0xb8, 0x0b, 0x3b, 0xb2, 0x61, 0x86, 0x6c, + 0x11, 0xab, 0x4e, 0xd6, 0xad, 0xba, 0xe5, 0x75, 0x4a, 0x9e, 0x43, 0x3c, 0x5a, 0xed, 0x48, 0xb3, + 0xec, 0x39, 0x39, 0x96, 0x99, 0x42, 0x4c, 0x9d, 0xdb, 0xdb, 0xf3, 0xf7, 0xc9, 0xb9, 0x88, 0x03, + 0xe3, 0x58, 0xc4, 0xe8, 0x3b, 0x06, 0xcc, 0x90, 0x98, 0xe8, 0x15, 0x37, 0xef, 0x12, 0xdb, 0xd1, + 0x71, 0xf1, 0xaf, 0xe2, 0x2c, 0xef, 0x69, 0x0c, 0x04, 0xc7, 0x52, 0x34, 0x7f, 0x36, 0x1c, 0xb0, + 0x45, 0xe9, 0xa1, 0x7c, 0x0f, 0x72, 0x65, 0xe1, 0x6d, 0xa9, 0x77, 0x96, 0x9b, 0xf2, 0x20, 0x2f, + 0xf5, 0xa1, 0x31, 0xe4, 0x17, 0x15, 0x9a, 0x88, 0x11, 0xa5, 0x41, 0xb0, 0x4e, 0x0d, 0xdd, 0x04, + 0x10, 0xe2, 0x93, 0x56, 0x96, 0x9b, 0x52, 0x3f, 0x58, 0xec, 0x87, 0xf6, 0xb5, 0x00, 0x8b, 0x20, + 0x1d, 0xc8, 0x37, 0x05, 0xc0, 0x1a, 0x29, 0x36, 0x6a, 0x3f, 0x9d, 0xe1, 0x92, 0xed, 0x48, 0xce, + 0xd8, 0xd7, 0xa8, 0x0b, 0x0a, 0x4d, 0xd4, 0x74, 0x54, 0x10, 0xac, 0x53, 0x43, 0x76, 0x28, 0xf2, + 0xcb, 0x28, 0x17, 0xfa, 0xa1, 0xec, 0x47, 0x7a, 0x05, 0xd9, 0x40, 0xbe, 0x76, 0x07, 0x80, 0xe7, + 0x1c, 0x98, 0x8a, 0x2e, 0x4e, 0x8c, 0x52, 0x72, 0x25, 0xac, 0x94, 0x9c, 0x49, 0xc8, 0x77, 0x35, + 0x57, 0x9d, 0x9e, 0xc1, 0xe3, 0xc0, 0x64, 0x64, 0x51, 0x62, 0x48, 0x2e, 0x87, 0x49, 0x3e, 0x99, + 0x46, 0x41, 0x93, 0x79, 0x2e, 0x3a, 0x4d, 0x17, 0xa6, 0xa2, 0xcb, 0x71, 0x60, 0x44, 0x43, 0xc9, + 0x35, 0x3a, 0xd1, 0xf7, 0x60, 0x3c, 0xb4, 0x12, 0x31, 0x14, 0xd7, 0xc2, 0x14, 0xf7, 0x19, 0xe7, + 0xd7, 0xd5, 0xbe, 0x7f, 0xcf, 0xc2, 0x0c, 0xf7, 0xde, 0x5b, 0x65, 0x69, 0x23, 0x17, 0x84, 0x42, + 0x7e, 0x09, 0x86, 0x08, 0xff, 0x25, 0xf5, 0x8e, 0xbc, 0x7f, 0x20, 0x04, 0x7c, 0xad, 0xd3, 0xa2, + 0xb7, 0xb7, 0xe7, 0x67, 0xe3, 0xda, 0xf2, 0xe4, 0x08, 0xd9, 0x1a, 0x5d, 0x80, 0x89, 0x9b, 0x35, + 0xda, 0x54, 0x6a, 0xa2, 0x54, 0x84, 0x82, 0xd0, 0xe4, 0xf5, 0x10, 0x14, 0x47, 0x6a, 0xa3, 0x6f, + 0x02, 0xb4, 0x88, 0x43, 0x1a, 0xd4, 0xa3, 0x8e, 0xaf, 0x26, 0x24, 0xcc, 0x42, 0x8b, 0xeb, 0x5b, + 0x7e, 0x35, 0x40, 0x16, 0x39, 0xe8, 0x0a, 0x80, 0x35, 0x8a, 0xe8, 0xdb, 0x06, 0x0c, 0x7b, 0xc4, + 0xa9, 0xd2, 0x40, 0x9f, 0x78, 0xb9, 0x1f, 0xea, 0x6b, 0x1c, 0x45, 0x90, 0x2b, 0xe0, 0xeb, 0xd6, + 0xc5, 0x79, 0x49, 0xfe, 0x64, 0x8f, 0x0a, 0xd8, 0x27, 0x3e, 0xf7, 0x02, 0x4c, 0x46, 0xfa, 0x9e, + 0xca, 0xab, 0xf3, 0x4b, 0x03, 0xee, 0x0f, 0x77, 0xe9, 0xe8, 0xf2, 0x37, 0x28, 0x0c, 0x8b, 0xdd, + 0x90, 0xd2, 0xbb, 0x1c, 0xb7, 0x80, 0x4a, 0xd1, 0x10, 0xff, 0x5d, 0xec, 0xe3, 0x36, 0xff, 0x23, + 0x03, 0x5f, 0x4e, 0x34, 0xeb, 0xe8, 0xf9, 0x90, 0x2a, 0xff, 0x70, 0x44, 0x95, 0x9f, 0x8d, 0x43, + 0x92, 0x46, 0xa3, 0x47, 0x2d, 0x18, 0xe7, 0x69, 0x94, 0x82, 0xb2, 0xed, 0x48, 0x85, 0xe4, 0xc9, + 0x84, 0x26, 0x8f, 0xde, 0xb4, 0x78, 0x42, 0xe2, 0x1f, 0x0f, 0x15, 0xe3, 0x30, 0x01, 0x46, 0xd1, + 0x6a, 0x56, 0xe8, 0xad, 0x80, 0xe2, 0x40, 0x1a, 0xde, 0xb4, 0xac, 0x37, 0x55, 0x14, 0x43, 0xc5, + 0x38, 0x4c, 0xc0, 0xfc, 0xd3, 0x0c, 0x8c, 0x06, 0x3a, 0x7e, 0x9a, 0xa4, 0x0a, 0x61, 0xea, 0x67, + 0xf6, 0xf0, 0x95, 0x67, 0x93, 0xf8, 0xca, 0x07, 0x7a, 0xfb, 0xca, 0xfd, 0x24, 0xc0, 0xa1, 0xdd, + 0x93, 0x00, 0x35, 0x5f, 0xf9, 0x70, 0x72, 0x5f, 0xf9, 0xc8, 0xde, 0xbe, 0x72, 0xf3, 0xcf, 0x0d, + 0x40, 0xdd, 0xa1, 0x97, 0x34, 0x13, 0x45, 0xa2, 0x96, 0xd7, 0xd3, 0x69, 0xbd, 0xd4, 0x7b, 0x19, + 0x60, 0xe6, 0x2d, 0xb8, 0xef, 0xb2, 0xe5, 0xdd, 0x09, 0x07, 0xa9, 0xa0, 0xbc, 0x42, 0x8e, 0x9e, + 0xf2, 0x3f, 0x0f, 0xc3, 0xe4, 0x65, 0x2b, 0x9c, 0x40, 0xb3, 0x00, 0xa3, 0xa4, 0x5e, 0xb7, 0x6f, + 0xae, 0x91, 0xaa, 0x1b, 0x4d, 0xfb, 0x2c, 0xf8, 0x00, 0xac, 0xea, 0xa0, 0x17, 0x61, 0x2a, 0xf8, + 0x83, 0x69, 0x95, 0xde, 0x0a, 0x6c, 0x14, 0x6e, 0x45, 0x14, 0x22, 0x30, 0xdc, 0x55, 0x3b, 0xf1, + 0x56, 0xf7, 0xe0, 0xa4, 0x58, 0xad, 0x80, 0x8d, 0x45, 0x0c, 0x8e, 0x67, 0x7d, 0x11, 0xb2, 0x18, + 0x5f, 0xed, 0x76, 0x6f, 0x10, 0xee, 0x85, 0x3a, 0x26, 0xa3, 0x68, 0x30, 0x55, 0x46, 0xd1, 0x53, + 0x30, 0x46, 0x6f, 0x95, 0xeb, 0xed, 0x0a, 0x5d, 0x25, 0x5e, 0xcd, 0x9d, 0x1d, 0xe2, 0x73, 0x33, + 0xb5, 0xb3, 0x3d, 0x3f, 0x76, 0x51, 0x2b, 0xc7, 0xa1, 0x5a, 0x68, 0x09, 0xa6, 0x94, 0x0f, 0xe9, + 0x92, 0x55, 0x67, 0x67, 0x6d, 0x38, 0x1c, 0x72, 0xb8, 0x18, 0x81, 0xe3, 0xae, 0x16, 0x28, 0x0f, + 0x60, 0x55, 0x9b, 0xb6, 0x43, 0xf9, 0x6a, 0x8e, 0x70, 0xca, 0x3c, 0x19, 0x79, 0x39, 0x28, 0xc5, + 0x5a, 0x0d, 0xb4, 0x08, 0xd3, 0xea, 0x9f, 0xbf, 0x98, 0xa3, 0xbc, 0xd9, 0x89, 0x9d, 0xed, 0xf9, + 0xe9, 0xe5, 0x28, 0x10, 0x77, 0xd7, 0x67, 0x03, 0xb6, 0x9a, 0xda, 0x80, 0x41, 0x0d, 0x78, 0xb9, + 0xa9, 0x0f, 0x58, 0xaf, 0xd5, 0x3b, 0xf1, 0x2a, 0xb7, 0x8f, 0xc4, 0x2b, 0x8d, 0xc5, 0x8c, 0xf5, + 0x91, 0x56, 0x35, 0x9e, 0x3a, 0x7d, 0x2d, 0x08, 0xb0, 0x4f, 0xec, 0x3f, 0xc0, 0x8e, 0xce, 0xc1, + 0xb8, 0xeb, 0x39, 0x56, 0xd9, 0x13, 0x84, 0xdd, 0xd9, 0x49, 0x3e, 0x15, 0xd3, 0x4c, 0x20, 0x95, + 0x74, 0x00, 0x0e, 0xd7, 0x33, 0x6f, 0xc2, 0xdc, 0x65, 0xcb, 0xa3, 0xe4, 0x4e, 0xb0, 0xb2, 0x2b, + 0xc4, 0x59, 0xb7, 0x9d, 0x23, 0xa7, 0xfc, 0xbd, 0x0c, 0x0c, 0x89, 0x14, 0x70, 0x74, 0x36, 0x92, + 0x67, 0xfd, 0x40, 0x57, 0x9e, 0x75, 0x2e, 0x2e, 0x5d, 0xde, 0x84, 0x21, 0xcb, 0x75, 0xdb, 0x61, + 0x0f, 0xcb, 0x32, 0x2f, 0xc1, 0x12, 0xc2, 0xe3, 0xf6, 0x7c, 0x28, 0x07, 0x94, 0x66, 0xcc, 0x69, + 0x88, 0xc9, 0xc1, 0x12, 0x33, 0xa3, 0x61, 0xb7, 0xbd, 0x56, 0xdb, 0x93, 0x3e, 0x8d, 0x03, 0xa1, + 0x71, 0x95, 0x63, 0xc4, 0x12, 0xb3, 0xf9, 0x89, 0x01, 0x93, 0x62, 0x0e, 0x16, 0x6b, 0xb4, 0xbc, + 0x59, 0xf2, 0x68, 0x8b, 0xe9, 0x72, 0x6d, 0x97, 0xba, 0x51, 0xe7, 0xea, 0x6b, 0x2e, 0x75, 0x31, + 0x87, 0x68, 0xa3, 0xcf, 0x1c, 0xd6, 0xe8, 0xcd, 0xf3, 0xa0, 0x2d, 0x0e, 0xbf, 0xc3, 0x20, 0x52, + 0xf9, 0x3b, 0x32, 0x8f, 0x33, 0x38, 0xc0, 0xa2, 0x56, 0x07, 0xfb, 0x70, 0xf3, 0xfb, 0x19, 0x18, + 0xe4, 0xfe, 0xcf, 0x34, 0x8a, 0xc5, 0x1e, 0x99, 0x06, 0x2a, 0x94, 0x3e, 0xb0, 0x6b, 0x28, 0xdd, + 0x8d, 0x8b, 0xa4, 0x3f, 0x9f, 0xc2, 0x85, 0xdb, 0xcf, 0x9d, 0xa0, 0xfd, 0x46, 0xb7, 0x7f, 0x65, + 0xc0, 0x4c, 0x5c, 0xd6, 0x4a, 0x9a, 0xf9, 0x7b, 0x0c, 0x46, 0x5a, 0x75, 0xe2, 0x6d, 0xd8, 0x4e, + 0x23, 0x7a, 0x2b, 0x61, 0x55, 0x96, 0xe3, 0xa0, 0x06, 0x72, 0x00, 0x1c, 0x15, 0x04, 0x17, 0x16, + 0xec, 0x85, 0xfd, 0xe5, 0x1b, 0x28, 0xab, 0x55, 0x8b, 0x81, 0x6b, 0x54, 0xcc, 0xff, 0x1e, 0x84, + 0x69, 0xde, 0xe4, 0x4e, 0x6b, 0x39, 0x67, 0x00, 0xca, 0xa4, 0x5c, 0xa3, 0xc5, 0xce, 0x9a, 0xdc, + 0x71, 0x23, 0x5a, 0x3a, 0x62, 0x00, 0xc1, 0x5a, 0x2d, 0xde, 0x46, 0x89, 0xa3, 0x81, 0x70, 0xbc, + 0x49, 0x13, 0x44, 0x5a, 0xad, 0x7d, 0xeb, 0x2b, 0x61, 0x9d, 0x61, 0xa8, 0x3f, 0x9d, 0x61, 0x38, + 0xa5, 0xce, 0xd0, 0x82, 0x7b, 0x78, 0xcc, 0xa2, 0x5b, 0xb3, 0x13, 0x06, 0xc6, 0x79, 0xd9, 0xf9, + 0x7b, 0x96, 0x63, 0x6b, 0xdd, 0xee, 0x09, 0xc1, 0x3d, 0xf0, 0xf6, 0xd6, 0x37, 0x46, 0xf7, 0xa1, + 0x6f, 0xe8, 0xc7, 0x01, 0xf6, 0x3c, 0x0e, 0xda, 0x39, 0xcb, 0xed, 0x71, 0xce, 0xba, 0x54, 0x81, + 0xb1, 0x84, 0xaa, 0xc0, 0xef, 0x1b, 0x10, 0x36, 0x5e, 0xd1, 0x2d, 0x18, 0x6b, 0x10, 0xaf, 0x5c, + 0x5b, 0x6e, 0x56, 0xac, 0x32, 0xf5, 0x43, 0xc9, 0x17, 0xfa, 0x30, 0x8f, 0x65, 0x80, 0xa0, 0x41, + 0x9b, 0x9e, 0x4a, 0xd9, 0x7b, 0x45, 0xc3, 0x8d, 0x43, 0x94, 0xcc, 0xbf, 0x30, 0x60, 0xb6, 0x17, + 0x02, 0xc6, 0x89, 0x03, 0xce, 0xa5, 0x38, 0xf1, 0xcb, 0xb4, 0x23, 0xd8, 0xd8, 0x45, 0x18, 0xb1, + 0x5b, 0xd4, 0x21, 0x1e, 0x77, 0x31, 0xb3, 0x3a, 0x8f, 0xf8, 0x33, 0x7b, 0x55, 0x96, 0xdf, 0xe6, + 0xab, 0xa5, 0xa1, 0xf7, 0x01, 0x38, 0x68, 0xaa, 0x92, 0x4a, 0xb2, 0xbb, 0x24, 0x95, 0x7c, 0x6a, + 0xc0, 0xf0, 0xaa, 0x63, 0xf3, 0x04, 0xb2, 0xc3, 0x4f, 0x2a, 0x79, 0x23, 0x92, 0xba, 0xfe, 0x64, + 0xe2, 0xe4, 0x56, 0x86, 0x6c, 0x8f, 0x14, 0x83, 0x1f, 0x64, 0x60, 0x5c, 0xd6, 0xbc, 0xbb, 0xd3, + 0xfc, 0x43, 0x9d, 0x3c, 0xe8, 0x34, 0xff, 0x30, 0xf2, 0xbd, 0xd3, 0xfc, 0x43, 0xf5, 0xef, 0xda, + 0x34, 0xff, 0x50, 0x2f, 0x7b, 0xa5, 0xf9, 0x67, 0x22, 0xa3, 0xe1, 0x69, 0xfe, 0xdf, 0x84, 0xe9, + 0x96, 0x1f, 0xce, 0xe2, 0x57, 0xb3, 0xac, 0x80, 0x0f, 0x9c, 0x4d, 0x99, 0x5a, 0x2d, 0x6e, 0x76, + 0x15, 0xef, 0x95, 0xd4, 0xa7, 0x57, 0xa3, 0x78, 0x71, 0x37, 0xa9, 0xf8, 0x6b, 0x06, 0x99, 0xa3, + 0xbf, 0x66, 0x10, 0xb3, 0x2f, 0x7e, 0x7d, 0xcd, 0xe0, 0x8e, 0x5f, 0x33, 0xf8, 0x91, 0x01, 0x39, + 0xb9, 0x32, 0x77, 0x6d, 0xc2, 0x8c, 0xec, 0x5f, 0x8f, 0x53, 0xf7, 0x99, 0x01, 0x63, 0x1a, 0x7f, + 0x76, 0x51, 0x0d, 0xe0, 0x26, 0x71, 0x68, 0xcd, 0x0e, 0x2c, 0xac, 0xc4, 0xc9, 0x05, 0xd7, 0xfd, + 0x76, 0x1c, 0x93, 0xda, 0x59, 0x41, 0xb9, 0x8b, 0x35, 0xdc, 0xe8, 0x6b, 0x5a, 0x9e, 0x80, 0x60, + 0xee, 0x89, 0xa8, 0xf0, 0x50, 0x9c, 0xa0, 0xa0, 0x33, 0x46, 0x2d, 0xbb, 0xc0, 0xfc, 0xb1, 0x11, + 0x88, 0x92, 0xd8, 0xa3, 0x92, 0x3d, 0x9c, 0xa3, 0x52, 0x82, 0x41, 0xc6, 0x99, 0xfd, 0x7b, 0xdb, + 0x67, 0x52, 0x4b, 0x47, 0x57, 0x7a, 0x56, 0xd8, 0x4f, 0x2c, 0x70, 0x99, 0xdf, 0xcd, 0xc0, 0x68, + 0xc0, 0xa9, 0x8e, 0x40, 0x24, 0xbe, 0x16, 0x12, 0x89, 0x4f, 0xa6, 0xe4, 0xb1, 0x3d, 0xc5, 0xe1, + 0x5b, 0x11, 0x71, 0x98, 0x96, 0x79, 0xef, 0x21, 0x0a, 0xff, 0x4e, 0xac, 0xb8, 0xa8, 0x7b, 0x04, + 0x47, 0x71, 0x2d, 0x7c, 0x14, 0x17, 0x52, 0x8e, 0xa6, 0xc7, 0x61, 0x7c, 0x3f, 0x03, 0x93, 0x11, + 0x71, 0xc5, 0xd4, 0x40, 0xbe, 0xab, 0xa5, 0xba, 0x19, 0x34, 0x94, 0x11, 0x69, 0x0e, 0x43, 0x5b, + 0x4c, 0xe7, 0x0e, 0x6c, 0x87, 0x20, 0x74, 0xf5, 0x42, 0x5f, 0x12, 0x32, 0x08, 0x29, 0x49, 0x95, + 0x5d, 0xc3, 0x8b, 0xc3, 0x64, 0xd0, 0x6a, 0x24, 0xc5, 0xe5, 0x62, 0x93, 0xac, 0xd7, 0x69, 0x45, + 0xde, 0x40, 0xbd, 0x3f, 0x48, 0xaa, 0x89, 0xa9, 0x83, 0x63, 0x5b, 0x9a, 0x7f, 0x65, 0xc0, 0xc9, + 0x1e, 0xfd, 0x49, 0x90, 0x53, 0x57, 0x8f, 0x86, 0xf0, 0x32, 0xfd, 0x87, 0xf0, 0xa6, 0xf7, 0x0a, + 0xdf, 0x99, 0x3f, 0xcd, 0x00, 0x0a, 0xfa, 0x9a, 0x26, 0xf5, 0xef, 0x2d, 0x18, 0xde, 0x10, 0x49, + 0x1d, 0xfb, 0x4b, 0x05, 0x2d, 0xe6, 0xf4, 0x6c, 0x58, 0x1f, 0x27, 0x7a, 0xfd, 0x60, 0xce, 0x1a, + 0x74, 0x9f, 0x33, 0x74, 0x03, 0x60, 0xc3, 0x6a, 0x5a, 0x6e, 0xad, 0xcf, 0x0b, 0x10, 0xdc, 0x3a, + 0xbf, 0x14, 0x60, 0xc0, 0x1a, 0x36, 0xf3, 0x8f, 0x32, 0xda, 0x19, 0xe6, 0xca, 0x5f, 0xa2, 0xbd, + 0xff, 0x48, 0x78, 0x32, 0x47, 0xbb, 0xd3, 0x84, 0x83, 0x89, 0xb9, 0x01, 0x03, 0x5b, 0xc4, 0xf1, + 0x53, 0x02, 0x12, 0xde, 0xc4, 0xea, 0xbe, 0x11, 0xa0, 0xd6, 0xf4, 0x1a, 0x71, 0x5c, 0xcc, 0x71, + 0x32, 0xc5, 0xd8, 0xf5, 0x68, 0xcb, 0x17, 0x2e, 0xa9, 0x19, 0xa7, 0x47, 0x5b, 0xfa, 0x00, 0x69, + 0x8b, 0x4b, 0x00, 0xda, 0x72, 0xcd, 0xff, 0x1c, 0xd6, 0xb8, 0x82, 0x94, 0x67, 0x07, 0xa9, 0x49, + 0x9d, 0xf5, 0x5f, 0xb2, 0x11, 0xb3, 0x3c, 0x1f, 0x7a, 0xc9, 0xe6, 0xf6, 0xf6, 0xfc, 0x84, 0x3a, + 0x8f, 0xda, 0xdb, 0x36, 0x29, 0xde, 0x6c, 0xd1, 0xf7, 0xfb, 0xe0, 0x21, 0xec, 0xf7, 0xdf, 0x86, + 0xe9, 0x8d, 0x68, 0xde, 0xb8, 0xbc, 0xe6, 0x74, 0xae, 0xcf, 0xb4, 0x73, 0xe1, 0x0f, 0xea, 0x2a, + 0xc6, 0xdd, 0x84, 0x90, 0xed, 0xbf, 0x14, 0xc3, 0xfd, 0xd3, 0x22, 0x74, 0x95, 0xf8, 0xcc, 0x45, + 0x3c, 0xdb, 0xd1, 0x37, 0x62, 0x04, 0x4a, 0x1c, 0x22, 0x80, 0xae, 0xc3, 0xa8, 0xeb, 0x11, 0x47, + 0xdc, 0x41, 0x1a, 0xeb, 0xef, 0x0e, 0x52, 0xc9, 0x47, 0x80, 0x15, 0xae, 0xc8, 0xe1, 0x1e, 0x3a, + 0xc8, 0xc3, 0x8d, 0xce, 0x06, 0x09, 0x87, 0x6c, 0x9c, 0xdc, 0x73, 0x95, 0xed, 0x4a, 0x15, 0x64, + 0x20, 0xac, 0xd7, 0x43, 0x1f, 0x19, 0x70, 0x82, 0x9d, 0x82, 0x8b, 0xb7, 0x68, 0xb9, 0xcd, 0xa6, + 0xdb, 0x4f, 0xba, 0x9a, 0xcd, 0xa5, 0xb1, 0xc1, 0x4a, 0x71, 0x28, 0x94, 0xe3, 0x2c, 0x16, 0x8c, + 0xe3, 0x09, 0xa3, 0xb7, 0x85, 0x96, 0x47, 0xb9, 0xd7, 0x6c, 0xff, 0x91, 0x85, 0x40, 0xe3, 0x13, + 0x0c, 0xcd, 0xa3, 0xe6, 0x77, 0x07, 0x74, 0x3e, 0x98, 0x2c, 0xde, 0x71, 0x03, 0x06, 0x3c, 0xe2, + 0x6e, 0xca, 0xe3, 0xf5, 0x7c, 0x1f, 0x97, 0x8e, 0xd5, 0x21, 0x1b, 0x61, 0xb8, 0x79, 0x11, 0xc7, + 0x89, 0xe6, 0x20, 0x43, 0xdc, 0x68, 0xea, 0x47, 0xc1, 0xc5, 0x19, 0xe2, 0xf2, 0xb4, 0x90, 0x0d, + 0x19, 0xed, 0x55, 0x69, 0x21, 0x1b, 0x38, 0x63, 0xf1, 0x07, 0x60, 0xca, 0x76, 0xd3, 0xb3, 0x9a, + 0x6d, 0x7a, 0xb5, 0x79, 0xd1, 0x71, 0x6c, 0x91, 0x82, 0x31, 0xa2, 0x1e, 0x80, 0x59, 0x0c, 0x83, + 0x71, 0xb4, 0x3e, 0x7a, 0x1d, 0x06, 0x1d, 0xea, 0x39, 0x1d, 0x29, 0x69, 0xce, 0xf7, 0xc1, 0x54, + 0x31, 0x6b, 0x2f, 0x66, 0x99, 0xff, 0xc4, 0x02, 0x63, 0x20, 0x0b, 0x86, 0x0e, 0x41, 0x16, 0xa8, + 0xe8, 0x53, 0xf6, 0xd0, 0xa2, 0x4f, 0xdf, 0x33, 0x34, 0xe5, 0x23, 0x18, 0x28, 0x7a, 0x0d, 0x86, + 0x3d, 0xab, 0x41, 0xed, 0xb6, 0x97, 0x4e, 0xeb, 0x0d, 0xf2, 0xa9, 0x39, 0x8b, 0x5d, 0x13, 0x28, + 0xb0, 0x8f, 0x0b, 0x5d, 0x80, 0x09, 0xca, 0x56, 0x64, 0xad, 0xc6, 0x44, 0x86, 0x5d, 0x17, 0x2a, + 0xde, 0xb8, 0xf2, 0xd4, 0x5f, 0x0c, 0x41, 0x71, 0xa4, 0xb6, 0xf9, 0x53, 0x5d, 0x3f, 0xff, 0xff, + 0x7f, 0x11, 0x5f, 0x7a, 0xde, 0x8e, 0xf4, 0x06, 0x7e, 0xdf, 0x9e, 0xb7, 0x3d, 0xaf, 0xde, 0xbf, + 0x09, 0xf7, 0xc4, 0xb3, 0x82, 0x03, 0x79, 0xa2, 0xee, 0xc7, 0xd1, 0xb9, 0xe2, 0xaa, 0x9d, 0x7f, + 0xfc, 0x8c, 0xc3, 0x54, 0xc5, 0x32, 0x07, 0xad, 0x8a, 0x39, 0xfa, 0x50, 0xe4, 0x83, 0x7e, 0xe8, + 0x2d, 0xb9, 0xcf, 0x8c, 0x34, 0x4f, 0xc4, 0x75, 0xa1, 0xe9, 0xb9, 0xd7, 0x7e, 0x66, 0xc0, 0x89, + 0xd8, 0xda, 0xc1, 0x1c, 0x66, 0x0e, 0x73, 0x0e, 0x8d, 0x83, 0x9e, 0xc3, 0x2d, 0xb8, 0xf7, 0xab, + 0x6d, 0x72, 0xe4, 0xef, 0x91, 0x99, 0x1f, 0x64, 0x61, 0x0a, 0xd3, 0x96, 0x1d, 0x0a, 0xae, 0xae, + 0xfa, 0x4f, 0x33, 0xa4, 0xb0, 0x93, 0x22, 0x69, 0x68, 0xc5, 0xe1, 0xd0, 0x9b, 0x0c, 0xec, 0x98, + 0x36, 0x7c, 0xa5, 0x38, 0x31, 0xdb, 0xe9, 0x0a, 0xfb, 0x0a, 0x89, 0x25, 0x02, 0xc8, 0x02, 0x21, + 0xc3, 0xcc, 0xef, 0x35, 0x49, 0xa1, 0x72, 0x2e, 0xc5, 0x0d, 0xa9, 0x6e, 0xcc, 0xbc, 0x18, 0x0b, + 0x84, 0xa8, 0x06, 0x63, 0xfa, 0x9b, 0x76, 0xe9, 0xfc, 0x57, 0x21, 0xdc, 0x3c, 0x75, 0x4a, 0x2f, + 0xc1, 0x21, 0xcc, 0xe6, 0x27, 0x19, 0x10, 0xd6, 0xdb, 0x11, 0xf0, 0xff, 0xaf, 0x86, 0xf8, 0xff, + 0x42, 0x1a, 0xef, 0x62, 0x2f, 0x2f, 0x56, 0xd4, 0xb2, 0x7e, 0x22, 0xa5, 0xcb, 0x72, 0x17, 0x0f, + 0xd6, 0x0f, 0x0d, 0x18, 0xe5, 0xf5, 0x8e, 0x40, 0x94, 0xac, 0x86, 0x45, 0xc9, 0xa3, 0x29, 0x46, + 0xd1, 0x43, 0x84, 0xfc, 0x57, 0x56, 0xf6, 0x3e, 0xb0, 0xdb, 0x6b, 0xc4, 0xa9, 0x48, 0x83, 0x54, + 0xf1, 0x01, 0x56, 0x88, 0x05, 0x2c, 0xe0, 0x5e, 0xc3, 0x87, 0xc0, 0xbd, 0xde, 0x15, 0xd7, 0xcb, + 0xa8, 0xeb, 0xd1, 0xca, 0xa5, 0xc0, 0xf2, 0xcc, 0xa6, 0xbe, 0x27, 0x27, 0xef, 0xf2, 0xa9, 0x98, + 0x00, 0x8e, 0x60, 0xc5, 0x5d, 0x74, 0x98, 0x35, 0xda, 0x8a, 0xb2, 0x6b, 0x69, 0x4c, 0x9d, 0xeb, + 0x53, 0x36, 0x08, 0x6b, 0xb4, 0xab, 0x18, 0x77, 0x13, 0x62, 0x47, 0x59, 0xbf, 0x9a, 0x2c, 0xf7, + 0xe9, 0x99, 0xf4, 0x77, 0xa0, 0xc5, 0x51, 0xd6, 0x4b, 0x70, 0x08, 0xb3, 0xf9, 0x07, 0x06, 0x80, + 0xf2, 0xc5, 0xb3, 0x35, 0x2f, 0xdb, 0xed, 0xa6, 0x70, 0xc2, 0x64, 0xd5, 0x9a, 0x2f, 0xb2, 0x42, + 0x2c, 0x60, 0xec, 0xfc, 0x08, 0x53, 0x56, 0x6e, 0xea, 0x27, 0xd2, 0x58, 0xc9, 0x11, 0x9f, 0xbf, + 0x28, 0xc4, 0x12, 0xa1, 0xf9, 0x37, 0x23, 0x90, 0xd3, 0xce, 0x59, 0xc4, 0xe3, 0x3f, 0x7e, 0x68, + 0xc1, 0xb1, 0x18, 0x37, 0x4c, 0xae, 0x2f, 0x37, 0x8c, 0x0b, 0x13, 0xd2, 0xb9, 0xe0, 0xdf, 0x5f, + 0x1f, 0x48, 0x73, 0x63, 0xb5, 0xdb, 0x85, 0x81, 0x98, 0x5e, 0x7e, 0x29, 0x84, 0x12, 0x47, 0x48, + 0x30, 0xbd, 0x5e, 0x96, 0x94, 0xda, 0x8d, 0x06, 0x71, 0x3a, 0x32, 0xf9, 0x34, 0xd0, 0xeb, 0x2f, + 0x85, 0xa0, 0x38, 0x52, 0x1b, 0xad, 0x06, 0x0b, 0x2a, 0x2e, 0x31, 0x3f, 0x96, 0x66, 0x41, 0x85, + 0x5d, 0x13, 0x5e, 0xc7, 0x1e, 0xf1, 0xc6, 0xa1, 0xbe, 0xe2, 0x8d, 0xef, 0xc2, 0x94, 0x74, 0x26, + 0x04, 0x67, 0x47, 0xfa, 0x85, 0xd2, 0x5a, 0x92, 0x4a, 0xc9, 0xe0, 0x39, 0x54, 0x8b, 0x11, 0xac, + 0xb8, 0x8b, 0x0e, 0x7a, 0x07, 0xc6, 0xd9, 0x22, 0x2b, 0xc2, 0xb0, 0x4f, 0xc2, 0xd2, 0x1f, 0xad, + 0xa1, 0xc4, 0x61, 0x0a, 0x3d, 0xbd, 0xf1, 0x13, 0xfd, 0x7a, 0xe3, 0x51, 0x43, 0x13, 0x43, 0x93, + 0x7c, 0x37, 0x7e, 0x25, 0xb5, 0xc4, 0x4b, 0x71, 0x63, 0xf1, 0x8e, 0x5e, 0xaa, 0xfb, 0x2c, 0x0b, + 0xf1, 0x8e, 0x20, 0xf5, 0x96, 0x8a, 0xb1, 0xcb, 0x5b, 0x2a, 0x21, 0xaf, 0x5c, 0xe6, 0xd0, 0xbc, + 0x72, 0xd9, 0x03, 0xf5, 0xca, 0x9d, 0x01, 0xe0, 0x86, 0x3a, 0x67, 0xd2, 0x5c, 0x5a, 0x8f, 0x6b, + 0x8f, 0x44, 0x04, 0x10, 0xac, 0xd5, 0x42, 0x2f, 0x04, 0x3a, 0x90, 0x78, 0xa7, 0xea, 0xcb, 0x5d, + 0x39, 0xcb, 0xc7, 0x43, 0x66, 0x40, 0x24, 0x82, 0x90, 0xe2, 0x96, 0x4f, 0x8c, 0x03, 0x69, 0x38, + 0x9d, 0x03, 0xc9, 0xfc, 0x93, 0x0c, 0x84, 0xd4, 0xd1, 0xe8, 0x83, 0xcf, 0xda, 0x73, 0xd1, 0xb1, + 0xef, 0x23, 0xf1, 0x5b, 0x91, 0x5d, 0x2d, 0x12, 0x5c, 0x26, 0x3b, 0x02, 0x17, 0x50, 0x4c, 0xfa, + 0x24, 0x5b, 0xc1, 0xc1, 0xa4, 0xe9, 0x93, 0xe6, 0xff, 0x64, 0x20, 0x24, 0xe0, 0xd1, 0x77, 0x0c, + 0x98, 0x26, 0x91, 0xf7, 0xea, 0x7d, 0x0b, 0xf0, 0x2b, 0xe9, 0x3e, 0x22, 0xd0, 0xf5, 0xdc, 0xbd, + 0xca, 0xbb, 0x89, 0x56, 0x71, 0x71, 0x37, 0x51, 0xf4, 0xbb, 0x06, 0x1c, 0x27, 0xdd, 0x1f, 0x24, + 0x90, 0x27, 0xeb, 0x99, 0xbe, 0xbf, 0x68, 0x50, 0x3c, 0xb9, 0xb3, 0x3d, 0x1f, 0xf7, 0xa9, 0x06, + 0x1c, 0x47, 0x0e, 0xbd, 0x01, 0x03, 0xc4, 0xa9, 0xfa, 0x41, 0x9d, 0xf4, 0x64, 0xfd, 0xef, 0x4c, + 0xa8, 0x3d, 0x52, 0x70, 0xaa, 0x2e, 0xe6, 0x48, 0xcd, 0x5f, 0x64, 0x61, 0x2a, 0xfa, 0xec, 0x8c, + 0xbc, 0x68, 0x37, 0x10, 0x7b, 0xd1, 0x8e, 0x31, 0x22, 0x1e, 0xd6, 0x8c, 0x3e, 0xea, 0xc4, 0xa3, + 0x93, 0x02, 0x16, 0x30, 0x22, 0xfe, 0xa6, 0xc2, 0xe0, 0x3e, 0x18, 0x11, 0x7f, 0x48, 0x41, 0xe1, + 0x42, 0xe7, 0xc3, 0x71, 0x22, 0x33, 0x1a, 0x27, 0x9a, 0xd6, 0xc7, 0xd2, 0x6f, 0xa8, 0xa8, 0x01, + 0x39, 0x6d, 0x1d, 0xe4, 0xe1, 0x79, 0x36, 0xf5, 0xbc, 0xab, 0x6d, 0x37, 0x29, 0x12, 0xd3, 0x15, + 0x44, 0xc7, 0xaf, 0x98, 0x2b, 0x9f, 0xad, 0x7d, 0x85, 0x3c, 0xf8, 0x74, 0x69, 0xd8, 0xcc, 0x7f, + 0x31, 0x60, 0x3c, 0x74, 0x69, 0x9d, 0x51, 0xf3, 0x5f, 0x23, 0xe8, 0xff, 0xe3, 0x0c, 0xd7, 0x02, + 0x0c, 0x58, 0xc3, 0x86, 0xbe, 0x01, 0xb9, 0xba, 0xdd, 0xac, 0x52, 0xd7, 0x2b, 0xd9, 0x64, 0x53, + 0x9e, 0x93, 0xb4, 0xce, 0x5f, 0xfe, 0xb0, 0xc4, 0x8a, 0x40, 0xb3, 0x68, 0x37, 0x5a, 0x75, 0xea, + 0x89, 0x27, 0x34, 0xb0, 0x8e, 0x9c, 0xe7, 0xa4, 0x04, 0x49, 0x3d, 0x77, 0x6b, 0x4e, 0x8a, 0xca, + 0x46, 0x3a, 0xe0, 0x9c, 0x94, 0x50, 0x9a, 0xd3, 0x1e, 0x39, 0x29, 0x41, 0xdd, 0xbb, 0x36, 0x27, + 0x25, 0xe8, 0x61, 0x0f, 0xcb, 0xfe, 0xe3, 0x01, 0x6d, 0x14, 0x61, 0xeb, 0x3e, 0xb3, 0x8b, 0x75, + 0xff, 0x26, 0x8c, 0x58, 0x4d, 0x8f, 0x3a, 0x5b, 0xa4, 0x2e, 0xdd, 0x49, 0x69, 0xf7, 0x62, 0x30, + 0xd4, 0x65, 0x89, 0x07, 0x07, 0x18, 0x51, 0x1d, 0x4e, 0x6c, 0x84, 0xdf, 0xbd, 0x92, 0x9f, 0x01, + 0x10, 0xb9, 0xd2, 0x4f, 0xfb, 0x81, 0xbd, 0x4b, 0x71, 0x95, 0x6e, 0xf7, 0x02, 0xe0, 0x78, 0xa4, + 0xe8, 0x3d, 0x18, 0xd7, 0x35, 0x00, 0x95, 0x87, 0xbe, 0x3f, 0x91, 0x1e, 0xdc, 0xd8, 0xd6, 0x15, + 0x0e, 0x17, 0x87, 0x69, 0xa1, 0x8f, 0x0d, 0x38, 0xb9, 0x11, 0xff, 0xc6, 0x97, 0xe4, 0xee, 0x2f, + 0xa4, 0x33, 0x10, 0x23, 0x48, 0x8a, 0xf7, 0xed, 0x6c, 0xcf, 0xf7, 0x7a, 0x45, 0x0c, 0xf7, 0x22, + 0x6d, 0x7e, 0x64, 0xc0, 0x44, 0x38, 0xdf, 0xef, 0x8e, 0x7b, 0x00, 0x3e, 0xcb, 0xc2, 0x64, 0xe4, + 0x6c, 0x46, 0xbc, 0x00, 0xa3, 0x47, 0xe9, 0x05, 0x18, 0xea, 0xcb, 0x0b, 0x10, 0x6f, 0xfe, 0x0e, + 0xf4, 0x65, 0xfe, 0x3e, 0x27, 0x4c, 0x50, 0xb9, 0xb6, 0xcb, 0x4b, 0xf2, 0x82, 0x8a, 0xf6, 0x36, + 0x81, 0x06, 0xc4, 0xe1, 0xba, 0x5c, 0x01, 0xab, 0x74, 0x3f, 0x99, 0x2c, 0xed, 0xe7, 0x67, 0xd2, + 0x5e, 0x85, 0x0a, 0x10, 0x08, 0x05, 0x2c, 0x06, 0x80, 0xe3, 0xc8, 0x99, 0xff, 0x36, 0x02, 0x27, + 0xe2, 0x43, 0x05, 0x7b, 0xc7, 0xa6, 0xde, 0x81, 0xd1, 0x75, 0xff, 0x53, 0x1a, 0xf2, 0xac, 0x24, + 0x7c, 0xec, 0x67, 0xf7, 0x2f, 0x70, 0x08, 0x1d, 0x29, 0xa8, 0x83, 0x15, 0x15, 0x46, 0xb2, 0xc2, + 0x9f, 0x2f, 0xad, 0xb5, 0xd7, 0xa5, 0x3a, 0x91, 0x90, 0xe4, 0xee, 0xaf, 0x9e, 0x0a, 0x92, 0x41, + 0x1d, 0xac, 0xa8, 0x20, 0x0a, 0x43, 0x82, 0x80, 0x14, 0x8f, 0x85, 0xc4, 0x51, 0x8c, 0x9e, 0xc4, + 0xb8, 0xb1, 0x21, 0x2a, 0x60, 0x89, 0x5c, 0x92, 0xa9, 0x93, 0x75, 0x29, 0x2c, 0x93, 0x93, 0xe9, + 0xf5, 0x5c, 0x40, 0x40, 0x66, 0x85, 0x08, 0x32, 0x75, 0xc2, 0xc9, 0xd4, 0xf8, 0xb5, 0x5c, 0xe9, + 0x2f, 0x49, 0x48, 0x66, 0x97, 0xab, 0xbc, 0xd2, 0xcb, 0xc4, 0x2b, 0x60, 0x89, 0x1c, 0xbd, 0x05, + 0x03, 0xef, 0xb4, 0x89, 0x9f, 0x57, 0x90, 0xd0, 0xb6, 0xe9, 0x19, 0xb6, 0x12, 0x29, 0x13, 0x0c, + 0x8c, 0x39, 0x5a, 0xd4, 0x81, 0x1c, 0x51, 0x9f, 0xde, 0x91, 0xaf, 0xab, 0x5e, 0x4a, 0xf7, 0xf4, + 0x5c, 0xaf, 0x6f, 0xf6, 0x48, 0x8d, 0x56, 0xd5, 0xc2, 0x3a, 0x2d, 0x44, 0x60, 0x90, 0xbc, 0xdb, + 0x76, 0xa8, 0x74, 0xc8, 0xbd, 0x98, 0x90, 0x68, 0xcf, 0x6f, 0xdd, 0x88, 0x70, 0x11, 0x87, 0x63, + 0x81, 0x99, 0x91, 0xa8, 0x5a, 0x1e, 0x25, 0x92, 0x17, 0xbc, 0x98, 0x78, 0x27, 0xf4, 0xb8, 0xe6, + 0x2d, 0x48, 0x70, 0x38, 0x16, 0x98, 0x91, 0x05, 0xc3, 0x55, 0xf1, 0x9e, 0x0b, 0xf7, 0xa6, 0x26, + 0x7e, 0x3f, 0x74, 0xb7, 0xc7, 0x72, 0x44, 0x6a, 0x83, 0xac, 0x81, 0x7d, 0xfc, 0xe6, 0x7b, 0x70, + 0x4f, 0xfc, 0x4d, 0x80, 0x64, 0xd1, 0xef, 0x16, 0xf1, 0x6a, 0xd1, 0xaf, 0xa5, 0xac, 0x12, 0xaf, + 0x86, 0x39, 0x04, 0x3d, 0x00, 0xd9, 0xb6, 0x53, 0x8f, 0xbe, 0x79, 0xf2, 0x1a, 0x5e, 0xc1, 0xac, + 0xbc, 0xf8, 0xd2, 0xa7, 0x5f, 0x9c, 0x3a, 0xf6, 0xf3, 0x2f, 0x4e, 0x1d, 0xfb, 0xfc, 0x8b, 0x53, + 0xc7, 0xde, 0xdf, 0x39, 0x65, 0x7c, 0xba, 0x73, 0xca, 0xf8, 0xf9, 0xce, 0x29, 0xe3, 0xf3, 0x9d, + 0x53, 0xc6, 0x2f, 0x77, 0x4e, 0x19, 0x1f, 0xfd, 0xea, 0xd4, 0xb1, 0x1b, 0x0f, 0x26, 0xf9, 0xa6, + 0xe4, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x32, 0x6a, 0x6c, 0x44, 0x7a, 0x72, 0x00, 0x00, } func (m *AnalysisRunArgument) Marshal() (dAtA []byte, err error) { @@ -3881,17 +3882,25 @@ func (m *ChartSubscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.SemverConstraint) i = encodeVarintGenerated(dAtA, i, uint64(len(m.SemverConstraint))) i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a i -= len(m.RepoURL) copy(dAtA[i:], m.RepoURL) i = encodeVarintGenerated(dAtA, i, uint64(len(m.RepoURL))) i-- - dAtA[i] = 0x1a + dAtA[i] = 0x22 i -= len(m.Name) copy(dAtA[i:], m.Name) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a + i-- + if m.InsecureSkipTLSVerify { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 i = encodeVarintGenerated(dAtA, i, uint64(m.DiscoveryLimit)) i-- dAtA[i] = 0x8 @@ -5553,7 +5562,19 @@ func (m *GitSubscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0 } i-- - dAtA[i] = 0x70 + dAtA[i] = 0x78 + } + if m.Since != nil { + { + size, err := m.Since.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x72 } i -= len(m.SemverConstraint) copy(dAtA[i:], m.SemverConstraint) @@ -8818,6 +8839,7 @@ func (m *ChartSubscription) Size() (n int) { var l int _ = l n += 1 + sovGenerated(uint64(m.DiscoveryLimit)) + n += 2 l = len(m.Name) n += 1 + l + sovGenerated(uint64(l)) l = len(m.RepoURL) @@ -9469,6 +9491,10 @@ func (m *GitSubscription) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = len(m.SemverConstraint) n += 1 + l + sovGenerated(uint64(l)) + if m.Since != nil { + l = m.Since.Size() + n += 1 + l + sovGenerated(uint64(l)) + } if m.StrictSemvers != nil { n += 2 } @@ -10738,6 +10764,7 @@ func (this *ChartSubscription) String() string { } s := strings.Join([]string{`&ChartSubscription{`, `DiscoveryLimit:` + fmt.Sprintf("%v", this.DiscoveryLimit) + `,`, + `InsecureSkipTLSVerify:` + fmt.Sprintf("%v", this.InsecureSkipTLSVerify) + `,`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `RepoURL:` + fmt.Sprintf("%v", this.RepoURL) + `,`, `SemverConstraint:` + fmt.Sprintf("%v", this.SemverConstraint) + `,`, @@ -11288,6 +11315,7 @@ func (this *GitSubscription) String() string { `InsecureSkipTLSVerify:` + fmt.Sprintf("%v", this.InsecureSkipTLSVerify) + `,`, `RepoURL:` + fmt.Sprintf("%v", this.RepoURL) + `,`, `SemverConstraint:` + fmt.Sprintf("%v", this.SemverConstraint) + `,`, + `Since:` + strings.Replace(fmt.Sprintf("%v", this.Since), "Time", "v1.Time", 1) + `,`, `StrictSemvers:` + valueToStringGenerated(this.StrictSemvers) + `,`, `}`, }, "") @@ -14243,6 +14271,26 @@ func (m *ChartSubscription) Unmarshal(dAtA []byte) error { } } case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InsecureSkipTLSVerify", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.InsecureSkipTLSVerify = bool(v != 0) + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } @@ -14274,7 +14322,7 @@ func (m *ChartSubscription) Unmarshal(dAtA []byte) error { } m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field RepoURL", wireType) } @@ -14306,7 +14354,7 @@ func (m *ChartSubscription) Unmarshal(dAtA []byte) error { } m.RepoURL = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field SemverConstraint", wireType) } @@ -19847,6 +19895,42 @@ func (m *GitSubscription) Unmarshal(dAtA []byte) error { m.SemverConstraint = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Since", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Since == nil { + m.Since = &v1.Time{} + } + if err := m.Since.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 15: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field StrictSemvers", wireType) } diff --git a/api/v1alpha1/generated.proto b/api/v1alpha1/generated.proto index 5243aa98a0..da8835ebb1 100644 --- a/api/v1alpha1/generated.proto +++ b/api/v1alpha1/generated.proto @@ -295,10 +295,14 @@ message ChartSubscription { // the semverConstraint field. The upper limit for this field is 100. optional int64 discoveryLimit = 1; + // InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored + // when connecting to the repository. This should be enabled only with great caution. + optional bool insecureSkipTLSVerify = 2; + // Name specifies the name of a Helm chart to subscribe to within a classic chart repository // specified by the repoURL field. This field is required when the repoURL field points to a // classic chart repository and MUST otherwise be empty. - optional string name = 2; + optional string name = 3; // RepoURL specifies the URL of a Helm chart repository. It may be a classic chart // repository (using HTTP/S) OR a repository within an OCI registry. Classic chart @@ -307,13 +311,13 @@ message ChartSubscription { // within that repository. In the case of a repository within an OCI registry, the URL // implicitly points to a specific chart and the name field MUST NOT be used. This field is // required. - optional string repoURL = 3; + optional string repoURL = 4; // SemverConstraint specifies constraints on what new chart versions are permissible. When // left unspecified, there will be no constraints, which means the latest version of the // chart will always be used. Care should be taken with leaving this field unspecified, as // it can lead to the unanticipated rollout of breaking changes. - optional string semverConstraint = 4; + optional string semverConstraint = 5; } // ClusterConfig is a resource type that describes cluster-level Kargo @@ -851,6 +855,8 @@ message GitCommit { message GitDiscoveryResult { // RepoURL is the repository URL of the GitSubscription. // + // TODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern. + // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:Pattern=`(?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*))` // +akuity:test-kubebuilder-pattern=GitRepoURLPattern @@ -954,7 +960,9 @@ message GitSubscription { // when connecting to the repository. This should be enabled only with great caution. optional bool insecureSkipTLSVerify = 11; - // URL is the repository's URL. This is a required field. + // URL is the repository's URL. This is a required field. Deprecated: Support for SSH URLs + // (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in + // v1.13.0. Use HTTPS URLs instead. optional string repoURL = 12; // SemverConstraint specifies constraints on what new tagged commits are considered in @@ -962,10 +970,15 @@ message GitSubscription { // is SemVer. optional string semverConstraint = 13; + // An optional date (RFC 3339) that limits commit discovery to commits at or after this + // date. When specified, discovery stops upon reaching a commit older than this date. When + // left unspecified, there is no cutoff. + optional .k8s.io.apimachinery.pkg.apis.meta.v1.Time since = 14; + // StrictSemvers specifies whether only "strict" semver tags should be considered. A // "strict" semver tag contains ALL of major, minor, and patch version components. Only has // effect when CommitSelectionStrategy is SemVer. - optional bool strictSemvers = 14; + optional bool strictSemvers = 15; } // GiteaWebhookReceiverConfig describes a webhook receiver that is compatible diff --git a/api/v1alpha1/warehouse_types.go b/api/v1alpha1/warehouse_types.go index 8f3b83eef7..11adbe021d 100644 --- a/api/v1alpha1/warehouse_types.go +++ b/api/v1alpha1/warehouse_types.go @@ -396,6 +396,8 @@ type DiscoveredArtifacts struct { type GitDiscoveryResult struct { // RepoURL is the repository URL of the GitSubscription. // + // TODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern. + // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:Pattern=`(?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*))` // +akuity:test-kubebuilder-pattern=GitRepoURLPattern diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 66d55b450e..b682822792 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1078,6 +1078,10 @@ func (in *GitSubscription) DeepCopyInto(out *GitSubscription) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.Since != nil { + in, out := &in.Since, &out.Since + *out = (*in).DeepCopy() + } if in.StrictSemvers != nil { in, out := &in.StrictSemvers, &out.StrictSemvers *out = new(bool) diff --git a/api/v1alpha1/zz_subscription_types.go b/api/v1alpha1/zz_subscription_types.go index 0776a0735f..ff56603c3a 100644 --- a/api/v1alpha1/zz_subscription_types.go +++ b/api/v1alpha1/zz_subscription_types.go @@ -2,16 +2,21 @@ package v1alpha1 +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + // ChartSubscription defines a subscription to a Helm chart repository. type ChartSubscription struct { // DiscoveryLimit is an optional limit on the number of chart versions that can be // discovered for this subscription. The limit is applied after filtering charts based on // the semverConstraint field. The upper limit for this field is 100. - DiscoveryLimit int64 `json:"discoveryLimit,omitempty" protobuf:"varint,1,opt,name=discoveryLimit"` + DiscoveryLimit int64 `json:"discoveryLimit,omitempty"` + // InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored + // when connecting to the repository. This should be enabled only with great caution. + InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty"` // Name specifies the name of a Helm chart to subscribe to within a classic chart repository // specified by the repoURL field. This field is required when the repoURL field points to a // classic chart repository and MUST otherwise be empty. - Name string `json:"name,omitempty" protobuf:"bytes,2,opt,name=name"` + Name string `json:"name,omitempty"` // RepoURL specifies the URL of a Helm chart repository. It may be a classic chart // repository (using HTTP/S) OR a repository within an OCI registry. Classic chart // repositories can contain differently named charts. When this field points to such a @@ -19,12 +24,12 @@ type ChartSubscription struct { // within that repository. In the case of a repository within an OCI registry, the URL // implicitly points to a specific chart and the name field MUST NOT be used. This field is // required. - RepoURL string `json:"repoURL" protobuf:"bytes,3,opt,name=repoURL"` + RepoURL string `json:"repoURL"` // SemverConstraint specifies constraints on what new chart versions are permissible. When // left unspecified, there will be no constraints, which means the latest version of the // chart will always be used. Care should be taken with leaving this field unspecified, as // it can lead to the unanticipated rollout of breaking changes. - SemverConstraint string `json:"semverConstraint,omitempty" protobuf:"bytes,4,opt,name=semverConstraint"` + SemverConstraint string `json:"semverConstraint,omitempty"` } // GitSubscription defines a subscription to a Git repository. @@ -32,52 +37,58 @@ type GitSubscription struct { // AllowTags is a regular expression that can optionally be used to limit the tags that are // considered in determining the newest commit of interest. Deprecated: Use allowTagsRegexes // instead. - AllowTags string `json:"allowTags,omitempty" protobuf:"bytes,1,opt,name=allowTags"` + AllowTags string `json:"allowTags,omitempty"` // AllowTagsRegexes is a list of regular expressions that can optionally be used to limit // the tags that are considered. Only has effect when CommitSelectionStrategy is Lexical, // NewestTag, or SemVer. - AllowTagsRegexes []string `json:"allowTagsRegexes,omitempty" protobuf:"bytes,2,rep,name=allowTagsRegexes"` + AllowTagsRegexes []string `json:"allowTagsRegexes,omitempty"` // Branch references a particular branch of the repository. Only has effect when // CommitSelectionStrategy is NewestFromBranch or unspecified. When left unspecified, the // subscription is implicitly to the repository's default branch. Must be a valid branch // name. - Branch string `json:"branch,omitempty" protobuf:"bytes,3,opt,name=branch"` + Branch string `json:"branch,omitempty"` // CommitSelectionStrategy specifies the rules for how to identify the newest commit of // interest in the repository specified by the RepoURL field. - CommitSelectionStrategy CommitSelectionStrategy `json:"commitSelectionStrategy,omitempty" protobuf:"bytes,4,opt,name=commitSelectionStrategy"` + CommitSelectionStrategy CommitSelectionStrategy `json:"commitSelectionStrategy,omitempty"` // DiscoveryLimit is an optional limit on the number of commits that can be discovered for // this subscription. The upper limit is 100. - DiscoveryLimit int64 `json:"discoveryLimit,omitempty" protobuf:"varint,5,opt,name=discoveryLimit"` + DiscoveryLimit int64 `json:"discoveryLimit,omitempty"` // ExcludePaths is a list of selectors that designate paths in the repository that should // NOT trigger the production of new Freight when changes are detected therein. - ExcludePaths []string `json:"excludePaths,omitempty" protobuf:"bytes,6,rep,name=excludePaths"` + ExcludePaths []string `json:"excludePaths,omitempty"` // ExpressionFilter is an expression that can optionally be used to limit the commits or // tags that are considered in determining the newest commit of interest based on their // metadata. - ExpressionFilter string `json:"expressionFilter,omitempty" protobuf:"bytes,7,opt,name=expressionFilter"` + ExpressionFilter string `json:"expressionFilter,omitempty"` // IgnoreTags is a list of tags that must be ignored when determining the newest commit of // interest. Deprecated: Use ignoreTagsRegexes instead. - IgnoreTags []string `json:"ignoreTags,omitempty" protobuf:"bytes,8,rep,name=ignoreTags"` + IgnoreTags []string `json:"ignoreTags,omitempty"` // IgnoreTagsRegexes is a list of regular expressions that can optionally be used to exclude // tags from consideration. Only has effect when CommitSelectionStrategy is Lexical, // NewestTag, or SemVer. - IgnoreTagsRegexes []string `json:"ignoreTagsRegexes,omitempty" protobuf:"bytes,9,rep,name=ignoreTagsRegexes"` + IgnoreTagsRegexes []string `json:"ignoreTagsRegexes,omitempty"` // IncludePaths is a list of selectors that designate paths in the repository that should // trigger the production of new Freight when changes are detected therein. - IncludePaths []string `json:"includePaths,omitempty" protobuf:"bytes,10,rep,name=includePaths"` + IncludePaths []string `json:"includePaths,omitempty"` // InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored // when connecting to the repository. This should be enabled only with great caution. - InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty" protobuf:"varint,11,opt,name=insecureSkipTLSVerify"` - // URL is the repository's URL. This is a required field. - RepoURL string `json:"repoURL" protobuf:"bytes,12,opt,name=repoURL"` + InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty"` + // URL is the repository's URL. This is a required field. Deprecated: Support for SSH URLs + // (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in + // v1.13.0. Use HTTPS URLs instead. + RepoURL string `json:"repoURL"` // SemverConstraint specifies constraints on what new tagged commits are considered in // determining the newest commit of interest. Only has effect when CommitSelectionStrategy // is SemVer. - SemverConstraint string `json:"semverConstraint,omitempty" protobuf:"bytes,13,opt,name=semverConstraint"` + SemverConstraint string `json:"semverConstraint,omitempty"` + // An optional date (RFC 3339) that limits commit discovery to commits at or after this + // date. When specified, discovery stops upon reaching a commit older than this date. When + // left unspecified, there is no cutoff. + Since *metav1.Time `json:"since,omitempty"` // StrictSemvers specifies whether only "strict" semver tags should be considered. A // "strict" semver tag contains ALL of major, minor, and patch version components. Only has // effect when CommitSelectionStrategy is SemVer. - StrictSemvers *bool `json:"strictSemvers,omitempty" protobuf:"varint,14,opt,name=strictSemvers"` + StrictSemvers *bool `json:"strictSemvers,omitempty"` } // ImageSubscription defines a subscription to a container image repository. @@ -86,58 +97,58 @@ type ImageSubscription struct { // that are considered in determining the newest version of an image. This field is // optional. Deprecated: Use allowTagsRegexes instead. Beginning in v1.11.0, artifact // discovery will FAIL if this field is non-empty. This field will be removed in v1.13.0. - AllowTags string `json:"allowTags,omitempty" protobuf:"bytes,1,opt,name=allowTags"` + AllowTags string `json:"allowTags,omitempty"` // AllowTagsRegexes is a list of regular expressions that can optionally be used to limit // the image tags that are considered in determining the newest revision of an image. This // field is optional. - AllowTagsRegexes []string `json:"allowTagsRegexes,omitempty" protobuf:"bytes,2,rep,name=allowTagsRegexes"` + AllowTagsRegexes []string `json:"allowTagsRegexes,omitempty"` // CacheByTag specifies whether to cache image metadata by tag. This can improve performance // but may lead to stale data if mutable tags are used. - CacheByTag bool `json:"cacheByTag,omitempty" protobuf:"varint,3,opt,name=cacheByTag"` + CacheByTag bool `json:"cacheByTag,omitempty"` // Constraint specifies ImageSelectionStrategy-specific constraints on what new image // revisions are permissible. Acceptable values for this field vary contextually by // ImageSelectionStrategy. The field is optional for some strategies. Others either require // it or ignore it. For strategies that treat this field as optional, specifying no value // means "no constraints." - Constraint string `json:"constraint,omitempty" protobuf:"bytes,4,opt,name=constraint"` + Constraint string `json:"constraint,omitempty"` // DiscoveryLimit is an optional limit on the number of image references that can be // discovered for this subscription. The limit is applied after filtering images based on // the AllowTagsRegexes and IgnoreTagsRegexes fields. When left unspecified, the field is // implicitly treated as if its value were "20". The upper limit for this field is 100. - DiscoveryLimit int64 `json:"discoveryLimit,omitempty" protobuf:"varint,5,opt,name=discoveryLimit"` + DiscoveryLimit int64 `json:"discoveryLimit,omitempty"` // IgnoreTags is a list of tags that must be ignored when determining the newest version of // an image. No regular expressions or glob patterns are supported yet. This field is // optional. Deprecated: Use ignoreTagsRegexes instead. Beginning in v1.11.0, artifact // discovery will FAIL if this field is non-empty. This field will be removed in v1.13.0. - IgnoreTags []string `json:"ignoreTags,omitempty" protobuf:"bytes,6,rep,name=ignoreTags"` + IgnoreTags []string `json:"ignoreTags,omitempty"` // IgnoreTagsRegexes is a list of regular expressions that can optionally be used to exclude // tags from consideration when determining the newest revision of an image. This field is // optional. - IgnoreTagsRegexes []string `json:"ignoreTagsRegexes,omitempty" protobuf:"bytes,7,rep,name=ignoreTagsRegexes"` + IgnoreTagsRegexes []string `json:"ignoreTagsRegexes,omitempty"` // ImageSelectionStrategy specifies the rules for how to identify the newest version of the // image specified by the RepoURL field. This field is optional. When left unspecified, the // field is implicitly treated as if its value were "SemVer". Accepted values: "Digest", // "Lexical", "NewestBuild", "SemVer". - ImageSelectionStrategy ImageSelectionStrategy `json:"imageSelectionStrategy,omitempty" protobuf:"bytes,8,opt,name=imageSelectionStrategy"` + ImageSelectionStrategy ImageSelectionStrategy `json:"imageSelectionStrategy,omitempty"` // InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored // when connecting to the repository. This should be enabled only with great caution. - InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty" protobuf:"varint,9,opt,name=insecureSkipTLSVerify"` + InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty"` // Platform is a string of the form / that limits the tags that can be considered // when searching for new versions of an image. This field is optional. When left // unspecified, it is implicitly equivalent to the OS/architecture of the Kargo controller. // Care should be taken to set this value correctly in cases where the image will run on a // Kubernetes node with a different OS/architecture than the Kargo controller. - Platform string `json:"platform,omitempty" protobuf:"bytes,10,opt,name=platform"` + Platform string `json:"platform,omitempty"` // RepoURL specifies the URL of the image repository to subscribe to. The value in this // field MUST NOT include an image tag. This field is required. - RepoURL string `json:"repoURL" protobuf:"bytes,11,opt,name=repoURL"` + RepoURL string `json:"repoURL"` // StrictSemvers specifies whether only "strict" semver tags should be considered. A // "strict" semver tag is one containing ALL of major, minor, and patch version components. // This is enabled by default, but only has any effect when the ImageSelectionStrategy is // SemVer. This should be disabled cautiously, as it is not uncommon to tag container images // with short Git commit hashes, which could be mistaken for a semver string containing the // major version number only. - StrictSemvers *bool `json:"strictSemvers,omitempty" protobuf:"varint,12,opt,name=strictSemvers"` + StrictSemvers *bool `json:"strictSemvers,omitempty"` } // CommitSelectionStrategy specifies the rules for how to identify the newest commit of diff --git a/charts/kargo/README.md b/charts/kargo/README.md index 9af22a4470..b6d475ba3d 100644 --- a/charts/kargo/README.md +++ b/charts/kargo/README.md @@ -198,6 +198,7 @@ the Kargo controller is running. | `controller.images.registries.rateLimit` | defines the rate limit in requests-per-second (on a per registry basis) that will be voluntarily enforced client-side for all interactions with container image registries. The default limit is very low, but tune this setting with great caution. Turning it up is not a guarantee of improved Warehouse performance. When registries begin enforcing rate limits because the client is not, the resulting errors may degrade performance worse than voluntarily observing a more conservative rate limit. | `20` | | `controller.images.cache.cacheByTagPolicy` | establishes a policy regarding the caching of container image metadata using tags as keys in order to realize a performance boost. Doing so is safest when it is known that image tags are immutable (never overwritten). Permissible values are: "Forbid" (no caching by tag; silently enforced), "Allow" (subscriptions MAY opt-in to caching by tag), "Require" (subscriptions MUST opt-in to caching by tag; effectively this is developer acknowledgement of the cache by tag behavior), "Force" (caching by tag is silently enforced). | `Allow` | | `controller.images.cache.maxEntries` | specifies the maximum number of entries in the internal image metadata cache. | `100000` | +| `controller.images.push.maxArtifactSize` | The maximum size (in bytes) for cross-repository OCI artifact pushes. Defaults to 1 GiB (1073741824). Set to 0 to block all cross-repo pushes, or -1 to disable the limit. | `1073741824` | | `controller.argocd.integrationEnabled` | Specifies whether Argo CD integration is enabled. When not enabled, the controller will not watch Argo CD Application resources or factor Application health and sync state into determinations of Stage health. Argo CD-based promotion mechanisms will also fail. When enabled, the controller will perform a sanity check at startup. If Argo CD CRDs are not found, the controller will proceed as if this integration had been explicitly disabled. Explicitly disabling is still preferable if this integration is not desired, as it will grant fewer permissions to the controller. | `true` | | `controller.argocd.namespace` | The namespace into which Argo CD is installed. | `argocd` | | `controller.argocd.watchArgocdNamespaceOnly` | Specifies whether the reconciler that watches Argo CD Applications for the sake of forcing related Stages to reconcile should only watch Argo CD Application resources residing in Argo CD's own namespace. Note: Older versions of Argo CD only supported Argo CD Application resources in Argo CD's own namespace, but newer versions support Argo CD Application resources in any namespace. This should usually be left as `false`. | `false` | diff --git a/charts/kargo/resources/crds/kargo.akuity.io_warehouses.yaml b/charts/kargo/resources/crds/kargo.akuity.io_warehouses.yaml index 2687ef99dc..94e09238a6 100644 --- a/charts/kargo/resources/crds/kargo.akuity.io_warehouses.yaml +++ b/charts/kargo/resources/crds/kargo.akuity.io_warehouses.yaml @@ -274,7 +274,8 @@ spec: type: object type: array repoURL: - description: RepoURL is the repository URL of the GitSubscription. + description: | + RepoURL is the repository URL of the GitSubscription. minLength: 1 pattern: (?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*)) type: string diff --git a/charts/kargo/templates/api/deployment.yaml b/charts/kargo/templates/api/deployment.yaml index 14d11ae57a..8d5f6f1d5a 100644 --- a/charts/kargo/templates/api/deployment.yaml +++ b/charts/kargo/templates/api/deployment.yaml @@ -45,7 +45,12 @@ spec: {{- end }} {{- end }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccount: kargo-api + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.api.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 8 }} @@ -98,7 +103,7 @@ spec: containerPort: 8080 protocol: TCP {{- if .Values.api.probes.enabled }} - livenessProbe: + startupProbe: {{- if .Values.api.tls.enabled }} exec: command: @@ -110,7 +115,20 @@ spec: grpc: port: 8080 {{- end }} + failureThreshold: 30 initialDelaySeconds: 10 + livenessProbe: + {{- if .Values.api.tls.enabled }} + exec: + command: + - /usr/local/bin/grpc_health_probe + - -addr=:8080 + - -tls + - -tls-no-verify + {{- else }} + grpc: + port: 8080 + {{- end }} readinessProbe: {{- if .Values.api.tls.enabled }} exec: diff --git a/charts/kargo/templates/controller/configmap.yaml b/charts/kargo/templates/controller/configmap.yaml index 5ab4d3ca69..0536bd3dea 100644 --- a/charts/kargo/templates/controller/configmap.yaml +++ b/charts/kargo/templates/controller/configmap.yaml @@ -35,6 +35,11 @@ data: CACHE_BY_TAG_POLICY: {{ quote .Values.controller.images.cache.cacheByTagPolicy }} MAX_IMAGE_CACHE_ENTRIES: {{ quote .Values.controller.images.cache.maxEntries }} IMAGE_REGISTRY_RATE_LIMIT: {{ quote .Values.controller.images.registries.rateLimit }} + {{- with .Values.controller.images.push }} + {{- if not (kindIs "invalid" .maxArtifactSize) }} + MAX_OCI_PUSH_ARTIFACT_SIZE: {{ int64 .maxArtifactSize | quote }} + {{- end }} + {{- end }} ARGOCD_INTEGRATION_ENABLED: {{ quote .Values.controller.argocd.integrationEnabled }} {{- if .Values.controller.argocd.integrationEnabled }} {{- if .Values.kubeconfigSecrets.argocd }} diff --git a/charts/kargo/templates/controller/deployment.yaml b/charts/kargo/templates/controller/deployment.yaml index 53da8af4bf..4f1633fd77 100644 --- a/charts/kargo/templates/controller/deployment.yaml +++ b/charts/kargo/templates/controller/deployment.yaml @@ -44,7 +44,12 @@ spec: {{- end }} {{- end }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccount: kargo-controller + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.controller.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/charts/kargo/templates/dex-server/deployment.yaml b/charts/kargo/templates/dex-server/deployment.yaml index d5c4f0a786..fb8d0d138b 100644 --- a/charts/kargo/templates/dex-server/deployment.yaml +++ b/charts/kargo/templates/dex-server/deployment.yaml @@ -27,7 +27,12 @@ spec: annotations: secret/checksum: {{ pick ( include (print $.Template.BasePath "/dex-server/secret.yaml") . | fromYaml ) "stringData" | toYaml | sha256sum }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccount: kargo-dex-server + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.api.oidc.dex.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/charts/kargo/templates/external-webhooks-server/deployment.yaml b/charts/kargo/templates/external-webhooks-server/deployment.yaml index 5bb21e2cfa..82c11babe8 100644 --- a/charts/kargo/templates/external-webhooks-server/deployment.yaml +++ b/charts/kargo/templates/external-webhooks-server/deployment.yaml @@ -44,7 +44,12 @@ spec: {{- end }} {{- end }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccount: kargo-external-webhooks-server + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.externalWebhooksServer.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/charts/kargo/templates/garbage-collector/cron-job.yaml b/charts/kargo/templates/garbage-collector/cron-job.yaml index 0ad48388c6..bc81b732b9 100644 --- a/charts/kargo/templates/garbage-collector/cron-job.yaml +++ b/charts/kargo/templates/garbage-collector/cron-job.yaml @@ -47,7 +47,12 @@ spec: {{- end }} {{- end }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccountName: kargo-garbage-collector + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.garbageCollector.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 12 }} diff --git a/charts/kargo/templates/kubernetes-webhooks-server/configmap.yaml b/charts/kargo/templates/kubernetes-webhooks-server/configmap.yaml index cd001ea9b9..dc0b2b64ec 100644 --- a/charts/kargo/templates/kubernetes-webhooks-server/configmap.yaml +++ b/charts/kargo/templates/kubernetes-webhooks-server/configmap.yaml @@ -19,5 +19,6 @@ data: {{- else }} CONTROLPLANE_USER_REGEX: {{ include "kargo.controlplane.defaultUserRegex" . }} {{- end }} + MANAGEMENT_CONTROLLER_USERNAME: system:serviceaccount:{{ .Release.Namespace }}:kargo-management-controller CACHE_BY_TAG_POLICY: {{ quote .Values.controller.images.cache.cacheByTagPolicy }} {{- end }} diff --git a/charts/kargo/templates/kubernetes-webhooks-server/deployment.yaml b/charts/kargo/templates/kubernetes-webhooks-server/deployment.yaml index 0e419c9a04..efcef36d8b 100644 --- a/charts/kargo/templates/kubernetes-webhooks-server/deployment.yaml +++ b/charts/kargo/templates/kubernetes-webhooks-server/deployment.yaml @@ -44,7 +44,12 @@ spec: {{- end }} {{- end }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccount: kargo-webhooks-server + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.webhooksServer.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/charts/kargo/templates/kubernetes-webhooks-server/webhooks.yaml b/charts/kargo/templates/kubernetes-webhooks-server/webhooks.yaml index b679043642..7e0f380052 100644 --- a/charts/kargo/templates/kubernetes-webhooks-server/webhooks.yaml +++ b/charts/kargo/templates/kubernetes-webhooks-server/webhooks.yaml @@ -254,4 +254,56 @@ webhooks: resources: ["warehouses"] operations: ["CREATE", "UPDATE"] failurePolicy: Fail +- name: replicated-resource-mutate.kargo.akuity.io + admissionReviewVersions: ["v1"] + sideEffects: None + clientConfig: + service: + namespace: {{ .Release.Namespace }} + name: kargo-webhooks-server + path: /validate-v1-replicated-resource + {{- if and (not .Values.webhooksServer.tls.selfSignedCert) .Values.webhooksServer.tls.caBundle }} + caBundle: {{ .Values.webhooksServer.tls.caBundle | b64enc }} + {{- end }} + rules: + - scope: Namespaced + apiGroups: [""] + apiVersions: ["v1"] + resources: ["secrets", "configmaps"] + operations: ["CREATE", "UPDATE"] + objectSelector: + matchExpressions: + - key: kargo.akuity.io/replicated-from + operator: Exists + namespaceSelector: + matchExpressions: + - key: kargo.akuity.io/project + operator: Exists + failurePolicy: Fail +- name: replicated-resource-delete.kargo.akuity.io + admissionReviewVersions: ["v1"] + sideEffects: None + clientConfig: + service: + namespace: {{ .Release.Namespace }} + name: kargo-webhooks-server + path: /validate-v1-replicated-resource + {{- if and (not .Values.webhooksServer.tls.selfSignedCert) .Values.webhooksServer.tls.caBundle }} + caBundle: {{ .Values.webhooksServer.tls.caBundle | b64enc }} + {{- end }} + rules: + - scope: Namespaced + apiGroups: [""] + apiVersions: ["v1"] + resources: ["secrets", "configmaps"] + operations: ["DELETE"] + objectSelector: + matchExpressions: + - key: kargo.akuity.io/replicated-from + operator: Exists + namespaceSelector: + matchExpressions: + - key: kargo.akuity.io/project + operator: Exists + failurePolicy: Ignore {{- end }} diff --git a/charts/kargo/templates/management-controller/deployment.yaml b/charts/kargo/templates/management-controller/deployment.yaml index a3fb6e1619..c1227b2064 100644 --- a/charts/kargo/templates/management-controller/deployment.yaml +++ b/charts/kargo/templates/management-controller/deployment.yaml @@ -44,7 +44,12 @@ spec: {{- end }} {{- end }} spec: + {{- if not .Values.rbac.useDefaultServiceAccount }} serviceAccount: kargo-management-controller + {{- end }} + {{- if .Values.rbac.disableAutomountServiceAccountToken }} + automountServiceAccountToken: false + {{- end }} {{- with .Values.managementController.affinity | default .Values.global.affinity }} affinity: {{- toYaml . | nindent 8 }} diff --git a/charts/kargo/values.yaml b/charts/kargo/values.yaml index 33f0721e35..0d0b0b250f 100755 --- a/charts/kargo/values.yaml +++ b/charts/kargo/values.yaml @@ -548,6 +548,9 @@ controller: cacheByTagPolicy: Allow ## @param controller.images.cache.maxEntries specifies the maximum number of entries in the internal image metadata cache. maxEntries: 100000 + push: + ## @param controller.images.push.maxArtifactSize The maximum size (in bytes) for cross-repository OCI artifact pushes. Defaults to 1 GiB (1073741824). Set to 0 to block all cross-repo pushes, or -1 to disable the limit. + maxArtifactSize: 1073741824 ## All settings relating to the Argo CD control plane this controller might ## integrate with. diff --git a/cmd/controlplane/kubernetes_webhooks.go b/cmd/controlplane/kubernetes_webhooks.go index 70cc7eb867..816b98a7c8 100644 --- a/cmd/controlplane/kubernetes_webhooks.go +++ b/cmd/controlplane/kubernetes_webhooks.go @@ -28,6 +28,7 @@ import ( "github.com/akuity/kargo/pkg/webhook/kubernetes/projectconfig" "github.com/akuity/kargo/pkg/webhook/kubernetes/promotion" "github.com/akuity/kargo/pkg/webhook/kubernetes/promotiontask" + "github.com/akuity/kargo/pkg/webhook/kubernetes/replicatedresource" "github.com/akuity/kargo/pkg/webhook/kubernetes/stage" "github.com/akuity/kargo/pkg/webhook/kubernetes/warehouse" versionpkg "github.com/akuity/kargo/pkg/x/version" @@ -149,10 +150,7 @@ func (o *kubernetesWebhooksServerOptions) run(ctx context.Context) error { if err = freight.SetupWebhookWithManager(ctx, webhookCfg, mgr); err != nil { return fmt.Errorf("setup Freight webhook: %w", err) } - if err = project.SetupWebhookWithManager( - mgr, - project.WebhookConfigFromEnv(), - ); err != nil { + if err = project.SetupWebhookWithManager(mgr, webhookCfg); err != nil { return fmt.Errorf("setup Project webhook: %w", err) } if err = projectconfig.SetupWebhookWithManager(mgr); err != nil { @@ -164,6 +162,9 @@ func (o *kubernetesWebhooksServerOptions) run(ctx context.Context) error { if err = promotiontask.SetupWebhookWithManager(mgr); err != nil { return fmt.Errorf("setup PromotionTask webhook: %w", err) } + if err = replicatedresource.SetupWebhookWithManager(webhookCfg, mgr); err != nil { + return fmt.Errorf("setup replicated resource webhook: %w", err) + } if err = stage.SetupWebhookWithManager(webhookCfg, mgr); err != nil { return fmt.Errorf("setup Stage webhook: %w", err) } diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..48cf9b5b56 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,2 @@ +ignore: +- "hack/**" \ No newline at end of file diff --git a/docs/docs/100-roadmap.md b/docs/docs/100-roadmap.md index c878490da4..432243f827 100644 --- a/docs/docs/100-roadmap.md +++ b/docs/docs/100-roadmap.md @@ -31,11 +31,29 @@ every submission. ### v1.10.0 -**Expected:** TBD +**Expected:** Mid-April, 2026 -* UI to begin transition to new API +🧬 Evolution; not revolution — apart from the usual slate of bug fixes and +performance + stability improvements, v1.10.0 is set to deliver a broad +collection of small, but meaningful quality-of-life improvements. -* Remaining scope TBD +A modest selection of anticipated highlights: + +* UI "My Projects" filter +* Path filtering for push events from Git repositories ➡️ fewer Warehouses + executing unnecessary artifact discovery cycles +* Broad range of new and improved promotion steps +* Enhanced trust model for commits made by Kargo +* New Helm chart options to support common operational concerns + +v1.10.0 will also include a partial UI transition from the deprecated gRPC API +to new RESTful API. + +## Upcoming + +### v1.11.0 + +**Expected:** Mid-June, 2026 ## Completed diff --git a/docs/docs/40-operator-guide/40-security/40-managing-secrets.md b/docs/docs/40-operator-guide/40-security/40-managing-secrets.md index f7b7250d3b..4ddf20b740 100644 --- a/docs/docs/40-operator-guide/40-security/40-managing-secrets.md +++ b/docs/docs/40-operator-guide/40-security/40-managing-secrets.md @@ -137,20 +137,20 @@ SSH-style URLs of the form `git@github.com:example/repo.git`), the key `sshPrivateKey` in the `Secret`'s `data` block may have as its value a PEM-encoded SSH private key. -:::warning[Not Recommended] +:::warning[Deprecated] -While an SSH private key is an adequate credential for basic Git operations that -are formally part of the Git specification (i.e. `clone`, `checkout`, etc.), the -proprietary APIs offered by the major git hosting platforms (e.g. GitHub or +Support for SSH URLs and SSH private keys is **deprecated as of v1.10.0** and +**scheduled for removal in v1.13.0**. + +The proprietary APIs offered by the major Git hosting platforms (e.g. GitHub or GitLab) to enable actions such as opening or closing pull requests are invariably HTTP-based and therefore cannot use an SSH private key for -authentication. +authentication. This forces users who rely on SSH to maintain a second set of +credentials (e.g. a personal access token) for API operations. -If your Projects will create or merge pull request, which is common, rather than -using an SSH private key for basic operations and a second credential, such as a -personal access token, for API calls, the Kargo team recommends using a single -credential that works for both -- and an SSH private key is not such a -credential. +Using HTTPS URLs with a single token-based credential that works for both +standard Git operations and provider API calls is simpler and more secure. Users +should migrate to HTTPS URLs before v1.13.0. ::: @@ -240,6 +240,94 @@ this manner. ::: +### Replicating Shared Resources to Project Namespaces + +By default, shared secrets are accessed _indirectly_ -- repository credentials +are matched automatically by URL, and generic credentials are accessed through +the `sharedSecret()` expression function. In both cases, the `Secret` resources +themselves remain in the shared resources namespace and their values are never +copied into Project namespaces. + +In some situations, however, workloads running in a Project namespace may need +_direct_ access to a `Secret` or `ConfigMap` -- for example, as a volume mount +or environment variable reference. For these cases, Kargo can automatically +**replicate** resources from the shared resources namespace into every Project +namespace. + +#### Enabling Replication + +To opt a resource into replication, annotate it with +`kargo.akuity.io/replicate-to: "*"`: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: shared-tls-cert + namespace: kargo-shared-resources + labels: + kargo.akuity.io/cred-type: generic + annotations: + kargo.akuity.io/replicate-to: "*" +data: + tls.crt: + tls.key: +``` + +`ConfigMap` resources work the same way: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: shared-config + namespace: kargo-shared-resources + annotations: + kargo.akuity.io/replicate-to: "*" +data: + settings.yaml: | + key: value +``` + +:::info + +Currently, the only supported value for the `kargo.akuity.io/replicate-to` +annotation is `"*"`, which replicates to all Project namespaces. Selective +replication to specific Projects is not yet supported. + +::: + +:::info + +Only `Secret` resources labeled with `kargo.akuity.io/cred-type` (i.e. +recognized as credentials) are eligible for replication. Arbitrary `Secret` +resources without this label will not be replicated, even if annotated with +`kargo.akuity.io/replicate-to`. All `ConfigMap` resources in the shared +resources namespace are eligible. + +::: + +#### How Replication Works + +When a resource in the shared resources namespace is annotated for replication, +Kargo's management controller automatically creates a copy of it in every +Project namespace. These copies are kept in sync: any change to the source +resource is propagated to all replicas. If the source is deleted, all replicas +are cleaned up. + +Replicated resources are labeled with `kargo.akuity.io/replicated-from` (set to +the name of the source resource) so they can be easily identified. + +#### Immutability of Replicated Resources + +Replicated copies are **immutable to end users.** A validating webhook prevents +any user from modifying or deleting them. Only Kargo's management controller is +permitted to update or remove replicated resources. + +To change the contents of a replicated resource, modify the **source** resource +in the shared resources namespace. The change will propagate automatically to +all replicas. + ### Configuring the Shared Resources Namespace The **shared resources namespace**, by default, is `kargo-shared-resources`. diff --git a/docs/docs/50-user-guide/20-how-to-guides/30-working-with-warehouses.md b/docs/docs/50-user-guide/20-how-to-guides/30-working-with-warehouses.md index 79d1cfcea2..157cb233a3 100644 --- a/docs/docs/50-user-guide/20-how-to-guides/30-working-with-warehouses.md +++ b/docs/docs/50-user-guide/20-how-to-guides/30-working-with-warehouses.md @@ -329,6 +329,20 @@ Git repository subscriptions can be defined using the following fields: subscription. ::: +- `since`: An optional date in RFC 3339 format (e.g. `2026-01-01T00:00:00Z`) + that bounds how far back commit discovery will look. When specified, only + commits at or after this date are considered. When left unspecified, there is + no date cutoff. + + :::note + + `since` only has effect when `commitSelectionStrategy` is + `NewestFromBranch` (or unspecified, since `NewestFromBranch` is the default). + It is particularly useful for large repositories with long histories where + `discoveryLimit` alone is not sufficient to prevent slow lookbacks. + + ::: + - `insecureSkipTLSVerify`: Set to `true` to disable validation of the repository's TLS certificate. @@ -761,6 +775,14 @@ Helm chart repository subscriptions can be defined using the following fields: The default is `20`. +- `insecureSkipTLSVerify`: Set to `true` to disable validation of the + repository's TLS certificate. + + :::warning + + This is a security risk and should only be used in development environments. + ::: + Example: ```yaml diff --git a/docs/docs/50-user-guide/50-security/30-managing-secrets.md b/docs/docs/50-user-guide/50-security/30-managing-secrets.md index e047483543..afd86c5e1a 100644 --- a/docs/docs/50-user-guide/50-security/30-managing-secrets.md +++ b/docs/docs/50-user-guide/50-security/30-managing-secrets.md @@ -96,20 +96,20 @@ SSH-style URLs of the form `git@github.com:example/repo.git`), the key `sshPrivateKey` in the `Secret`'s `data` block may have as its value a PEM-encoded SSH private key. -:::warning[Not Recommended] +:::warning[Deprecated] -While an SSH private key is an adequate credential for basic Git operations that -are formally part of the Git specification (i.e. `clone`, `checkout`, etc.), the -proprietary APIs offered by the major git hosting platforms (e.g. GitHub or +Support for SSH URLs and SSH private keys is **deprecated as of v1.10.0** and +**scheduled for removal in v1.13.0**. + +The proprietary APIs offered by the major Git hosting platforms (e.g. GitHub or GitLab) to enable actions such as opening or closing pull requests are invariably HTTP-based and therefore cannot use an SSH private key for -authentication. +authentication. This forces users who rely on SSH to maintain a second set of +credentials (e.g. a personal access token) for API operations. -If your Project will create or merge pull request, which is common, rather than -using an SSH private key for basic Git operations and a second credential, such -as a personal access token, for API calls, the Kargo team recommends using a -single credential that works for both -- and an SSH private key is not such a -credential. +Using HTTPS URLs with a single token-based credential that works for both +standard Git operations and provider API calls is simpler and more secure. Users +should migrate to HTTPS URLs before v1.13.0. ::: @@ -600,7 +600,7 @@ in a `Secret` resource. Both of these options rely upon extensive external configuration that likely requires the assistance of Kargo's operator and an AWS account administrator, and as such, further details are covered in the -[Managing Secrets](../../40-operator-guide/40-security/40-managing-secrets.md) +[Ambient Credentials](../../40-operator-guide/40-security/50-ambient-credentials.md) section of the Operator Guide. ::: diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/argocd-wait.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/argocd-wait.md new file mode 100644 index 0000000000..ac59839c89 --- /dev/null +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/argocd-wait.md @@ -0,0 +1,160 @@ +--- +sidebar_label: argocd-wait +description: Waits for one or more Argo CD Application resources to reach desired conditions. +--- + +# `argocd-wait` + +`argocd-wait` waits for one or more Argo CD `Application` resources to reach +desired conditions. `Application`s can be selected either by exact name or by +using label selectors to match multiple `Application`s at once. + +This step is useful when a sync is triggered by means other than an +[`argocd-update` step](argocd-update.md) — for example, when an external system +or a human operator triggers the sync — and you want a `Promotion` to wait for +the `Application` to become healthy and synced before proceeding. + +:::note + +Unlike [`argocd-update`](argocd-update.md), `argocd-wait` does **not** require +the `kargo.akuity.io/authorized-stage` annotation on the `Application`. It can +wait for any `Application` that the Kargo controller has read access to. + +::: + +## Application Selection + +The `argocd-wait` step supports two methods for selecting Argo CD `Application` +resources: + +1. **By Name**: Specify an exact application name using the `name` field. +2. **By Label Selector**: Match one or more `Application`s using the `selector` + field with label-based criteria. + +These two methods are mutually exclusive — you must specify either `name` or +`selector`, but not both. + +See the [`argocd-update` documentation](argocd-update.md#application-selection) +for a full description of both selection methods including label selector syntax. + +## Wait Conditions + +The `waitFor` field controls which conditions must be satisfied before the step +succeeds. Supported values are: + +| Value | Description | +|-------|-------------| +| `health` | `Application` health is `Healthy`. | +| `sync` | `Application` sync status is `Synced`. | +| `operation` | No operation (e.g. sync) is currently in progress. | +| `suspended` | `Application` health is `Suspended`. | +| `degraded` | `Application` health is `Degraded`. | + +When `waitFor` is omitted, it defaults to `[health, sync, operation]`. + +The health-related values (`health`, `suspended`, `degraded`) are OR'd: the +health check passes if _any_ of the specified health conditions is met. All +other conditions (`sync`, `operation`) are AND'd with the result. + +:::note + +If `waitFor` includes `health` and an `Application` transitions to `Degraded` +from a state that was neither `Degraded` nor `Unknown`, the step fails +immediately rather than continuing to wait. This degradation detection prevents +a `Promotion` from hanging indefinitely on an `Application` that regressed +during the wait. + +::: + +## Configuration + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `apps` | `[]object` | Y | Describes Argo CD `Application` resources to wait for. At least one must be specified. | +| `apps[].name` | `string` | N | The name of the Argo CD `Application`. Mutually exclusive with `selector`. Either `name` or `selector` must be specified. __Note:__ Expressions in this field are limited to accessing `ctx` and `vars` and may not access `secrets` or any Freight. This is because templates in this field are, at times, evaluated outside the context of an actual `Promotion` for the purposes of building an index. In practice, this restriction does not prove to be especially limiting. | +| `apps[].namespace` | `string` | N | The namespace of the Argo CD `Application` resource(s) to wait for. If left unspecified, the namespace will be the Kargo controller's configured default — typically `argocd`. __Note:__ This field is subject to the same restrictions as the `name` field. See above. | +| `apps[].selector` | `object` | N | Label selector for matching one or more Argo CD `Application` resources. Mutually exclusive with `name`. Either `name` or `selector` must be specified. | +| `apps[].selector.matchLabels` | `map[string]string` | N | A map of label key-value pairs. All specified labels must match for an `Application` to be selected (AND logic). At least one of `matchLabels` or `matchExpressions` must be specified. | +| `apps[].selector.matchExpressions` | `[]object` | N | A list of label selector requirements. All expressions must be satisfied for an `Application` to be selected. At least one of `matchLabels` or `matchExpressions` must be specified. | +| `apps[].selector.matchExpressions[].key` | `string` | Y | The label key that the selector applies to. | +| `apps[].selector.matchExpressions[].operator` | `string` | Y | The operator to use for matching. Valid values: `In`, `NotIn`, `Exists`, `DoesNotExist`. | +| `apps[].selector.matchExpressions[].values` | `[]string` | N | An array of string values. Required when `operator` is `In` or `NotIn`. Must be empty when `operator` is `Exists` or `DoesNotExist`. | +| `apps[].waitFor` | `[]string` | N | Conditions to wait for. Valid values: `health`, `sync`, `operation`, `suspended`, `degraded`. Defaults to `[health, sync, operation]` when omitted. | + +## Examples + +### Common Usage + +In this example, `argocd-wait` is used after [`argocd-update`](argocd-update.md) +to confirm that the `Application` has reached a healthy and synced state before +the `Promotion` is marked as succeeded. + +```yaml +steps: +# Clone, render manifests, commit, push, etc... +- uses: git-commit + as: commit + config: + path: ./out + message: ${{ outputs['update-image'].commitMessage }} +- uses: git-push + config: + path: ./out +- uses: argocd-update + config: + apps: + - name: my-app + sources: + - repoURL: https://github.com/example/repo.git + desiredRevision: ${{ outputs.commit.commit }} +- uses: argocd-wait + config: + apps: + - name: my-app +``` + +### Waiting Only for Operation Completion + +This example waits only for any in-progress sync operation to finish, without +requiring the `Application` to be healthy or synced to a specific revision. + +```yaml +steps: +- uses: argocd-wait + config: + apps: + - name: my-app + waitFor: + - operation +``` + +### Waiting with Label Selector + +This example waits for all `Application`s with a given label to become healthy, +synced, and idle — useful when multiple `Application`s are updated together. + +```yaml +steps: +- uses: argocd-wait + config: + apps: + - selector: + matchLabels: + environment: staging +``` + +### Waiting for a Suspended Application + +This example waits for an `Application` to reach the `Suspended` health state, +which can serve as a manual gate: a human suspends the `Application` to pause +a rollout, and this step waits until that state is observed. + +```yaml +steps: +- uses: argocd-wait + config: + apps: + - name: my-app + waitFor: + - suspended +``` diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-clone.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-clone.md index 3c0e938423..095ac65828 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-clone.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-clone.md @@ -29,7 +29,7 @@ system to access the git repos. | Name | Type | Required | Description | |------|------|----------|-------------| -| `repoURL` | `string` | Y | The URL of a remote Git repository to clone. | +| `repoURL` | `string` | Y | The URL of a remote Git repository to clone. **Deprecated:** Support for SSH URLs (`ssh://` and SCP-style `git@host:path`) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead. | | `insecureSkipTLSVerify` | `boolean` | N | Whether to bypass TLS certificate verification when cloning (and for all subsequent operations involving this clone). Setting this to `true` is highly discouraged in production. | | `author` | `[]object` | N | Default authorship information for any commits made to the cloned repository. If provided, this overrides any system-level defaults. Note: Configuration of the [`git-commit`](./git-commit.md) step can override this information. | | `author.name` | `string` | Y | The committer's name. | diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md index 2eba549e72..871f857436 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md @@ -15,14 +15,14 @@ description: Merges an open pull request. This step only executes synchronous merges. It can neither initiate an asynchronous merge by placing a PR on a merge queue (or similar), nor can it recognize when an open PR is already _in_ a merge queue (having been placed -there by someone or something else), and thus cannot wait for an aynchronous +there by someone or something else), and thus cannot wait for an asynchronous merge in-progress to complete. ::: :::caution -__GitHub__ repositories can be configured with branch protection rules that +**GitHub** repositories can be configured with branch protection rules that require PRs to be merged via a merge queue. When such a rule is in place, the results of the `git-merge-pr` step attempting a synchronous merge will depend upon permissions. With sufficient permissions to bypass branch protection rules, @@ -40,10 +40,11 @@ system to access the git repos. | Name | Type | Required | Description | | ----------------------- | --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `repoURL` | `string` | Y | The URL of a remote Git repository. | +| `repoURL` | `string` | Y | The URL of a remote Git repository. **Deprecated:** Support for SSH URLs (`ssh://` and SCP-style `git@host:path`) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead. | | `provider` | `string` | N | The name of the Git provider to use. Currently `azure`, `bitbucket`, `gitea`, `github`, and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. | | `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. | | `prNumber` | `integer` | Y | The pull request number to merge. | +| `mergeMethod` | `string` | N | The merge method to use when merging the pull request. The supported methods are provider-specific; refer to the [Merge Method](#merge-method) section. | | `wait` | `boolean` | N | If `true`, the step will return a running status instead of failing when the PR is not yet mergeable. The merge will be retried on the next reconciliation until it succeeds or times out. Default is `false`. | :::warning @@ -52,6 +53,19 @@ The `wait` option is unreliable for repositories hosted by Bitbucket due to API ::: +### Merge Method + +The table below documents the supported merge methods/strategies for each of the +currently supported Git hosting providers. + +| Provider | Supported Methods | Default | +| -------- | ----------------- | ------- | +| Azure |
  • `noFastForward`
  • `rebase`
  • `rebaseMerge`
  • `squash`
| First allowed strategy per the target branch's merge type policy; merge commit if no policy is configured | +| BitBucket | Client does not yet support specifying a merge strategy | The repository's configured default merge strategy | +| Gitea |
  • `fast-forward-only`
  • `manually-merged`
  • `merge`
  • `rebase`
  • `rebase-merge`
  • `squash`
| `merge` | +| GitHub |
  • `merge`
  • `rebase`
  • `squash`
| `merge` | +| GitLab |
  • `merge`
  • `squash`
| Defers to the merge request and project-level squash settings | + ## Output | Name | Type | Description | @@ -88,3 +102,18 @@ steps: prNumber: 42 wait: true ``` + +### Specifying a Merge Method + +This example demonstrates merging a pull request with a specific merge method. +Refer to the [Merge Method](#merge-method) section for supported values per +provider. + +```yaml +steps: +- uses: git-merge-pr + config: + repoURL: https://github.com/example/repo.git + prNumber: 42 + mergeMethod: squash +``` diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md index 3c3c14553e..e38a2c3433 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-open-pr.md @@ -22,7 +22,7 @@ system to access the git repos. | Name | Type | Required | Description | |------|------|----------|-------------| -| `repoURL` | `string` | Y | The URL of a remote Git repository. | +| `repoURL` | `string` | Y | The URL of a remote Git repository. **Deprecated:** Support for SSH URLs (`ssh://` and SCP-style `git@host:path`) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead. | | `provider` | `string` | N | The name of the Git provider to use. Currently `azure`, `bitbucket`, `gitea`, `github`, and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. | | `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. | | `sourceBranch` | `string` | Y | Specifies the source branch for the pull request. | diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-wait-for-pr.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-wait-for-pr.md index 20edcc57ad..e2689b6d77 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-wait-for-pr.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-wait-for-pr.md @@ -18,7 +18,7 @@ system to access the git repos. | Name | Type | Required | Description | |------|------|----------|-------------| -| `repoURL` | `string` | Y | The URL of a remote Git repository. | +| `repoURL` | `string` | Y | The URL of a remote Git repository. **Deprecated:** Support for SSH URLs (`ssh://` and SCP-style `git@host:path`) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead. | | `provider` | `string` | N | The name of the Git provider to use. Currently `azure`, `bitbucket`, `gitea`, `github`, and `gitlab` are supported. Kargo will try to infer the provider if it is not explicitly specified. | | `insecureSkipTLSVerify` | `boolean` | N | Indicates whether to bypass TLS certificate verification when interfacing with the Git provider. Setting this to `true` is highly discouraged in production. | | `prNumber` | `integer` | Y | The pull request number to wait for. | diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-parse.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-parse.md index a4bf0e8e89..065a0085fd 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-parse.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-parse.md @@ -47,7 +47,7 @@ its configuration. In this example, a values file is parsed to find the container image tag. After cloning the repository and clearing the output directory, the `json-parse` -step parses `values.json` to extract the image tag from the `Freight` being +step parses `config.json` to extract the image tag from the `Freight` being promoted. Using dot notation (`image.tag`), it extracts the nested value from the JSON file. @@ -71,7 +71,7 @@ steps: - uses: json-parse as: values config: - path: './src/charts/my-chart/values.json' + path: './src/config.json' outputs: - name: imageTag fromExpression: image.tag @@ -83,10 +83,7 @@ Given the sample input JSON: ```json { "image": { - "tag": "latest" - }, - "rbac": { - "installClusterRoles": true + "tag": "v1.2.3" } } ``` @@ -96,6 +93,6 @@ The step would produce the following | Name | Type | Value | |------|------|-------| -| `imageTag` | `string` | `latest` | +| `imageTag` | `string` | `v1.2.3` | [expr-lang]: https://expr-lang.org diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-update.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-update.md index 1db8c86b23..98996ba47e 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-update.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/json-update.md @@ -5,22 +5,72 @@ description: Updates the values of specified keys in any JSON file. # `json-update` -`json-update` updates the values of specified keys in any JSON file. +`json-update` updates the values of specified keys in any JSON file, in-place, +without disruption to existing formatting choices. + +:::note[Limitations] + +`json-update` updates scalar values only. + +::: ## Configuration | Name | Type | Required | Description | |------|------|----------|-------------| -| `path` | `string` | Y | Path to a JSON file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. | | +| `path` | `string` | Y | Path to a JSON file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. | | `updates` | `[]object` | Y | The details of changes to be applied to the file. At least one must be specified. | -| `updates[].key` | `string` | Y | The key to update within the file. For nested values, use a JSON dot notation path. See [sjson documentation](https://github.com/tidwall/sjson) for supported syntax. | -| `updates[].value`| `any` | Y | The new value for the key. Typically specified using an expression. Supports strings, numbers, booleans, arrays, and objects. | +| `updates[].key` | `string` | Y | The key to update within the file. For nested values, use a JSON dot notation path. See [sjson documentation](https://github.com/tidwall/sjson?tab=readme-ov-file#path-syntax) for supported syntax. | +| `updates[].value`| `any` | Y | The new scalar value for the key. Typically specified using an expression. Supports strings, numbers, and booleans. | ## Output | Name | Type | Description | |------|------|-------------| -| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit` step](git-commit.md) reference this output and aggregate this commit message fragment with others like it to build a comprehensive commit message that describes all changes. | +| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit` step](git-commit.md) will reference this output and aggregate this commit message fragment with others like it to build a comprehensive commit message that describes all changes. | + +## Writing Keys + +**Nested keys:** + +```json +{ + "image": { + "tag": "v1.0.0" + } +} +``` + +Update key: `image.tag` + +**Keys with literal dots:** + +```json +{ + "example.com/version": "v1.0.0" +} +``` + +Update key: `example\.com/version` + +**Sequences:** + +```json +{ + "containers": [ + { "name": "my-app", "image": "my-app:v1.0" } + ] +} +``` + +Update key: `containers.0.image` + +:::note + +See the [sjson path syntax documentation](https://github.com/tidwall/sjson?tab=readme-ov-file#path-syntax) +for the full description of the syntax. + +::: ## Examples @@ -30,19 +80,10 @@ In this example, a JSON file's values are updated according to changes in a container image tag. After cloning the repository and clearing the output directory, the `json-update` step updates the `image.tag` field in `configs/settings.json` to match the tag of the image being promoted. -This demonstrates how to modify nested JSON values using dot notation -(similar to how you would reference nested object properties). -This pattern is commonly used when managing configuration files that need to +This pattern is commonly seen when managing configuration files that need to stay synchronized with deployed container versions. -:::info - -For more information on `imageFrom` and expressions, see the -[Expressions](../40-expressions.md#functions) documentation. - -::: - ```yaml vars: - name: gitRepo @@ -57,14 +98,21 @@ steps: - branch: stage/${{ ctx.stage }} create: true path: ./out - - uses: git-clear - config: - path: ./out +- uses: git-clear + config: + path: ./out - uses: json-update config: - path: configs/settings.json + path: ./src/configs/settings.json updates: - key: image.tag value: ${{ imageFrom("my/image").Tag }} # Render manifests to ./out, commit, push, etc... ``` + +:::info + +For more information on `imageFrom()` and expressions used in the example above, +see the [Expressions](../40-expressions.md#functions) documentation. + +::: diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/oci-push.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/oci-push.md new file mode 100644 index 0000000000..b1b3827bfe --- /dev/null +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/oci-push.md @@ -0,0 +1,159 @@ +--- +sidebar_label: oci-push +description: Copies or retags OCI artifacts (container images, Helm charts) between registries. +--- + +# `oci-push` + +`oci-push` copies or retags OCI artifacts between registries or within the same +registry. This step supports container images and Helm charts stored in OCI +registries, making it useful for promoting artifacts through a pipeline — for +example, retagging an image with a release version or copying it to a production +registry. Multi-arch image indexes are copied in full. Registry authentication +is supported for both source and destination. + +## Configuration + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `srcRef` | `string` | Y | Reference to the source OCI artifact. Supports both tag format `registry/repository:tag` and digest format `registry/repository@sha256:digest`. For Helm OCI artifacts, the `oci://` prefix is supported (e.g., `oci://registry/repository:tag`) and will use Helm-specific credential lookup. | +| `destRef` | `string` | Y | Destination reference including tag (e.g., `registry/repository:tag`). For Helm OCI artifacts, the `oci://` prefix is supported. For retag-in-place, use the same repository as `srcRef` with the new tag. | +| `annotations` | `object` | N | Annotations to set on the destination artifact. Keys may be prefixed with `index:` or `manifest:` to scope them to the index or image manifest respectively. Unprefixed keys default to the image manifest. For single images, `index:`-prefixed keys are ignored. Values support expressions. Existing annotations on the source artifact are preserved; specified annotations are added or overwritten. | +| `insecureSkipTLSVerify` | `boolean` | N | Whether to skip TLS verification for both source and destination registries. Defaults to `false`. | + +## Outputs + +| Name | Type | Description | +|------|------|-------------| +| `image` | `string` | Full destination reference with tag (e.g., `prod.example.com/myapp:v1.2.3`). | +| `digest` | `string` | Digest of the pushed artifact (e.g., `sha256:abc123...`). | +| `tag` | `string` | Tag that was applied, parsed from `destRef`. | + +## Limits + +The total compressed size of the artifact (config blob and all layers) must not +exceed 1 GiB (or as configured by your administrator). For multi-arch image indexes, this includes the sum across all +child images. Exceeding this limit causes a terminal (non-retryable) error. + +This limit is not enforced when `srcRef` and `destRef` refer to the same +repository (i.e. retagging within the same registry and path), since no blob +transfer occurs in that case. + +## Examples + +### Retagging an Image with a Release Version + +In this example, a dedicated "release" Stage sits downstream from a testing +Stage. When verified Freight is promoted into this Stage, its single step retags +the image with a semver release version in the same repository. Because the +source and destination are in the same repository, this is a lightweight +metadata operation with no blob transfer. + +```yaml +steps: +- uses: oci-push + config: + srcRef: registry.example.com/myapp@${{ imageFrom("registry.example.com/myapp").digest }} + destRef: registry.example.com/myapp:v1.2.3 +``` + +### Copying to a Production Registry + +In this example, a verified image is copied from a sandbox registry to a +production registry, preserving its original tag. Credentials for each registry +are resolved independently. + +```yaml +steps: +- uses: oci-push + config: + srcRef: sandbox.example.com/myapp@${{ imageFrom("sandbox.example.com/myapp").digest }} + destRef: prod.example.com/myapp:${{ imageFrom("sandbox.example.com/myapp").tag }} +``` + +### Copying to a Per-Stage Repository + +In this example, images are copied to stage-specific repositories (e.g., for +garbage collection policies that limit images per repository). The step output +is then used by `kustomize-set-image` to update the deployment manifest. + +```yaml +steps: +- uses: oci-push + as: push-to-stage + config: + srcRef: registry.example.com/widget-service@${{ imageFrom("registry.example.com/widget-service").digest }} + destRef: registry.example.com/widget-service/${{ ctx.stage }}:${{ imageFrom("registry.example.com/widget-service").tag }} +- uses: kustomize-set-image + config: + path: ./out + images: + - image: registry.example.com/widget-service + newName: registry.example.com/widget-service/${{ ctx.stage }} + digest: ${{ outputs["push-to-stage"].digest }} +``` + +### Promoting an OCI Helm Chart + +In this example, a Helm chart stored in an OCI registry is copied to a +production registry. The `oci://` prefix ensures Helm-specific +[credentials](../../50-security/30-managing-secrets.md) are used for +authentication. + +```yaml +steps: +- uses: oci-push + config: + srcRef: oci://registry.example.com/charts/my-app:${{ chartFrom("oci://registry.example.com/charts/my-app").version }} + destRef: oci://prod-registry.example.com/charts/my-app:${{ chartFrom("oci://registry.example.com/charts/my-app").version }} +``` + +### Adding Annotations + +In this example, OCI annotations are stamped onto the destination manifest +during the push. This can be used to record provenance metadata such as the +source repository or Kargo promotion name. + +```yaml +steps: +- uses: oci-push + config: + srcRef: registry.example.com/myapp@${{ imageFrom("registry.example.com/myapp").digest }} + destRef: registry.example.com/myapp:v1.2.3 + annotations: + org.opencontainers.image.source: "https://github.com/example/myapp" + io.kargo.promotion: ${{ ctx.promotion }} +``` + +### Scoped Annotations for Multi-Arch Images + +When pushing image indexes (multi-arch), annotation keys can be prefixed with +`index:` or `manifest:` to control where they are applied. Unprefixed keys +default to the image manifest. + +```yaml +steps: +- uses: oci-push + config: + srcRef: registry.example.com/myapp@${{ imageFrom("registry.example.com/myapp").digest }} + destRef: registry.example.com/myapp:v1.2.3 + annotations: + org.opencontainers.image.source: "https://github.com/example/myapp" + index:org.opencontainers.image.revision: ${{ commitFrom("https://github.com/example/myapp").id }} + manifest:org.opencontainers.image.description: "my app image" +``` + +### Copying with TLS Verification Disabled + +In this example, an artifact is copied between registries with self-signed +certificates by disabling TLS verification. This should only be used in +development or testing environments where the registries are trusted. + +```yaml +steps: +- uses: oci-push + config: + srcRef: internal-registry.local/myapp:latest + destRef: staging-registry.local/myapp:latest + insecureSkipTLSVerify: true +``` diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/toml-parse.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/toml-parse.md new file mode 100644 index 0000000000..b8c6618afe --- /dev/null +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/toml-parse.md @@ -0,0 +1,100 @@ +--- +sidebar_label: toml-parse +description: Parses a TOML file and extracts values based on specified expressions. +--- + +# `toml-parse` + + + +`toml-parse` is a utility step that parses a TOML file and extracts values +using [expr-lang] expressions. + +## Configuration + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `path` | `string` | Y | Path to a TOML file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. | +| `outputs` | `[]object` | Y | A list of rules for extracting values from the parsed TOML. | +| `outputs[].name` | `string` | Y | The name of the output variable. | +| `outputs[].fromExpression` | `string` | Y | An [expr-lang] expression that can extract the value from the TOML file. Note that this expression should not be offset by `${{` and `}}`. See [examples](#examples) for more details. | + +## Expressions + +The `fromExpression` field supports [expr-lang] expressions. + +:::note + +Expressions should _not_ be offset by `${{` and `}}` to prevent pre-processing +evaluation by Kargo. The `toml-parse` step itself will evaluate these +expressions. + +::: + +An `outputs` object (a `map[string]any`) is available to these expressions. It +is structured as follows: + +| Field | Type | Description | +|-------|------|-------------| +| `outputs` | `map[string]any` | The parsed TOML object. | + +## Outputs + +The `toml-parse` step produces the outputs described by the `outputs` field in +its configuration. + +## Examples + +### Common Usage + +In this example, a TOML file is parsed to find the container image tag. After +cloning the repository and clearing the output directory, the `toml-parse` step +parses `config.toml` to extract the image tag from the `Freight` being promoted. +Using dot notation (`image.tag`), it extracts the nested value from the TOML +file. + +```yaml +vars: +- name: gitRepo + value: https://github.com/example/repo.git +steps: +- uses: git-clone + config: + repoURL: ${{ vars.gitRepo }} + checkout: + - commit: ${{ commitFrom(vars.gitRepo).ID }} + path: ./src + - branch: stage/${{ ctx.stage }} + create: true + path: ./out +- uses: git-clear + config: + path: ./out +- uses: toml-parse + as: values + config: + path: './src/config.toml' + outputs: + - name: imageTag + fromExpression: image.tag +# Render manifests to ./out, commit, push, etc... +``` + +Given the sample input TOML: + +```toml +[image] +tag = "v1.2.3" + +[rbac] +installClusterRoles = true +``` + +The step would produce the following +[outputs](../15-promotion-templates.md#step-outputs): + +| Name | Type | Value | +|------|------|-------| +| `imageTag` | `string` | `v1.2.3` | + +[expr-lang]: https://expr-lang.org diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/toml-update.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/toml-update.md new file mode 100644 index 0000000000..c87696fa09 --- /dev/null +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/toml-update.md @@ -0,0 +1,113 @@ +--- +sidebar_label: toml-update +description: Updates the values of specified keys in any TOML file. +--- + +# `toml-update` + + + +`toml-update` updates the values of specified keys in any TOML file, in-place, +without disruption to existing formatting choices. + +:::note[Limitations] + +`toml-update` updates scalar values only and can only update the values of +existing keys. + +::: + +## Configuration + +| Name | Type | Required | Description | +|------|------|----------|-------------| +| `path` | `string` | Y | Path to a TOML file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. | +| `updates` | `[]object` | Y | The details of changes to be applied to the file. At least one must be specified. | +| `updates[].key` | `string` | Y | The key to update within the file. For nested values, use dots to delimit key parts. e.g. `image.tag`. The syntax is identical to that supported by the `json-update` step and is documented in more detail [here](https://github.com/tidwall/sjson?tab=readme-ov-file#path-syntax). | +| `updates[].value` | `any` | Y | The new scalar value for the key. Typically specified using an expression. Supports strings, numbers, and booleans. | + +## Output + +| Name | Type | Description | +|------|------|-------------| +| `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit` step](git-commit.md) will reference this output and aggregate this commit message fragment with others like it to build a comprehensive commit message that describes all changes. | + +## Writing Keys + +**Nested keys:** + +```toml +[package] +version = "1.0.0" +``` + +Update key: `package.version` + +**Keys with literal dots:** + +```toml +[labels] +"example.com/version" = "1.0.0" +``` + +Update key: `labels.example\.com/version` + +**Sequences:** + +```toml +values = [1, 2, 3] +``` + +Update key: `values.1` + +:::note + +See the [sjson path syntax documentation](https://github.com/tidwall/sjson?tab=readme-ov-file#path-syntax) +for the full description of the syntax. + +::: + +## Examples + +### Common Usage + +In this example, a TOML file's values are updated according to changes in a +container image tag. After cloning the repository and clearing the output +directory, the `toml-update` step updates the `image.tag` field in +`configs/settings.toml` to match the tag of the image being promoted. + +This pattern is commonly seen when managing configuration files that need to +stay synchronized with deployed container versions. + +```yaml +vars: +- name: gitRepo + value: https://github.com/example/repo.git +steps: +- uses: git-clone + config: + repoURL: ${{ vars.gitRepo }} + checkout: + - commit: ${{ commitFrom(vars.gitRepo).ID }} + path: ./src + - branch: stage/${{ ctx.stage }} + create: true + path: ./out +- uses: git-clear + config: + path: ./out +- uses: toml-update + config: + path: ./src/configs/settings.toml + updates: + - key: image.tag + value: ${{ imageFrom("my/image").Tag }} +# Render manifests to ./out, commit, push, etc... +``` + +:::info + +For more information on `imageFrom()` and expressions used in the example above, +see the [Expressions](../40-expressions.md#functions) documentation. + +::: diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-parse.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-parse.md index 4ebc6a1a2c..f39ac94e37 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-parse.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-parse.md @@ -82,9 +82,7 @@ Given the sample input YAML: ```yaml image: - tag: latest -rbac: - installClusterRoles: true + tag: "v1.2.3" ``` The step would produce the following @@ -92,6 +90,6 @@ The step would produce the following | Name | Type | Value | |------|------|-------| -| `imageTag` | `string` | `latest` | +| `imageTag` | `string` | `v1.2.3` | [expr-lang]: https://expr-lang.org diff --git a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-update.md b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-update.md index 0da01627ff..357f0ef0df 100644 --- a/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-update.md +++ b/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/yaml-update.md @@ -5,9 +5,15 @@ description: Updates the values of specified keys in any YAML file. # `yaml-update` -`yaml-update` updates the values of specified keys in any YAML file. This step -most often used to update image tags or digests in a Helm values and is commonly -followed by a [`helm-template` step](helm-template.md). +`yaml-update` updates the values of specified keys in any YAML file, in-place, +without disruption to existing formatting choices. + +:::note[Limitations] + +`yaml-update` updates scalar values only and can only update the values of +existing keys. + +::: ## Configuration @@ -16,7 +22,7 @@ followed by a [`helm-template` step](helm-template.md). | `path` | `string` | Y | Path to a YAML file. This path is relative to the temporary workspace that Kargo provisions for use by the promotion process. | | `updates` | `[]object` | Y | The details of changes to be applied to the file. At least one must be specified. | | `updates[].key` | `string` | Y | The key to update within the file. For nested values, use dots to delimit key parts. e.g. `image.tag`. The syntax is identical to that supported by the `json-update` step and is documented in more detail [here](https://github.com/tidwall/sjson?tab=readme-ov-file#path-syntax). | -| `updates[].value` | `string` | Y | The new value for the key. Typically specified using an expression. | +| `updates[].value` | `any` | Y | The new scalar value for the key. Typically specified using an expression. Supports strings, numbers, and booleans. | ## Output @@ -24,7 +30,6 @@ followed by a [`helm-template` step](helm-template.md). |------|------|-------------| | `commitMessage` | `string` | A description of the change(s) applied by this step. Typically, a subsequent [`git-commit` step](git-commit.md) will reference this output and aggregate this commit message fragment with others like it to build a comprehensive commit message that describes all changes. | - ## Writing Keys **Nested keys:** @@ -44,30 +49,20 @@ example.com/version: v1.0.0 Update key: `example\.com/version` -**Sequences/arrays:** +**Sequences:** ```yaml containers: - - name: my-app - image: my-app:v1.0 +- name: my-app + image: my-app:v1.0 ``` Update key: `containers.0.image` -**Combination of literal dots and nested maps:** - -```yaml -configs: - example.com/feature: - enabled: false -``` - -Update key: `configs.example\.com/version.enabled` - :::note -Use `\\` to represent a literal backslash in keys. For example, `path\\to.file` -results in the path `["path\to", "file"]`. +See the [sjson path syntax documentation](https://github.com/tidwall/sjson?tab=readme-ov-file#path-syntax) +for the full description of the syntax. ::: @@ -75,22 +70,13 @@ results in the path `["path\to", "file"]`. ### Common Usage -In this example, a Helm values file is updated to use a new container image -tag. After cloning the repository and clearing the output directory, the +In this example, a Helm values file is updated to use a new container image tag. +After cloning the repository and clearing the output directory, the `yaml-update` step modifies `values.yaml` to use the image tag from the -`Freight` being promoted. Using dot notation (`image.tag`), it updates -the nested value in the YAML file. +`Freight` being promoted. -This pattern is commonly used when you need to update Helm values files or -other YAML-based configuration files with new versions or settings during the -promotion process. - -:::info - -For more information on `imageFrom` and expressions, see the -[Expressions](../40-expressions.md#functions) documentation. - -::: +This pattern is commonly seen when managing configuration files that need to +stay synchronized with deployed container versions. ```yaml vars: @@ -117,3 +103,10 @@ steps: value: ${{ imageFrom("my/image").Tag }} # Render manifests to ./out, commit, push, etc... ``` + +:::info + +For more information on `imageFrom()` and expressions used in the example above, +see the [Expressions](../40-expressions.md#functions) documentation. + +::: diff --git a/docs/docs/50-user-guide/60-reference-docs/70-annotations.md b/docs/docs/50-user-guide/60-reference-docs/70-annotations.md index b11036e2c9..3e2a6f4642 100644 --- a/docs/docs/50-user-guide/60-reference-docs/70-annotations.md +++ b/docs/docs/50-user-guide/60-reference-docs/70-annotations.md @@ -25,6 +25,8 @@ programmatically with Kargo. | `rbac.kargo.akuity.io/claim.` | `ServiceAccount` | Any valid OIDC claim value (e.g., `sub`, `email`, or `groups`) | Maps an OIDC claim to a `ServiceAccount`, enabling user-to-ServiceAccount mappings. For more details, refer to the access control sections of the [Operator Guide](../../40-operator-guide/40-security/30-access-controls.md) and [User Guide](../50-security/20-access-controls/index.md). | | `rbac.kargo.akuity.io/claims` | `ServiceAccount` | Any valid OIDC claim values (e.g., `sub`, `email`, or `groups`) | Maps multiple OIDC claims to a `ServiceAccount`, enabling user-to-ServiceAccount mappings. This method is preferred over `rbac.kargo.akuity.io/claim.`. For more details, refer to the access control sections of the [Operator Guide](../../40-operator-guide/40-security/30-access-controls.md) and [User Guide](../50-security/20-access-controls/index.md). | `rbac.kargo.akuity.io/managed` | `ServiceAccount`, `Role`, `RoleBinding` | `"true"` | Permits the UI or CLI (via the API server) to programmatically manage trios of `ServiceAccount`, `Role`, and `RoleBinding` resources via Kargo's own ["roles" abstraction](../50-security/20-access-controls/index.md#managing-mappings-and-permissions). Omit this annotation if you wish to exclusively manage these resources [declaratively](../50-security/20-access-controls/index.md#managing-kargo-roles-declaratively). | +| `kargo.akuity.io/replicate-to` | `Secret`, `ConfigMap` (in the shared resources namespace) | `"*"` | Enables automatic replication of the resource to all Project namespaces. For more details, see the [Replicating Shared Resources](../../40-operator-guide/40-security/40-managing-secrets.md#replicating-shared-resources-to-project-namespaces) section of the Operator Guide. | +| `kargo.akuity.io/replicated-at` | `Secret`, `ConfigMap` (replicated copies) | UTC timestamp | Records when the resource was last replicated from the source. Managed by the system. | ## Labels @@ -33,4 +35,6 @@ programmatically with Kargo. | `kargo.akuity.io/alias` | `Freight` | Any string that is unique within the project | Mutable, human-readable alias for a piece of `Freight`. This label is automatically synced from the resource's `alias` field. Users are discouraged from modifying the label directly. The label exists primarily to enable querying for `Freight` by alias using `kubectl`. | | `kargo.akuity.io/cred-type` | `Secret` | `git`, `helm`, `image`, `generic` | Indicates a `Secret` represents credentials for a repository of the specified type. For more details, see the [Managing Secrets](../50-security/30-managing-secrets.md#repository-credentials). | | `kargo.akuity.io/project` | `Namespace` | `"true"` | Indicates that the `Namespace` is eligible for adoption by a `Project` with the same name. This label is useful when `Namespace`s are unavoidably pre-created by some other agent. For more details, see the [Working with Projects](../20-how-to-guides/20-working-with-projects.md#namespace-adoption) section. | +| `kargo.akuity.io/replicated-from` | `Secret`, `ConfigMap` (replicated copies) | Source resource name | Identifies the resource as a replica and names its source in the shared resources namespace. Managed by the system. | +| `kargo.akuity.io/replicated-sha` | `Secret`, `ConfigMap` (replicated copies) | 16-character truncated SHA-256 | Hash of the source resource's data at the time of last replication, used for change detection. Managed by the system. | | `kargo.akuity.io/shard` | `Promotion`, `Stage`, `Warehouse` | Shard ID | Indicates a specific controller instance responsible for reconciling the resource. For `Warehouse` and `Stage` resources, this label is automatically synced from the resource's `spec.shard` field. Users are discouraged from modifying the label directly. The label exists primarily to enable querying for resources by shard using `kubectl`. | diff --git a/docs/docs/80-release-notes/100-deprecations.md b/docs/docs/80-release-notes/100-deprecations.md index 87861235bd..6a6e810d5e 100644 --- a/docs/docs/80-release-notes/100-deprecations.md +++ b/docs/docs/80-release-notes/100-deprecations.md @@ -16,6 +16,7 @@ or scheduled for removal. | Feature | Deprecated In | Removed In | Replacement/Notes | |---------|---------------|------------|-------------------| +| SSH URLs and SSH private keys for Git repositories | v1.10.0 | Scheduled for v1.13.0 | Use HTTPS URLs with a personal access token or equivalent. SSH keys cannot authenticate to git provider APIs, forcing users to maintain two sets of credentials. See [#5858](https://github.com/akuity/kargo/issues/5858) for details. | | The Connect-based API | [v1.9.0](./90-v1.9.0.md) | Scheduled for v1.12.0 | A new, RESTful API has been introduced. Most users will not be impacted beyond simply needing to upgrade their CLI when upgrading the back end to v1.9.0 or greater. | | "global credentials namespace(s)" | [v1.9.0](./90-v1.9.0.md) | Scheduled for v1.12.0 | Replaced with "shared secrets namespace." See [release notes](./90-v1.9.0.md#-the-secret-shuffle) and [docs](../40-operator-guide/40-security/40-managing-secrets.md#transitioning) for details. | | "cluster secrets namespace" | [v1.9.0](./90-v1.9.0.md) | Scheduled for v1.12.0 | Replaced with "system resources namespace." See [release notes](./90-v1.9.0.md#-the-secret-shuffle) and [docs](../40-operator-guide/40-security/40-managing-secrets.md#transitioning) for details. | diff --git a/docs/docs/90-api-documentation.md b/docs/docs/90-api-documentation.md index c10fe6e99a..a38471f518 100644 --- a/docs/docs/90-api-documentation.md +++ b/docs/docs/90-api-documentation.md @@ -1864,6 +1864,7 @@ RawFormat specifies the format for raw resource representation. | Field | Type | Description | | ----- | ---- | ----------- | | discoveryLimit | [int64](#int64) | DiscoveryLimit is an optional limit on the number of chart versions that can be discovered for this subscription. The limit is applied after filtering charts based on the semverConstraint field. The upper limit for this field is 100. | +| insecureSkipTLSVerify | [bool](#bool) | InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored when connecting to the repository. This should be enabled only with great caution. | | name | [string](#string) | Name specifies the name of a Helm chart to subscribe to within a classic chart repository specified by the repoURL field. This field is required when the repoURL field points to a classic chart repository and MUST otherwise be empty. | | repoURL | [string](#string) | RepoURL specifies the URL of a Helm chart repository. It may be a classic chart repository (using HTTP/S) OR a repository within an OCI registry. Classic chart repositories can contain differently named charts. When this field points to such a repository, the name field MUST also be used to specify the name of the desired chart within that repository. In the case of a repository within an OCI registry, the URL implicitly points to a specific chart and the name field MUST NOT be used. This field is required. | | semverConstraint | [string](#string) | SemverConstraint specifies constraints on what new chart versions are permissible. When left unspecified, there will be no constraints, which means the latest version of the chart will always be used. Care should be taken with leaving this field unspecified, as it can lead to the unanticipated rollout of breaking changes. | @@ -2205,7 +2206,7 @@ RawFormat specifies the format for raw resource representation. GitDiscoveryResult represents the result of a Git discovery operation for a GitSubscription. | Field | Type | Description | | ----- | ---- | ----------- | -| repoURL | [string](#string) | RepoURL is the repository URL of the GitSubscription. | +| repoURL | [string](#string) | RepoURL is the repository URL of the GitSubscription. TODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern. | | commits | [DiscoveredCommit](#github-com-akuity-kargo-api-v1alpha1-DiscoveredCommit) | Commits is a list of commits discovered by the Warehouse for the GitSubscription. An empty list indicates that the discovery operation was successful, but no commits matching the GitSubscription criteria were found. +optional | @@ -2241,8 +2242,9 @@ RawFormat specifies the format for raw resource representation. | ignoreTagsRegexes | [string](#string) | IgnoreTagsRegexes is a list of regular expressions that can optionally be used to exclude tags from consideration. Only has effect when CommitSelectionStrategy is Lexical, NewestTag, or SemVer. | | includePaths | [string](#string) | IncludePaths is a list of selectors that designate paths in the repository that should trigger the production of new Freight when changes are detected therein. | | insecureSkipTLSVerify | [bool](#bool) | InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored when connecting to the repository. This should be enabled only with great caution. | -| repoURL | [string](#string) | URL is the repository's URL. This is a required field. | +| repoURL | [string](#string) | URL is the repository's URL. This is a required field. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead. | | semverConstraint | [string](#string) | SemverConstraint specifies constraints on what new tagged commits are considered in determining the newest commit of interest. Only has effect when CommitSelectionStrategy is SemVer. | +| since | k8s.io.apimachinery.pkg.apis.meta.v1.Time | An optional date (RFC 3339) that limits commit discovery to commits at or after this date. When specified, discovery stops upon reaching a commit older than this date. When left unspecified, there is no cutoff. | | strictSemvers | [bool](#bool) | StrictSemvers specifies whether only "strict" semver tags should be considered. A "strict" semver tag contains ALL of major, minor, and patch version components. Only has effect when CommitSelectionStrategy is SemVer. | diff --git a/docs/enterprise-features.json b/docs/enterprise-features.json index 8a24e29e48..2c078da0f2 100644 --- a/docs/enterprise-features.json +++ b/docs/enterprise-features.json @@ -14,7 +14,9 @@ "snow-update", "snow-delete", "snow-query-for-records", - "snow-wait-for-condition" + "snow-wait-for-condition", + "toml-parse", + "toml-update" ], "pro": [ "jira", diff --git a/docs/package.json b/docs/package.json index ad4df2d049..7909fffe4b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "copy-swagger": "cp ../swagger.yaml ../swagger.json static/", + "copy-swagger": "cp ../swagger.json static/", "docusaurus": "docusaurus", "prestart": "pnpm copy-swagger", "start": "pnpm build-gtag-plugin && docusaurus start --host 0.0.0.0", diff --git a/extended/docs/upstream-kargo-merge-reports/2026-04-09.yaml b/extended/docs/upstream-kargo-merge-reports/2026-04-09.yaml new file mode 100644 index 0000000000..12526d7975 --- /dev/null +++ b/extended/docs/upstream-kargo-merge-reports/2026-04-09.yaml @@ -0,0 +1,27 @@ +date: 2026-04-09 +merge_branch: upstream-kargo-merge/2026-04-09 +target_branch: main +target_remote: origin +source_remote: upstream +source_branch: main +fork_base_commit: 5d5b1044f90d6579782ba694620a1a67052e8509 +upstream_commit: a97d75921adc0348a0318de0419e82a8bc83dd3f +conflicted_files: [] +conflicts: [] +post_merge_adjustments: [] +validation: + make_test_unit: pass + make_lint: pass + make_build_cli_with_ui: pass + go_build_cmd_controlplane: pass + git_diff_check: pass + stepplugins_only_e2e: skipped +notes: + - No textual merge conflicts occurred. + - No conflict-resolution PR inline comments are required for this merge. + - Local validation required forcing $(go env GOROOT)/bin ahead of the Homebrew + go shim because /opt/homebrew/bin/go is still 1.25.4 while this repo now + uses go 1.26.0. + - Local UI validation required a full pnpm install, not pnpm install --dev, + and a manual unpack of @rollup/rollup-darwin-arm64 because optional + dependencies were skipped on this machine. diff --git a/go.mod b/go.mod index c0de814e45..6c26c46186 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,10 @@ module github.com/akuity/kargo go 1.26.0 -replace github.com/akuity/kargo/api => ./api - replace ( + github.com/akuity/kargo/api => ./api + github.com/akuity/kargo/pkg/client/generated => ./pkg/client/generated + // NB(hidde): required because of https://github.com/kubernetes-sigs/kustomize/issues/6014 sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.20.1 sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.20.1 @@ -22,11 +23,12 @@ require ( github.com/Masterminds/semver/v3 v3.4.0 github.com/adrg/xdg v0.5.3 github.com/akuity/kargo/api v0.0.0 - github.com/aws/aws-sdk-go-v2 v1.41.4 - github.com/aws/aws-sdk-go-v2/config v1.32.12 - github.com/aws/aws-sdk-go-v2/credentials v1.19.12 + github.com/akuity/kargo/pkg/client/generated v0.0.0 + github.com/aws/aws-sdk-go-v2 v1.41.5 + github.com/aws/aws-sdk-go-v2/config v1.32.14 + github.com/aws/aws-sdk-go-v2/credentials v1.19.14 github.com/aws/aws-sdk-go-v2/service/ecr v1.55.4 - github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 + github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 github.com/bmatcuk/doublestar/v4 v4.9.2 github.com/coreos/go-oidc/v3 v3.17.0 github.com/cyphar/filepath-securejoin v0.6.1 @@ -35,14 +37,11 @@ require ( github.com/fatih/structtag v1.2.0 github.com/fluxcd/pkg/kustomize v1.24.0 github.com/gin-gonic/gin v1.11.0 - github.com/go-git/go-git/v5 v5.16.5 + github.com/go-git/go-git/v5 v5.17.2 github.com/go-logr/logr v1.4.3 github.com/go-logr/zapr v1.3.0 - github.com/go-openapi/errors v0.22.7 github.com/go-openapi/runtime v0.29.3 github.com/go-openapi/strfmt v0.26.1 - github.com/go-openapi/swag v0.25.5 - github.com/go-openapi/validate v0.25.2 github.com/gogo/protobuf v1.3.2 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/google/go-containerregistry v0.20.7 @@ -58,6 +57,7 @@ require ( github.com/oklog/ulid/v2 v2.1.1 github.com/otiai10/copy v1.14.1 github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pelletier/go-toml/v2 v2.2.4 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c github.com/rs/cors v1.11.1 github.com/sosedoff/gitkit v0.4.0 @@ -111,15 +111,15 @@ require ( github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 // indirect - github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 // indirect github.com/aws/smithy-go v1.24.2 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -151,15 +151,17 @@ require ( github.com/go-errors/errors v1.5.1 // indirect github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.6.2 // indirect + github.com/go-git/go-billy/v5 v5.8.0 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.24.3 // indirect + github.com/go-openapi/errors v0.22.7 // indirect github.com/go-openapi/jsonpointer v0.22.5 // indirect github.com/go-openapi/jsonreference v0.21.5 // indirect github.com/go-openapi/loads v0.23.3 // indirect github.com/go-openapi/spec v0.22.4 // indirect + github.com/go-openapi/swag v0.25.5 // indirect github.com/go-openapi/swag/cmdutils v0.25.5 // indirect github.com/go-openapi/swag/conv v0.25.5 // indirect github.com/go-openapi/swag/fileutils v0.25.5 // indirect @@ -171,6 +173,7 @@ require ( github.com/go-openapi/swag/stringutils v0.25.5 // indirect github.com/go-openapi/swag/typeutils v0.25.5 // indirect github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + github.com/go-openapi/validate v0.25.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.27.0 // indirect @@ -225,7 +228,6 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/otiai10/mint v1.6.3 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/go.sum b/go.sum index 47ba1465ff..bb645fd955 100644 --- a/go.sum +++ b/go.sum @@ -58,34 +58,34 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 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/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k= -github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= -github.com/aws/aws-sdk-go-v2/config v1.32.12 h1:O3csC7HUGn2895eNrLytOJQdoL2xyJy0iYXhoZ1OmP0= -github.com/aws/aws-sdk-go-v2/config v1.32.12/go.mod h1:96zTvoOFR4FURjI+/5wY1vc1ABceROO4lWgWJuxgy0g= -github.com/aws/aws-sdk-go-v2/credentials v1.19.12 h1:oqtA6v+y5fZg//tcTWahyN9PEn5eDU/Wpvc2+kJ4aY8= -github.com/aws/aws-sdk-go-v2/credentials v1.19.12/go.mod h1:U3R1RtSHx6NB0DvEQFGyf/0sbrpJrluENHdPy1j/3TE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20 h1:zOgq3uezl5nznfoK3ODuqbhVg1JzAGDUhXOsU0IDCAo= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.20/go.mod h1:z/MVwUARehy6GAg/yQ1GO2IMl0k++cu1ohP9zo887wE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc= +github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY= +github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o= +github.com/aws/aws-sdk-go-v2/config v1.32.14 h1:opVIRo/ZbbI8OIqSOKmpFaY7IwfFUOCCXBsUpJOwDdI= +github.com/aws/aws-sdk-go-v2/config v1.32.14/go.mod h1:U4/V0uKxh0Tl5sxmCBZ3AecYny4UNlVmObYjKuuaiOo= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14 h1:n+UcGWAIZHkXzYt87uMFBv/l8THYELoX6gVcUvgl6fI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.14/go.mod h1:cJKuyWB59Mqi0jM3nFYQRmnHVQIcgoxjEMAbLkpr62w= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.4 h1:BpSZ3fLXb8HLI/zhiiCOQj10bEsXUcbNHBEkDlYuxB0= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.4/go.mod h1:T+Tz2Xp1gnvtlgvP7OyRHlr84KtI3fZW5Ax/e+s9b64= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20 h1:2HvVAIq+YqgGotK6EkMf+KIEqTISmTYh5zLpYyeTo1Y= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.8 h1:0GFOLzEbOyZABS3PhYfBIx2rNBACYcKty+XGkTgw1ow= -github.com/aws/aws-sdk-go-v2/service/signin v1.0.8/go.mod h1:LXypKvk85AROkKhOG6/YEcHFPoX+prKTowKnVdcaIxE= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.13 h1:kiIDLZ005EcKomYYITtfsjn7dtOwHDOFy7IbPXKek2o= -github.com/aws/aws-sdk-go-v2/service/sso v1.30.13/go.mod h1:2h/xGEowcW/g38g06g3KpRWDlT+OTfxxI0o1KqayAB8= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17 h1:jzKAXIlhZhJbnYwHbvUQZEB8KfgAEuG0dc08Bkda7NU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.17/go.mod h1:Al9fFsXjv4KfbzQHGe6V4NZSZQXecFcvaIF4e70FoRA= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8MSU6Ch5i9PgBkcU= -github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15 h1:lFd1+ZSEYJZYvv9d6kXzhkZu07si3f+GQ1AaYwa2LUM= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.15/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19 h1:dzztQ1YmfPrxdrOiuZRMF6fuOwWlWpD2StNLTceKpys= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.19/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= @@ -192,14 +192,14 @@ github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= -github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= -github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s= -github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M= +github.com/go-git/go-billy/v5 v5.8.0 h1:I8hjc3LbBlXTtVuFNJuwYuMiHvQJDq1AT6u4DwDzZG0= +github.com/go-git/go-billy/v5 v5.8.0/go.mod h1:RpvI/rw4Vr5QA+Z60c6d6LXH0rYJo0uD5SqfmrrheCY= +github.com/go-git/go-git/v5 v5.17.2 h1:B+nkdlxdYrvyFK4GPXVU8w1U+YkbsgciIR7f2sZJ104= +github.com/go-git/go-git/v5 v5.17.2/go.mod h1:pW/VmeqkanRFqR6AljLcs7EA7FbZaN5MQqO7oZADXpo= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= -github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= diff --git a/hack/best-releases/fetch_test.go b/hack/best-releases/fetch_test.go index 5c40906519..ef4cdc5c3d 100644 --- a/hack/best-releases/fetch_test.go +++ b/hack/best-releases/fetch_test.go @@ -1,7 +1,6 @@ package main import ( - "context" "encoding/json" "fmt" "net/http" @@ -57,7 +56,7 @@ func TestFetchBestReleases(t *testing.T) { defer srv.Close() results, err := fetchBestReleases( - context.Background(), srv.URL, + t.Context(), srv.URL, ) require.NoError(t, err) @@ -77,7 +76,7 @@ func TestFetchBestReleases(t *testing.T) { defer srv.Close() results, err := fetchBestReleases( - context.Background(), srv.URL, + t.Context(), srv.URL, ) require.Error(t, err) assert.Nil(t, results) diff --git a/hack/codegen/fix-swagger-spec.sh b/hack/codegen/fix-swagger-spec.sh new file mode 100755 index 0000000000..3cb56dfaeb --- /dev/null +++ b/hack/codegen/fix-swagger-spec.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# fix-swagger-spec.sh +# +# Post-processes swagger.json to: +# +# 1. Rename verbose definition keys (derived from full Go package paths) to +# short, ergonomic names and update all $ref pointers accordingly. This +# benefits both the generated Go client (go-swagger) and the TypeScript +# client (orval). +# +# 2. Fix []byte field representations. Go's []byte is JSON-serialized as a +# base64-encoded string, but swag expands it to {"type":"array","items": +# {"type":"integer","format":"int32"}} because byte is an alias for uint8. +# This script rewrites those fields to {"type":"string","format":"byte"} +# so that go-swagger generates the correct Go types. +# +# 3. Add `required` arrays derived from +kubebuilder:validation:Required +# markers. swag copies these markers into description strings but does not +# translate them into the OpenAPI `required` array, causing generated +# TypeScript clients to treat all fields as optional. + +SWAGGER_FILE="${1:?Usage: fix-swagger-spec.sh }" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +JQ="${SCRIPT_DIR}/../bin/jq" + +if [[ ! -x "$JQ" ]]; then + echo "Error: jq not found at $JQ -- run 'make install-jq' first" >&2 + exit 1 +fi + +# --- Pass 1: Rename verbose definition keys and update $ref pointers ---------- + +"$JQ" ' + # Compute a short name for a swagger definition key. + def rename_key: + if startswith("github_com_akuity_kargo_api_v1alpha1.") then + split(".") | last + elif startswith("github_com_akuity_kargo_api_stubs_rollouts_v1alpha1.") then + "Rollouts" + (split(".") | last) + elif startswith("github_com_akuity_kargo_api_rbac_v1alpha1.") then + "Rbac" + (split(".") | last) + elif startswith("k8s_io_api_core_v1.") then + "V1" + (split(".") | last) + elif startswith("v1.") then + "V1" + .[3:] + elif startswith("intstr.") then + split(".") | last + elif startswith("resource.") then + split(".") | last + else + . + end; + + # Build old_name -> new_name mapping. + (.definitions | keys | map({(.) : (. | rename_key)}) | add) as $map | + + # Collision detection: ensure all new names are unique. + ([$map | to_entries[].value] | unique | length) as $unique_count | + (if ($map | length) != $unique_count then + # Find and report the collisions. + [$map | to_entries[] | .value] | group_by(.) | map(select(length > 1) | .[0]) | + error("Definition name collision detected for: \(join(", "))") + else . end) | + + # Rename definition keys. + .definitions |= ( + to_entries | map(.key = $map[.key]) | from_entries + ) | + + # Rewrite all $ref pointers to use new names. + walk( + if type == "object" and has("$ref") and (.["$ref"] | startswith("#/definitions/")) then + .["$ref"] |= ( + split("/") | last | . as $old | + "#/definitions/" + ($map[$old] // $old) + ) + else . end + ) +' "$SWAGGER_FILE" > "${SWAGGER_FILE}.tmp" && mv "${SWAGGER_FILE}.tmp" "$SWAGGER_FILE" + +echo "Renamed swagger definitions to short names." + +# --- Pass 2: Fix map[string][]byte fields ------------------------------------ +# +# Fix Secret.data, ConfigMap.binaryData, and AnalysisRun MetricProvider.plugin. +# These appear as additionalProperties with array-of-int32; they should be +# additionalProperties with string format byte. + +"$JQ" ' + # Fix Secret.data + (if .definitions["V1Secret"].properties.data.additionalProperties then + .definitions["V1Secret"].properties.data.additionalProperties = {"type": "string", "format": "byte"} + else . end) | + # Fix ConfigMap.binaryData + (if .definitions["V1ConfigMap"].properties.binaryData.additionalProperties then + .definitions["V1ConfigMap"].properties.binaryData.additionalProperties = {"type": "string", "format": "byte"} + else . end) | + # Fix AnalysisRun MetricProvider.plugin + (if .definitions["RolloutsMetricProvider"].properties.plugin.additionalProperties then + .definitions["RolloutsMetricProvider"].properties.plugin.additionalProperties = {"type": "string", "format": "byte"} + else . end) +' "$SWAGGER_FILE" > "${SWAGGER_FILE}.tmp" && mv "${SWAGGER_FILE}.tmp" "$SWAGGER_FILE" + +# --- Pass 3: Add `required` arrays from kubebuilder validation markers ------- +# +# swag copies +kubebuilder:validation:Required into description strings but +# does not translate them into the OpenAPI `required` array. Derive the +# required array from descriptions automatically. + +"$JQ" ' + .definitions |= map_values( + . as $def | + ( + $def.properties // {} | + to_entries | + map(select( + .value.description != null and + (.value.description | contains("+kubebuilder:validation:Required")) + )) | + map(.key) + ) as $required | + if ($required | length) > 0 + then .required = $required + else . end + ) +' "$SWAGGER_FILE" > "${SWAGGER_FILE}.tmp" && mv "${SWAGGER_FILE}.tmp" "$SWAGGER_FILE" + +echo "Added required arrays from kubebuilder validation markers." + +# --- Pass 4: Validate no broken $ref pointers remain ------------------------- + +"$JQ" -e ' + [.. | objects | select(has("$ref")) | .["$ref"] | + select(startswith("#/definitions/")) | + split("/") | last] as $refs | + (.definitions | keys) as $defs | + ($refs - $defs) | if length > 0 then + error("Broken $ref pointers found: \(join(", "))") + else true end +' "$SWAGGER_FILE" > /dev/null + +echo "Swagger spec post-processing complete." diff --git a/hack/codegen/subscriptions.sh b/hack/codegen/subscriptions.sh index edec592f8c..bdf0f9bf58 100755 --- a/hack/codegen/subscriptions.sh +++ b/hack/codegen/subscriptions.sh @@ -31,7 +31,12 @@ sed -i.bak 's/Digest[[:space:]]*ImageSelectionStrategy/ImageSelectionStrategyDig sed -i.bak 's/NewestBuild[[:space:]]*ImageSelectionStrategy/ImageSelectionStrategyNewestBuild ImageSelectionStrategy/' ${out_file} sed -i.bak 's/CacheByTag[[:space:]]*\*bool/CacheByTag bool/' ${out_file} sed -i.bak 's/InsecureSkipTLSVerify[[:space:]]*\*bool/InsecureSkipTLSVerify bool/' ${out_file} +sed -i.bak 's/time\.Time/metav1.Time/g' ${out_file} +# quicktype emits per-schema import statements that can end up in the middle of +# the file when multiple schemas are combined. Remove them and let goimports +# add a proper import block based on usage. +sed -i.bak '/^import /d' ${out_file} rm ${out_file}.bak -gofmt -w ${out_file} +hack/bin/goimports -w ${out_file} diff --git a/hack/testing/promo-gater/README.md b/hack/testing/promo-gater/README.md new file mode 100644 index 0000000000..9e984e8f4e --- /dev/null +++ b/hack/testing/promo-gater/README.md @@ -0,0 +1,126 @@ +# promo-gater + +An HTTP server that gates Kargo promotion steps. Use it to pause a promotion +at a specific point — to inspect state, manipulate a remote branch between +`git-clone` and `git-push`, or hold for manual observation. + +## Usage + +``` +promo-gater [flags] [-- command [args...]] +``` + +### Flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--port` | `24365` | Port to listen on | +| `--addr` | `0.0.0.0` | Bind address | +| `--once` | `true` | Exit after handling one request | + +### Modes + +**Command mode** — runs a command when the promotion step hits the gate: + +```bash +# Run a script between promotion steps +go run ./hack/testing/promo-gater/ -- bash -c "cd /tmp/repo && git rebase main" + +# Block for a fixed duration +go run ./hack/testing/promo-gater/ -- sleep 30 + +# Simple signal (create a file, return immediately) +go run ./hack/testing/promo-gater/ -- touch /tmp/gate-reached +``` + +Returns the command's combined output as the response body. HTTP 200 on exit +code 0, HTTP 500 otherwise. + +**Interactive mode** — blocks until you press Enter: + +```bash +go run ./hack/testing/promo-gater/ +``` + +When a request arrives, the terminal prints a prompt and waits. Press Enter to +release the promotion step with HTTP 200. + +### Multiple requests + +By default the server exits after one request. To keep it running: + +```bash +go run ./hack/testing/promo-gater/ --once=false -- date +``` + +## Promotion step configuration + +Add an `http` step to your promotion (or Stage's `promotionTemplate`) that +calls the gater. Use `host.docker.internal` when the promotion controller runs +in a local cluster (kind, k3d, OrbStack) and the gater runs on the host: + +```yaml +- uses: http + config: + url: http://host.docker.internal:24365 + method: GET + timeout: 600s + successExpression: "response.status == 200" + failureExpression: "response.status == 500" +``` + +Set `timeout` high enough for your use case — the HTTP connection stays open +while the gate blocks. + +## Environment variables + +The command receives request metadata as environment variables: + +| Variable | Description | +|----------|-------------| +| `GATE_METHOD` | HTTP method (e.g. `GET`) | +| `GATE_PATH` | Request path (e.g. `/`) | +| `GATE_QUERY` | Raw query string | +| `GATE_BODY` | Request body | + +## Example: manipulate a branch between clone and push + +Insert the gate between `git-clone` and `git-commit` in your promotion steps: + +```yaml +steps: +- uses: git-clone + config: + repoURL: https://github.com/example/repo.git + checkout: + - branch: main + path: ./src + - branch: stage/test + path: ./out +- uses: http + config: + url: http://host.docker.internal:24365 + timeout: 600s + successExpression: "response.status == 200" +- uses: kustomize-set-image + config: + path: ./src/base + images: + - image: nginx +- uses: git-commit + config: + path: ./out + message: "promote" +- uses: git-push + config: + path: ./out +``` + +Then start the gater before triggering the promotion: + +```bash +go run ./hack/testing/promo-gater/ +# ... promotion reaches the http step and blocks ... +# Inspect state, force-push a branch, etc. +# Press Enter to continue +``` diff --git a/hack/testing/promo-gater/main.go b/hack/testing/promo-gater/main.go new file mode 100644 index 0000000000..456aeeee54 --- /dev/null +++ b/hack/testing/promo-gater/main.go @@ -0,0 +1,164 @@ +// promo-gater starts an HTTP server that gates Kargo promotion steps. +// +// Usage: +// +// promo-gater [flags] [-- command [args...]] +// +// When a promotion's HTTP step sends a request to this server: +// - With a command: executes the command, returns stdout (HTTP 200) or +// stderr (HTTP 500) depending on the exit code. +// - Without a command: blocks until the user presses Enter in the +// terminal, then returns HTTP 200. +// +// The server exits after handling one request by default. Use --once=false +// to keep it running. See README.md for promotion step configuration examples. +package main + +import ( + "bufio" + "context" + "errors" + "flag" + "fmt" + "io" + "log" + "net" + "net/http" + "os" + "os/exec" + "os/signal" + "strings" + "syscall" + "time" +) + +func main() { + port := flag.Int("port", 24365, "port to listen on") + addr := flag.String("addr", "0.0.0.0", "bind address") + once := flag.Bool("once", true, "exit after handling one request") + flag.Parse() + + // Everything after flag parsing is the command to run. + cmdArgs := flag.Args() + + listenAddr := fmt.Sprintf("%s:%d", *addr, *port) + + // Channel used by the handler to signal the server to shut down. + done := make(chan struct{}) + + mux := http.NewServeMux() + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + log.Printf( //nolint:gosec + "request received: %s %s from %s", + r.Method, r.URL.Path, r.RemoteAddr, + ) + + // Pass request metadata as env vars for the command. + body, _ := io.ReadAll(r.Body) + env := append( + os.Environ(), + "GATE_METHOD="+r.Method, + "GATE_PATH="+r.URL.Path, + "GATE_QUERY="+r.URL.RawQuery, + "GATE_BODY="+string(body), + ) + + if len(cmdArgs) > 0 { + handleCommand(r.Context(), w, cmdArgs, env) + } else { + handleInteractive(w) + } + + if *once { + close(done) + } + }) + + server := &http.Server{ // nolint: gosec + Addr: listenAddr, + Handler: mux, + ReadHeaderTimeout: 10 * time.Second, + } + + // Graceful shutdown on signal. + ctx, stop := signal.NotifyContext( + context.Background(), + syscall.SIGINT, syscall.SIGTERM, + ) + defer stop() + + go func() { + select { + case <-done: + case <-ctx.Done(): + } + _ = server.Shutdown(context.Background()) + }() + + ln, err := net.Listen("tcp", listenAddr) + if err != nil { + log.Fatalf("error listening on %s: %v", listenAddr, err) + } + if len(cmdArgs) > 0 { + log.Printf( + "listening on %s — will run: %s", + ln.Addr(), strings.Join(cmdArgs, " "), + ) + } else { + log.Printf( + "listening on %s — interactive mode (press Enter to release)", + ln.Addr(), + ) + } + + if err := server.Serve(ln); !errors.Is(err, http.ErrServerClosed) { + log.Fatalf("server error: %v", err) + } +} + +func handleCommand( + ctx context.Context, + w http.ResponseWriter, + args []string, + env []string, +) { + cmd := exec.CommandContext(ctx, args[0], args[1:]...) // nolint: gosec + cmd.Env = env + + out, err := cmd.CombinedOutput() + + if err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + log.Printf( + "command exited with code %d", + exitErr.ExitCode(), + ) + } else { + log.Printf("command error: %v", err) + } + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write(out) // nolint: gosec + return + } + + log.Printf("command succeeded") + w.WriteHeader(http.StatusOK) + _, _ = w.Write(out) // nolint: gosec +} + +func handleInteractive(w http.ResponseWriter) { + fmt.Fprintln(os.Stderr, "") + fmt.Fprintln( + os.Stderr, + ">>> Promotion step is waiting. Press Enter to release...", + ) + fmt.Fprintln(os.Stderr, "") + + scanner := bufio.NewScanner(os.Stdin) + scanner.Scan() + + log.Printf("gate released by user") + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("released\n")) +} diff --git a/hack/tools.mk b/hack/tools.mk index db71b7c061..14d78f8208 100644 --- a/hack/tools.mk +++ b/hack/tools.mk @@ -34,6 +34,7 @@ TILT_VERSION ?= v0.36.3 CTLPTL_VERSION ?= v0.9.0 KIND_VERSION ?= v0.31.0 K3D_VERSION ?= v5.8.3 +JQ_VERSION ?= 1.8.1 ################################################################################ # Tool targets # @@ -55,6 +56,7 @@ TILT := $(BIN_DIR)/tilt-$(OS)-$(ARCH)-$(TILT_VERSION) CTLPTL := $(BIN_DIR)/ctlptl-$(OS)-$(ARCH)-$(CTLPTL_VERSION) KIND := $(BIN_DIR)/kind-$(OS)-$(ARCH)-$(KIND_VERSION) K3D := $(BIN_DIR)/k3d-$(OS)-$(ARCH)-$(K3D_VERSION) +JQ := $(BIN_DIR)/jq-$(OS)-$(ARCH)-$(JQ_VERSION) $(GOLANGCI_LINT): $(call install-golangci-lint,$@,$(GOLANGCI_LINT_VERSION)) @@ -104,6 +106,9 @@ $(KIND): $(K3D): $(call install-k3d,$@,$(K3D_VERSION)) +$(JQ): + $(call install-jq,$@,$(JQ_VERSION)) + ################################################################################ # Symlink targets # ################################################################################ @@ -124,6 +129,7 @@ TILT_LINK := $(BIN_DIR)/tilt CTLPTL_LINK := $(BIN_DIR)/ctlptl KIND_LINK := $(BIN_DIR)/kind K3D_LINK := $(BIN_DIR)/k3d +JQ_LINK := $(BIN_DIR)/jq .PHONY: $(GOLANGCI_LINT_LINK) $(GOLANGCI_LINT_LINK): $(GOLANGCI_LINT) @@ -189,11 +195,15 @@ $(KIND_LINK): $(KIND) $(K3D_LINK): $(K3D) $(call create-symlink,$(K3D),$(K3D_LINK)) +.PHONY: $(JQ_LINK) +$(JQ_LINK): $(JQ) + $(call create-symlink,$(JQ),$(JQ_LINK)) + ################################################################################ # Alias targets # ################################################################################ -TOOLS := install-golangci-lint install-helm install-goimports install-go-to-protobuf install-protoc-gen-gogo install-controller-gen install-protoc install-buf install-quill install-protoc-gen-doc install-swag install-go-swagger install-tilt install-ctlptl install-kind install-k3d +TOOLS := install-golangci-lint install-helm install-goimports install-go-to-protobuf install-protoc-gen-gogo install-controller-gen install-protoc install-buf install-quill install-protoc-gen-doc install-swag install-go-swagger install-tilt install-ctlptl install-kind install-k3d install-jq .PHONY: install-tools install-tools: $(TOOLS) @@ -246,6 +256,9 @@ install-kind: $(KIND) $(KIND_LINK) .PHONY: install-k3d install-k3d: $(K3D) $(K3D_LINK) +.PHONY: install-jq +install-jq: $(JQ) $(JQ_LINK) + ################################################################################ # Clean up targets # ################################################################################ @@ -428,6 +441,34 @@ define install-k3d } endef +# JQ_OS and JQ_ARCH are used to determine the platform-specific binary to +# download for jq. +JQ_OS ?= $(OS) +ifeq ($(JQ_OS),darwin) + JQ_OS := macos +endif + +JQ_ARCH ?= $(ARCH) +ifeq ($(JQ_ARCH),x86_64) + override JQ_ARCH = amd64 +else ifeq ($(JQ_ARCH),aarch64) + override JQ_ARCH = arm64 +endif + +# install-jq installs jq. +# +# $(1) binary path +# $(2) version +define install-jq + @[ -f $(1) ] || { \ + set -e ;\ + echo "Installing jq $(2) to $(1)" ;\ + mkdir -p $(dir $(1)) ;\ + curl -fsSL -o $(1) https://github.com/jqlang/jq/releases/download/jq-$(2)/jq-$(JQ_OS)-$(JQ_ARCH) ;\ + chmod 0755 $(1) ;\ + } +endef + # create-symlink creates a relative symlink to the platform-specific binary. # # $(1) platform-specific binary path diff --git a/pkg/api/cluster_config_test.go b/pkg/api/cluster_config_test.go index 27d0b98972..46c0057803 100644 --- a/pkg/api/cluster_config_test.go +++ b/pkg/api/cluster_config_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -45,7 +44,7 @@ func TestGetClusterConfig(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - clusterCfg, err := GetClusterConfig(context.Background(), testCase.client) + clusterCfg, err := GetClusterConfig(t.Context(), testCase.client) testCase.assertions(t, clusterCfg, err) }) } diff --git a/pkg/api/finalizers_test.go b/pkg/api/finalizers_test.go index e14d95cb51..f85744cb2d 100644 --- a/pkg/api/finalizers_test.go +++ b/pkg/api/finalizers_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -21,7 +20,7 @@ func TestEnsureFinalizer(t *testing.T) { const testNamespace = "fake-namespace" const testStageName = "fake-stage" - ctx := context.Background() + ctx := t.Context() stage := &kargoapi.Stage{ ObjectMeta: metav1.ObjectMeta{ @@ -57,7 +56,7 @@ func TestRemoveFinalizer(t *testing.T) { const testNamespace = "fake-namespace" const testStageName = "fake-stage" - ctx := context.Background() + ctx := t.Context() stage := &kargoapi.Stage{ ObjectMeta: metav1.ObjectMeta{ @@ -93,7 +92,7 @@ func TestPatchOwnerReferences(t *testing.T) { const testNamespace = "fake-namespace" const testProjectName = "fake-project" - ctx := context.Background() + ctx := t.Context() initialNS := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ @@ -214,7 +213,7 @@ func Test_patchAnnotation(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { t.Parallel() - err := patchAnnotation(context.Background(), tc.client, tc.obj, tc.key, tc.value) + err := patchAnnotation(t.Context(), tc.client, tc.obj, tc.key, tc.value) if tc.errExpected { require.Error(t, err) return @@ -292,7 +291,7 @@ func Test_deleteAnnotation(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { t.Parallel() - err := deleteAnnotation(context.Background(), tc.client, tc.obj, tc.key) + err := deleteAnnotation(t.Context(), tc.client, tc.obj, tc.key) if tc.errExpected { require.Error(t, err) return diff --git a/pkg/api/freight_test.go b/pkg/api/freight_test.go index a8d8a3908a..28d66eee96 100644 --- a/pkg/api/freight_test.go +++ b/pkg/api/freight_test.go @@ -109,7 +109,7 @@ func TestGetFreight(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { freight, err := GetFreight( - context.Background(), + t.Context(), testCase.client, types.NamespacedName{ Namespace: "fake-namespace", @@ -163,7 +163,7 @@ func TestGetFreightByAlias(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { freight, err := GetFreightByAlias( - context.Background(), + t.Context(), testCase.client, "fake-namespace", "fake-alias", @@ -250,7 +250,7 @@ func TestListFreightByCurrentStage(t *testing.T) { Build() t.Run(testCase.name, func(t *testing.T) { - freight, err := ListFreightByCurrentStage(context.Background(), c, testStage) + freight, err := ListFreightByCurrentStage(t.Context(), c, testStage) testCase.assertions(t, freight, err) }) } diff --git a/pkg/api/project_config_test.go b/pkg/api/project_config_test.go index b9f62e886e..9e8b673111 100644 --- a/pkg/api/project_config_test.go +++ b/pkg/api/project_config_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -52,7 +51,7 @@ func TestGetProjectConfig(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { projectCfg, err := GetProjectConfig( - context.Background(), + t.Context(), testCase.client, testProjectName, ) diff --git a/pkg/api/project_test.go b/pkg/api/project_test.go index f9e7ef495d..df792d8d01 100644 --- a/pkg/api/project_test.go +++ b/pkg/api/project_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -50,7 +49,7 @@ func TestGetProject(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { project, err := GetProject( - context.Background(), + t.Context(), testCase.client, "fake-project", ) diff --git a/pkg/api/promotion_test.go b/pkg/api/promotion_test.go index 085905db2a..ef5d42c8bb 100644 --- a/pkg/api/promotion_test.go +++ b/pkg/api/promotion_test.go @@ -1,7 +1,6 @@ package api import ( - "context" "testing" "time" @@ -55,7 +54,7 @@ func TestGetPromotion(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { promo, err := GetPromotion( - context.Background(), + t.Context(), testCase.client, types.NamespacedName{ Namespace: "fake-namespace", @@ -74,7 +73,7 @@ func TestAbortPromotion(t *testing.T) { t.Run("not found", func(t *testing.T) { c := fake.NewClientBuilder().WithScheme(scheme).Build() - err := AbortPromotion(context.TODO(), c, types.NamespacedName{ + err := AbortPromotion(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-promotion", }, kargoapi.AbortActionTerminate) @@ -94,13 +93,13 @@ func TestAbortPromotion(t *testing.T) { }, ).Build() - err := AbortPromotion(context.TODO(), c, types.NamespacedName{ + err := AbortPromotion(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-promotion", }, kargoapi.AbortActionTerminate) require.NoError(t, err) - promotion, err := GetPromotion(context.TODO(), c, types.NamespacedName{ + promotion, err := GetPromotion(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-promotion", }) @@ -119,13 +118,13 @@ func TestAbortPromotion(t *testing.T) { }, ).Build() - err := AbortPromotion(context.TODO(), c, types.NamespacedName{ + err := AbortPromotion(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-promotion", }, kargoapi.AbortActionTerminate) require.NoError(t, err) - stage, err := GetPromotion(context.TODO(), c, types.NamespacedName{ + stage, err := GetPromotion(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-promotion", }) diff --git a/pkg/api/stage_test.go b/pkg/api/stage_test.go index ae5f2faa64..ece6b86743 100644 --- a/pkg/api/stage_test.go +++ b/pkg/api/stage_test.go @@ -57,7 +57,7 @@ func TestGetStage(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { stage, err := GetStage( - context.Background(), + t.Context(), testCase.client, types.NamespacedName{ Namespace: "fake-namespace", @@ -261,7 +261,7 @@ func TestListFreightAvailableToStage(t *testing.T) { }, } freight, err := ListFreightAvailableToStage( - context.Background(), c, stage, + t.Context(), c, stage, ) testCase.assertions(t, freight, err) }) @@ -275,7 +275,7 @@ func TestReverifyStageFreight(t *testing.T) { t.Run("not found", func(t *testing.T) { c := fake.NewClientBuilder().WithScheme(scheme).Build() - err := ReverifyStageFreight(context.TODO(), c, types.NamespacedName{ + err := ReverifyStageFreight(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -292,7 +292,7 @@ func TestReverifyStageFreight(t *testing.T) { }, ).Build() - err := ReverifyStageFreight(context.TODO(), c, types.NamespacedName{ + err := ReverifyStageFreight(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -318,7 +318,7 @@ func TestReverifyStageFreight(t *testing.T) { }, ).Build() - err := ReverifyStageFreight(context.TODO(), c, types.NamespacedName{ + err := ReverifyStageFreight(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -345,7 +345,7 @@ func TestReverifyStageFreight(t *testing.T) { }, ).Build() - err := ReverifyStageFreight(context.TODO(), c, types.NamespacedName{ + err := ReverifyStageFreight(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -374,13 +374,13 @@ func TestReverifyStageFreight(t *testing.T) { }, ).Build() - err := ReverifyStageFreight(context.TODO(), c, types.NamespacedName{ + err := ReverifyStageFreight(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) require.NoError(t, err) - stage, err := GetStage(context.TODO(), c, types.NamespacedName{ + stage, err := GetStage(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -398,7 +398,7 @@ func TestAbortStageFreightVerification(t *testing.T) { t.Run("not found", func(t *testing.T) { c := fake.NewClientBuilder().WithScheme(scheme).Build() - err := AbortStageFreightVerification(context.TODO(), c, types.NamespacedName{ + err := AbortStageFreightVerification(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -415,7 +415,7 @@ func TestAbortStageFreightVerification(t *testing.T) { }, ).Build() - err := AbortStageFreightVerification(context.TODO(), c, types.NamespacedName{ + err := AbortStageFreightVerification(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -441,7 +441,7 @@ func TestAbortStageFreightVerification(t *testing.T) { }, ).Build() - err := AbortStageFreightVerification(context.TODO(), c, types.NamespacedName{ + err := AbortStageFreightVerification(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -468,7 +468,7 @@ func TestAbortStageFreightVerification(t *testing.T) { }, ).Build() - err := AbortStageFreightVerification(context.TODO(), c, types.NamespacedName{ + err := AbortStageFreightVerification(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -498,13 +498,13 @@ func TestAbortStageFreightVerification(t *testing.T) { }, ).Build() - err := AbortStageFreightVerification(context.TODO(), c, types.NamespacedName{ + err := AbortStageFreightVerification(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) require.NoError(t, err) - stage, err := GetStage(context.TODO(), c, types.NamespacedName{ + stage, err := GetStage(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -535,13 +535,13 @@ func TestAbortStageFreightVerification(t *testing.T) { }, ).Build() - err := AbortStageFreightVerification(context.TODO(), c, types.NamespacedName{ + err := AbortStageFreightVerification(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) require.NoError(t, err) - stage, err := GetStage(context.TODO(), c, types.NamespacedName{ + stage, err := GetStage(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -559,7 +559,7 @@ func TestAnnotateStageWithArgoCDContext(t *testing.T) { t.Run("not found", func(t *testing.T) { c := fake.NewClientBuilder().WithScheme(scheme).Build() - err := AnnotateStageWithArgoCDContext(context.TODO(), c, []kargoapi.HealthCheckStep{}, &kargoapi.Stage{ + err := AnnotateStageWithArgoCDContext(t.Context(), c, []kargoapi.HealthCheckStep{}, &kargoapi.Stage{ ObjectMeta: metav1.ObjectMeta{ Name: "fake-stage", Namespace: "fake-namespace", @@ -578,7 +578,7 @@ func TestAnnotateStageWithArgoCDContext(t *testing.T) { }, ).Build() - err := AnnotateStageWithArgoCDContext(context.TODO(), c, []kargoapi.HealthCheckStep{ + err := AnnotateStageWithArgoCDContext(t.Context(), c, []kargoapi.HealthCheckStep{ { Uses: "argocd-update", Config: &apiextensionsv1.JSON{ @@ -593,7 +593,7 @@ func TestAnnotateStageWithArgoCDContext(t *testing.T) { }) require.NoError(t, err) - stage, err := GetStage(context.TODO(), c, types.NamespacedName{ + stage, err := GetStage(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) @@ -616,7 +616,7 @@ func TestAnnotateStageWithArgoCDContext(t *testing.T) { }, ).Build() - err := AnnotateStageWithArgoCDContext(context.TODO(), c, []kargoapi.HealthCheckStep{}, &kargoapi.Stage{ + err := AnnotateStageWithArgoCDContext(t.Context(), c, []kargoapi.HealthCheckStep{}, &kargoapi.Stage{ ObjectMeta: metav1.ObjectMeta{ Name: "fake-stage", Namespace: "fake-namespace", @@ -624,7 +624,7 @@ func TestAnnotateStageWithArgoCDContext(t *testing.T) { }) require.NoError(t, err) - stage, err := GetStage(context.TODO(), c, types.NamespacedName{ + stage, err := GetStage(t.Context(), c, types.NamespacedName{ Namespace: "fake-namespace", Name: "fake-stage", }) diff --git a/pkg/api/stubs/rollouts/analysis_test.go b/pkg/api/stubs/rollouts/analysis_test.go index 01f1ad8963..77bf0d0de7 100644 --- a/pkg/api/stubs/rollouts/analysis_test.go +++ b/pkg/api/stubs/rollouts/analysis_test.go @@ -1,7 +1,6 @@ package rollouts import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -53,7 +52,7 @@ func TestGetAnalysisTemplate(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { template, err := GetAnalysisTemplate( - context.Background(), + t.Context(), testCase.client, types.NamespacedName{ Namespace: "fake-namespace", @@ -102,7 +101,7 @@ func TestGetClusterAnalysisTemplate(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { template, err := GetClusterAnalysisTemplate( - context.Background(), + t.Context(), testCase.client, "fake-template", ) @@ -150,7 +149,7 @@ func TestGetAnalysisRun(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { run, err := GetAnalysisRun( - context.Background(), + t.Context(), testCase.client, types.NamespacedName{ Namespace: "fake-namespace", diff --git a/pkg/api/warehouse_test.go b/pkg/api/warehouse_test.go index eb969c92f2..ef0cfad51d 100644 --- a/pkg/api/warehouse_test.go +++ b/pkg/api/warehouse_test.go @@ -98,7 +98,7 @@ func TestGetWarehouse(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { warehouse, err := GetWarehouse( - context.Background(), + t.Context(), testCase.client, types.NamespacedName{ Namespace: "fake-namespace", @@ -489,7 +489,7 @@ func TestListFreightFromWarehouse(t *testing.T) { }, } freight, err := ListFreightFromWarehouse( - context.Background(), c, warehouse, testCase.opts, + t.Context(), c, warehouse, testCase.opts, ) testCase.assertions(t, freight, err) }) diff --git a/pkg/argocd/refresh.go b/pkg/argocd/refresh.go new file mode 100644 index 0000000000..686a03aabf --- /dev/null +++ b/pkg/argocd/refresh.go @@ -0,0 +1,34 @@ +package argocd + +import ( + "context" + + "sigs.k8s.io/controller-runtime/pkg/client" + + argocd "github.com/akuity/kargo/pkg/controller/argocd/api/v1alpha1" + "github.com/akuity/kargo/pkg/logging" +) + +// RequestAppRefresh annotates the Argo CD Application with a hard refresh +// request. This ensures Argo CD invalidates its cache and persists the full +// status (including reconciledAt) on the next reconciliation — even when +// health and sync status are unchanged from before the operation. +func RequestAppRefresh( + ctx context.Context, + argocdClient client.Client, + app *argocd.Application, +) { + patch := client.MergeFrom(app.DeepCopy()) + if app.Annotations == nil { + app.Annotations = make(map[string]string, 1) + } + app.Annotations[argocd.AnnotationKeyRefresh] = string(argocd.RefreshTypeHard) + if err := argocdClient.Patch(ctx, app, patch); err != nil { + logging.LoggerFromContext(ctx).Error( + err, + "failed to request hard refresh for Argo CD Application", + "namespace", app.Namespace, + "name", app.Name, + ) + } +} diff --git a/pkg/cache/memory_test.go b/pkg/cache/memory_test.go index 82c75defd4..9803f7404d 100644 --- a/pkg/cache/memory_test.go +++ b/pkg/cache/memory_test.go @@ -1,7 +1,6 @@ package cache import ( - "context" "testing" lru "github.com/hashicorp/golang-lru/v2" @@ -89,7 +88,7 @@ func TestInMemoryCache_Get(t *testing.T) { testCase.setup(internalCache) } cache := &inMemoryCache[testStruct]{cache: internalCache} - value, found, err := cache.Get(context.Background(), testKey) + value, found, err := cache.Get(t.Context(), testKey) require.NoError(t, err) testCase.assertions(t, value, found, err) }) diff --git a/pkg/cli/client/token_refresher_test.go b/pkg/cli/client/token_refresher_test.go index 828e6005cc..07ee896a1b 100644 --- a/pkg/cli/client/token_refresher_test.go +++ b/pkg/cli/client/token_refresher_test.go @@ -193,7 +193,7 @@ func TestRefreshToken(t *testing.T) { } cfg := testCase.setup() newCfg, err := - tf.refreshToken(context.Background(), testCase.setup(), false) + tf.refreshToken(t.Context(), testCase.setup(), false) testCase.assertions(t, cfg, newCfg, err) }) } diff --git a/pkg/cli/cmd/login/login_test.go b/pkg/cli/cmd/login/login_test.go index 3258363ae8..bf7f8bb903 100644 --- a/pkg/cli/cmd/login/login_test.go +++ b/pkg/cli/cmd/login/login_test.go @@ -1,7 +1,6 @@ package login import ( - "context" "crypto/sha256" "encoding/base64" "fmt" @@ -20,7 +19,7 @@ func TestReceiveAuthCode(t *testing.T) { testState = "fake-state" testCode = "fake-code" ) - ctx := context.Background() + ctx := t.Context() codeCh := make(chan string) errCh := make(chan error) listener, err := net.Listen("tcp", "localhost:0") diff --git a/pkg/client/generated/core/create_project_config_map_responses.go b/pkg/client/generated/core/create_project_config_map_responses.go index b7409101d4..bce1b42f18 100644 --- a/pkg/client/generated/core/create_project_config_map_responses.go +++ b/pkg/client/generated/core/create_project_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateProjectConfigMapReader is a Reader for the CreateProjectConfigMap structure. @@ -42,7 +44,7 @@ CreateProjectConfigMapCreated describes a response with status code 201, with de ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type CreateProjectConfigMapCreated struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this create project config map created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateProjectConfigMapCreated) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/configmaps][%d] createProjectConfigMapCreated %s", 201, payload) } -func (o *CreateProjectConfigMapCreated) GetPayload() any { +func (o *CreateProjectConfigMapCreated) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *CreateProjectConfigMapCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/create_shared_config_map_responses.go b/pkg/client/generated/core/create_shared_config_map_responses.go index 058c90fb01..8b3ed0fb91 100644 --- a/pkg/client/generated/core/create_shared_config_map_responses.go +++ b/pkg/client/generated/core/create_shared_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateSharedConfigMapReader is a Reader for the CreateSharedConfigMap structure. @@ -42,7 +44,7 @@ CreateSharedConfigMapCreated describes a response with status code 201, with def ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type CreateSharedConfigMapCreated struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this create shared config map created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateSharedConfigMapCreated) String() string { return fmt.Sprintf("[POST /v1beta1/shared/configmaps][%d] createSharedConfigMapCreated %s", 201, payload) } -func (o *CreateSharedConfigMapCreated) GetPayload() any { +func (o *CreateSharedConfigMapCreated) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *CreateSharedConfigMapCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/create_system_config_map_responses.go b/pkg/client/generated/core/create_system_config_map_responses.go index ab85e1c90b..4bea4bfe9c 100644 --- a/pkg/client/generated/core/create_system_config_map_responses.go +++ b/pkg/client/generated/core/create_system_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateSystemConfigMapReader is a Reader for the CreateSystemConfigMap structure. @@ -42,7 +44,7 @@ CreateSystemConfigMapCreated describes a response with status code 201, with def ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type CreateSystemConfigMapCreated struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this create system config map created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateSystemConfigMapCreated) String() string { return fmt.Sprintf("[POST /v1beta1/system/configmaps][%d] createSystemConfigMapCreated %s", 201, payload) } -func (o *CreateSystemConfigMapCreated) GetPayload() any { +func (o *CreateSystemConfigMapCreated) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *CreateSystemConfigMapCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_cluster_promotion_task_responses.go b/pkg/client/generated/core/get_cluster_promotion_task_responses.go index ff29e983b4..6b08fc8d6b 100644 --- a/pkg/client/generated/core/get_cluster_promotion_task_responses.go +++ b/pkg/client/generated/core/get_cluster_promotion_task_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetClusterPromotionTaskReader is a Reader for the GetClusterPromotionTask structure. @@ -42,7 +44,7 @@ GetClusterPromotionTaskOK describes a response with status code 200, with defaul ClusterPromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTask) */ type GetClusterPromotionTaskOK struct { - Payload any + Payload *models.ClusterPromotionTask } // IsSuccess returns true when this get cluster promotion task o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetClusterPromotionTaskOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/cluster-promotion-tasks/{cluster-promotion-task}][%d] getClusterPromotionTaskOK %s", 200, payload) } -func (o *GetClusterPromotionTaskOK) GetPayload() any { +func (o *GetClusterPromotionTaskOK) GetPayload() *models.ClusterPromotionTask { return o.Payload } func (o *GetClusterPromotionTaskOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.ClusterPromotionTask) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_freight_responses.go b/pkg/client/generated/core/get_freight_responses.go index e8796415b3..09137b18d9 100644 --- a/pkg/client/generated/core/get_freight_responses.go +++ b/pkg/client/generated/core/get_freight_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetFreightReader is a Reader for the GetFreight structure. @@ -42,7 +44,7 @@ GetFreightOK describes a response with status code 200, with default header valu Freight custom resource (github.com/akuity/kargo/api/v1alpha1.Freight) */ type GetFreightOK struct { - Payload any + Payload *models.Freight } // IsSuccess returns true when this get freight o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetFreightOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/freight/{freight-name-or-alias}][%d] getFreightOK %s", 200, payload) } -func (o *GetFreightOK) GetPayload() any { +func (o *GetFreightOK) GetPayload() *models.Freight { return o.Payload } func (o *GetFreightOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.Freight) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_project_config_map_responses.go b/pkg/client/generated/core/get_project_config_map_responses.go index 86e457b3bb..837cde884e 100644 --- a/pkg/client/generated/core/get_project_config_map_responses.go +++ b/pkg/client/generated/core/get_project_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetProjectConfigMapReader is a Reader for the GetProjectConfigMap structure. @@ -42,7 +44,7 @@ GetProjectConfigMapOK describes a response with status code 200, with default he ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type GetProjectConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this get project config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetProjectConfigMapOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/configmaps/{configmap}][%d] getProjectConfigMapOK %s", 200, payload) } -func (o *GetProjectConfigMapOK) GetPayload() any { +func (o *GetProjectConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *GetProjectConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_project_config_responses.go b/pkg/client/generated/core/get_project_config_responses.go index 88d5bb050c..61938ba0de 100644 --- a/pkg/client/generated/core/get_project_config_responses.go +++ b/pkg/client/generated/core/get_project_config_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetProjectConfigReader is a Reader for the GetProjectConfig structure. @@ -39,10 +41,10 @@ func NewGetProjectConfigOK() *GetProjectConfigOK { /* GetProjectConfigOK describes a response with status code 200, with default header values. -ProjectConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectConfig) +ProjectConfig custom resource */ type GetProjectConfigOK struct { - Payload any + Payload *models.ProjectConfig } // IsSuccess returns true when this get project config o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetProjectConfigOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/config][%d] getProjectConfigOK %s", 200, payload) } -func (o *GetProjectConfigOK) GetPayload() any { +func (o *GetProjectConfigOK) GetPayload() *models.ProjectConfig { return o.Payload } func (o *GetProjectConfigOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.ProjectConfig) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_project_responses.go b/pkg/client/generated/core/get_project_responses.go index 5b897c6b5c..36e32173e1 100644 --- a/pkg/client/generated/core/get_project_responses.go +++ b/pkg/client/generated/core/get_project_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetProjectReader is a Reader for the GetProject structure. @@ -42,7 +44,7 @@ GetProjectOK describes a response with status code 200, with default header valu Project custom resource (github.com/akuity/kargo/api/v1alpha1.Project) */ type GetProjectOK struct { - Payload any + Payload *models.Project } // IsSuccess returns true when this get project o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetProjectOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}][%d] getProjectOK %s", 200, payload) } -func (o *GetProjectOK) GetPayload() any { +func (o *GetProjectOK) GetPayload() *models.Project { return o.Payload } func (o *GetProjectOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.Project) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_promotion_responses.go b/pkg/client/generated/core/get_promotion_responses.go index dfdc1a1cd2..ca61280a05 100644 --- a/pkg/client/generated/core/get_promotion_responses.go +++ b/pkg/client/generated/core/get_promotion_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetPromotionReader is a Reader for the GetPromotion structure. @@ -42,7 +44,7 @@ GetPromotionOK describes a response with status code 200, with default header va Promotion custom resource (github.com/akuity/kargo/api/v1alpha1.Promotion) */ type GetPromotionOK struct { - Payload any + Payload *models.Promotion } // IsSuccess returns true when this get promotion o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetPromotionOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/promotions/{promotion}][%d] getPromotionOK %s", 200, payload) } -func (o *GetPromotionOK) GetPayload() any { +func (o *GetPromotionOK) GetPayload() *models.Promotion { return o.Payload } func (o *GetPromotionOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.Promotion) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_promotion_task_responses.go b/pkg/client/generated/core/get_promotion_task_responses.go index 81d364ae21..e180589139 100644 --- a/pkg/client/generated/core/get_promotion_task_responses.go +++ b/pkg/client/generated/core/get_promotion_task_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetPromotionTaskReader is a Reader for the GetPromotionTask structure. @@ -39,10 +41,10 @@ func NewGetPromotionTaskOK() *GetPromotionTaskOK { /* GetPromotionTaskOK describes a response with status code 200, with default header values. -PromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTask) +PromotionTask custom resource */ type GetPromotionTaskOK struct { - Payload any + Payload *models.PromotionTask } // IsSuccess returns true when this get promotion task o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetPromotionTaskOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/promotion-tasks/{promotion-task}][%d] getPromotionTaskOK %s", 200, payload) } -func (o *GetPromotionTaskOK) GetPayload() any { +func (o *GetPromotionTaskOK) GetPayload() *models.PromotionTask { return o.Payload } func (o *GetPromotionTaskOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.PromotionTask) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_shared_config_map_responses.go b/pkg/client/generated/core/get_shared_config_map_responses.go index b551f661bf..0784a6335a 100644 --- a/pkg/client/generated/core/get_shared_config_map_responses.go +++ b/pkg/client/generated/core/get_shared_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetSharedConfigMapReader is a Reader for the GetSharedConfigMap structure. @@ -42,7 +44,7 @@ GetSharedConfigMapOK describes a response with status code 200, with default hea ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type GetSharedConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this get shared config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetSharedConfigMapOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/configmaps/{configmap}][%d] getSharedConfigMapOK %s", 200, payload) } -func (o *GetSharedConfigMapOK) GetPayload() any { +func (o *GetSharedConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *GetSharedConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_stage_responses.go b/pkg/client/generated/core/get_stage_responses.go index aa7cd0f164..e4e26d06f0 100644 --- a/pkg/client/generated/core/get_stage_responses.go +++ b/pkg/client/generated/core/get_stage_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetStageReader is a Reader for the GetStage structure. @@ -42,7 +44,7 @@ GetStageOK describes a response with status code 200, with default header values Stage custom resource (github.com/akuity/kargo/api/v1alpha1.Stage) */ type GetStageOK struct { - Payload any + Payload *models.Stage } // IsSuccess returns true when this get stage o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetStageOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/stages/{stage}][%d] getStageOK %s", 200, payload) } -func (o *GetStageOK) GetPayload() any { +func (o *GetStageOK) GetPayload() *models.Stage { return o.Payload } func (o *GetStageOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.Stage) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_system_config_map_responses.go b/pkg/client/generated/core/get_system_config_map_responses.go index 543bc8df2a..55e6de6005 100644 --- a/pkg/client/generated/core/get_system_config_map_responses.go +++ b/pkg/client/generated/core/get_system_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetSystemConfigMapReader is a Reader for the GetSystemConfigMap structure. @@ -42,7 +44,7 @@ GetSystemConfigMapOK describes a response with status code 200, with default hea ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type GetSystemConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this get system config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetSystemConfigMapOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/configmaps/{configmap}][%d] getSystemConfigMapOK %s", 200, payload) } -func (o *GetSystemConfigMapOK) GetPayload() any { +func (o *GetSystemConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *GetSystemConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/get_warehouse_responses.go b/pkg/client/generated/core/get_warehouse_responses.go index f728287279..fbe2c3b9f9 100644 --- a/pkg/client/generated/core/get_warehouse_responses.go +++ b/pkg/client/generated/core/get_warehouse_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetWarehouseReader is a Reader for the GetWarehouse structure. @@ -42,7 +44,7 @@ GetWarehouseOK describes a response with status code 200, with default header va Warehouse custom resource (github.com/akuity/kargo/api/v1alpha1.Warehouse) */ type GetWarehouseOK struct { - Payload any + Payload *models.Warehouse } // IsSuccess returns true when this get warehouse o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetWarehouseOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/warehouses/{warehouse}][%d] getWarehouseOK %s", 200, payload) } -func (o *GetWarehouseOK) GetPayload() any { +func (o *GetWarehouseOK) GetPayload() *models.Warehouse { return o.Payload } func (o *GetWarehouseOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.Warehouse) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_cluster_promotion_tasks_responses.go b/pkg/client/generated/core/list_cluster_promotion_tasks_responses.go index 5a24aa417c..a882698675 100644 --- a/pkg/client/generated/core/list_cluster_promotion_tasks_responses.go +++ b/pkg/client/generated/core/list_cluster_promotion_tasks_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListClusterPromotionTasksReader is a Reader for the ListClusterPromotionTasks structure. @@ -42,7 +44,7 @@ ListClusterPromotionTasksOK describes a response with status code 200, with defa ClusterPromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTaskList) */ type ListClusterPromotionTasksOK struct { - Payload any + Payload *models.ClusterPromotionTaskList } // IsSuccess returns true when this list cluster promotion tasks o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListClusterPromotionTasksOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/cluster-promotion-tasks][%d] listClusterPromotionTasksOK %s", 200, payload) } -func (o *ListClusterPromotionTasksOK) GetPayload() any { +func (o *ListClusterPromotionTasksOK) GetPayload() *models.ClusterPromotionTaskList { return o.Payload } func (o *ListClusterPromotionTasksOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.ClusterPromotionTaskList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_project_config_maps_responses.go b/pkg/client/generated/core/list_project_config_maps_responses.go index 828b79a586..ff9a4ec5cb 100644 --- a/pkg/client/generated/core/list_project_config_maps_responses.go +++ b/pkg/client/generated/core/list_project_config_maps_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListProjectConfigMapsReader is a Reader for the ListProjectConfigMaps structure. @@ -42,7 +44,7 @@ ListProjectConfigMapsOK describes a response with status code 200, with default ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList) */ type ListProjectConfigMapsOK struct { - Payload any + Payload *models.V1ConfigMapList } // IsSuccess returns true when this list project config maps o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListProjectConfigMapsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/configmaps][%d] listProjectConfigMapsOK %s", 200, payload) } -func (o *ListProjectConfigMapsOK) GetPayload() any { +func (o *ListProjectConfigMapsOK) GetPayload() *models.V1ConfigMapList { return o.Payload } func (o *ListProjectConfigMapsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMapList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_projects_responses.go b/pkg/client/generated/core/list_projects_responses.go index a25b448142..6b9e03b94c 100644 --- a/pkg/client/generated/core/list_projects_responses.go +++ b/pkg/client/generated/core/list_projects_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListProjectsReader is a Reader for the ListProjects structure. @@ -39,10 +41,10 @@ func NewListProjectsOK() *ListProjectsOK { /* ListProjectsOK describes a response with status code 200, with default header values. -ProjectList custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectList) +ProjectList custom resource */ type ListProjectsOK struct { - Payload any + Payload *models.ProjectList } // IsSuccess returns true when this list projects o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListProjectsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects][%d] listProjectsOK %s", 200, payload) } -func (o *ListProjectsOK) GetPayload() any { +func (o *ListProjectsOK) GetPayload() *models.ProjectList { return o.Payload } func (o *ListProjectsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.ProjectList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_promotion_tasks_responses.go b/pkg/client/generated/core/list_promotion_tasks_responses.go index a578df79d2..7b1bb71f8e 100644 --- a/pkg/client/generated/core/list_promotion_tasks_responses.go +++ b/pkg/client/generated/core/list_promotion_tasks_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListPromotionTasksReader is a Reader for the ListPromotionTasks structure. @@ -42,7 +44,7 @@ ListPromotionTasksOK describes a response with status code 200, with default hea PromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTaskList) */ type ListPromotionTasksOK struct { - Payload any + Payload *models.PromotionTaskList } // IsSuccess returns true when this list promotion tasks o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListPromotionTasksOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/promotion-tasks][%d] listPromotionTasksOK %s", 200, payload) } -func (o *ListPromotionTasksOK) GetPayload() any { +func (o *ListPromotionTasksOK) GetPayload() *models.PromotionTaskList { return o.Payload } func (o *ListPromotionTasksOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.PromotionTaskList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_promotions_responses.go b/pkg/client/generated/core/list_promotions_responses.go index 1e17bc2621..dfa52d37ff 100644 --- a/pkg/client/generated/core/list_promotions_responses.go +++ b/pkg/client/generated/core/list_promotions_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListPromotionsReader is a Reader for the ListPromotions structure. @@ -39,10 +41,10 @@ func NewListPromotionsOK() *ListPromotionsOK { /* ListPromotionsOK describes a response with status code 200, with default header values. -PromotionList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionList) +PromotionList custom resource */ type ListPromotionsOK struct { - Payload any + Payload *models.PromotionList } // IsSuccess returns true when this list promotions o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListPromotionsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/promotions][%d] listPromotionsOK %s", 200, payload) } -func (o *ListPromotionsOK) GetPayload() any { +func (o *ListPromotionsOK) GetPayload() *models.PromotionList { return o.Payload } func (o *ListPromotionsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.PromotionList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_shared_config_maps_responses.go b/pkg/client/generated/core/list_shared_config_maps_responses.go index 7a839e466f..de14679cac 100644 --- a/pkg/client/generated/core/list_shared_config_maps_responses.go +++ b/pkg/client/generated/core/list_shared_config_maps_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListSharedConfigMapsReader is a Reader for the ListSharedConfigMaps structure. @@ -42,7 +44,7 @@ ListSharedConfigMapsOK describes a response with status code 200, with default h ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList) */ type ListSharedConfigMapsOK struct { - Payload any + Payload *models.V1ConfigMapList } // IsSuccess returns true when this list shared config maps o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListSharedConfigMapsOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/configmaps][%d] listSharedConfigMapsOK %s", 200, payload) } -func (o *ListSharedConfigMapsOK) GetPayload() any { +func (o *ListSharedConfigMapsOK) GetPayload() *models.V1ConfigMapList { return o.Payload } func (o *ListSharedConfigMapsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMapList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_stages_responses.go b/pkg/client/generated/core/list_stages_responses.go index 63b60a243b..7dbbed9362 100644 --- a/pkg/client/generated/core/list_stages_responses.go +++ b/pkg/client/generated/core/list_stages_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListStagesReader is a Reader for the ListStages structure. @@ -42,7 +44,7 @@ ListStagesOK describes a response with status code 200, with default header valu StageList custom resource (github.com/akuity/kargo/api/v1alpha1.StageList) */ type ListStagesOK struct { - Payload any + Payload *models.StageList } // IsSuccess returns true when this list stages o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListStagesOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/stages][%d] listStagesOK %s", 200, payload) } -func (o *ListStagesOK) GetPayload() any { +func (o *ListStagesOK) GetPayload() *models.StageList { return o.Payload } func (o *ListStagesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.StageList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_system_config_maps_responses.go b/pkg/client/generated/core/list_system_config_maps_responses.go index f959f04bc2..2008f08d9a 100644 --- a/pkg/client/generated/core/list_system_config_maps_responses.go +++ b/pkg/client/generated/core/list_system_config_maps_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListSystemConfigMapsReader is a Reader for the ListSystemConfigMaps structure. @@ -42,7 +44,7 @@ ListSystemConfigMapsOK describes a response with status code 200, with default h ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList) */ type ListSystemConfigMapsOK struct { - Payload any + Payload *models.V1ConfigMapList } // IsSuccess returns true when this list system config maps o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListSystemConfigMapsOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/configmaps][%d] listSystemConfigMapsOK %s", 200, payload) } -func (o *ListSystemConfigMapsOK) GetPayload() any { +func (o *ListSystemConfigMapsOK) GetPayload() *models.V1ConfigMapList { return o.Payload } func (o *ListSystemConfigMapsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMapList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/list_warehouses_responses.go b/pkg/client/generated/core/list_warehouses_responses.go index 31c15d7060..4998ca7fbb 100644 --- a/pkg/client/generated/core/list_warehouses_responses.go +++ b/pkg/client/generated/core/list_warehouses_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListWarehousesReader is a Reader for the ListWarehouses structure. @@ -39,10 +41,10 @@ func NewListWarehousesOK() *ListWarehousesOK { /* ListWarehousesOK describes a response with status code 200, with default header values. -WarehouseList custom resource (github.com/akuity/kargo/api/v1alpha1.WarehouseList) +WarehouseList custom resource */ type ListWarehousesOK struct { - Payload any + Payload *models.WarehouseList } // IsSuccess returns true when this list warehouses o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListWarehousesOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/warehouses][%d] listWarehousesOK %s", 200, payload) } -func (o *ListWarehousesOK) GetPayload() any { +func (o *ListWarehousesOK) GetPayload() *models.WarehouseList { return o.Payload } func (o *ListWarehousesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.WarehouseList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/patch_project_config_map_responses.go b/pkg/client/generated/core/patch_project_config_map_responses.go index fb1f00ccd5..73030fd5f1 100644 --- a/pkg/client/generated/core/patch_project_config_map_responses.go +++ b/pkg/client/generated/core/patch_project_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchProjectConfigMapReader is a Reader for the PatchProjectConfigMap structure. @@ -42,7 +44,7 @@ PatchProjectConfigMapOK describes a response with status code 200, with default ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type PatchProjectConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this patch project config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchProjectConfigMapOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/projects/{project}/configmaps/{configmap}][%d] patchProjectConfigMapOK %s", 200, payload) } -func (o *PatchProjectConfigMapOK) GetPayload() any { +func (o *PatchProjectConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *PatchProjectConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/patch_shared_config_map_responses.go b/pkg/client/generated/core/patch_shared_config_map_responses.go index 2ca22c553d..77d66d83c4 100644 --- a/pkg/client/generated/core/patch_shared_config_map_responses.go +++ b/pkg/client/generated/core/patch_shared_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchSharedConfigMapReader is a Reader for the PatchSharedConfigMap structure. @@ -42,7 +44,7 @@ PatchSharedConfigMapOK describes a response with status code 200, with default h ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type PatchSharedConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this patch shared config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchSharedConfigMapOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/shared/configmaps/{configmap}][%d] patchSharedConfigMapOK %s", 200, payload) } -func (o *PatchSharedConfigMapOK) GetPayload() any { +func (o *PatchSharedConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *PatchSharedConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/patch_system_config_map_responses.go b/pkg/client/generated/core/patch_system_config_map_responses.go index 8e5c9d2b17..5bb090a13e 100644 --- a/pkg/client/generated/core/patch_system_config_map_responses.go +++ b/pkg/client/generated/core/patch_system_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchSystemConfigMapReader is a Reader for the PatchSystemConfigMap structure. @@ -42,7 +44,7 @@ PatchSystemConfigMapOK describes a response with status code 200, with default h ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type PatchSystemConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this patch system config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchSystemConfigMapOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/system/configmaps/{configmap}][%d] patchSystemConfigMapOK %s", 200, payload) } -func (o *PatchSystemConfigMapOK) GetPayload() any { +func (o *PatchSystemConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *PatchSystemConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/promote_to_stage_responses.go b/pkg/client/generated/core/promote_to_stage_responses.go index 4acbdc377b..e40de5800a 100644 --- a/pkg/client/generated/core/promote_to_stage_responses.go +++ b/pkg/client/generated/core/promote_to_stage_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PromoteToStageReader is a Reader for the PromoteToStage structure. @@ -42,7 +44,7 @@ PromoteToStageCreated describes a response with status code 201, with default he Promotion resource (github.com/akuity/kargo/api/v1alpha1.Promotion) */ type PromoteToStageCreated struct { - Payload any + Payload *models.Promotion } // IsSuccess returns true when this promote to stage created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PromoteToStageCreated) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/stages/{stage}/promotions][%d] promoteToStageCreated %s", 201, payload) } -func (o *PromoteToStageCreated) GetPayload() any { +func (o *PromoteToStageCreated) GetPayload() *models.Promotion { return o.Payload } func (o *PromoteToStageCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.Promotion) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/update_project_config_map_responses.go b/pkg/client/generated/core/update_project_config_map_responses.go index 4caef5fe42..c39defce9f 100644 --- a/pkg/client/generated/core/update_project_config_map_responses.go +++ b/pkg/client/generated/core/update_project_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateProjectConfigMapReader is a Reader for the UpdateProjectConfigMap structure. @@ -42,7 +44,7 @@ UpdateProjectConfigMapOK describes a response with status code 200, with default ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type UpdateProjectConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this update project config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateProjectConfigMapOK) String() string { return fmt.Sprintf("[PUT /v1beta1/projects/{project}/configmaps/{configmap}][%d] updateProjectConfigMapOK %s", 200, payload) } -func (o *UpdateProjectConfigMapOK) GetPayload() any { +func (o *UpdateProjectConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *UpdateProjectConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/update_shared_config_map_responses.go b/pkg/client/generated/core/update_shared_config_map_responses.go index 62cb5d76eb..cfe65b2140 100644 --- a/pkg/client/generated/core/update_shared_config_map_responses.go +++ b/pkg/client/generated/core/update_shared_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateSharedConfigMapReader is a Reader for the UpdateSharedConfigMap structure. @@ -42,7 +44,7 @@ UpdateSharedConfigMapOK describes a response with status code 200, with default ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type UpdateSharedConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this update shared config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateSharedConfigMapOK) String() string { return fmt.Sprintf("[PUT /v1beta1/shared/configmaps/{configmap}][%d] updateSharedConfigMapOK %s", 200, payload) } -func (o *UpdateSharedConfigMapOK) GetPayload() any { +func (o *UpdateSharedConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *UpdateSharedConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/core/update_system_config_map_responses.go b/pkg/client/generated/core/update_system_config_map_responses.go index bbbbbabb2f..874e759504 100644 --- a/pkg/client/generated/core/update_system_config_map_responses.go +++ b/pkg/client/generated/core/update_system_config_map_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateSystemConfigMapReader is a Reader for the UpdateSystemConfigMap structure. @@ -42,7 +44,7 @@ UpdateSystemConfigMapOK describes a response with status code 200, with default ConfigMap resource (k8s.io/api/core/v1.ConfigMap) */ type UpdateSystemConfigMapOK struct { - Payload any + Payload *models.V1ConfigMap } // IsSuccess returns true when this update system config map o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateSystemConfigMapOK) String() string { return fmt.Sprintf("[PUT /v1beta1/system/configmaps/{configmap}][%d] updateSystemConfigMapOK %s", 200, payload) } -func (o *UpdateSystemConfigMapOK) GetPayload() any { +func (o *UpdateSystemConfigMapOK) GetPayload() *models.V1ConfigMap { return o.Payload } func (o *UpdateSystemConfigMapOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1ConfigMap) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/create_project_generic_credentials_responses.go b/pkg/client/generated/credentials/create_project_generic_credentials_responses.go index 2d4472c2ef..46b0fc25d2 100644 --- a/pkg/client/generated/credentials/create_project_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/create_project_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateProjectGenericCredentialsReader is a Reader for the CreateProjectGenericCredentials structure. @@ -42,7 +44,7 @@ CreateProjectGenericCredentialsCreated describes a response with status code 201 Secret resource (k8s.io/api/core/v1.Secret) */ type CreateProjectGenericCredentialsCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create project generic credentials created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateProjectGenericCredentialsCreated) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/generic-credentials][%d] createProjectGenericCredentialsCreated %s", 201, payload) } -func (o *CreateProjectGenericCredentialsCreated) GetPayload() any { +func (o *CreateProjectGenericCredentialsCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateProjectGenericCredentialsCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/create_project_repo_credentials_responses.go b/pkg/client/generated/credentials/create_project_repo_credentials_responses.go index 722b792767..4f6257df49 100644 --- a/pkg/client/generated/credentials/create_project_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/create_project_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateProjectRepoCredentialsReader is a Reader for the CreateProjectRepoCredentials structure. @@ -42,7 +44,7 @@ CreateProjectRepoCredentialsCreated describes a response with status code 201, w Secret resource (k8s.io/api/core/v1.Secret) */ type CreateProjectRepoCredentialsCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create project repo credentials created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateProjectRepoCredentialsCreated) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/repo-credentials][%d] createProjectRepoCredentialsCreated %s", 201, payload) } -func (o *CreateProjectRepoCredentialsCreated) GetPayload() any { +func (o *CreateProjectRepoCredentialsCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateProjectRepoCredentialsCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/create_shared_generic_credentials_responses.go b/pkg/client/generated/credentials/create_shared_generic_credentials_responses.go index d53c692cf0..6443b1f32e 100644 --- a/pkg/client/generated/credentials/create_shared_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/create_shared_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateSharedGenericCredentialsReader is a Reader for the CreateSharedGenericCredentials structure. @@ -42,7 +44,7 @@ CreateSharedGenericCredentialsCreated describes a response with status code 201, Secret resource (k8s.io/api/core/v1.Secret) */ type CreateSharedGenericCredentialsCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create shared generic credentials created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateSharedGenericCredentialsCreated) String() string { return fmt.Sprintf("[POST /v1beta1/shared/generic-credentials][%d] createSharedGenericCredentialsCreated %s", 201, payload) } -func (o *CreateSharedGenericCredentialsCreated) GetPayload() any { +func (o *CreateSharedGenericCredentialsCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateSharedGenericCredentialsCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/create_shared_repo_credentials_responses.go b/pkg/client/generated/credentials/create_shared_repo_credentials_responses.go index 9c6b1a6c75..bf20137eec 100644 --- a/pkg/client/generated/credentials/create_shared_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/create_shared_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateSharedRepoCredentialsReader is a Reader for the CreateSharedRepoCredentials structure. @@ -42,7 +44,7 @@ CreateSharedRepoCredentialsCreated describes a response with status code 201, wi Secret resource (k8s.io/api/core/v1.Secret) */ type CreateSharedRepoCredentialsCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create shared repo credentials created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateSharedRepoCredentialsCreated) String() string { return fmt.Sprintf("[POST /v1beta1/shared/repo-credentials][%d] createSharedRepoCredentialsCreated %s", 201, payload) } -func (o *CreateSharedRepoCredentialsCreated) GetPayload() any { +func (o *CreateSharedRepoCredentialsCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateSharedRepoCredentialsCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/create_system_generic_credentials_responses.go b/pkg/client/generated/credentials/create_system_generic_credentials_responses.go index bb72a20051..33a2703838 100644 --- a/pkg/client/generated/credentials/create_system_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/create_system_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateSystemGenericCredentialsReader is a Reader for the CreateSystemGenericCredentials structure. @@ -42,7 +44,7 @@ CreateSystemGenericCredentialsCreated describes a response with status code 201, Secret resource (k8s.io/api/core/v1.Secret) */ type CreateSystemGenericCredentialsCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create system generic credentials created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateSystemGenericCredentialsCreated) String() string { return fmt.Sprintf("[POST /v1beta1/system/generic-credentials][%d] createSystemGenericCredentialsCreated %s", 201, payload) } -func (o *CreateSystemGenericCredentialsCreated) GetPayload() any { +func (o *CreateSystemGenericCredentialsCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateSystemGenericCredentialsCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/get_project_generic_credentials_responses.go b/pkg/client/generated/credentials/get_project_generic_credentials_responses.go index 0565611161..22f1a4d8e7 100644 --- a/pkg/client/generated/credentials/get_project_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/get_project_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetProjectGenericCredentialsReader is a Reader for the GetProjectGenericCredentials structure. @@ -42,7 +44,7 @@ GetProjectGenericCredentialsOK describes a response with status code 200, with d Secret resource (k8s.io/api/core/v1.Secret) */ type GetProjectGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get project generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetProjectGenericCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/generic-credentials/{generic-credentials}][%d] getProjectGenericCredentialsOK %s", 200, payload) } -func (o *GetProjectGenericCredentialsOK) GetPayload() any { +func (o *GetProjectGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetProjectGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/get_project_repo_credentials_responses.go b/pkg/client/generated/credentials/get_project_repo_credentials_responses.go index 542ed9ca4b..2c7c19cd3a 100644 --- a/pkg/client/generated/credentials/get_project_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/get_project_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetProjectRepoCredentialsReader is a Reader for the GetProjectRepoCredentials structure. @@ -42,7 +44,7 @@ GetProjectRepoCredentialsOK describes a response with status code 200, with defa Secret resource (k8s.io/api/core/v1.Secret) */ type GetProjectRepoCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get project repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetProjectRepoCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/repo-credentials/{repo-credentials}][%d] getProjectRepoCredentialsOK %s", 200, payload) } -func (o *GetProjectRepoCredentialsOK) GetPayload() any { +func (o *GetProjectRepoCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetProjectRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/get_shared_generic_credentials_responses.go b/pkg/client/generated/credentials/get_shared_generic_credentials_responses.go index 2b3b93f7b9..5fac711c34 100644 --- a/pkg/client/generated/credentials/get_shared_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/get_shared_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetSharedGenericCredentialsReader is a Reader for the GetSharedGenericCredentials structure. @@ -42,7 +44,7 @@ GetSharedGenericCredentialsOK describes a response with status code 200, with de Secret resource (k8s.io/api/core/v1.Secret) */ type GetSharedGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get shared generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetSharedGenericCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/generic-credentials/{generic-credentials}][%d] getSharedGenericCredentialsOK %s", 200, payload) } -func (o *GetSharedGenericCredentialsOK) GetPayload() any { +func (o *GetSharedGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetSharedGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/get_shared_repo_credentials_responses.go b/pkg/client/generated/credentials/get_shared_repo_credentials_responses.go index 5fde1638e7..cea7594b7a 100644 --- a/pkg/client/generated/credentials/get_shared_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/get_shared_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetSharedRepoCredentialsReader is a Reader for the GetSharedRepoCredentials structure. @@ -42,7 +44,7 @@ GetSharedRepoCredentialsOK describes a response with status code 200, with defau Secret resource (k8s.io/api/core/v1.Secret) */ type GetSharedRepoCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get shared repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetSharedRepoCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/repo-credentials/{repo-credentials}][%d] getSharedRepoCredentialsOK %s", 200, payload) } -func (o *GetSharedRepoCredentialsOK) GetPayload() any { +func (o *GetSharedRepoCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetSharedRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/get_system_generic_credentials_responses.go b/pkg/client/generated/credentials/get_system_generic_credentials_responses.go index b98461eac5..32f181e4c2 100644 --- a/pkg/client/generated/credentials/get_system_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/get_system_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetSystemGenericCredentialsReader is a Reader for the GetSystemGenericCredentials structure. @@ -42,7 +44,7 @@ GetSystemGenericCredentialsOK describes a response with status code 200, with de Secret resource (k8s.io/api/core/v1.Secret) */ type GetSystemGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get system generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetSystemGenericCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/generic-credentials/{generic-credentials}][%d] getSystemGenericCredentialsOK %s", 200, payload) } -func (o *GetSystemGenericCredentialsOK) GetPayload() any { +func (o *GetSystemGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetSystemGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/list_project_generic_credentials_responses.go b/pkg/client/generated/credentials/list_project_generic_credentials_responses.go index fd7d61fb52..b2eb40ac4b 100644 --- a/pkg/client/generated/credentials/list_project_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/list_project_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListProjectGenericCredentialsReader is a Reader for the ListProjectGenericCredentials structure. @@ -42,7 +44,7 @@ ListProjectGenericCredentialsOK describes a response with status code 200, with SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListProjectGenericCredentialsOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list project generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListProjectGenericCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/generic-credentials][%d] listProjectGenericCredentialsOK %s", 200, payload) } -func (o *ListProjectGenericCredentialsOK) GetPayload() any { +func (o *ListProjectGenericCredentialsOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListProjectGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/list_project_repo_credentials_responses.go b/pkg/client/generated/credentials/list_project_repo_credentials_responses.go index 5a6d2103d4..be6767c97e 100644 --- a/pkg/client/generated/credentials/list_project_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/list_project_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListProjectRepoCredentialsReader is a Reader for the ListProjectRepoCredentials structure. @@ -42,7 +44,7 @@ ListProjectRepoCredentialsOK describes a response with status code 200, with def SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListProjectRepoCredentialsOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list project repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListProjectRepoCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/repo-credentials][%d] listProjectRepoCredentialsOK %s", 200, payload) } -func (o *ListProjectRepoCredentialsOK) GetPayload() any { +func (o *ListProjectRepoCredentialsOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListProjectRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/list_shared_generic_credentials_responses.go b/pkg/client/generated/credentials/list_shared_generic_credentials_responses.go index 1b2f132942..dd344c0eba 100644 --- a/pkg/client/generated/credentials/list_shared_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/list_shared_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListSharedGenericCredentialsReader is a Reader for the ListSharedGenericCredentials structure. @@ -42,7 +44,7 @@ ListSharedGenericCredentialsOK describes a response with status code 200, with d SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListSharedGenericCredentialsOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list shared generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListSharedGenericCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/generic-credentials][%d] listSharedGenericCredentialsOK %s", 200, payload) } -func (o *ListSharedGenericCredentialsOK) GetPayload() any { +func (o *ListSharedGenericCredentialsOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListSharedGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/list_shared_repo_credentials_responses.go b/pkg/client/generated/credentials/list_shared_repo_credentials_responses.go index af775af7f4..8e4adcd310 100644 --- a/pkg/client/generated/credentials/list_shared_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/list_shared_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListSharedRepoCredentialsReader is a Reader for the ListSharedRepoCredentials structure. @@ -42,7 +44,7 @@ ListSharedRepoCredentialsOK describes a response with status code 200, with defa SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListSharedRepoCredentialsOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list shared repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListSharedRepoCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/repo-credentials][%d] listSharedRepoCredentialsOK %s", 200, payload) } -func (o *ListSharedRepoCredentialsOK) GetPayload() any { +func (o *ListSharedRepoCredentialsOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListSharedRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/list_system_generic_credentials_responses.go b/pkg/client/generated/credentials/list_system_generic_credentials_responses.go index 604a49effc..c63d9968ed 100644 --- a/pkg/client/generated/credentials/list_system_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/list_system_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListSystemGenericCredentialsReader is a Reader for the ListSystemGenericCredentials structure. @@ -42,7 +44,7 @@ ListSystemGenericCredentialsOK describes a response with status code 200, with d SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListSystemGenericCredentialsOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list system generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListSystemGenericCredentialsOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/generic-credentials][%d] listSystemGenericCredentialsOK %s", 200, payload) } -func (o *ListSystemGenericCredentialsOK) GetPayload() any { +func (o *ListSystemGenericCredentialsOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListSystemGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/patch_project_generic_credentials_responses.go b/pkg/client/generated/credentials/patch_project_generic_credentials_responses.go index f9773b80c8..a036b0b8f6 100644 --- a/pkg/client/generated/credentials/patch_project_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/patch_project_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchProjectGenericCredentialsReader is a Reader for the PatchProjectGenericCredentials structure. @@ -42,7 +44,7 @@ PatchProjectGenericCredentialsOK describes a response with status code 200, with Secret resource (k8s.io/api/core/v1.Secret) */ type PatchProjectGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this patch project generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchProjectGenericCredentialsOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/projects/{project}/generic-credentials/{generic-credentials}][%d] patchProjectGenericCredentialsOK %s", 200, payload) } -func (o *PatchProjectGenericCredentialsOK) GetPayload() any { +func (o *PatchProjectGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *PatchProjectGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/patch_project_repo_credentials_responses.go b/pkg/client/generated/credentials/patch_project_repo_credentials_responses.go index e90a43b2c3..6327a50594 100644 --- a/pkg/client/generated/credentials/patch_project_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/patch_project_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchProjectRepoCredentialsReader is a Reader for the PatchProjectRepoCredentials structure. @@ -42,7 +44,7 @@ PatchProjectRepoCredentialsOK describes a response with status code 200, with de Secret resource (k8s.io/api/core/v1.Secret) */ type PatchProjectRepoCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this patch project repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchProjectRepoCredentialsOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/projects/{project}/repo-credentials/{repo-credentials}][%d] patchProjectRepoCredentialsOK %s", 200, payload) } -func (o *PatchProjectRepoCredentialsOK) GetPayload() any { +func (o *PatchProjectRepoCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *PatchProjectRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/patch_shared_generic_credentials_responses.go b/pkg/client/generated/credentials/patch_shared_generic_credentials_responses.go index d0e2b414d0..0dac0bf830 100644 --- a/pkg/client/generated/credentials/patch_shared_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/patch_shared_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchSharedGenericCredentialsReader is a Reader for the PatchSharedGenericCredentials structure. @@ -42,7 +44,7 @@ PatchSharedGenericCredentialsOK describes a response with status code 200, with Secret resource (k8s.io/api/core/v1.Secret) */ type PatchSharedGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this patch shared generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchSharedGenericCredentialsOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/shared/generic-credentials/{generic-credentials}][%d] patchSharedGenericCredentialsOK %s", 200, payload) } -func (o *PatchSharedGenericCredentialsOK) GetPayload() any { +func (o *PatchSharedGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *PatchSharedGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/patch_shared_repo_credentials_responses.go b/pkg/client/generated/credentials/patch_shared_repo_credentials_responses.go index fdf93e8e38..eb75ae5fbd 100644 --- a/pkg/client/generated/credentials/patch_shared_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/patch_shared_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchSharedRepoCredentialsReader is a Reader for the PatchSharedRepoCredentials structure. @@ -42,7 +44,7 @@ PatchSharedRepoCredentialsOK describes a response with status code 200, with def Secret resource (k8s.io/api/core/v1.Secret) */ type PatchSharedRepoCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this patch shared repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchSharedRepoCredentialsOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/shared/repo-credentials/{repo-credentials}][%d] patchSharedRepoCredentialsOK %s", 200, payload) } -func (o *PatchSharedRepoCredentialsOK) GetPayload() any { +func (o *PatchSharedRepoCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *PatchSharedRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/patch_system_generic_credentials_responses.go b/pkg/client/generated/credentials/patch_system_generic_credentials_responses.go index ad1a37567c..9c68d081ff 100644 --- a/pkg/client/generated/credentials/patch_system_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/patch_system_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // PatchSystemGenericCredentialsReader is a Reader for the PatchSystemGenericCredentials structure. @@ -42,7 +44,7 @@ PatchSystemGenericCredentialsOK describes a response with status code 200, with Secret resource (k8s.io/api/core/v1.Secret) */ type PatchSystemGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this patch system generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *PatchSystemGenericCredentialsOK) String() string { return fmt.Sprintf("[PATCH /v1beta1/system/generic-credentials/{generic-credentials}][%d] patchSystemGenericCredentialsOK %s", 200, payload) } -func (o *PatchSystemGenericCredentialsOK) GetPayload() any { +func (o *PatchSystemGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *PatchSystemGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/update_project_generic_credentials_responses.go b/pkg/client/generated/credentials/update_project_generic_credentials_responses.go index 760a665823..8de385d835 100644 --- a/pkg/client/generated/credentials/update_project_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/update_project_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateProjectGenericCredentialsReader is a Reader for the UpdateProjectGenericCredentials structure. @@ -42,7 +44,7 @@ UpdateProjectGenericCredentialsOK describes a response with status code 200, wit Secret resource (k8s.io/api/core/v1.Secret) */ type UpdateProjectGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this update project generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateProjectGenericCredentialsOK) String() string { return fmt.Sprintf("[PUT /v1beta1/projects/{project}/generic-credentials/{generic-credentials}][%d] updateProjectGenericCredentialsOK %s", 200, payload) } -func (o *UpdateProjectGenericCredentialsOK) GetPayload() any { +func (o *UpdateProjectGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *UpdateProjectGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/update_project_repo_credentials_responses.go b/pkg/client/generated/credentials/update_project_repo_credentials_responses.go index 28c3fca3ff..8f0038376c 100644 --- a/pkg/client/generated/credentials/update_project_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/update_project_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateProjectRepoCredentialsReader is a Reader for the UpdateProjectRepoCredentials structure. @@ -42,7 +44,7 @@ UpdateProjectRepoCredentialsOK describes a response with status code 200, with d Secret resource (k8s.io/api/core/v1.Secret) */ type UpdateProjectRepoCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this update project repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateProjectRepoCredentialsOK) String() string { return fmt.Sprintf("[PUT /v1beta1/projects/{project}/repo-credentials/{repo-credentials}][%d] updateProjectRepoCredentialsOK %s", 200, payload) } -func (o *UpdateProjectRepoCredentialsOK) GetPayload() any { +func (o *UpdateProjectRepoCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *UpdateProjectRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/update_shared_generic_credentials_responses.go b/pkg/client/generated/credentials/update_shared_generic_credentials_responses.go index 6212a8e31f..8cacac24c3 100644 --- a/pkg/client/generated/credentials/update_shared_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/update_shared_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateSharedGenericCredentialsReader is a Reader for the UpdateSharedGenericCredentials structure. @@ -42,7 +44,7 @@ UpdateSharedGenericCredentialsOK describes a response with status code 200, with Secret resource (k8s.io/api/core/v1.Secret) */ type UpdateSharedGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this update shared generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateSharedGenericCredentialsOK) String() string { return fmt.Sprintf("[PUT /v1beta1/shared/generic-credentials/{generic-credentials}][%d] updateSharedGenericCredentialsOK %s", 200, payload) } -func (o *UpdateSharedGenericCredentialsOK) GetPayload() any { +func (o *UpdateSharedGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *UpdateSharedGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/update_shared_repo_credentials_responses.go b/pkg/client/generated/credentials/update_shared_repo_credentials_responses.go index ae5a14040f..c6f1a38c5b 100644 --- a/pkg/client/generated/credentials/update_shared_repo_credentials_responses.go +++ b/pkg/client/generated/credentials/update_shared_repo_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateSharedRepoCredentialsReader is a Reader for the UpdateSharedRepoCredentials structure. @@ -42,7 +44,7 @@ UpdateSharedRepoCredentialsOK describes a response with status code 200, with de Secret resource (k8s.io/api/core/v1.Secret) */ type UpdateSharedRepoCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this update shared repo credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateSharedRepoCredentialsOK) String() string { return fmt.Sprintf("[PUT /v1beta1/shared/repo-credentials/{repo-credentials}][%d] updateSharedRepoCredentialsOK %s", 200, payload) } -func (o *UpdateSharedRepoCredentialsOK) GetPayload() any { +func (o *UpdateSharedRepoCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *UpdateSharedRepoCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/credentials/update_system_generic_credentials_responses.go b/pkg/client/generated/credentials/update_system_generic_credentials_responses.go index 4e95858e45..8f79ab98ff 100644 --- a/pkg/client/generated/credentials/update_system_generic_credentials_responses.go +++ b/pkg/client/generated/credentials/update_system_generic_credentials_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateSystemGenericCredentialsReader is a Reader for the UpdateSystemGenericCredentials structure. @@ -42,7 +44,7 @@ UpdateSystemGenericCredentialsOK describes a response with status code 200, with Secret resource (k8s.io/api/core/v1.Secret) */ type UpdateSystemGenericCredentialsOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this update system generic credentials o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateSystemGenericCredentialsOK) String() string { return fmt.Sprintf("[PUT /v1beta1/system/generic-credentials/{generic-credentials}][%d] updateSystemGenericCredentialsOK %s", 200, payload) } -func (o *UpdateSystemGenericCredentialsOK) GetPayload() any { +func (o *UpdateSystemGenericCredentialsOK) GetPayload() *models.V1Secret { return o.Payload } func (o *UpdateSystemGenericCredentialsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/events/list_project_events_responses.go b/pkg/client/generated/events/list_project_events_responses.go index 1b4deda0f6..b0549b5360 100644 --- a/pkg/client/generated/events/list_project_events_responses.go +++ b/pkg/client/generated/events/list_project_events_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListProjectEventsReader is a Reader for the ListProjectEvents structure. @@ -42,7 +44,7 @@ ListProjectEventsOK describes a response with status code 200, with default head EventList resource (k8s.io/api/core/v1.EventList) */ type ListProjectEventsOK struct { - Payload any + Payload *models.V1EventList } // IsSuccess returns true when this list project events o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListProjectEventsOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/events][%d] listProjectEventsOK %s", 200, payload) } -func (o *ListProjectEventsOK) GetPayload() any { +func (o *ListProjectEventsOK) GetPayload() *models.V1EventList { return o.Payload } func (o *ListProjectEventsOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1EventList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/go.mod b/pkg/client/generated/go.mod new file mode 100644 index 0000000000..9d8bfd92a5 --- /dev/null +++ b/pkg/client/generated/go.mod @@ -0,0 +1,44 @@ +module github.com/akuity/kargo/pkg/client/generated + +go 1.26.0 + +require ( + github.com/go-openapi/errors v0.22.7 + github.com/go-openapi/runtime v0.29.3 + github.com/go-openapi/strfmt v0.26.1 + github.com/go-openapi/swag v0.25.5 + github.com/go-openapi/validate v0.25.2 +) + +require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/analysis v0.24.3 // indirect + github.com/go-openapi/jsonpointer v0.22.5 // indirect + github.com/go-openapi/jsonreference v0.21.5 // indirect + github.com/go-openapi/loads v0.23.3 // indirect + github.com/go-openapi/spec v0.22.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.5 // indirect + github.com/go-openapi/swag/conv v0.25.5 // indirect + github.com/go-openapi/swag/fileutils v0.25.5 // indirect + github.com/go-openapi/swag/jsonname v0.25.5 // indirect + github.com/go-openapi/swag/jsonutils v0.25.5 // indirect + github.com/go-openapi/swag/loading v0.25.5 // indirect + github.com/go-openapi/swag/mangling v0.25.5 // indirect + github.com/go-openapi/swag/netutils v0.25.5 // indirect + github.com/go-openapi/swag/stringutils v0.25.5 // indirect + github.com/go-openapi/swag/typeutils v0.25.5 // indirect + github.com/go-openapi/swag/yamlutils v0.25.5 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/oklog/ulid/v2 v2.1.1 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/otel v1.41.0 // indirect + go.opentelemetry.io/otel/metric v1.41.0 // indirect + go.opentelemetry.io/otel/trace v1.41.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/net v0.50.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.34.0 // indirect +) diff --git a/pkg/client/generated/go.sum b/pkg/client/generated/go.sum new file mode 100644 index 0000000000..691a2a36e2 --- /dev/null +++ b/pkg/client/generated/go.sum @@ -0,0 +1,101 @@ +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/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.24.3 h1:a1hrvMr8X0Xt69KP5uVTu5jH62DscmDifrLzNglAayk= +github.com/go-openapi/analysis v0.24.3/go.mod h1:Nc+dWJ/FxZbhSow5Yh3ozg5CLJioB+XXT6MdLvJUsUw= +github.com/go-openapi/errors v0.22.7 h1:JLFBGC0Apwdzw3484MmBqspjPbwa2SHvpDm0u5aGhUA= +github.com/go-openapi/errors v0.22.7/go.mod h1://QW6SD9OsWtH6gHllUCddOXDL0tk0ZGNYHwsw4sW3w= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE= +github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= +github.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ= +github.com/go-openapi/loads v0.23.3/go.mod h1:NOH07zLajXo8y55hom0omlHWDVVvCwBM/S+csCK8LqA= +github.com/go-openapi/runtime v0.29.3 h1:h5twGaEqxtQg40ePiYm9vFFH1q06Czd7Ot6ufdK0w/Y= +github.com/go-openapi/runtime v0.29.3/go.mod h1:8A1W0/L5eyNJvKciqZtvIVQvYO66NlB7INMSZ9bw/oI= +github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ= +github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ= +github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c= +github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y= +github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= +github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= +github.com/go-openapi/swag/cmdutils v0.25.5 h1:yh5hHrpgsw4NwM9KAEtaDTXILYzdXh/I8Whhx9hKj7c= +github.com/go-openapi/swag/cmdutils v0.25.5/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= +github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= +github.com/go-openapi/swag/fileutils v0.25.5 h1:B6JTdOcs2c0dBIs9HnkyTW+5gC+8NIhVBUwERkFhMWk= +github.com/go-openapi/swag/fileutils v0.25.5/go.mod h1:V3cT9UdMQIaH4WiTrUc9EPtVA4txS0TOmRURmhGF4kc= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= +github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= +github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= +github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= +github.com/go-openapi/swag/mangling v0.25.5 h1:hyrnvbQRS7vKePQPHHDso+k6CGn5ZBs5232UqWZmJZw= +github.com/go-openapi/swag/mangling v0.25.5/go.mod h1:6hadXM/o312N/h98RwByLg088U61TPGiltQn71Iw0NY= +github.com/go-openapi/swag/netutils v0.25.5 h1:LZq2Xc2QI8+7838elRAaPCeqJnHODfSyOa7ZGfxDKlU= +github.com/go-openapi/swag/netutils v0.25.5/go.mod h1:lHbtmj4m57APG/8H7ZcMMSWzNqIQcu0RFiXrPUara14= +github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= +github.com/go-openapi/swag/stringutils v0.25.5/go.mod h1:PKK8EZdu4QJq8iezt17HM8RXnLAzY7gW0O1KKarrZII= +github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzzr9u4rJk7L7E= +github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= +github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= +github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.1 h1:NZOrZmIb6PTv5LTFxr5/mKV/FjbUzGE7E6gLz7vFoOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.1/go.mod h1:r7dwsujEHawapMsxA69i+XMGZrQ5tRauhLAjV/sxg3Q= +github.com/go-openapi/testify/v2 v2.4.1 h1:zB34HDKj4tHwyUQHrUkpV0Q0iXQ6dUCOQtIqn8hE6Iw= +github.com/go-openapi/testify/v2 v2.4.1/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0= +github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= +github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= +go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= +go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= +go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= +go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8= +go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90= +go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= +go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= +golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/client/generated/models/analysis_run_argument.go b/pkg/client/generated/models/analysis_run_argument.go new file mode 100644 index 0000000000..cdc2d8c24d --- /dev/null +++ b/pkg/client/generated/models/analysis_run_argument.go @@ -0,0 +1,89 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// AnalysisRunArgument analysis run argument +// +// swagger:model AnalysisRunArgument +type AnalysisRunArgument struct { + + // Name is the name of the argument. + // + // +kubebuilder:validation:Required + // Required: true + Name *string `json:"name"` + + // Value is the value of the argument. + // + // +kubebuilder:validation:Required + // Required: true + Value *string `json:"value"` +} + +// Validate validates this analysis run argument +func (m *AnalysisRunArgument) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if err := m.validateValue(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *AnalysisRunArgument) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +func (m *AnalysisRunArgument) validateValue(formats strfmt.Registry) error { + + if err := validate.Required("value", "body", m.Value); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this analysis run argument based on context it is used +func (m *AnalysisRunArgument) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *AnalysisRunArgument) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *AnalysisRunArgument) UnmarshalBinary(b []byte) error { + var res AnalysisRunArgument + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/analysis_run_metadata.go b/pkg/client/generated/models/analysis_run_metadata.go new file mode 100644 index 0000000000..87d5685f64 --- /dev/null +++ b/pkg/client/generated/models/analysis_run_metadata.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// AnalysisRunMetadata analysis run metadata +// +// swagger:model AnalysisRunMetadata +type AnalysisRunMetadata struct { + + // Additional annotations to apply to an AnalysisRun. + Annotations map[string]string `json:"annotations,omitempty"` + + // Additional labels to apply to an AnalysisRun. + Labels map[string]string `json:"labels,omitempty"` +} + +// Validate validates this analysis run metadata +func (m *AnalysisRunMetadata) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this analysis run metadata based on context it is used +func (m *AnalysisRunMetadata) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *AnalysisRunMetadata) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *AnalysisRunMetadata) UnmarshalBinary(b []byte) error { + var res AnalysisRunMetadata + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/analysis_run_reference.go b/pkg/client/generated/models/analysis_run_reference.go new file mode 100644 index 0000000000..d63cb08ded --- /dev/null +++ b/pkg/client/generated/models/analysis_run_reference.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// AnalysisRunReference analysis run reference +// +// swagger:model AnalysisRunReference +type AnalysisRunReference struct { + + // Name is the name of the AnalysisRun. + Name string `json:"name,omitempty"` + + // Namespace is the namespace of the AnalysisRun. + Namespace string `json:"namespace,omitempty"` + + // Phase is the last observed phase of the AnalysisRun referenced by Name. + Phase string `json:"phase,omitempty"` +} + +// Validate validates this analysis run reference +func (m *AnalysisRunReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this analysis run reference based on context it is used +func (m *AnalysisRunReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *AnalysisRunReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *AnalysisRunReference) UnmarshalBinary(b []byte) error { + var res AnalysisRunReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/analysis_template_reference.go b/pkg/client/generated/models/analysis_template_reference.go new file mode 100644 index 0000000000..1a3afba450 --- /dev/null +++ b/pkg/client/generated/models/analysis_template_reference.go @@ -0,0 +1,78 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// AnalysisTemplateReference analysis template reference +// +// swagger:model AnalysisTemplateReference +type AnalysisTemplateReference struct { + + // Kind is the type of the AnalysisTemplate. Can be either AnalysisTemplate or + // ClusterAnalysisTemplate, default is AnalysisTemplate. + // + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Enum=AnalysisTemplate;ClusterAnalysisTemplate + Kind string `json:"kind,omitempty"` + + // Name is the name of the AnalysisTemplate in the same project/namespace as + // the Stage. + // + // +kubebuilder:validation:Required + // Required: true + Name *string `json:"name"` +} + +// Validate validates this analysis template reference +func (m *AnalysisTemplateReference) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *AnalysisTemplateReference) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this analysis template reference based on context it is used +func (m *AnalysisTemplateReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *AnalysisTemplateReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *AnalysisTemplateReference) UnmarshalBinary(b []byte) error { + var res AnalysisTemplateReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/approved_stage.go b/pkg/client/generated/models/approved_stage.go new file mode 100644 index 0000000000..a361f5090e --- /dev/null +++ b/pkg/client/generated/models/approved_stage.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ApprovedStage approved stage +// +// swagger:model ApprovedStage +type ApprovedStage struct { + + // ApprovedAt is the time at which the Freight was approved for the Stage. + ApprovedAt string `json:"approvedAt,omitempty"` +} + +// Validate validates this approved stage +func (m *ApprovedStage) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this approved stage based on context it is used +func (m *ApprovedStage) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *ApprovedStage) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ApprovedStage) UnmarshalBinary(b []byte) error { + var res ApprovedStage + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/artifact_reference.go b/pkg/client/generated/models/artifact_reference.go new file mode 100644 index 0000000000..c914a4254f --- /dev/null +++ b/pkg/client/generated/models/artifact_reference.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ArtifactReference artifact reference +// +// swagger:model ArtifactReference +type ArtifactReference struct { + + // ArtifactType specifies the type of artifact this is. Often, but not always, + // it will be the media type (MIME type) of the artifact referenced by this + // ArtifactReference. + // + // +kubebuilder:validation:MinLength=1 + ArtifactType string `json:"artifactType,omitempty"` + + // Metadata is a JSON object containing a mostly opaque collection of artifact + // attributes. (It must be an object. It may not be a list or a scalar value.) + // "Mostly" because Kargo may understand how to interpret some documented, + // well-known, top-level keys. Those aside, this metadata is only understood + // by a corresponding Subscriber implementation that created it. + // + // +optional + Metadata any `json:"metadata,omitempty"` + + // SubscriptionName is the name of the Subscription that discovered this + // artifact. + // + // +kubebuilder:validation:MinLength=1 + SubscriptionName string `json:"subscriptionName,omitempty"` + + // Version identifies a specific revision of this artifact. + // + // +kubebuilder:validation:MinLength=1 + Version string `json:"version,omitempty"` +} + +// Validate validates this artifact reference +func (m *ArtifactReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this artifact reference based on context it is used +func (m *ArtifactReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *ArtifactReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ArtifactReference) UnmarshalBinary(b []byte) error { + var res ArtifactReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/artifactory_webhook_receiver_config.go b/pkg/client/generated/models/artifactory_webhook_receiver_config.go new file mode 100644 index 0000000000..3d9bbecc6f --- /dev/null +++ b/pkg/client/generated/models/artifactory_webhook_receiver_config.go @@ -0,0 +1,120 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ArtifactoryWebhookReceiverConfig artifactory webhook receiver config +// +// swagger:model ArtifactoryWebhookReceiverConfig +type ArtifactoryWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret-token` key whose + // value is the shared secret used to authenticate the webhook requests sent + // by JFrog Artifactory. For more information please refer to the JFrog + // Artifactory documentation: + // https://jfrog.com/help/r/jfrog-platform-administration-documentation/webhooks + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` + + // VirtualRepoName is the name of an Artifactory virtual repository. + // + // When unspecified, the Artifactory webhook receiver depends on the value of + // the webhook payload's `data.repo_key` field when inferring the URL of the + // repository from which the webhook originated, which will always be an + // Artifactory "local repository." In cases where a Warehouse subscribes to + // such a repository indirectly via a "virtual repository," there will be a + // discrepancy between the inferred (local) repository URL and the URL + // actually used by the subscription, which can prevent the receiver from + // identifying such a Warehouse as one in need of refreshing. When specified, + // the value of the VirtualRepoName field supersedes the value of the webhook + // payload's `data.repo_key` field to compensate for that discrepancy. + // + // In practice, when using virtual repositories, a separate Artifactory + // webhook receiver should be configured for each, but one such receiver can + // handle inbound webhooks from any number of local repositories that are + // aggregated by that virtual repository. For example, if a virtual repository + // `proj-virtual` aggregates container images from all of the `proj` + // Artifactory project's local image repositories, with a single webhook + // configured to post to a single receiver configured for the `proj-virtual` + // virtual repository, an image pushed to + // `example.frog.io/proj-//image`, will cause that + // receiver to refresh all Warehouses subscribed to + // `example.frog.io/proj-virtual//image`. + // + // +optional + VirtualRepoName string `json:"virtualRepoName,omitempty"` +} + +// Validate validates this artifactory webhook receiver config +func (m *ArtifactoryWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ArtifactoryWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this artifactory webhook receiver config based on the context it is used +func (m *ArtifactoryWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ArtifactoryWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *ArtifactoryWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ArtifactoryWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res ArtifactoryWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/auto_promotion_options.go b/pkg/client/generated/models/auto_promotion_options.go new file mode 100644 index 0000000000..52e90c8da7 --- /dev/null +++ b/pkg/client/generated/models/auto_promotion_options.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// AutoPromotionOptions auto promotion options +// +// swagger:model AutoPromotionOptions +type AutoPromotionOptions struct { + + // SelectionPolicy specifies the rules for identifying new Freight that is + // eligible for auto-promotion to this Stage. This field is optional. When + // left unspecified, the field is implicitly treated as if its value were + // "NewestFreight". + // + // Accepted Values: + // + // - "NewestFreight": The newest Freight that is available to the Stage is + // eligible for auto-promotion. + // + // - "MatchUpstream": Only the Freight currently used immediately upstream + // from this Stage is eligible for auto-promotion. This policy may only + // be applied when the Stage has exactly one upstream Stage. + SelectionPolicy string `json:"selectionPolicy,omitempty"` +} + +// Validate validates this auto promotion options +func (m *AutoPromotionOptions) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this auto promotion options based on context it is used +func (m *AutoPromotionOptions) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *AutoPromotionOptions) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *AutoPromotionOptions) UnmarshalBinary(b []byte) error { + var res AutoPromotionOptions + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/azure_webhook_receiver_config.go b/pkg/client/generated/models/azure_webhook_receiver_config.go new file mode 100644 index 0000000000..6658c3ac11 --- /dev/null +++ b/pkg/client/generated/models/azure_webhook_receiver_config.go @@ -0,0 +1,98 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// AzureWebhookReceiverConfig azure webhook receiver config +// +// swagger:model AzureWebhookReceiverConfig +type AzureWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret` key whose value + // does NOT need to be shared directly with Azure when registering a webhook. + // It is used only by Kargo to create a complex, hard-to-guess URL, + // which implicitly serves as a shared secret. For more information about + // Azure webhooks, please refer to the Azure documentation: + // + // Azure Container Registry: + // https://learn.microsoft.com/en-us/azure/container-registry/container-registry-repositories + // + // Azure DevOps: + // http://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this azure webhook receiver config +func (m *AzureWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *AzureWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this azure webhook receiver config based on the context it is used +func (m *AzureWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *AzureWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *AzureWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *AzureWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res AzureWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/bitbucket_webhook_receiver_config.go b/pkg/client/generated/models/bitbucket_webhook_receiver_config.go new file mode 100644 index 0000000000..abbeca3df5 --- /dev/null +++ b/pkg/client/generated/models/bitbucket_webhook_receiver_config.go @@ -0,0 +1,92 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// BitbucketWebhookReceiverConfig bitbucket webhook receiver config +// +// swagger:model BitbucketWebhookReceiverConfig +type BitbucketWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret` key whose + // value is the shared secret used to authenticate the webhook requests sent + // by Bitbucket. For more information please refer to the Bitbucket + // documentation: + // https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/ + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this bitbucket webhook receiver config +func (m *BitbucketWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *BitbucketWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this bitbucket webhook receiver config based on the context it is used +func (m *BitbucketWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *BitbucketWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *BitbucketWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *BitbucketWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res BitbucketWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/chart.go b/pkg/client/generated/models/chart.go new file mode 100644 index 0000000000..d77d75760e --- /dev/null +++ b/pkg/client/generated/models/chart.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Chart chart +// +// swagger:model Chart +type Chart struct { + + // Name specifies the name of the chart. + Name string `json:"name,omitempty"` + + // RepoURL specifies the URL of a Helm chart repository. Classic chart + // repositories (using HTTP/S) can contain differently named charts. When this + // field points to such a repository, the Name field will specify the name of + // the chart within the repository. In the case of a repository within an OCI + // registry, the URL implicitly points to a specific chart and the Name field + // will be empty. + RepoURL string `json:"repoURL,omitempty"` + + // Version specifies a particular version of the chart. + Version string `json:"version,omitempty"` +} + +// Validate validates this chart +func (m *Chart) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this chart based on context it is used +func (m *Chart) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *Chart) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Chart) UnmarshalBinary(b []byte) error { + var res Chart + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/chart_discovery_result.go b/pkg/client/generated/models/chart_discovery_result.go new file mode 100644 index 0000000000..c0ab4249de --- /dev/null +++ b/pkg/client/generated/models/chart_discovery_result.go @@ -0,0 +1,66 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ChartDiscoveryResult chart discovery result +// +// swagger:model ChartDiscoveryResult +type ChartDiscoveryResult struct { + + // Name is the name of the Helm chart, as specified in the ChartSubscription. + Name string `json:"name,omitempty"` + + // RepoURL is the repository URL of the Helm chart, as specified in the + // ChartSubscription. + // + // +kubebuilder:validation:MinLength=1 + RepoURL string `json:"repoURL,omitempty"` + + // SemverConstraint is the constraint for which versions were discovered. + // This field is optional, and only populated if the ChartSubscription + // specifies a SemverConstraint. + SemverConstraint string `json:"semverConstraint,omitempty"` + + // Versions is a list of versions discovered by the Warehouse for the + // ChartSubscription. An empty list indicates that the discovery operation was + // successful, but no versions matching the ChartSubscription criteria were + // found. + // + // +optional + Versions []string `json:"versions"` +} + +// Validate validates this chart discovery result +func (m *ChartDiscoveryResult) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this chart discovery result based on context it is used +func (m *ChartDiscoveryResult) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *ChartDiscoveryResult) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ChartDiscoveryResult) UnmarshalBinary(b []byte) error { + var res ChartDiscoveryResult + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/cluster_config.go b/pkg/client/generated/models/cluster_config.go new file mode 100644 index 0000000000..f8b7f5a04e --- /dev/null +++ b/pkg/client/generated/models/cluster_config.go @@ -0,0 +1,182 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ClusterConfig cluster config +// +// swagger:model ClusterConfig +type ClusterConfig struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes the configuration of a cluster. + Spec struct { + ClusterConfigSpec + } `json:"spec,omitempty"` + + // Status describes the current status of a ClusterConfig. + Status struct { + ClusterConfigStatus + } `json:"status,omitempty"` +} + +// Validate validates this cluster config +func (m *ClusterConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterConfig) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *ClusterConfig) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + return nil +} + +func (m *ClusterConfig) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this cluster config based on the context it is used +func (m *ClusterConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterConfig) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *ClusterConfig) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *ClusterConfig) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *ClusterConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ClusterConfig) UnmarshalBinary(b []byte) error { + var res ClusterConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/cluster_config_spec.go b/pkg/client/generated/models/cluster_config_spec.go new file mode 100644 index 0000000000..5d32808765 --- /dev/null +++ b/pkg/client/generated/models/cluster_config_spec.go @@ -0,0 +1,128 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ClusterConfigSpec cluster config spec +// +// swagger:model ClusterConfigSpec +type ClusterConfigSpec struct { + + // WebhookReceivers describes cluster-scoped webhook receivers used for + // processing events from various external platforms + WebhookReceivers []*WebhookReceiverConfig `json:"webhookReceivers"` +} + +// Validate validates this cluster config spec +func (m *ClusterConfigSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateWebhookReceivers(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterConfigSpec) validateWebhookReceivers(formats strfmt.Registry) error { + if swag.IsZero(m.WebhookReceivers) { // not required + return nil + } + + for i := 0; i < len(m.WebhookReceivers); i++ { + if swag.IsZero(m.WebhookReceivers[i]) { // not required + continue + } + + if m.WebhookReceivers[i] != nil { + if err := m.WebhookReceivers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this cluster config spec based on the context it is used +func (m *ClusterConfigSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateWebhookReceivers(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterConfigSpec) contextValidateWebhookReceivers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.WebhookReceivers); i++ { + + if m.WebhookReceivers[i] != nil { + + if swag.IsZero(m.WebhookReceivers[i]) { // not required + return nil + } + + if err := m.WebhookReceivers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ClusterConfigSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ClusterConfigSpec) UnmarshalBinary(b []byte) error { + var res ClusterConfigSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/cluster_config_status.go b/pkg/client/generated/models/cluster_config_status.go new file mode 100644 index 0000000000..2b6bcd37b2 --- /dev/null +++ b/pkg/client/generated/models/cluster_config_status.go @@ -0,0 +1,213 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ClusterConfigStatus cluster config status +// +// swagger:model ClusterConfigStatus +type ClusterConfigStatus struct { + + // Conditions contains the last observations of the ClusterConfig's current + // state. + // + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []*V1Condition `json:"conditions"` + + // LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh + // annotation that was handled by the controller. This field can be used to + // determine whether the request to refresh the resource has been handled. + // +optional + LastHandledRefresh string `json:"lastHandledRefresh,omitempty"` + + // ObservedGeneration represents the .metadata.generation that this + // ClusterConfig was reconciled against. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // WebhookReceivers describes the status of cluster-scoped webhook receivers. + WebhookReceivers []*WebhookReceiverDetails `json:"webhookReceivers"` +} + +// Validate validates this cluster config status +func (m *ClusterConfigStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConditions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWebhookReceivers(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterConfigStatus) validateConditions(formats strfmt.Registry) error { + if swag.IsZero(m.Conditions) { // not required + return nil + } + + for i := 0; i < len(m.Conditions); i++ { + if swag.IsZero(m.Conditions[i]) { // not required + continue + } + + if m.Conditions[i] != nil { + if err := m.Conditions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ClusterConfigStatus) validateWebhookReceivers(formats strfmt.Registry) error { + if swag.IsZero(m.WebhookReceivers) { // not required + return nil + } + + for i := 0; i < len(m.WebhookReceivers); i++ { + if swag.IsZero(m.WebhookReceivers[i]) { // not required + continue + } + + if m.WebhookReceivers[i] != nil { + if err := m.WebhookReceivers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this cluster config status based on the context it is used +func (m *ClusterConfigStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConditions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWebhookReceivers(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterConfigStatus) contextValidateConditions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Conditions); i++ { + + if m.Conditions[i] != nil { + + if swag.IsZero(m.Conditions[i]) { // not required + return nil + } + + if err := m.Conditions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ClusterConfigStatus) contextValidateWebhookReceivers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.WebhookReceivers); i++ { + + if m.WebhookReceivers[i] != nil { + + if swag.IsZero(m.WebhookReceivers[i]) { // not required + return nil + } + + if err := m.WebhookReceivers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ClusterConfigStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ClusterConfigStatus) UnmarshalBinary(b []byte) error { + var res ClusterConfigStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/cluster_promotion_task.go b/pkg/client/generated/models/cluster_promotion_task.go new file mode 100644 index 0000000000..338ecf3b47 --- /dev/null +++ b/pkg/client/generated/models/cluster_promotion_task.go @@ -0,0 +1,157 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ClusterPromotionTask cluster promotion task +// +// swagger:model ClusterPromotionTask +type ClusterPromotionTask struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes the desired transition of a specific Stage into a specific + // Freight. + // + // +kubebuilder:validation:Required + // Required: true + Spec struct { + PromotionTaskSpec + } `json:"spec"` +} + +// Validate validates this cluster promotion task +func (m *ClusterPromotionTask) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterPromotionTask) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *ClusterPromotionTask) validateSpec(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this cluster promotion task based on the context it is used +func (m *ClusterPromotionTask) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterPromotionTask) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *ClusterPromotionTask) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *ClusterPromotionTask) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ClusterPromotionTask) UnmarshalBinary(b []byte) error { + var res ClusterPromotionTask + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/cluster_promotion_task_list.go b/pkg/client/generated/models/cluster_promotion_task_list.go new file mode 100644 index 0000000000..0483cc9333 --- /dev/null +++ b/pkg/client/generated/models/cluster_promotion_task_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ClusterPromotionTaskList cluster promotion task list +// +// swagger:model ClusterPromotionTaskList +type ClusterPromotionTaskList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*ClusterPromotionTask `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this cluster promotion task list +func (m *ClusterPromotionTaskList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterPromotionTaskList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ClusterPromotionTaskList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this cluster promotion task list based on the context it is used +func (m *ClusterPromotionTaskList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ClusterPromotionTaskList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ClusterPromotionTaskList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ClusterPromotionTaskList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ClusterPromotionTaskList) UnmarshalBinary(b []byte) error { + var res ClusterPromotionTaskList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/current_stage.go b/pkg/client/generated/models/current_stage.go new file mode 100644 index 0000000000..2d8de59484 --- /dev/null +++ b/pkg/client/generated/models/current_stage.go @@ -0,0 +1,49 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// CurrentStage current stage +// +// swagger:model CurrentStage +type CurrentStage struct { + + // Since is the time at which the Stage most recently started using the + // Freight. This can be used to calculate how long the Freight has been in use + // by the Stage. + Since string `json:"since,omitempty"` +} + +// Validate validates this current stage +func (m *CurrentStage) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this current stage based on context it is used +func (m *CurrentStage) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *CurrentStage) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *CurrentStage) UnmarshalBinary(b []byte) error { + var res CurrentStage + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/discovered_artifacts.go b/pkg/client/generated/models/discovered_artifacts.go new file mode 100644 index 0000000000..a29ea0941c --- /dev/null +++ b/pkg/client/generated/models/discovered_artifacts.go @@ -0,0 +1,353 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DiscoveredArtifacts discovered artifacts +// +// swagger:model DiscoveredArtifacts +type DiscoveredArtifacts struct { + + // Charts holds the charts discovered by the Warehouse for the chart + // subscriptions. + // + // +optional + Charts []*ChartDiscoveryResult `json:"charts"` + + // DiscoveredAt is the time at which the Warehouse discovered the artifacts. + // + // +optional + DiscoveredAt string `json:"discoveredAt,omitempty"` + + // Git holds the commits discovered by the Warehouse for the Git + // subscriptions. + // + // +optional + Git []*GitDiscoveryResult `json:"git"` + + // Images holds the image references discovered by the Warehouse for the + // image subscriptions. + // + // +optional + Images []*ImageDiscoveryResult `json:"images"` + + // Results holds the artifact references discovered by the Warehouse. + // + // +optional + Results []*DiscoveryResult `json:"results"` +} + +// Validate validates this discovered artifacts +func (m *DiscoveredArtifacts) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCharts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGit(formats); err != nil { + res = append(res, err) + } + + if err := m.validateImages(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResults(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DiscoveredArtifacts) validateCharts(formats strfmt.Registry) error { + if swag.IsZero(m.Charts) { // not required + return nil + } + + for i := 0; i < len(m.Charts); i++ { + if swag.IsZero(m.Charts[i]) { // not required + continue + } + + if m.Charts[i] != nil { + if err := m.Charts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("charts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("charts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *DiscoveredArtifacts) validateGit(formats strfmt.Registry) error { + if swag.IsZero(m.Git) { // not required + return nil + } + + for i := 0; i < len(m.Git); i++ { + if swag.IsZero(m.Git[i]) { // not required + continue + } + + if m.Git[i] != nil { + if err := m.Git[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("git" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("git" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *DiscoveredArtifacts) validateImages(formats strfmt.Registry) error { + if swag.IsZero(m.Images) { // not required + return nil + } + + for i := 0; i < len(m.Images); i++ { + if swag.IsZero(m.Images[i]) { // not required + continue + } + + if m.Images[i] != nil { + if err := m.Images[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("images" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("images" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *DiscoveredArtifacts) validateResults(formats strfmt.Registry) error { + if swag.IsZero(m.Results) { // not required + return nil + } + + for i := 0; i < len(m.Results); i++ { + if swag.IsZero(m.Results[i]) { // not required + continue + } + + if m.Results[i] != nil { + if err := m.Results[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("results" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("results" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this discovered artifacts based on the context it is used +func (m *DiscoveredArtifacts) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateCharts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGit(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateImages(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResults(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DiscoveredArtifacts) contextValidateCharts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Charts); i++ { + + if m.Charts[i] != nil { + + if swag.IsZero(m.Charts[i]) { // not required + return nil + } + + if err := m.Charts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("charts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("charts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *DiscoveredArtifacts) contextValidateGit(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Git); i++ { + + if m.Git[i] != nil { + + if swag.IsZero(m.Git[i]) { // not required + return nil + } + + if err := m.Git[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("git" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("git" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *DiscoveredArtifacts) contextValidateImages(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Images); i++ { + + if m.Images[i] != nil { + + if swag.IsZero(m.Images[i]) { // not required + return nil + } + + if err := m.Images[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("images" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("images" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *DiscoveredArtifacts) contextValidateResults(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Results); i++ { + + if m.Results[i] != nil { + + if swag.IsZero(m.Results[i]) { // not required + return nil + } + + if err := m.Results[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("results" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("results" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *DiscoveredArtifacts) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DiscoveredArtifacts) UnmarshalBinary(b []byte) error { + var res DiscoveredArtifacts + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/discovered_commit.go b/pkg/client/generated/models/discovered_commit.go new file mode 100644 index 0000000000..b439b2bd0f --- /dev/null +++ b/pkg/client/generated/models/discovered_commit.go @@ -0,0 +1,72 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DiscoveredCommit discovered commit +// +// swagger:model DiscoveredCommit +type DiscoveredCommit struct { + + // Author is the author of the commit. + Author string `json:"author,omitempty"` + + // Branch is the branch in which the commit was found. This field is + // optional, and populated based on the CommitSelectionStrategy of the + // GitSubscription. + Branch string `json:"branch,omitempty"` + + // Committer is the person who committed the commit. + Committer string `json:"committer,omitempty"` + + // CreatorDate is the commit creation date as specified by the commit, or + // the tagger date if the commit belongs to an annotated tag. + CreatorDate string `json:"creatorDate,omitempty"` + + // ID is the identifier of the commit. This typically is a SHA-1 hash. + // + // +kubebuilder:validation:MinLength=1 + ID string `json:"id,omitempty"` + + // Subject is the subject of the commit (i.e. the first line of the commit + // message). + Subject string `json:"subject,omitempty"` + + // Tag is the tag that resolved to this commit. This field is optional, and + // populated based on the CommitSelectionStrategy of the GitSubscription. + Tag string `json:"tag,omitempty"` +} + +// Validate validates this discovered commit +func (m *DiscoveredCommit) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this discovered commit based on context it is used +func (m *DiscoveredCommit) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *DiscoveredCommit) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DiscoveredCommit) UnmarshalBinary(b []byte) error { + var res DiscoveredCommit + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/discovered_image_reference.go b/pkg/client/generated/models/discovered_image_reference.go new file mode 100644 index 0000000000..fe2402655e --- /dev/null +++ b/pkg/client/generated/models/discovered_image_reference.go @@ -0,0 +1,67 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DiscoveredImageReference discovered image reference +// +// swagger:model DiscoveredImageReference +type DiscoveredImageReference struct { + + // Annotations is a map of key-value pairs that provide additional + // information about the image. + Annotations map[string]string `json:"annotations,omitempty"` + + // CreatedAt is the time the image was created. This field is optional, and + // not populated for every ImageSelectionStrategy. + CreatedAt string `json:"createdAt,omitempty"` + + // Digest is the digest of the image. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^[a-z0-9]+:[a-f0-9]+$` + // +akuity:test-kubebuilder-pattern=Digest + Digest string `json:"digest,omitempty"` + + // Tag is the tag of the image. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=128 + // +kubebuilder:validation:Pattern=`^[\w.\-\_]+$` + // +akuity:test-kubebuilder-pattern=Tag + Tag string `json:"tag,omitempty"` +} + +// Validate validates this discovered image reference +func (m *DiscoveredImageReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this discovered image reference based on context it is used +func (m *DiscoveredImageReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *DiscoveredImageReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DiscoveredImageReference) UnmarshalBinary(b []byte) error { + var res DiscoveredImageReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/discovery_result.go b/pkg/client/generated/models/discovery_result.go new file mode 100644 index 0000000000..08c498795d --- /dev/null +++ b/pkg/client/generated/models/discovery_result.go @@ -0,0 +1,136 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DiscoveryResult discovery result +// +// swagger:model DiscoveryResult +type DiscoveryResult struct { + + // ArtifactReferences is a list of references to specific versions of an + // artifact. + // + // +optional + ArtifactReferences []*ArtifactReference `json:"artifactReferences"` + + // SubscriptionName is the name of the Subscription that discovered these + // results. + // + // +kubebuilder:validation:MinLength=1 + Name string `json:"name,omitempty"` +} + +// Validate validates this discovery result +func (m *DiscoveryResult) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateArtifactReferences(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DiscoveryResult) validateArtifactReferences(formats strfmt.Registry) error { + if swag.IsZero(m.ArtifactReferences) { // not required + return nil + } + + for i := 0; i < len(m.ArtifactReferences); i++ { + if swag.IsZero(m.ArtifactReferences[i]) { // not required + continue + } + + if m.ArtifactReferences[i] != nil { + if err := m.ArtifactReferences[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("artifactReferences" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("artifactReferences" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this discovery result based on the context it is used +func (m *DiscoveryResult) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateArtifactReferences(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DiscoveryResult) contextValidateArtifactReferences(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ArtifactReferences); i++ { + + if m.ArtifactReferences[i] != nil { + + if swag.IsZero(m.ArtifactReferences[i]) { // not required + return nil + } + + if err := m.ArtifactReferences[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("artifactReferences" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("artifactReferences" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *DiscoveryResult) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DiscoveryResult) UnmarshalBinary(b []byte) error { + var res DiscoveryResult + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/docker_hub_webhook_receiver_config.go b/pkg/client/generated/models/docker_hub_webhook_receiver_config.go new file mode 100644 index 0000000000..894f9bdb52 --- /dev/null +++ b/pkg/client/generated/models/docker_hub_webhook_receiver_config.go @@ -0,0 +1,90 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// DockerHubWebhookReceiverConfig docker hub webhook receiver config +// +// swagger:model DockerHubWebhookReceiverConfig +type DockerHubWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // The Secret's data map is expected to contain a `secret` key whose value + // does NOT need to be shared directly with Docker Hub when registering a + // webhook. It is used only by Kargo to create a complex, hard-to-guess URL, + // which implicitly serves as a shared secret. For more information about + // Docker Hub webhooks, please refer to the Docker documentation: + // https://docs.docker.com/docker-hub/webhooks/ + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this docker hub webhook receiver config +func (m *DockerHubWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DockerHubWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this docker hub webhook receiver config based on the context it is used +func (m *DockerHubWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DockerHubWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *DockerHubWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DockerHubWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res DockerHubWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/expression_variable.go b/pkg/client/generated/models/expression_variable.go new file mode 100644 index 0000000000..f4a0de2c3e --- /dev/null +++ b/pkg/client/generated/models/expression_variable.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ExpressionVariable expression variable +// +// swagger:model ExpressionVariable +type ExpressionVariable struct { + + // Name is the name of the variable. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=^[a-zA-Z_]\w*$ + Name string `json:"name,omitempty"` + + // Value is the value of the variable. It is allowed to utilize expressions + // in the value. + // See https://docs.kargo.io/user-guide/reference-docs/expressions for details. + Value string `json:"value,omitempty"` +} + +// Validate validates this expression variable +func (m *ExpressionVariable) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this expression variable based on context it is used +func (m *ExpressionVariable) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *ExpressionVariable) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ExpressionVariable) UnmarshalBinary(b []byte) error { + var res ExpressionVariable + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight.go b/pkg/client/generated/models/freight.go new file mode 100644 index 0000000000..64e54cc20a --- /dev/null +++ b/pkg/client/generated/models/freight.go @@ -0,0 +1,475 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Freight freight +// +// swagger:model Freight +type Freight struct { + + // Alias is a human-friendly alias for a piece of Freight. This is an optional + // field. A defaulting webhook will sync this field with the value of the + // kargo.akuity.io/alias label. When the alias label is not present or differs + // from the value of this field, the defaulting webhook will set the label to + // the value of this field. If the alias label is present and this field is + // empty, the defaulting webhook will set the value of this field to the value + // of the alias label. If this field is empty and the alias label is not + // present, the defaulting webhook will choose an available alias and assign + // it to both the field and label. + Alias string `json:"alias,omitempty"` + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Artifacts describes specific versions of artifacts other + // than Git repository commits, container images, and Helm charts. + Artifacts []*ArtifactReference `json:"artifacts"` + + // Charts describes specific versions of specific Helm charts. + Charts []*Chart `json:"charts"` + + // Commits describes specific Git repository commits. + Commits []*GitCommit `json:"commits"` + + // Images describes specific versions of specific container images. + Images []*Image `json:"images"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Origin describes a kind of Freight in terms of its origin. + // + // +kubebuilder:validation:Required + // Required: true + Origin struct { + FreightOrigin + } `json:"origin"` + + // Status describes the current status of this Freight. + Status struct { + FreightStatus + } `json:"status,omitempty"` +} + +// Validate validates this freight +func (m *Freight) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateArtifacts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCharts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCommits(formats); err != nil { + res = append(res, err) + } + + if err := m.validateImages(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOrigin(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Freight) validateArtifacts(formats strfmt.Registry) error { + if swag.IsZero(m.Artifacts) { // not required + return nil + } + + for i := 0; i < len(m.Artifacts); i++ { + if swag.IsZero(m.Artifacts[i]) { // not required + continue + } + + if m.Artifacts[i] != nil { + if err := m.Artifacts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) validateCharts(formats strfmt.Registry) error { + if swag.IsZero(m.Charts) { // not required + return nil + } + + for i := 0; i < len(m.Charts); i++ { + if swag.IsZero(m.Charts[i]) { // not required + continue + } + + if m.Charts[i] != nil { + if err := m.Charts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("charts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("charts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) validateCommits(formats strfmt.Registry) error { + if swag.IsZero(m.Commits) { // not required + return nil + } + + for i := 0; i < len(m.Commits); i++ { + if swag.IsZero(m.Commits[i]) { // not required + continue + } + + if m.Commits[i] != nil { + if err := m.Commits[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("commits" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("commits" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) validateImages(formats strfmt.Registry) error { + if swag.IsZero(m.Images) { // not required + return nil + } + + for i := 0; i < len(m.Images); i++ { + if swag.IsZero(m.Images[i]) { // not required + continue + } + + if m.Images[i] != nil { + if err := m.Images[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("images" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("images" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Freight) validateOrigin(formats strfmt.Registry) error { + + return nil +} + +func (m *Freight) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this freight based on the context it is used +func (m *Freight) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateArtifacts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCharts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCommits(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateImages(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOrigin(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Freight) contextValidateArtifacts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Artifacts); i++ { + + if m.Artifacts[i] != nil { + + if swag.IsZero(m.Artifacts[i]) { // not required + return nil + } + + if err := m.Artifacts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) contextValidateCharts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Charts); i++ { + + if m.Charts[i] != nil { + + if swag.IsZero(m.Charts[i]) { // not required + return nil + } + + if err := m.Charts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("charts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("charts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) contextValidateCommits(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Commits); i++ { + + if m.Commits[i] != nil { + + if swag.IsZero(m.Commits[i]) { // not required + return nil + } + + if err := m.Commits[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("commits" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("commits" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) contextValidateImages(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Images); i++ { + + if m.Images[i] != nil { + + if swag.IsZero(m.Images[i]) { // not required + return nil + } + + if err := m.Images[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("images" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("images" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Freight) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Freight) contextValidateOrigin(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *Freight) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *Freight) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Freight) UnmarshalBinary(b []byte) error { + var res Freight + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_collection.go b/pkg/client/generated/models/freight_collection.go new file mode 100644 index 0000000000..5678474115 --- /dev/null +++ b/pkg/client/generated/models/freight_collection.go @@ -0,0 +1,190 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// FreightCollection freight collection +// +// swagger:model FreightCollection +type FreightCollection struct { + + // ID is a unique and deterministically calculated identifier for the + // FreightCollection. It is updated on each use of the UpdateOrPush method. + ID string `json:"id,omitempty"` + + // Freight is a map of FreightReference objects, indexed by their Warehouse + // origin. + Items map[string]FreightReference `json:"items,omitempty"` + + // VerificationHistory is a stack of recent VerificationInfo. By default, + // the last ten VerificationInfo are stored. + VerificationHistory []*VerificationInfo `json:"verificationHistory"` +} + +// Validate validates this freight collection +func (m *FreightCollection) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVerificationHistory(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightCollection) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for k := range m.Items { + + if err := validate.Required("items"+"."+k, "body", m.Items[k]); err != nil { + return err + } + if val, ok := m.Items[k]; ok { + if err := val.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + k) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + k) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightCollection) validateVerificationHistory(formats strfmt.Registry) error { + if swag.IsZero(m.VerificationHistory) { // not required + return nil + } + + for i := 0; i < len(m.VerificationHistory); i++ { + if swag.IsZero(m.VerificationHistory[i]) { // not required + continue + } + + if m.VerificationHistory[i] != nil { + if err := m.VerificationHistory[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("verificationHistory" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("verificationHistory" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this freight collection based on the context it is used +func (m *FreightCollection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVerificationHistory(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightCollection) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for k := range m.Items { + + if val, ok := m.Items[k]; ok { + if err := val.ContextValidate(ctx, formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *FreightCollection) contextValidateVerificationHistory(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.VerificationHistory); i++ { + + if m.VerificationHistory[i] != nil { + + if swag.IsZero(m.VerificationHistory[i]) { // not required + return nil + } + + if err := m.VerificationHistory[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("verificationHistory" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("verificationHistory" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *FreightCollection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightCollection) UnmarshalBinary(b []byte) error { + var res FreightCollection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_creation_criteria.go b/pkg/client/generated/models/freight_creation_criteria.go new file mode 100644 index 0000000000..5b339a7ccc --- /dev/null +++ b/pkg/client/generated/models/freight_creation_criteria.go @@ -0,0 +1,48 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// FreightCreationCriteria freight creation criteria +// +// swagger:model FreightCreationCriteria +type FreightCreationCriteria struct { + + // Expression is an expr-lang expression that must evaluate to true for + // Freight to be created automatically from new artifacts following discovery. + Expression string `json:"expression,omitempty"` +} + +// Validate validates this freight creation criteria +func (m *FreightCreationCriteria) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this freight creation criteria based on context it is used +func (m *FreightCreationCriteria) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *FreightCreationCriteria) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightCreationCriteria) UnmarshalBinary(b []byte) error { + var res FreightCreationCriteria + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_origin.go b/pkg/client/generated/models/freight_origin.go new file mode 100644 index 0000000000..791582c26f --- /dev/null +++ b/pkg/client/generated/models/freight_origin.go @@ -0,0 +1,91 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// FreightOrigin freight origin +// +// swagger:model FreightOrigin +type FreightOrigin struct { + + // Kind is the kind of resource from which Freight may have originated. At + // present, this can only be "Warehouse". + // + // +kubebuilder:validation:Required + // Required: true + Kind *string `json:"kind"` + + // Name is the name of the resource of the kind indicated by the Kind field + // from which Freight may originate. + // + // +kubebuilder:validation:Required + // Required: true + Name *string `json:"name"` +} + +// Validate validates this freight origin +func (m *FreightOrigin) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateKind(formats); err != nil { + res = append(res, err) + } + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightOrigin) validateKind(formats strfmt.Registry) error { + + if err := validate.Required("kind", "body", m.Kind); err != nil { + return err + } + + return nil +} + +func (m *FreightOrigin) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this freight origin based on context it is used +func (m *FreightOrigin) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *FreightOrigin) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightOrigin) UnmarshalBinary(b []byte) error { + var res FreightOrigin + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_reference.go b/pkg/client/generated/models/freight_reference.go new file mode 100644 index 0000000000..a8e1032320 --- /dev/null +++ b/pkg/client/generated/models/freight_reference.go @@ -0,0 +1,369 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// FreightReference freight reference +// +// swagger:model FreightReference +type FreightReference struct { + + // Artifacts describes specific versions of artifacts other + // than Git repository commits, container images, and Helm charts. + Artifacts []*ArtifactReference `json:"artifacts"` + + // Charts describes specific versions of specific Helm charts. + Charts []*Chart `json:"charts"` + + // Commits describes specific Git repository commits. + Commits []*GitCommit `json:"commits"` + + // Images describes specific versions of specific container images. + Images []*Image `json:"images"` + + // Name is a system-assigned identifier derived deterministically from + // the contents of the Freight. I.e., two pieces of Freight can be compared + // for equality by comparing their Names. + Name string `json:"name,omitempty"` + + // Origin describes a kind of Freight in terms of its origin. + Origin struct { + FreightOrigin + } `json:"origin,omitempty"` +} + +// Validate validates this freight reference +func (m *FreightReference) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateArtifacts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCharts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCommits(formats); err != nil { + res = append(res, err) + } + + if err := m.validateImages(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOrigin(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightReference) validateArtifacts(formats strfmt.Registry) error { + if swag.IsZero(m.Artifacts) { // not required + return nil + } + + for i := 0; i < len(m.Artifacts); i++ { + if swag.IsZero(m.Artifacts[i]) { // not required + continue + } + + if m.Artifacts[i] != nil { + if err := m.Artifacts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) validateCharts(formats strfmt.Registry) error { + if swag.IsZero(m.Charts) { // not required + return nil + } + + for i := 0; i < len(m.Charts); i++ { + if swag.IsZero(m.Charts[i]) { // not required + continue + } + + if m.Charts[i] != nil { + if err := m.Charts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("charts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("charts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) validateCommits(formats strfmt.Registry) error { + if swag.IsZero(m.Commits) { // not required + return nil + } + + for i := 0; i < len(m.Commits); i++ { + if swag.IsZero(m.Commits[i]) { // not required + continue + } + + if m.Commits[i] != nil { + if err := m.Commits[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("commits" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("commits" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) validateImages(formats strfmt.Registry) error { + if swag.IsZero(m.Images) { // not required + return nil + } + + for i := 0; i < len(m.Images); i++ { + if swag.IsZero(m.Images[i]) { // not required + continue + } + + if m.Images[i] != nil { + if err := m.Images[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("images" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("images" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) validateOrigin(formats strfmt.Registry) error { + if swag.IsZero(m.Origin) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this freight reference based on the context it is used +func (m *FreightReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateArtifacts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCharts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCommits(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateImages(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOrigin(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightReference) contextValidateArtifacts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Artifacts); i++ { + + if m.Artifacts[i] != nil { + + if swag.IsZero(m.Artifacts[i]) { // not required + return nil + } + + if err := m.Artifacts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("artifacts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) contextValidateCharts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Charts); i++ { + + if m.Charts[i] != nil { + + if swag.IsZero(m.Charts[i]) { // not required + return nil + } + + if err := m.Charts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("charts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("charts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) contextValidateCommits(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Commits); i++ { + + if m.Commits[i] != nil { + + if swag.IsZero(m.Commits[i]) { // not required + return nil + } + + if err := m.Commits[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("commits" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("commits" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) contextValidateImages(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Images); i++ { + + if m.Images[i] != nil { + + if swag.IsZero(m.Images[i]) { // not required + return nil + } + + if err := m.Images[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("images" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("images" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightReference) contextValidateOrigin(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *FreightReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightReference) UnmarshalBinary(b []byte) error { + var res FreightReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_request.go b/pkg/client/generated/models/freight_request.go new file mode 100644 index 0000000000..1c9899aa4f --- /dev/null +++ b/pkg/client/generated/models/freight_request.go @@ -0,0 +1,109 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// FreightRequest freight request +// +// swagger:model FreightRequest +type FreightRequest struct { + + // Origin specifies from where the requested Freight must have originated. + // This is a required field. + // + // +kubebuilder:validation:Required + // Required: true + Origin struct { + FreightOrigin + } `json:"origin"` + + // Sources describes where the requested Freight may be obtained from. This is + // a required field. + Sources struct { + FreightSources + } `json:"sources,omitempty"` +} + +// Validate validates this freight request +func (m *FreightRequest) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateOrigin(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSources(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightRequest) validateOrigin(formats strfmt.Registry) error { + + return nil +} + +func (m *FreightRequest) validateSources(formats strfmt.Registry) error { + if swag.IsZero(m.Sources) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this freight request based on the context it is used +func (m *FreightRequest) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateOrigin(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSources(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightRequest) contextValidateOrigin(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *FreightRequest) contextValidateSources(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *FreightRequest) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightRequest) UnmarshalBinary(b []byte) error { + var res FreightRequest + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_sources.go b/pkg/client/generated/models/freight_sources.go new file mode 100644 index 0000000000..cdeedaf5da --- /dev/null +++ b/pkg/client/generated/models/freight_sources.go @@ -0,0 +1,124 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// FreightSources freight sources +// +// swagger:model FreightSources +type FreightSources struct { + + // AutoPromotionOptions specifies options pertaining to auto-promotion. These + // settings have no effect if auto-promotion is not enabled for this Stage at + // the ProjectConfig level. + AutoPromotionOptions struct { + AutoPromotionOptions + } `json:"autoPromotionOptions,omitempty"` + + // AvailabilityStrategy specifies the semantics for how requested Freight is + // made available to the Stage. This field is optional. When left unspecified, + // the field is implicitly treated as if its value were "OneOf". + // + // Accepted Values: + // + // - "All": Freight must be verified and, if applicable, soaked in all + // upstream Stages to be considered available for promotion. + // - "OneOf": Freight must be verified and, if applicable, soaked in at least + // one upstream Stage to be considered available for promotion. + // - "": Treated the same as "OneOf". + // + // +kubebuilder:validation:Optional + AvailabilityStrategy string `json:"availabilityStrategy,omitempty"` + + // Direct indicates the requested Freight may be obtained directly from the + // Warehouse from which it originated. If this field's value is false, then + // the value of the Stages field must be non-empty. i.e. Between the two + // fields, at least one source must be specified. + Direct bool `json:"direct,omitempty"` + + // RequiredSoakTime specifies a minimum duration for which the requested + // Freight must have continuously occupied ("soaked in") in an upstream Stage + // before becoming available for promotion to this Stage. This is an optional + // field. If nil or zero, no soak time is required. Any soak time requirement + // is in ADDITION to the requirement that Freight be verified in an upstream + // Stage to become available for promotion to this Stage, although a manual + // approval for promotion to this Stage will supersede any soak time + // requirement. + // + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern=`^([0-9]+(\.[0-9]+)?(s|m|h))+$` + // +akuity:test-kubebuilder-pattern=Duration + RequiredSoakTime string `json:"requiredSoakTime,omitempty"` + + // Stages identifies other "upstream" Stages as potential sources of the + // requested Freight. If this field's value is empty, then the value of the + // Direct field must be true. i.e. Between the two fields, at least on source + // must be specified. + Stages []string `json:"stages"` +} + +// Validate validates this freight sources +func (m *FreightSources) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAutoPromotionOptions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightSources) validateAutoPromotionOptions(formats strfmt.Registry) error { + if swag.IsZero(m.AutoPromotionOptions) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this freight sources based on the context it is used +func (m *FreightSources) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAutoPromotionOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightSources) contextValidateAutoPromotionOptions(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *FreightSources) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightSources) UnmarshalBinary(b []byte) error { + var res FreightSources + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/freight_status.go b/pkg/client/generated/models/freight_status.go new file mode 100644 index 0000000000..af098999da --- /dev/null +++ b/pkg/client/generated/models/freight_status.go @@ -0,0 +1,234 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// FreightStatus freight status +// +// swagger:model FreightStatus +type FreightStatus struct { + + // ApprovedFor describes the Stages for which this Freight has been approved + // preemptively/manually by a user. This is useful for hotfixes, where one + // might wish to promote a piece of Freight to a given Stage without + // transiting the entire pipeline. + ApprovedFor map[string]ApprovedStage `json:"approvedFor,omitempty"` + + // CurrentlyIn describes the Stages in which this Freight is currently in use. + CurrentlyIn map[string]CurrentStage `json:"currentlyIn,omitempty"` + + // Metadata is a map of arbitrary metadata associated with the Freight. + // This is useful for storing additional information about the Freight + // or Promotion that can be shared across steps or stages. + Metadata map[string]any `json:"metadata,omitempty"` + + // VerifiedIn describes the Stages in which this Freight has been verified + // through promotion and subsequent health checks. + VerifiedIn map[string]VerifiedStage `json:"verifiedIn,omitempty"` +} + +// Validate validates this freight status +func (m *FreightStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateApprovedFor(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCurrentlyIn(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVerifiedIn(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightStatus) validateApprovedFor(formats strfmt.Registry) error { + if swag.IsZero(m.ApprovedFor) { // not required + return nil + } + + for k := range m.ApprovedFor { + + if err := validate.Required("approvedFor"+"."+k, "body", m.ApprovedFor[k]); err != nil { + return err + } + if val, ok := m.ApprovedFor[k]; ok { + if err := val.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("approvedFor" + "." + k) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("approvedFor" + "." + k) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightStatus) validateCurrentlyIn(formats strfmt.Registry) error { + if swag.IsZero(m.CurrentlyIn) { // not required + return nil + } + + for k := range m.CurrentlyIn { + + if err := validate.Required("currentlyIn"+"."+k, "body", m.CurrentlyIn[k]); err != nil { + return err + } + if val, ok := m.CurrentlyIn[k]; ok { + if err := val.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("currentlyIn" + "." + k) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("currentlyIn" + "." + k) + } + + return err + } + } + + } + + return nil +} + +func (m *FreightStatus) validateVerifiedIn(formats strfmt.Registry) error { + if swag.IsZero(m.VerifiedIn) { // not required + return nil + } + + for k := range m.VerifiedIn { + + if err := validate.Required("verifiedIn"+"."+k, "body", m.VerifiedIn[k]); err != nil { + return err + } + if val, ok := m.VerifiedIn[k]; ok { + if err := val.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("verifiedIn" + "." + k) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("verifiedIn" + "." + k) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this freight status based on the context it is used +func (m *FreightStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateApprovedFor(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCurrentlyIn(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVerifiedIn(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *FreightStatus) contextValidateApprovedFor(ctx context.Context, formats strfmt.Registry) error { + + for k := range m.ApprovedFor { + + if val, ok := m.ApprovedFor[k]; ok { + if err := val.ContextValidate(ctx, formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *FreightStatus) contextValidateCurrentlyIn(ctx context.Context, formats strfmt.Registry) error { + + for k := range m.CurrentlyIn { + + if val, ok := m.CurrentlyIn[k]; ok { + if err := val.ContextValidate(ctx, formats); err != nil { + return err + } + } + + } + + return nil +} + +func (m *FreightStatus) contextValidateVerifiedIn(ctx context.Context, formats strfmt.Registry) error { + + for k := range m.VerifiedIn { + + if val, ok := m.VerifiedIn[k]; ok { + if err := val.ContextValidate(ctx, formats); err != nil { + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *FreightStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *FreightStatus) UnmarshalBinary(b []byte) error { + var res FreightStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/generic_webhook_action.go b/pkg/client/generated/models/generic_webhook_action.go new file mode 100644 index 0000000000..ad9a808edc --- /dev/null +++ b/pkg/client/generated/models/generic_webhook_action.go @@ -0,0 +1,148 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GenericWebhookAction generic webhook action +// +// swagger:model GenericWebhookAction +type GenericWebhookAction struct { + + // ActionType indicates the type of action to be performed. `Refresh` is the + // only currently supported action. + // + // +kubebuilder:validation:Enum=Refresh; + Action string `json:"action,omitempty"` + + // Parameters contains additional, action-specific parameters. Values may be + // static or extracted from the request using expressions. + // + // +optional + Parameters map[string]string `json:"parameters,omitempty"` + + // TargetSelectionCriteria is a list of selection criteria for the resources on which the + // action should be performed. + // + // +kubebuilder:validation:MinItems=1 + TargetSelectionCriteria []*GenericWebhookTargetSelectionCriteria `json:"targetSelectionCriteria"` + + // WhenExpression defines criteria that a request must meet to run this + // action. + // + // +optional + WhenExpression string `json:"whenExpression,omitempty"` +} + +// Validate validates this generic webhook action +func (m *GenericWebhookAction) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateTargetSelectionCriteria(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GenericWebhookAction) validateTargetSelectionCriteria(formats strfmt.Registry) error { + if swag.IsZero(m.TargetSelectionCriteria) { // not required + return nil + } + + for i := 0; i < len(m.TargetSelectionCriteria); i++ { + if swag.IsZero(m.TargetSelectionCriteria[i]) { // not required + continue + } + + if m.TargetSelectionCriteria[i] != nil { + if err := m.TargetSelectionCriteria[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("targetSelectionCriteria" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("targetSelectionCriteria" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this generic webhook action based on the context it is used +func (m *GenericWebhookAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateTargetSelectionCriteria(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GenericWebhookAction) contextValidateTargetSelectionCriteria(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.TargetSelectionCriteria); i++ { + + if m.TargetSelectionCriteria[i] != nil { + + if swag.IsZero(m.TargetSelectionCriteria[i]) { // not required + return nil + } + + if err := m.TargetSelectionCriteria[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("targetSelectionCriteria" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("targetSelectionCriteria" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *GenericWebhookAction) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GenericWebhookAction) UnmarshalBinary(b []byte) error { + var res GenericWebhookAction + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/generic_webhook_receiver_config.go b/pkg/client/generated/models/generic_webhook_receiver_config.go new file mode 100644 index 0000000000..49675caff6 --- /dev/null +++ b/pkg/client/generated/models/generic_webhook_receiver_config.go @@ -0,0 +1,165 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GenericWebhookReceiverConfig generic webhook receiver config +// +// swagger:model GenericWebhookReceiverConfig +type GenericWebhookReceiverConfig struct { + + // Actions is a list of actions to be performed when a webhook event is received. + // + // +kubebuilder:validation:MinItems=1 + Actions []*GenericWebhookAction `json:"actions"` + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret` key whose value + // does NOT need to be shared directly with the sender. It is used only by + // Kargo to create a complex, hard-to-guess URL, which implicitly serves as a + // shared secret. + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this generic webhook receiver config +func (m *GenericWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateActions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GenericWebhookReceiverConfig) validateActions(formats strfmt.Registry) error { + if swag.IsZero(m.Actions) { // not required + return nil + } + + for i := 0; i < len(m.Actions); i++ { + if swag.IsZero(m.Actions[i]) { // not required + continue + } + + if m.Actions[i] != nil { + if err := m.Actions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("actions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("actions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *GenericWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this generic webhook receiver config based on the context it is used +func (m *GenericWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateActions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GenericWebhookReceiverConfig) contextValidateActions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Actions); i++ { + + if m.Actions[i] != nil { + + if swag.IsZero(m.Actions[i]) { // not required + return nil + } + + if err := m.Actions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("actions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("actions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *GenericWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *GenericWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GenericWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res GenericWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/generic_webhook_target_selection_criteria.go b/pkg/client/generated/models/generic_webhook_target_selection_criteria.go new file mode 100644 index 0000000000..81d8cc97f8 --- /dev/null +++ b/pkg/client/generated/models/generic_webhook_target_selection_criteria.go @@ -0,0 +1,124 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GenericWebhookTargetSelectionCriteria generic webhook target selection criteria +// +// swagger:model GenericWebhookTargetSelectionCriteria +type GenericWebhookTargetSelectionCriteria struct { + + // IndexSelector is a selector used to identify cached target resources by cache key. + // If used with LabelSelector and/or Name, the results are the combined (logical AND) of all the criteria. + // + // +optional + IndexSelector struct { + IndexSelector + } `json:"indexSelector,omitempty"` + + // Kind is the kind of the target resource. + // + // +kubebuilder:validation:Enum=Warehouse; + Kind string `json:"kind,omitempty"` + + // LabelSelector is a label selector to identify the target resources. + // If used with IndexSelector and/or Name, the results are the combined (logical AND) of all the criteria. + // + // +optional + LabelSelector struct { + V1LabelSelector + } `json:"labelSelector,omitempty"` + + // Name is the name of the target resource. If LabelSelector and/or IndexSelectors + // are also specified, the results are the combined (logical AND) of the criteria. + // + // +optional + Name string `json:"name,omitempty"` +} + +// Validate validates this generic webhook target selection criteria +func (m *GenericWebhookTargetSelectionCriteria) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateIndexSelector(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLabelSelector(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GenericWebhookTargetSelectionCriteria) validateIndexSelector(formats strfmt.Registry) error { + if swag.IsZero(m.IndexSelector) { // not required + return nil + } + + return nil +} + +func (m *GenericWebhookTargetSelectionCriteria) validateLabelSelector(formats strfmt.Registry) error { + if swag.IsZero(m.LabelSelector) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this generic webhook target selection criteria based on the context it is used +func (m *GenericWebhookTargetSelectionCriteria) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateIndexSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLabelSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GenericWebhookTargetSelectionCriteria) contextValidateIndexSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *GenericWebhookTargetSelectionCriteria) contextValidateLabelSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *GenericWebhookTargetSelectionCriteria) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GenericWebhookTargetSelectionCriteria) UnmarshalBinary(b []byte) error { + var res GenericWebhookTargetSelectionCriteria + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/git_commit.go b/pkg/client/generated/models/git_commit.go new file mode 100644 index 0000000000..5cebcaf3a6 --- /dev/null +++ b/pkg/client/generated/models/git_commit.go @@ -0,0 +1,68 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GitCommit git commit +// +// swagger:model GitCommit +type GitCommit struct { + + // Author is the author of the commit. + Author string `json:"author,omitempty"` + + // Branch denotes the branch of the repository where this commit was found. + Branch string `json:"branch,omitempty"` + + // Committer is the person who committed the commit. + Committer string `json:"committer,omitempty"` + + // ID is the ID of a specific commit in the Git repository specified by + // RepoURL. + ID string `json:"id,omitempty"` + + // Message is the message associated with the commit. At present, this only + // contains the first line (subject) of the commit message. + Message string `json:"message,omitempty"` + + // RepoURL is the URL of a Git repository. + RepoURL string `json:"repoURL,omitempty"` + + // Tag denotes a tag in the repository that matched selection criteria and + // resolved to this commit. + Tag string `json:"tag,omitempty"` +} + +// Validate validates this git commit +func (m *GitCommit) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this git commit based on context it is used +func (m *GitCommit) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *GitCommit) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GitCommit) UnmarshalBinary(b []byte) error { + var res GitCommit + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/git_discovery_result.go b/pkg/client/generated/models/git_discovery_result.go new file mode 100644 index 0000000000..224588ccfa --- /dev/null +++ b/pkg/client/generated/models/git_discovery_result.go @@ -0,0 +1,140 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GitDiscoveryResult git discovery result +// +// swagger:model GitDiscoveryResult +type GitDiscoveryResult struct { + + // Commits is a list of commits discovered by the Warehouse for the + // GitSubscription. An empty list indicates that the discovery operation was + // successful, but no commits matching the GitSubscription criteria were found. + // + // +optional + Commits []*DiscoveredCommit `json:"commits"` + + // RepoURL is the repository URL of the GitSubscription. + // + // TODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern. + // + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`(?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*))` + // +akuity:test-kubebuilder-pattern=GitRepoURLPattern + RepoURL string `json:"repoURL,omitempty"` +} + +// Validate validates this git discovery result +func (m *GitDiscoveryResult) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCommits(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GitDiscoveryResult) validateCommits(formats strfmt.Registry) error { + if swag.IsZero(m.Commits) { // not required + return nil + } + + for i := 0; i < len(m.Commits); i++ { + if swag.IsZero(m.Commits[i]) { // not required + continue + } + + if m.Commits[i] != nil { + if err := m.Commits[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("commits" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("commits" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this git discovery result based on the context it is used +func (m *GitDiscoveryResult) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateCommits(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GitDiscoveryResult) contextValidateCommits(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Commits); i++ { + + if m.Commits[i] != nil { + + if swag.IsZero(m.Commits[i]) { // not required + return nil + } + + if err := m.Commits[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("commits" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("commits" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *GitDiscoveryResult) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GitDiscoveryResult) UnmarshalBinary(b []byte) error { + var res GitDiscoveryResult + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/git_hub_webhook_receiver_config.go b/pkg/client/generated/models/git_hub_webhook_receiver_config.go new file mode 100644 index 0000000000..72411d267e --- /dev/null +++ b/pkg/client/generated/models/git_hub_webhook_receiver_config.go @@ -0,0 +1,91 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GitHubWebhookReceiverConfig git hub webhook receiver config +// +// swagger:model GitHubWebhookReceiverConfig +type GitHubWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret` key whose value is + // the shared secret used to authenticate the webhook requests sent by GitHub. + // For more information please refer to GitHub documentation: + // https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this git hub webhook receiver config +func (m *GitHubWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GitHubWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this git hub webhook receiver config based on the context it is used +func (m *GitHubWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GitHubWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *GitHubWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GitHubWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res GitHubWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/git_lab_webhook_receiver_config.go b/pkg/client/generated/models/git_lab_webhook_receiver_config.go new file mode 100644 index 0000000000..9489b1704d --- /dev/null +++ b/pkg/client/generated/models/git_lab_webhook_receiver_config.go @@ -0,0 +1,91 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GitLabWebhookReceiverConfig git lab webhook receiver config +// +// swagger:model GitLabWebhookReceiverConfig +type GitLabWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The secret is expected to contain a `secret-token` key containing the + // shared secret specified when registering the webhook in GitLab. For more + // information about this token, please refer to the GitLab documentation: + // https://docs.gitlab.com/user/project/integrations/webhooks/ + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this git lab webhook receiver config +func (m *GitLabWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GitLabWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this git lab webhook receiver config based on the context it is used +func (m *GitLabWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GitLabWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *GitLabWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GitLabWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res GitLabWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/gitea_webhook_receiver_config.go b/pkg/client/generated/models/gitea_webhook_receiver_config.go new file mode 100644 index 0000000000..fcc14e1d61 --- /dev/null +++ b/pkg/client/generated/models/gitea_webhook_receiver_config.go @@ -0,0 +1,91 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// GiteaWebhookReceiverConfig gitea webhook receiver config +// +// swagger:model GiteaWebhookReceiverConfig +type GiteaWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret` key whose value is + // the shared secret used to authenticate the webhook requests sent by Gitea. + // For more information please refer to the Gitea documentation: + // https://docs.gitea.io/en-us/webhooks/ + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this gitea webhook receiver config +func (m *GiteaWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GiteaWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this gitea webhook receiver config based on the context it is used +func (m *GiteaWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *GiteaWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *GiteaWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *GiteaWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res GiteaWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/harbor_webhook_receiver_config.go b/pkg/client/generated/models/harbor_webhook_receiver_config.go new file mode 100644 index 0000000000..0afc22c1a3 --- /dev/null +++ b/pkg/client/generated/models/harbor_webhook_receiver_config.go @@ -0,0 +1,91 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// HarborWebhookReceiverConfig harbor webhook receiver config +// +// swagger:model HarborWebhookReceiverConfig +type HarborWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The secret is expected to contain an `auth-header` key containing the "auth + // header" specified when registering the webhook in Harbor. For more + // information, please refer to the Harbor documentation: + // https://goharbor.io/docs/main/working-with-projects/project-configuration/configure-webhooks/ + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this harbor webhook receiver config +func (m *HarborWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *HarborWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this harbor webhook receiver config based on the context it is used +func (m *HarborWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *HarborWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *HarborWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *HarborWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res HarborWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/health.go b/pkg/client/generated/models/health.go new file mode 100644 index 0000000000..ce7cd67fe5 --- /dev/null +++ b/pkg/client/generated/models/health.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Health health +// +// swagger:model Health +type Health struct { + + // Config is the opaque configuration of all health checks performed on this + // Stage. + Config any `json:"config,omitempty"` + + // Issues clarifies why a Stage in any state other than Healthy is in that + // state. This field will always be the empty when a Stage is Healthy. + Issues []string `json:"issues"` + + // Output is the opaque output of all health checks performed on this Stage. + Output any `json:"output,omitempty"` + + // Status describes the health of the Stage. + Status string `json:"status,omitempty"` +} + +// Validate validates this health +func (m *Health) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this health based on context it is used +func (m *Health) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *Health) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Health) UnmarshalBinary(b []byte) error { + var res Health + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/health_check_step.go b/pkg/client/generated/models/health_check_step.go new file mode 100644 index 0000000000..38a270d523 --- /dev/null +++ b/pkg/client/generated/models/health_check_step.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// HealthCheckStep health check step +// +// swagger:model HealthCheckStep +type HealthCheckStep struct { + + // Config is the configuration for the directive. + Config any `json:"config,omitempty"` + + // Uses identifies a runner that can execute this step. + // + // +kubebuilder:validation:MinLength=1 + Uses string `json:"uses,omitempty"` +} + +// Validate validates this health check step +func (m *HealthCheckStep) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this health check step based on context it is used +func (m *HealthCheckStep) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *HealthCheckStep) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *HealthCheckStep) UnmarshalBinary(b []byte) error { + var res HealthCheckStep + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/health_stats.go b/pkg/client/generated/models/health_stats.go new file mode 100644 index 0000000000..5aa5377ffe --- /dev/null +++ b/pkg/client/generated/models/health_stats.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// HealthStats health stats +// +// swagger:model HealthStats +type HealthStats struct { + + // Healthy contains the number of resources that are explicitly healthy. + Healthy int64 `json:"healthy,omitempty"` +} + +// Validate validates this health stats +func (m *HealthStats) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this health stats based on context it is used +func (m *HealthStats) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *HealthStats) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *HealthStats) UnmarshalBinary(b []byte) error { + var res HealthStats + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/image.go b/pkg/client/generated/models/image.go new file mode 100644 index 0000000000..11c0ce4725 --- /dev/null +++ b/pkg/client/generated/models/image.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Image image +// +// swagger:model Image +type Image struct { + + // Annotations is a map of arbitrary metadata for the image. + Annotations map[string]string `json:"annotations,omitempty"` + + // Digest identifies a specific version of the image in the repository + // specified by RepoURL. This is a more precise identifier than Tag. + Digest string `json:"digest,omitempty"` + + // RepoURL describes the repository in which the image can be found. + RepoURL string `json:"repoURL,omitempty"` + + // Tag identifies a specific version of the image in the repository specified + // by RepoURL. + Tag string `json:"tag,omitempty"` +} + +// Validate validates this image +func (m *Image) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this image based on context it is used +func (m *Image) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *Image) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Image) UnmarshalBinary(b []byte) error { + var res Image + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/image_discovery_result.go b/pkg/client/generated/models/image_discovery_result.go new file mode 100644 index 0000000000..75faf5f2c8 --- /dev/null +++ b/pkg/client/generated/models/image_discovery_result.go @@ -0,0 +1,143 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ImageDiscoveryResult image discovery result +// +// swagger:model ImageDiscoveryResult +type ImageDiscoveryResult struct { + + // Platform is the target platform constraint of the ImageSubscription + // for which references were discovered. This field is optional, and + // only populated if the ImageSubscription specifies a Platform. + Platform string `json:"platform,omitempty"` + + // References is a list of image references discovered by the Warehouse for + // the ImageSubscription. An empty list indicates that the discovery + // operation was successful, but no images matching the ImageSubscription + // criteria were found. + // + // +optional + References []*DiscoveredImageReference `json:"references"` + + // RepoURL is the repository URL of the image, as specified in the + // ImageSubscription. + // + // +kubebuilder:validation:MinLength=1 + RepoURL string `json:"repoURL,omitempty"` +} + +// Validate validates this image discovery result +func (m *ImageDiscoveryResult) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateReferences(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ImageDiscoveryResult) validateReferences(formats strfmt.Registry) error { + if swag.IsZero(m.References) { // not required + return nil + } + + for i := 0; i < len(m.References); i++ { + if swag.IsZero(m.References[i]) { // not required + continue + } + + if m.References[i] != nil { + if err := m.References[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("references" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("references" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this image discovery result based on the context it is used +func (m *ImageDiscoveryResult) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateReferences(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ImageDiscoveryResult) contextValidateReferences(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.References); i++ { + + if m.References[i] != nil { + + if swag.IsZero(m.References[i]) { // not required + return nil + } + + if err := m.References[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("references" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("references" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ImageDiscoveryResult) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ImageDiscoveryResult) UnmarshalBinary(b []byte) error { + var res ImageDiscoveryResult + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/index_selector.go b/pkg/client/generated/models/index_selector.go new file mode 100644 index 0000000000..5453923865 --- /dev/null +++ b/pkg/client/generated/models/index_selector.go @@ -0,0 +1,129 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// IndexSelector index selector +// +// swagger:model IndexSelector +type IndexSelector struct { + + // MatchIndices is a list of index selector requirements. + // + // +kubebuilder:validation:MinItems=1 + MatchIndices []*IndexSelectorRequirement `json:"matchIndices"` +} + +// Validate validates this index selector +func (m *IndexSelector) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMatchIndices(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IndexSelector) validateMatchIndices(formats strfmt.Registry) error { + if swag.IsZero(m.MatchIndices) { // not required + return nil + } + + for i := 0; i < len(m.MatchIndices); i++ { + if swag.IsZero(m.MatchIndices[i]) { // not required + continue + } + + if m.MatchIndices[i] != nil { + if err := m.MatchIndices[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchIndices" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchIndices" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this index selector based on the context it is used +func (m *IndexSelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMatchIndices(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *IndexSelector) contextValidateMatchIndices(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MatchIndices); i++ { + + if m.MatchIndices[i] != nil { + + if swag.IsZero(m.MatchIndices[i]) { // not required + return nil + } + + if err := m.MatchIndices[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchIndices" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchIndices" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *IndexSelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IndexSelector) UnmarshalBinary(b []byte) error { + var res IndexSelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/index_selector_requirement.go b/pkg/client/generated/models/index_selector_requirement.go new file mode 100644 index 0000000000..02a7a4b31f --- /dev/null +++ b/pkg/client/generated/models/index_selector_requirement.go @@ -0,0 +1,60 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// IndexSelectorRequirement index selector requirement +// +// swagger:model IndexSelectorRequirement +type IndexSelectorRequirement struct { + + // Key is the key of the index. + // + // +kubebuilder:validation:Enum=subscribedURLs;receiverPaths + Key string `json:"key,omitempty"` + + // Operator indicates the operation that should be used to evaluate + // whether the selection requirement is satisfied. + // + // kubebuilder:validation:Enum=Equal;NotEqual; + Operator string `json:"operator,omitempty"` + + // Value can be a static string or an expression that will be evaluated. + // + // kubebuilder:validation:Required + Value string `json:"value,omitempty"` +} + +// Validate validates this index selector requirement +func (m *IndexSelectorRequirement) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this index selector requirement based on context it is used +func (m *IndexSelectorRequirement) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *IndexSelectorRequirement) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IndexSelectorRequirement) UnmarshalBinary(b []byte) error { + var res IndexSelectorRequirement + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/int_or_string.go b/pkg/client/generated/models/int_or_string.go new file mode 100644 index 0000000000..2eea9562c5 --- /dev/null +++ b/pkg/client/generated/models/int_or_string.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// IntOrString int or string +// +// swagger:model IntOrString +type IntOrString struct { + + // int val + IntVal int64 `json:"intVal,omitempty"` + + // str val + StrVal string `json:"strVal,omitempty"` + + // type + Type int64 `json:"type,omitempty"` +} + +// Validate validates this int or string +func (m *IntOrString) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this int or string based on context it is used +func (m *IntOrString) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *IntOrString) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *IntOrString) UnmarshalBinary(b []byte) error { + var res IntOrString + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project.go b/pkg/client/generated/models/project.go new file mode 100644 index 0000000000..c49754cc24 --- /dev/null +++ b/pkg/client/generated/models/project.go @@ -0,0 +1,156 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Project project +// +// swagger:model Project +type Project struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Status describes the Project's current status. + Status struct { + ProjectStatus + } `json:"status,omitempty"` +} + +// Validate validates this project +func (m *Project) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Project) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Project) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this project based on the context it is used +func (m *Project) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Project) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Project) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *Project) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Project) UnmarshalBinary(b []byte) error { + var res Project + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project_config.go b/pkg/client/generated/models/project_config.go new file mode 100644 index 0000000000..85aaa72bdf --- /dev/null +++ b/pkg/client/generated/models/project_config.go @@ -0,0 +1,182 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ProjectConfig project config +// +// swagger:model ProjectConfig +type ProjectConfig struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes the configuration of a Project. + Spec struct { + ProjectConfigSpec + } `json:"spec,omitempty"` + + // Status describes the current status of a ProjectConfig. + Status struct { + ProjectConfigStatus + } `json:"status,omitempty"` +} + +// Validate validates this project config +func (m *ProjectConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectConfig) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *ProjectConfig) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + return nil +} + +func (m *ProjectConfig) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this project config based on the context it is used +func (m *ProjectConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectConfig) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *ProjectConfig) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *ProjectConfig) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *ProjectConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ProjectConfig) UnmarshalBinary(b []byte) error { + var res ProjectConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project_config_spec.go b/pkg/client/generated/models/project_config_spec.go new file mode 100644 index 0000000000..875d81940e --- /dev/null +++ b/pkg/client/generated/models/project_config_spec.go @@ -0,0 +1,199 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ProjectConfigSpec project config spec +// +// swagger:model ProjectConfigSpec +type ProjectConfigSpec struct { + + // PromotionPolicies defines policies governing the promotion of Freight to + // specific Stages within the Project. + PromotionPolicies []*PromotionPolicy `json:"promotionPolicies"` + + // WebhookReceivers describes Project-specific webhook receivers used for + // processing events from various external platforms + WebhookReceivers []*WebhookReceiverConfig `json:"webhookReceivers"` +} + +// Validate validates this project config spec +func (m *ProjectConfigSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePromotionPolicies(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWebhookReceivers(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectConfigSpec) validatePromotionPolicies(formats strfmt.Registry) error { + if swag.IsZero(m.PromotionPolicies) { // not required + return nil + } + + for i := 0; i < len(m.PromotionPolicies); i++ { + if swag.IsZero(m.PromotionPolicies[i]) { // not required + continue + } + + if m.PromotionPolicies[i] != nil { + if err := m.PromotionPolicies[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("promotionPolicies" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("promotionPolicies" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectConfigSpec) validateWebhookReceivers(formats strfmt.Registry) error { + if swag.IsZero(m.WebhookReceivers) { // not required + return nil + } + + for i := 0; i < len(m.WebhookReceivers); i++ { + if swag.IsZero(m.WebhookReceivers[i]) { // not required + continue + } + + if m.WebhookReceivers[i] != nil { + if err := m.WebhookReceivers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this project config spec based on the context it is used +func (m *ProjectConfigSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePromotionPolicies(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWebhookReceivers(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectConfigSpec) contextValidatePromotionPolicies(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.PromotionPolicies); i++ { + + if m.PromotionPolicies[i] != nil { + + if swag.IsZero(m.PromotionPolicies[i]) { // not required + return nil + } + + if err := m.PromotionPolicies[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("promotionPolicies" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("promotionPolicies" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectConfigSpec) contextValidateWebhookReceivers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.WebhookReceivers); i++ { + + if m.WebhookReceivers[i] != nil { + + if swag.IsZero(m.WebhookReceivers[i]) { // not required + return nil + } + + if err := m.WebhookReceivers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ProjectConfigSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ProjectConfigSpec) UnmarshalBinary(b []byte) error { + var res ProjectConfigSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project_config_status.go b/pkg/client/generated/models/project_config_status.go new file mode 100644 index 0000000000..8e6f36bf9b --- /dev/null +++ b/pkg/client/generated/models/project_config_status.go @@ -0,0 +1,214 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ProjectConfigStatus project config status +// +// swagger:model ProjectConfigStatus +type ProjectConfigStatus struct { + + // Conditions contains the last observations of the Project Config's current + // state. + // + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []*V1Condition `json:"conditions"` + + // LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh + // annotation that was handled by the controller. This field can be used to + // determine whether the request to refresh the resource has been handled. + // +optional + LastHandledRefresh string `json:"lastHandledRefresh,omitempty"` + + // ObservedGeneration represents the .metadata.generation that this + // ProjectConfig was reconciled against. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // WebhookReceivers describes the status of Project-specific webhook + // receivers. + WebhookReceivers []*WebhookReceiverDetails `json:"webhookReceivers"` +} + +// Validate validates this project config status +func (m *ProjectConfigStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConditions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWebhookReceivers(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectConfigStatus) validateConditions(formats strfmt.Registry) error { + if swag.IsZero(m.Conditions) { // not required + return nil + } + + for i := 0; i < len(m.Conditions); i++ { + if swag.IsZero(m.Conditions[i]) { // not required + continue + } + + if m.Conditions[i] != nil { + if err := m.Conditions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectConfigStatus) validateWebhookReceivers(formats strfmt.Registry) error { + if swag.IsZero(m.WebhookReceivers) { // not required + return nil + } + + for i := 0; i < len(m.WebhookReceivers); i++ { + if swag.IsZero(m.WebhookReceivers[i]) { // not required + continue + } + + if m.WebhookReceivers[i] != nil { + if err := m.WebhookReceivers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this project config status based on the context it is used +func (m *ProjectConfigStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConditions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWebhookReceivers(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectConfigStatus) contextValidateConditions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Conditions); i++ { + + if m.Conditions[i] != nil { + + if swag.IsZero(m.Conditions[i]) { // not required + return nil + } + + if err := m.Conditions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectConfigStatus) contextValidateWebhookReceivers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.WebhookReceivers); i++ { + + if m.WebhookReceivers[i] != nil { + + if swag.IsZero(m.WebhookReceivers[i]) { // not required + return nil + } + + if err := m.WebhookReceivers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("webhookReceivers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ProjectConfigStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ProjectConfigStatus) UnmarshalBinary(b []byte) error { + var res ProjectConfigStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project_list.go b/pkg/client/generated/models/project_list.go new file mode 100644 index 0000000000..89a1d20248 --- /dev/null +++ b/pkg/client/generated/models/project_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ProjectList project list +// +// swagger:model ProjectList +type ProjectList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*Project `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this project list +func (m *ProjectList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this project list based on the context it is used +func (m *ProjectList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *ProjectList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ProjectList) UnmarshalBinary(b []byte) error { + var res ProjectList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project_stats.go b/pkg/client/generated/models/project_stats.go new file mode 100644 index 0000000000..bac6245590 --- /dev/null +++ b/pkg/client/generated/models/project_stats.go @@ -0,0 +1,108 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ProjectStats project stats +// +// swagger:model ProjectStats +type ProjectStats struct { + + // Stages contains a summary of the collective state of the Project's Stages. + Stages struct { + StageStats + } `json:"stages,omitempty"` + + // Warehouses contains a summary of the collective state of the Project's + // Warehouses. + Warehouses struct { + WarehouseStats + } `json:"warehouses,omitempty"` +} + +// Validate validates this project stats +func (m *ProjectStats) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateStages(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWarehouses(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectStats) validateStages(formats strfmt.Registry) error { + if swag.IsZero(m.Stages) { // not required + return nil + } + + return nil +} + +func (m *ProjectStats) validateWarehouses(formats strfmt.Registry) error { + if swag.IsZero(m.Warehouses) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this project stats based on the context it is used +func (m *ProjectStats) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateStages(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWarehouses(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectStats) contextValidateStages(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *ProjectStats) contextValidateWarehouses(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *ProjectStats) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ProjectStats) UnmarshalBinary(b []byte) error { + var res ProjectStats + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/project_status.go b/pkg/client/generated/models/project_status.go new file mode 100644 index 0000000000..57c520b769 --- /dev/null +++ b/pkg/client/generated/models/project_status.go @@ -0,0 +1,159 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// ProjectStatus project status +// +// swagger:model ProjectStatus +type ProjectStatus struct { + + // Conditions contains the last observations of the Project's current + // state. + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []*V1Condition `json:"conditions"` + + // Stats contains a summary of the collective state of a Project's + // constituent resources. + Stats struct { + ProjectStats + } `json:"stats,omitempty"` +} + +// Validate validates this project status +func (m *ProjectStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConditions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStats(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectStatus) validateConditions(formats strfmt.Registry) error { + if swag.IsZero(m.Conditions) { // not required + return nil + } + + for i := 0; i < len(m.Conditions); i++ { + if swag.IsZero(m.Conditions[i]) { // not required + continue + } + + if m.Conditions[i] != nil { + if err := m.Conditions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectStatus) validateStats(formats strfmt.Registry) error { + if swag.IsZero(m.Stats) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this project status based on the context it is used +func (m *ProjectStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConditions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStats(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *ProjectStatus) contextValidateConditions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Conditions); i++ { + + if m.Conditions[i] != nil { + + if swag.IsZero(m.Conditions[i]) { // not required + return nil + } + + if err := m.Conditions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *ProjectStatus) contextValidateStats(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *ProjectStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *ProjectStatus) UnmarshalBinary(b []byte) error { + var res ProjectStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion.go b/pkg/client/generated/models/promotion.go new file mode 100644 index 0000000000..be2953526c --- /dev/null +++ b/pkg/client/generated/models/promotion.go @@ -0,0 +1,184 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Promotion promotion +// +// swagger:model Promotion +type Promotion struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes the desired transition of a specific Stage into a specific + // Freight. + // + // +kubebuilder:validation:Required + // Required: true + Spec struct { + PromotionSpec + } `json:"spec"` + + // Status describes the current state of the transition represented by this + // Promotion. + Status struct { + PromotionStatus + } `json:"status,omitempty"` +} + +// Validate validates this promotion +func (m *Promotion) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Promotion) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Promotion) validateSpec(formats strfmt.Registry) error { + + return nil +} + +func (m *Promotion) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this promotion based on the context it is used +func (m *Promotion) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Promotion) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Promotion) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *Promotion) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *Promotion) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Promotion) UnmarshalBinary(b []byte) error { + var res Promotion + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_list.go b/pkg/client/generated/models/promotion_list.go new file mode 100644 index 0000000000..530ff04afc --- /dev/null +++ b/pkg/client/generated/models/promotion_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionList promotion list +// +// swagger:model PromotionList +type PromotionList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*Promotion `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this promotion list +func (m *PromotionList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this promotion list based on the context it is used +func (m *PromotionList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionList) UnmarshalBinary(b []byte) error { + var res PromotionList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_policy.go b/pkg/client/generated/models/promotion_policy.go new file mode 100644 index 0000000000..7e88b3bac8 --- /dev/null +++ b/pkg/client/generated/models/promotion_policy.go @@ -0,0 +1,98 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionPolicy promotion policy +// +// swagger:model PromotionPolicy +type PromotionPolicy struct { + + // AutoPromotionEnabled indicates whether new Freight can automatically be + // promoted into the Stage referenced by the Stage field. Note: There are may + // be other conditions also required for an auto-promotion to occur. This + // field defaults to false, but is commonly set to true for Stages that + // subscribe to Warehouses instead of other, upstream Stages. This allows + // users to define Stages that are automatically updated as soon as new + // artifacts are detected. + AutoPromotionEnabled bool `json:"autoPromotionEnabled,omitempty"` + + // Stage is the name of the Stage to which this policy applies. + // + // Deprecated: Use StageSelector instead. + // + // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + Stage string `json:"stage,omitempty"` + + // StageSelector is a selector that matches the Stage resource to which + // this policy applies. + StageSelector struct { + PromotionPolicySelector + } `json:"stageSelector,omitempty"` +} + +// Validate validates this promotion policy +func (m *PromotionPolicy) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateStageSelector(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionPolicy) validateStageSelector(formats strfmt.Registry) error { + if swag.IsZero(m.StageSelector) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this promotion policy based on the context it is used +func (m *PromotionPolicy) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateStageSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionPolicy) contextValidateStageSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionPolicy) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionPolicy) UnmarshalBinary(b []byte) error { + var res PromotionPolicy + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_policy_selector.go b/pkg/client/generated/models/promotion_policy_selector.go new file mode 100644 index 0000000000..23727623d2 --- /dev/null +++ b/pkg/client/generated/models/promotion_policy_selector.go @@ -0,0 +1,154 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionPolicySelector promotion policy selector +// +// swagger:model PromotionPolicySelector +type PromotionPolicySelector struct { + + // matchExpressions is a list of label selector requirements. The requirements are ANDed. + // +optional + // +listType=atomic + MatchExpressions []*V1LabelSelectorRequirement `json:"matchExpressions"` + + // matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + // map is equivalent to an element of matchExpressions, whose key field is "key", the + // operator is "In", and the values array contains only "value". The requirements are ANDed. + // +optional + MatchLabels map[string]string `json:"matchLabels,omitempty"` + + // Name is the name of the resource to which this policy applies. + // + // It can be an exact name, a regex pattern (with prefix "regex:"), or a + // glob pattern (with prefix "glob:"). + // + // When both Name and LabelSelector are specified, the Name is ANDed with + // the LabelSelector. I.e., the resource must match both the Name and + // LabelSelector to be selected by this policy. + // + // NOTE: Using a specific exact name is the most secure option. Pattern + // matching via regex or glob can be exploited by users with permissions to + // match promotion policies that weren't intended to apply to their + // resources. For example, a user could create a resource with a name + // deliberately crafted to match the pattern, potentially bypassing intended + // promotion controls. + // + // +optional + Name string `json:"name,omitempty"` +} + +// Validate validates this promotion policy selector +func (m *PromotionPolicySelector) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMatchExpressions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionPolicySelector) validateMatchExpressions(formats strfmt.Registry) error { + if swag.IsZero(m.MatchExpressions) { // not required + return nil + } + + for i := 0; i < len(m.MatchExpressions); i++ { + if swag.IsZero(m.MatchExpressions[i]) { // not required + continue + } + + if m.MatchExpressions[i] != nil { + if err := m.MatchExpressions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this promotion policy selector based on the context it is used +func (m *PromotionPolicySelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMatchExpressions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionPolicySelector) contextValidateMatchExpressions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MatchExpressions); i++ { + + if m.MatchExpressions[i] != nil { + + if swag.IsZero(m.MatchExpressions[i]) { // not required + return nil + } + + if err := m.MatchExpressions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionPolicySelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionPolicySelector) UnmarshalBinary(b []byte) error { + var res PromotionPolicySelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_reference.go b/pkg/client/generated/models/promotion_reference.go new file mode 100644 index 0000000000..c527c7842d --- /dev/null +++ b/pkg/client/generated/models/promotion_reference.go @@ -0,0 +1,113 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionReference promotion reference +// +// swagger:model PromotionReference +type PromotionReference struct { + + // FinishedAt is the time at which the Promotion was completed. + FinishedAt string `json:"finishedAt,omitempty"` + + // Freight is the freight being promoted. + Freight struct { + FreightReference + } `json:"freight,omitempty"` + + // Name is the name of the Promotion. + Name string `json:"name,omitempty"` + + // Status is the (optional) status of the Promotion. + Status struct { + PromotionStatus + } `json:"status,omitempty"` +} + +// Validate validates this promotion reference +func (m *PromotionReference) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFreight(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionReference) validateFreight(formats strfmt.Registry) error { + if swag.IsZero(m.Freight) { // not required + return nil + } + + return nil +} + +func (m *PromotionReference) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this promotion reference based on the context it is used +func (m *PromotionReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateFreight(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionReference) contextValidateFreight(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *PromotionReference) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionReference) UnmarshalBinary(b []byte) error { + var res PromotionReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_spec.go b/pkg/client/generated/models/promotion_spec.go new file mode 100644 index 0000000000..8f5c656400 --- /dev/null +++ b/pkg/client/generated/models/promotion_spec.go @@ -0,0 +1,256 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// PromotionSpec promotion spec +// +// swagger:model PromotionSpec +type PromotionSpec struct { + + // Freight specifies the piece of Freight to be promoted into the Stage + // referenced by the Stage field. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` + // +akuity:test-kubebuilder-pattern=KubernetesName + // Required: true + Freight *string `json:"freight"` + + // Stage specifies the name of the Stage to which this Promotion + // applies. The Stage referenced by this field MUST be in the same + // namespace as the Promotion. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` + // +akuity:test-kubebuilder-pattern=KubernetesName + // Required: true + Stage *string `json:"stage"` + + // Steps specifies the directives to be executed as part of this Promotion. + // The order in which the directives are executed is the order in which they + // are listed in this field. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:items:XValidation:message="Promotion step must have uses set and must not reference a task",rule="has(self.uses) && !has(self.task)" + // Required: true + Steps []*PromotionStep `json:"steps"` + + // Vars is a list of variables that can be referenced by expressions in + // promotion steps. + Vars []*ExpressionVariable `json:"vars"` +} + +// Validate validates this promotion spec +func (m *PromotionSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFreight(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStage(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSteps(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVars(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionSpec) validateFreight(formats strfmt.Registry) error { + + if err := validate.Required("freight", "body", m.Freight); err != nil { + return err + } + + return nil +} + +func (m *PromotionSpec) validateStage(formats strfmt.Registry) error { + + if err := validate.Required("stage", "body", m.Stage); err != nil { + return err + } + + return nil +} + +func (m *PromotionSpec) validateSteps(formats strfmt.Registry) error { + + if err := validate.Required("steps", "body", m.Steps); err != nil { + return err + } + + for i := 0; i < len(m.Steps); i++ { + if swag.IsZero(m.Steps[i]) { // not required + continue + } + + if m.Steps[i] != nil { + if err := m.Steps[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("steps" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("steps" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionSpec) validateVars(formats strfmt.Registry) error { + if swag.IsZero(m.Vars) { // not required + return nil + } + + for i := 0; i < len(m.Vars); i++ { + if swag.IsZero(m.Vars[i]) { // not required + continue + } + + if m.Vars[i] != nil { + if err := m.Vars[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this promotion spec based on the context it is used +func (m *PromotionSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSteps(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVars(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionSpec) contextValidateSteps(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Steps); i++ { + + if m.Steps[i] != nil { + + if swag.IsZero(m.Steps[i]) { // not required + return nil + } + + if err := m.Steps[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("steps" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("steps" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionSpec) contextValidateVars(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Vars); i++ { + + if m.Vars[i] != nil { + + if swag.IsZero(m.Vars[i]) { // not required + return nil + } + + if err := m.Vars[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionSpec) UnmarshalBinary(b []byte) error { + var res PromotionSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_status.go b/pkg/client/generated/models/promotion_status.go new file mode 100644 index 0000000000..d88a47bacd --- /dev/null +++ b/pkg/client/generated/models/promotion_status.go @@ -0,0 +1,283 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionStatus promotion status +// +// swagger:model PromotionStatus +type PromotionStatus struct { + + // CurrentStep is the index of the current promotion step being executed. This + // permits steps that have already run successfully to be skipped on + // subsequent reconciliations attempts. + CurrentStep int64 `json:"currentStep,omitempty"` + + // FinishedAt is the time when the promotion was completed. + FinishedAt string `json:"finishedAt,omitempty"` + + // Freight is the detail of the piece of freight that was referenced by this promotion. + Freight struct { + FreightReference + } `json:"freight,omitempty"` + + // FreightCollection contains the details of the piece of Freight referenced + // by this Promotion as well as any additional Freight that is carried over + // from the target Stage's current state. + FreightCollection struct { + FreightCollection + } `json:"freightCollection,omitempty"` + + // HealthChecks contains the health check directives to be executed after + // the Promotion has completed. + HealthChecks []*HealthCheckStep `json:"healthChecks"` + + // LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh + // annotation that was handled by the controller. This field can be used to + // determine whether the request to refresh the resource has been handled. + // +optional + LastHandledRefresh string `json:"lastHandledRefresh,omitempty"` + + // Message is a display message about the promotion, including any errors + // preventing the Promotion controller from executing this Promotion. + // i.e. If the Phase field has a value of Failed, this field can be expected + // to explain why. + Message string `json:"message,omitempty"` + + // Phase describes where the Promotion currently is in its lifecycle. + Phase string `json:"phase,omitempty"` + + // StartedAt is the time when the promotion started. + StartedAt string `json:"startedAt,omitempty"` + + // State stores the state of the promotion process between reconciliation + // attempts. + State any `json:"state,omitempty"` + + // StepExecutionMetadata tracks metadata pertaining to the execution + // of individual promotion steps. + StepExecutionMetadata []*StepExecutionMetadata `json:"stepExecutionMetadata"` +} + +// Validate validates this promotion status +func (m *PromotionStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFreight(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFreightCollection(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHealthChecks(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStepExecutionMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionStatus) validateFreight(formats strfmt.Registry) error { + if swag.IsZero(m.Freight) { // not required + return nil + } + + return nil +} + +func (m *PromotionStatus) validateFreightCollection(formats strfmt.Registry) error { + if swag.IsZero(m.FreightCollection) { // not required + return nil + } + + return nil +} + +func (m *PromotionStatus) validateHealthChecks(formats strfmt.Registry) error { + if swag.IsZero(m.HealthChecks) { // not required + return nil + } + + for i := 0; i < len(m.HealthChecks); i++ { + if swag.IsZero(m.HealthChecks[i]) { // not required + continue + } + + if m.HealthChecks[i] != nil { + if err := m.HealthChecks[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("healthChecks" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("healthChecks" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionStatus) validateStepExecutionMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.StepExecutionMetadata) { // not required + return nil + } + + for i := 0; i < len(m.StepExecutionMetadata); i++ { + if swag.IsZero(m.StepExecutionMetadata[i]) { // not required + continue + } + + if m.StepExecutionMetadata[i] != nil { + if err := m.StepExecutionMetadata[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("stepExecutionMetadata" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("stepExecutionMetadata" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this promotion status based on the context it is used +func (m *PromotionStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateFreight(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFreightCollection(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHealthChecks(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStepExecutionMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionStatus) contextValidateFreight(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *PromotionStatus) contextValidateFreightCollection(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *PromotionStatus) contextValidateHealthChecks(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.HealthChecks); i++ { + + if m.HealthChecks[i] != nil { + + if swag.IsZero(m.HealthChecks[i]) { // not required + return nil + } + + if err := m.HealthChecks[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("healthChecks" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("healthChecks" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionStatus) contextValidateStepExecutionMetadata(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.StepExecutionMetadata); i++ { + + if m.StepExecutionMetadata[i] != nil { + + if swag.IsZero(m.StepExecutionMetadata[i]) { // not required + return nil + } + + if err := m.StepExecutionMetadata[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("stepExecutionMetadata" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("stepExecutionMetadata" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionStatus) UnmarshalBinary(b []byte) error { + var res PromotionStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_step.go b/pkg/client/generated/models/promotion_step.go new file mode 100644 index 0000000000..dea2357b51 --- /dev/null +++ b/pkg/client/generated/models/promotion_step.go @@ -0,0 +1,209 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionStep promotion step +// +// swagger:model PromotionStep +type PromotionStep struct { + + // As is the alias this step can be referred to as. + As string `json:"as,omitempty"` + + // Config is opaque configuration for the PromotionStep that is understood + // only by each PromotionStep's implementation. It is legal to utilize + // expressions in defining values at any level of this block. + // See https://docs.kargo.io/user-guide/reference-docs/expressions for details. + Config any `json:"config,omitempty"` + + // ContinueOnError is a boolean value that, if set to true, will cause the + // Promotion to continue executing the next step even if this step fails. It + // also will not permit this failure to impact the overall status of the + // Promotion. + ContinueOnError bool `json:"continueOnError,omitempty"` + + // If is an optional expression that, if present, must evaluate to a boolean + // value. If the expression evaluates to false, the step will be skipped. + // If the expression does not evaluate to a boolean value, the step will be + // considered to have failed. + If string `json:"if,omitempty"` + + // Retry is the retry policy for this step. + Retry struct { + PromotionStepRetry + } `json:"retry,omitempty"` + + // Task is a reference to a PromotionTask that should be inflated into a + // Promotion when it is built from a PromotionTemplate. + Task struct { + PromotionTaskReference + } `json:"task,omitempty"` + + // Uses identifies a runner that can execute this step. + // + // +kubebuilder:validation:Optional + // +kubebuilder:validation:MinLength=1 + Uses string `json:"uses,omitempty"` + + // Vars is a list of variables that can be referenced by expressions in + // the step's Config. The values override the values specified in the + // PromotionSpec. + Vars []*ExpressionVariable `json:"vars"` +} + +// Validate validates this promotion step +func (m *PromotionStep) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateRetry(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTask(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVars(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionStep) validateRetry(formats strfmt.Registry) error { + if swag.IsZero(m.Retry) { // not required + return nil + } + + return nil +} + +func (m *PromotionStep) validateTask(formats strfmt.Registry) error { + if swag.IsZero(m.Task) { // not required + return nil + } + + return nil +} + +func (m *PromotionStep) validateVars(formats strfmt.Registry) error { + if swag.IsZero(m.Vars) { // not required + return nil + } + + for i := 0; i < len(m.Vars); i++ { + if swag.IsZero(m.Vars[i]) { // not required + continue + } + + if m.Vars[i] != nil { + if err := m.Vars[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this promotion step based on the context it is used +func (m *PromotionStep) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateRetry(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTask(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVars(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionStep) contextValidateRetry(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *PromotionStep) contextValidateTask(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *PromotionStep) contextValidateVars(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Vars); i++ { + + if m.Vars[i] != nil { + + if swag.IsZero(m.Vars[i]) { // not required + return nil + } + + if err := m.Vars[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionStep) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionStep) UnmarshalBinary(b []byte) error { + var res PromotionStep + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_step_retry.go b/pkg/client/generated/models/promotion_step_retry.go new file mode 100644 index 0000000000..0547d3f12b --- /dev/null +++ b/pkg/client/generated/models/promotion_step_retry.go @@ -0,0 +1,81 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionStepRetry promotion step retry +// +// swagger:model PromotionStepRetry +type PromotionStepRetry struct { + + // ErrorThreshold is the number of consecutive times the step must fail (for + // any reason) before retries are abandoned and the entire Promotion is marked + // as failed. + // + // If this field is set to 0, the effective default will be a step-specific + // one. If no step-specific default exists (i.e. is also 0), the effective + // default will be the system-wide default of 1. + // + // A value of 1 will cause the Promotion to be marked as failed after just + // a single failure; i.e. no retries will be attempted. + // + // There is no option to specify an infinite number of retries using a value + // such as -1. + // + // In a future release, Kargo is likely to become capable of distinguishing + // between recoverable and non-recoverable step failures. At that time, it is + // planned that unrecoverable failures will not be subject to this threshold + // and will immediately cause the Promotion to be marked as failed without + // further condition. + ErrorThreshold int64 `json:"errorThreshold,omitempty"` + + // Timeout is the soft maximum interval in which a step that returns a Running + // status (which typically indicates it's waiting for something to happen) + // may be retried. + // + // The maximum is a soft one because the check for whether the interval has + // elapsed occurs AFTER the step has run. This effectively means a step may + // run ONCE beyond the close of the interval. + // + // If this field is set to nil, the effective default will be a step-specific + // one. If no step-specific default exists (i.e. is also nil), the effective + // default will be the system-wide default of 0. + // + // A value of 0 will cause the step to be retried indefinitely unless the + // ErrorThreshold is reached. + Timeout string `json:"timeout,omitempty"` +} + +// Validate validates this promotion step retry +func (m *PromotionStepRetry) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this promotion step retry based on context it is used +func (m *PromotionStepRetry) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionStepRetry) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionStepRetry) UnmarshalBinary(b []byte) error { + var res PromotionStepRetry + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_task.go b/pkg/client/generated/models/promotion_task.go new file mode 100644 index 0000000000..e88806a2ed --- /dev/null +++ b/pkg/client/generated/models/promotion_task.go @@ -0,0 +1,157 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionTask promotion task +// +// swagger:model PromotionTask +type PromotionTask struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes the composition of a PromotionTask, including the + // variables available to the task and the steps. + // + // +kubebuilder:validation:Required + // Required: true + Spec struct { + PromotionTaskSpec + } `json:"spec"` +} + +// Validate validates this promotion task +func (m *PromotionTask) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTask) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *PromotionTask) validateSpec(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this promotion task based on the context it is used +func (m *PromotionTask) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTask) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *PromotionTask) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionTask) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionTask) UnmarshalBinary(b []byte) error { + var res PromotionTask + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_task_list.go b/pkg/client/generated/models/promotion_task_list.go new file mode 100644 index 0000000000..aad15fab83 --- /dev/null +++ b/pkg/client/generated/models/promotion_task_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionTaskList promotion task list +// +// swagger:model PromotionTaskList +type PromotionTaskList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*PromotionTask `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this promotion task list +func (m *PromotionTaskList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTaskList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionTaskList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this promotion task list based on the context it is used +func (m *PromotionTaskList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTaskList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionTaskList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionTaskList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionTaskList) UnmarshalBinary(b []byte) error { + var res PromotionTaskList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_task_reference.go b/pkg/client/generated/models/promotion_task_reference.go new file mode 100644 index 0000000000..0a774d1789 --- /dev/null +++ b/pkg/client/generated/models/promotion_task_reference.go @@ -0,0 +1,81 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// PromotionTaskReference promotion task reference +// +// swagger:model PromotionTaskReference +type PromotionTaskReference struct { + + // Kind is the type of the PromotionTask. Can be either PromotionTask or + // ClusterPromotionTask, default is PromotionTask. + // + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Enum=PromotionTask;ClusterPromotionTask + Kind string `json:"kind,omitempty"` + + // Name is the name of the (Cluster)PromotionTask. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` + // +akuity:test-kubebuilder-pattern=KubernetesName + // Required: true + Name *string `json:"name"` +} + +// Validate validates this promotion task reference +func (m *PromotionTaskReference) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTaskReference) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this promotion task reference based on context it is used +func (m *PromotionTaskReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionTaskReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionTaskReference) UnmarshalBinary(b []byte) error { + var res PromotionTaskReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_task_spec.go b/pkg/client/generated/models/promotion_task_spec.go new file mode 100644 index 0000000000..2f98d4dbc3 --- /dev/null +++ b/pkg/client/generated/models/promotion_task_spec.go @@ -0,0 +1,208 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// PromotionTaskSpec promotion task spec +// +// swagger:model PromotionTaskSpec +type PromotionTaskSpec struct { + + // Steps specifies the directives to be executed as part of this + // PromotionTask. The steps as defined here are inflated into a + // Promotion when it is built from a PromotionTemplate. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:items:XValidation:message="PromotionTask step must have uses set and must not reference another task",rule="has(self.uses) && !has(self.task)" + // Required: true + Steps []*PromotionStep `json:"steps"` + + // Vars specifies the variables available to the PromotionTask. The + // values of these variables are the default values that can be + // overridden by the step referencing the task. + Vars []*ExpressionVariable `json:"vars"` +} + +// Validate validates this promotion task spec +func (m *PromotionTaskSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSteps(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVars(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTaskSpec) validateSteps(formats strfmt.Registry) error { + + if err := validate.Required("steps", "body", m.Steps); err != nil { + return err + } + + for i := 0; i < len(m.Steps); i++ { + if swag.IsZero(m.Steps[i]) { // not required + continue + } + + if m.Steps[i] != nil { + if err := m.Steps[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("steps" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("steps" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionTaskSpec) validateVars(formats strfmt.Registry) error { + if swag.IsZero(m.Vars) { // not required + return nil + } + + for i := 0; i < len(m.Vars); i++ { + if swag.IsZero(m.Vars[i]) { // not required + continue + } + + if m.Vars[i] != nil { + if err := m.Vars[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this promotion task spec based on the context it is used +func (m *PromotionTaskSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSteps(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVars(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTaskSpec) contextValidateSteps(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Steps); i++ { + + if m.Steps[i] != nil { + + if swag.IsZero(m.Steps[i]) { // not required + return nil + } + + if err := m.Steps[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("steps" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("steps" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionTaskSpec) contextValidateVars(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Vars); i++ { + + if m.Vars[i] != nil { + + if swag.IsZero(m.Vars[i]) { // not required + return nil + } + + if err := m.Vars[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionTaskSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionTaskSpec) UnmarshalBinary(b []byte) error { + var res PromotionTaskSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_template.go b/pkg/client/generated/models/promotion_template.go new file mode 100644 index 0000000000..7a496d2b5c --- /dev/null +++ b/pkg/client/generated/models/promotion_template.go @@ -0,0 +1,115 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionTemplate promotion template +// +// swagger:model PromotionTemplate +type PromotionTemplate struct { + + // spec + Spec *PromotionTemplateSpec `json:"spec,omitempty"` +} + +// Validate validates this promotion template +func (m *PromotionTemplate) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTemplate) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + if m.Spec != nil { + if err := m.Spec.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this promotion template based on the context it is used +func (m *PromotionTemplate) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTemplate) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + if m.Spec != nil { + + if swag.IsZero(m.Spec) { // not required + return nil + } + + if err := m.Spec.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionTemplate) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionTemplate) UnmarshalBinary(b []byte) error { + var res PromotionTemplate + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/promotion_template_spec.go b/pkg/client/generated/models/promotion_template_spec.go new file mode 100644 index 0000000000..7a12f76a94 --- /dev/null +++ b/pkg/client/generated/models/promotion_template_spec.go @@ -0,0 +1,205 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// PromotionTemplateSpec promotion template spec +// +// swagger:model PromotionTemplateSpec +type PromotionTemplateSpec struct { + + // Steps specifies the directives to be executed as part of a Promotion. + // The order in which the directives are executed is the order in which they + // are listed in this field. + // + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:items:XValidation:message="PromotionTemplate step must have exactly one of uses or task set",rule="(has(self.uses) ? !has(self.task) : has(self.task))" + // +kubebuilder:validation:items:XValidation:message="PromotionTemplate step referencing a task cannot set continueOnError",rule="!has(self.task) || !has(self.continueOnError)" + // +kubebuilder:validation:items:XValidation:message="PromotionTemplate step referencing a task cannot set retry",rule="!has(self.task) || !has(self.retry)" + Steps []*PromotionStep `json:"steps"` + + // Vars is a list of variables that can be referenced by expressions in + // promotion steps. + Vars []*ExpressionVariable `json:"vars"` +} + +// Validate validates this promotion template spec +func (m *PromotionTemplateSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSteps(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVars(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTemplateSpec) validateSteps(formats strfmt.Registry) error { + if swag.IsZero(m.Steps) { // not required + return nil + } + + for i := 0; i < len(m.Steps); i++ { + if swag.IsZero(m.Steps[i]) { // not required + continue + } + + if m.Steps[i] != nil { + if err := m.Steps[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("steps" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("steps" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionTemplateSpec) validateVars(formats strfmt.Registry) error { + if swag.IsZero(m.Vars) { // not required + return nil + } + + for i := 0; i < len(m.Vars); i++ { + if swag.IsZero(m.Vars[i]) { // not required + continue + } + + if m.Vars[i] != nil { + if err := m.Vars[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this promotion template spec based on the context it is used +func (m *PromotionTemplateSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSteps(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVars(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *PromotionTemplateSpec) contextValidateSteps(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Steps); i++ { + + if m.Steps[i] != nil { + + if swag.IsZero(m.Steps[i]) { // not required + return nil + } + + if err := m.Steps[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("steps" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("steps" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *PromotionTemplateSpec) contextValidateVars(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Vars); i++ { + + if m.Vars[i] != nil { + + if swag.IsZero(m.Vars[i]) { // not required + return nil + } + + if err := m.Vars[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *PromotionTemplateSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *PromotionTemplateSpec) UnmarshalBinary(b []byte) error { + var res PromotionTemplateSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/quantity.go b/pkg/client/generated/models/quantity.go new file mode 100644 index 0000000000..278ec8148c --- /dev/null +++ b/pkg/client/generated/models/quantity.go @@ -0,0 +1,105 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// Quantity quantity +// +// swagger:model Quantity +type Quantity struct { + + // format + // Enum: ["DecimalExponent","BinarySI","DecimalSI"] + Format string `json:"Format,omitempty"` +} + +// Validate validates this quantity +func (m *Quantity) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFormat(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var quantityTypeFormatPropEnum []any + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["DecimalExponent","BinarySI","DecimalSI"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + quantityTypeFormatPropEnum = append(quantityTypeFormatPropEnum, v) + } +} + +const ( + + // QuantityFormatDecimalExponent captures enum value "DecimalExponent" + QuantityFormatDecimalExponent string = "DecimalExponent" + + // QuantityFormatBinarySI captures enum value "BinarySI" + QuantityFormatBinarySI string = "BinarySI" + + // QuantityFormatDecimalSI captures enum value "DecimalSI" + QuantityFormatDecimalSI string = "DecimalSI" +) + +// prop value enum +func (m *Quantity) validateFormatEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, quantityTypeFormatPropEnum, true); err != nil { + return err + } + return nil +} + +func (m *Quantity) validateFormat(formats strfmt.Registry) error { + if swag.IsZero(m.Format) { // not required + return nil + } + + // value enum + if err := m.validateFormatEnum("Format", "body", m.Format); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this quantity based on context it is used +func (m *Quantity) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *Quantity) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Quantity) UnmarshalBinary(b []byte) error { + var res Quantity + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/quay_webhook_receiver_config.go b/pkg/client/generated/models/quay_webhook_receiver_config.go new file mode 100644 index 0000000000..258f5c9c54 --- /dev/null +++ b/pkg/client/generated/models/quay_webhook_receiver_config.go @@ -0,0 +1,93 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// QuayWebhookReceiverConfig quay webhook receiver config +// +// swagger:model QuayWebhookReceiverConfig +type QuayWebhookReceiverConfig struct { + + // SecretRef contains a reference to a Secret. For Project-scoped webhook + // receivers, the referenced Secret must be in the same namespace as the + // ProjectConfig. + // + // For cluster-scoped webhook receivers, the referenced Secret must be in the + // designated "system resources" namespace. + // + // The Secret's data map is expected to contain a `secret` key whose value + // does NOT need to be shared directly with Quay when registering a + // webhook. It is used only by Kargo to create a complex, hard-to-guess URL, + // which implicitly serves as a shared secret. For more information about + // Quay webhooks, please refer to the Quay documentation: + // https://docs.quay.io/guides/notifications.html + // + // +kubebuilder:validation:Required + // Required: true + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef"` +} + +// Validate validates this quay webhook receiver config +func (m *QuayWebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *QuayWebhookReceiverConfig) validateSecretRef(formats strfmt.Registry) error { + + return nil +} + +// ContextValidate validate this quay webhook receiver config based on the context it is used +func (m *QuayWebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *QuayWebhookReceiverConfig) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *QuayWebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *QuayWebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res QuayWebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rbac_role.go b/pkg/client/generated/models/rbac_role.go new file mode 100644 index 0000000000..a716e4cd72 --- /dev/null +++ b/pkg/client/generated/models/rbac_role.go @@ -0,0 +1,274 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RbacRole rbac role +// +// swagger:model RbacRole +type RbacRole struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // claims + Claims []*Claim `json:"claims"` + + // kargo managed + KargoManaged bool `json:"kargoManaged,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // rules + Rules []*V1PolicyRule `json:"rules"` +} + +// Validate validates this rbac role +func (m *RbacRole) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateClaims(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRules(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RbacRole) validateClaims(formats strfmt.Registry) error { + if swag.IsZero(m.Claims) { // not required + return nil + } + + for i := 0; i < len(m.Claims); i++ { + if swag.IsZero(m.Claims[i]) { // not required + continue + } + + if m.Claims[i] != nil { + if err := m.Claims[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("claims" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("claims" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RbacRole) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RbacRole) validateRules(formats strfmt.Registry) error { + if swag.IsZero(m.Rules) { // not required + return nil + } + + for i := 0; i < len(m.Rules); i++ { + if swag.IsZero(m.Rules[i]) { // not required + continue + } + + if m.Rules[i] != nil { + if err := m.Rules[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("rules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("rules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rbac role based on the context it is used +func (m *RbacRole) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateClaims(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRules(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RbacRole) contextValidateClaims(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Claims); i++ { + + if m.Claims[i] != nil { + + if swag.IsZero(m.Claims[i]) { // not required + return nil + } + + if err := m.Claims[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("claims" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("claims" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RbacRole) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RbacRole) contextValidateRules(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Rules); i++ { + + if m.Rules[i] != nil { + + if swag.IsZero(m.Rules[i]) { // not required + return nil + } + + if err := m.Rules[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("rules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("rules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RbacRole) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RbacRole) UnmarshalBinary(b []byte) error { + var res RbacRole + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_analysis_run.go b/pkg/client/generated/models/rollouts_analysis_run.go new file mode 100644 index 0000000000..6700689ef6 --- /dev/null +++ b/pkg/client/generated/models/rollouts_analysis_run.go @@ -0,0 +1,248 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAnalysisRun rollouts analysis run +// +// swagger:model RolloutsAnalysisRun +type RolloutsAnalysisRun struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // spec + Spec *RolloutsAnalysisRunSpec `json:"spec,omitempty"` + + // status + Status *RolloutsAnalysisRunStatus `json:"status,omitempty"` +} + +// Validate validates this rollouts analysis run +func (m *RolloutsAnalysisRun) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisRun) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisRun) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + if m.Spec != nil { + if err := m.Spec.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisRun) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + if m.Status != nil { + if err := m.Status.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("status") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("status") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts analysis run based on the context it is used +func (m *RolloutsAnalysisRun) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisRun) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisRun) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + if m.Spec != nil { + + if swag.IsZero(m.Spec) { // not required + return nil + } + + if err := m.Spec.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisRun) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + if m.Status != nil { + + if swag.IsZero(m.Status) { // not required + return nil + } + + if err := m.Status.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("status") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("status") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAnalysisRun) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAnalysisRun) UnmarshalBinary(b []byte) error { + var res RolloutsAnalysisRun + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_analysis_run_spec.go b/pkg/client/generated/models/rollouts_analysis_run_spec.go new file mode 100644 index 0000000000..ed2ed52cbe --- /dev/null +++ b/pkg/client/generated/models/rollouts_analysis_run_spec.go @@ -0,0 +1,340 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAnalysisRunSpec rollouts analysis run spec +// +// swagger:model RolloutsAnalysisRunSpec +type RolloutsAnalysisRunSpec struct { + + // args + Args []*RolloutsArgument `json:"args"` + + // dry run + DryRun []*RolloutsDryRun `json:"dryRun"` + + // measurement retention + MeasurementRetention []*RolloutsMeasurementRetention `json:"measurementRetention"` + + // metrics + Metrics []*RolloutsMetric `json:"metrics"` + + // terminate + Terminate bool `json:"terminate,omitempty"` +} + +// Validate validates this rollouts analysis run spec +func (m *RolloutsAnalysisRunSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateArgs(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDryRun(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMeasurementRetention(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetrics(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisRunSpec) validateArgs(formats strfmt.Registry) error { + if swag.IsZero(m.Args) { // not required + return nil + } + + for i := 0; i < len(m.Args); i++ { + if swag.IsZero(m.Args[i]) { // not required + continue + } + + if m.Args[i] != nil { + if err := m.Args[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("args" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("args" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunSpec) validateDryRun(formats strfmt.Registry) error { + if swag.IsZero(m.DryRun) { // not required + return nil + } + + for i := 0; i < len(m.DryRun); i++ { + if swag.IsZero(m.DryRun[i]) { // not required + continue + } + + if m.DryRun[i] != nil { + if err := m.DryRun[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunSpec) validateMeasurementRetention(formats strfmt.Registry) error { + if swag.IsZero(m.MeasurementRetention) { // not required + return nil + } + + for i := 0; i < len(m.MeasurementRetention); i++ { + if swag.IsZero(m.MeasurementRetention[i]) { // not required + continue + } + + if m.MeasurementRetention[i] != nil { + if err := m.MeasurementRetention[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunSpec) validateMetrics(formats strfmt.Registry) error { + if swag.IsZero(m.Metrics) { // not required + return nil + } + + for i := 0; i < len(m.Metrics); i++ { + if swag.IsZero(m.Metrics[i]) { // not required + continue + } + + if m.Metrics[i] != nil { + if err := m.Metrics[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts analysis run spec based on the context it is used +func (m *RolloutsAnalysisRunSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateArgs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDryRun(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMeasurementRetention(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetrics(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisRunSpec) contextValidateArgs(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Args); i++ { + + if m.Args[i] != nil { + + if swag.IsZero(m.Args[i]) { // not required + return nil + } + + if err := m.Args[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("args" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("args" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunSpec) contextValidateDryRun(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.DryRun); i++ { + + if m.DryRun[i] != nil { + + if swag.IsZero(m.DryRun[i]) { // not required + return nil + } + + if err := m.DryRun[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunSpec) contextValidateMeasurementRetention(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MeasurementRetention); i++ { + + if m.MeasurementRetention[i] != nil { + + if swag.IsZero(m.MeasurementRetention[i]) { // not required + return nil + } + + if err := m.MeasurementRetention[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunSpec) contextValidateMetrics(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Metrics); i++ { + + if m.Metrics[i] != nil { + + if swag.IsZero(m.Metrics[i]) { // not required + return nil + } + + if err := m.Metrics[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAnalysisRunSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAnalysisRunSpec) UnmarshalBinary(b []byte) error { + var res RolloutsAnalysisRunSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_analysis_run_status.go b/pkg/client/generated/models/rollouts_analysis_run_status.go new file mode 100644 index 0000000000..a0dd9d6b2d --- /dev/null +++ b/pkg/client/generated/models/rollouts_analysis_run_status.go @@ -0,0 +1,254 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAnalysisRunStatus rollouts analysis run status +// +// swagger:model RolloutsAnalysisRunStatus +type RolloutsAnalysisRunStatus struct { + + // dry run summary + DryRunSummary *RolloutsRunSummary `json:"dryRunSummary,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // metric results + MetricResults []*RolloutsMetricResult `json:"metricResults"` + + // phase + Phase string `json:"phase,omitempty"` + + // run summary + RunSummary *RolloutsRunSummary `json:"runSummary,omitempty"` + + // started at + StartedAt string `json:"startedAt,omitempty"` +} + +// Validate validates this rollouts analysis run status +func (m *RolloutsAnalysisRunStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateDryRunSummary(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetricResults(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRunSummary(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisRunStatus) validateDryRunSummary(formats strfmt.Registry) error { + if swag.IsZero(m.DryRunSummary) { // not required + return nil + } + + if m.DryRunSummary != nil { + if err := m.DryRunSummary.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dryRunSummary") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dryRunSummary") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisRunStatus) validateMetricResults(formats strfmt.Registry) error { + if swag.IsZero(m.MetricResults) { // not required + return nil + } + + for i := 0; i < len(m.MetricResults); i++ { + if swag.IsZero(m.MetricResults[i]) { // not required + continue + } + + if m.MetricResults[i] != nil { + if err := m.MetricResults[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metricResults" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metricResults" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunStatus) validateRunSummary(formats strfmt.Registry) error { + if swag.IsZero(m.RunSummary) { // not required + return nil + } + + if m.RunSummary != nil { + if err := m.RunSummary.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("runSummary") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("runSummary") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts analysis run status based on the context it is used +func (m *RolloutsAnalysisRunStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateDryRunSummary(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetricResults(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRunSummary(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisRunStatus) contextValidateDryRunSummary(ctx context.Context, formats strfmt.Registry) error { + + if m.DryRunSummary != nil { + + if swag.IsZero(m.DryRunSummary) { // not required + return nil + } + + if err := m.DryRunSummary.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dryRunSummary") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dryRunSummary") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisRunStatus) contextValidateMetricResults(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MetricResults); i++ { + + if m.MetricResults[i] != nil { + + if swag.IsZero(m.MetricResults[i]) { // not required + return nil + } + + if err := m.MetricResults[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metricResults" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metricResults" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisRunStatus) contextValidateRunSummary(ctx context.Context, formats strfmt.Registry) error { + + if m.RunSummary != nil { + + if swag.IsZero(m.RunSummary) { // not required + return nil + } + + if err := m.RunSummary.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("runSummary") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("runSummary") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAnalysisRunStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAnalysisRunStatus) UnmarshalBinary(b []byte) error { + var res RolloutsAnalysisRunStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_analysis_template.go b/pkg/client/generated/models/rollouts_analysis_template.go new file mode 100644 index 0000000000..3d5d0b4503 --- /dev/null +++ b/pkg/client/generated/models/rollouts_analysis_template.go @@ -0,0 +1,189 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAnalysisTemplate rollouts analysis template +// +// swagger:model RolloutsAnalysisTemplate +type RolloutsAnalysisTemplate struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // spec + Spec *RolloutsAnalysisTemplateSpec `json:"spec,omitempty"` +} + +// Validate validates this rollouts analysis template +func (m *RolloutsAnalysisTemplate) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisTemplate) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisTemplate) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + if m.Spec != nil { + if err := m.Spec.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts analysis template based on the context it is used +func (m *RolloutsAnalysisTemplate) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisTemplate) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAnalysisTemplate) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + if m.Spec != nil { + + if swag.IsZero(m.Spec) { // not required + return nil + } + + if err := m.Spec.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAnalysisTemplate) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAnalysisTemplate) UnmarshalBinary(b []byte) error { + var res RolloutsAnalysisTemplate + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_analysis_template_list.go b/pkg/client/generated/models/rollouts_analysis_template_list.go new file mode 100644 index 0000000000..407c7ce39f --- /dev/null +++ b/pkg/client/generated/models/rollouts_analysis_template_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAnalysisTemplateList rollouts analysis template list +// +// swagger:model RolloutsAnalysisTemplateList +type RolloutsAnalysisTemplateList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*RolloutsAnalysisTemplate `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this rollouts analysis template list +func (m *RolloutsAnalysisTemplateList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisTemplateList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts analysis template list based on the context it is used +func (m *RolloutsAnalysisTemplateList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisTemplateList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAnalysisTemplateList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAnalysisTemplateList) UnmarshalBinary(b []byte) error { + var res RolloutsAnalysisTemplateList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_analysis_template_spec.go b/pkg/client/generated/models/rollouts_analysis_template_spec.go new file mode 100644 index 0000000000..566212c2c8 --- /dev/null +++ b/pkg/client/generated/models/rollouts_analysis_template_spec.go @@ -0,0 +1,337 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAnalysisTemplateSpec rollouts analysis template spec +// +// swagger:model RolloutsAnalysisTemplateSpec +type RolloutsAnalysisTemplateSpec struct { + + // args + Args []*RolloutsArgument `json:"args"` + + // dry run + DryRun []*RolloutsDryRun `json:"dryRun"` + + // measurement retention + MeasurementRetention []*RolloutsMeasurementRetention `json:"measurementRetention"` + + // metrics + Metrics []*RolloutsMetric `json:"metrics"` +} + +// Validate validates this rollouts analysis template spec +func (m *RolloutsAnalysisTemplateSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateArgs(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDryRun(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMeasurementRetention(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetrics(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) validateArgs(formats strfmt.Registry) error { + if swag.IsZero(m.Args) { // not required + return nil + } + + for i := 0; i < len(m.Args); i++ { + if swag.IsZero(m.Args[i]) { // not required + continue + } + + if m.Args[i] != nil { + if err := m.Args[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("args" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("args" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) validateDryRun(formats strfmt.Registry) error { + if swag.IsZero(m.DryRun) { // not required + return nil + } + + for i := 0; i < len(m.DryRun); i++ { + if swag.IsZero(m.DryRun[i]) { // not required + continue + } + + if m.DryRun[i] != nil { + if err := m.DryRun[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) validateMeasurementRetention(formats strfmt.Registry) error { + if swag.IsZero(m.MeasurementRetention) { // not required + return nil + } + + for i := 0; i < len(m.MeasurementRetention); i++ { + if swag.IsZero(m.MeasurementRetention[i]) { // not required + continue + } + + if m.MeasurementRetention[i] != nil { + if err := m.MeasurementRetention[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) validateMetrics(formats strfmt.Registry) error { + if swag.IsZero(m.Metrics) { // not required + return nil + } + + for i := 0; i < len(m.Metrics); i++ { + if swag.IsZero(m.Metrics[i]) { // not required + continue + } + + if m.Metrics[i] != nil { + if err := m.Metrics[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts analysis template spec based on the context it is used +func (m *RolloutsAnalysisTemplateSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateArgs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDryRun(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMeasurementRetention(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetrics(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) contextValidateArgs(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Args); i++ { + + if m.Args[i] != nil { + + if swag.IsZero(m.Args[i]) { // not required + return nil + } + + if err := m.Args[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("args" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("args" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) contextValidateDryRun(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.DryRun); i++ { + + if m.DryRun[i] != nil { + + if swag.IsZero(m.DryRun[i]) { // not required + return nil + } + + if err := m.DryRun[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dryRun" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) contextValidateMeasurementRetention(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MeasurementRetention); i++ { + + if m.MeasurementRetention[i] != nil { + + if swag.IsZero(m.MeasurementRetention[i]) { // not required + return nil + } + + if err := m.MeasurementRetention[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("measurementRetention" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsAnalysisTemplateSpec) contextValidateMetrics(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Metrics); i++ { + + if m.Metrics[i] != nil { + + if swag.IsZero(m.Metrics[i]) { // not required + return nil + } + + if err := m.Metrics[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metrics" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAnalysisTemplateSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAnalysisTemplateSpec) UnmarshalBinary(b []byte) error { + var res RolloutsAnalysisTemplateSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_argument.go b/pkg/client/generated/models/rollouts_argument.go new file mode 100644 index 0000000000..59793fa02c --- /dev/null +++ b/pkg/client/generated/models/rollouts_argument.go @@ -0,0 +1,121 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsArgument rollouts argument +// +// swagger:model RolloutsArgument +type RolloutsArgument struct { + + // name + Name string `json:"name,omitempty"` + + // value + Value string `json:"value,omitempty"` + + // value from + ValueFrom *RolloutsValueFrom `json:"valueFrom,omitempty"` +} + +// Validate validates this rollouts argument +func (m *RolloutsArgument) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateValueFrom(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsArgument) validateValueFrom(formats strfmt.Registry) error { + if swag.IsZero(m.ValueFrom) { // not required + return nil + } + + if m.ValueFrom != nil { + if err := m.ValueFrom.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("valueFrom") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("valueFrom") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts argument based on the context it is used +func (m *RolloutsArgument) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateValueFrom(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsArgument) contextValidateValueFrom(ctx context.Context, formats strfmt.Registry) error { + + if m.ValueFrom != nil { + + if swag.IsZero(m.ValueFrom) { // not required + return nil + } + + if err := m.ValueFrom.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("valueFrom") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("valueFrom") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsArgument) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsArgument) UnmarshalBinary(b []byte) error { + var res RolloutsArgument + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_authentication.go b/pkg/client/generated/models/rollouts_authentication.go new file mode 100644 index 0000000000..78df817fd5 --- /dev/null +++ b/pkg/client/generated/models/rollouts_authentication.go @@ -0,0 +1,174 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsAuthentication rollouts authentication +// +// swagger:model RolloutsAuthentication +type RolloutsAuthentication struct { + + // oauth2 + Oauth2 *RolloutsOAuth2Config `json:"oauth2,omitempty"` + + // sigv4 + Sigv4 *RolloutsSigv4Config `json:"sigv4,omitempty"` +} + +// Validate validates this rollouts authentication +func (m *RolloutsAuthentication) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateOauth2(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSigv4(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAuthentication) validateOauth2(formats strfmt.Registry) error { + if swag.IsZero(m.Oauth2) { // not required + return nil + } + + if m.Oauth2 != nil { + if err := m.Oauth2.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("oauth2") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("oauth2") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAuthentication) validateSigv4(formats strfmt.Registry) error { + if swag.IsZero(m.Sigv4) { // not required + return nil + } + + if m.Sigv4 != nil { + if err := m.Sigv4.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sigv4") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sigv4") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts authentication based on the context it is used +func (m *RolloutsAuthentication) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateOauth2(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSigv4(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsAuthentication) contextValidateOauth2(ctx context.Context, formats strfmt.Registry) error { + + if m.Oauth2 != nil { + + if swag.IsZero(m.Oauth2) { // not required + return nil + } + + if err := m.Oauth2.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("oauth2") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("oauth2") + } + + return err + } + } + + return nil +} + +func (m *RolloutsAuthentication) contextValidateSigv4(ctx context.Context, formats strfmt.Registry) error { + + if m.Sigv4 != nil { + + if swag.IsZero(m.Sigv4) { // not required + return nil + } + + if err := m.Sigv4.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sigv4") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sigv4") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsAuthentication) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsAuthentication) UnmarshalBinary(b []byte) error { + var res RolloutsAuthentication + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cloud_watch_metric.go b/pkg/client/generated/models/rollouts_cloud_watch_metric.go new file mode 100644 index 0000000000..db230bc311 --- /dev/null +++ b/pkg/client/generated/models/rollouts_cloud_watch_metric.go @@ -0,0 +1,130 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsCloudWatchMetric rollouts cloud watch metric +// +// swagger:model RolloutsCloudWatchMetric +type RolloutsCloudWatchMetric struct { + + // interval + Interval string `json:"interval,omitempty"` + + // metric data queries + MetricDataQueries []*RolloutsCloudWatchMetricDataQuery `json:"metricDataQueries"` +} + +// Validate validates this rollouts cloud watch metric +func (m *RolloutsCloudWatchMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetricDataQueries(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetric) validateMetricDataQueries(formats strfmt.Registry) error { + if swag.IsZero(m.MetricDataQueries) { // not required + return nil + } + + for i := 0; i < len(m.MetricDataQueries); i++ { + if swag.IsZero(m.MetricDataQueries[i]) { // not required + continue + } + + if m.MetricDataQueries[i] != nil { + if err := m.MetricDataQueries[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metricDataQueries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metricDataQueries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts cloud watch metric based on the context it is used +func (m *RolloutsCloudWatchMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetricDataQueries(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetric) contextValidateMetricDataQueries(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MetricDataQueries); i++ { + + if m.MetricDataQueries[i] != nil { + + if swag.IsZero(m.MetricDataQueries[i]) { // not required + return nil + } + + if err := m.MetricDataQueries[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metricDataQueries" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metricDataQueries" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsCloudWatchMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsCloudWatchMetric) UnmarshalBinary(b []byte) error { + var res RolloutsCloudWatchMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cloud_watch_metric_data_query.go b/pkg/client/generated/models/rollouts_cloud_watch_metric_data_query.go new file mode 100644 index 0000000000..6e59813e3d --- /dev/null +++ b/pkg/client/generated/models/rollouts_cloud_watch_metric_data_query.go @@ -0,0 +1,186 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsCloudWatchMetricDataQuery rollouts cloud watch metric data query +// +// swagger:model RolloutsCloudWatchMetricDataQuery +type RolloutsCloudWatchMetricDataQuery struct { + + // expression + Expression string `json:"expression,omitempty"` + + // id + ID string `json:"id,omitempty"` + + // label + Label string `json:"label,omitempty"` + + // metric stat + MetricStat *RolloutsCloudWatchMetricStat `json:"metricStat,omitempty"` + + // period + Period *IntOrString `json:"period,omitempty"` + + // return data + ReturnData bool `json:"returnData,omitempty"` +} + +// Validate validates this rollouts cloud watch metric data query +func (m *RolloutsCloudWatchMetricDataQuery) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetricStat(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePeriod(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetricDataQuery) validateMetricStat(formats strfmt.Registry) error { + if swag.IsZero(m.MetricStat) { // not required + return nil + } + + if m.MetricStat != nil { + if err := m.MetricStat.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metricStat") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metricStat") + } + + return err + } + } + + return nil +} + +func (m *RolloutsCloudWatchMetricDataQuery) validatePeriod(formats strfmt.Registry) error { + if swag.IsZero(m.Period) { // not required + return nil + } + + if m.Period != nil { + if err := m.Period.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("period") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("period") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts cloud watch metric data query based on the context it is used +func (m *RolloutsCloudWatchMetricDataQuery) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetricStat(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePeriod(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetricDataQuery) contextValidateMetricStat(ctx context.Context, formats strfmt.Registry) error { + + if m.MetricStat != nil { + + if swag.IsZero(m.MetricStat) { // not required + return nil + } + + if err := m.MetricStat.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metricStat") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metricStat") + } + + return err + } + } + + return nil +} + +func (m *RolloutsCloudWatchMetricDataQuery) contextValidatePeriod(ctx context.Context, formats strfmt.Registry) error { + + if m.Period != nil { + + if swag.IsZero(m.Period) { // not required + return nil + } + + if err := m.Period.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("period") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("period") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricDataQuery) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricDataQuery) UnmarshalBinary(b []byte) error { + var res RolloutsCloudWatchMetricDataQuery + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cloud_watch_metric_stat.go b/pkg/client/generated/models/rollouts_cloud_watch_metric_stat.go new file mode 100644 index 0000000000..46142ce497 --- /dev/null +++ b/pkg/client/generated/models/rollouts_cloud_watch_metric_stat.go @@ -0,0 +1,180 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsCloudWatchMetricStat rollouts cloud watch metric stat +// +// swagger:model RolloutsCloudWatchMetricStat +type RolloutsCloudWatchMetricStat struct { + + // metric + Metric *RolloutsCloudWatchMetricStatMetric `json:"metric,omitempty"` + + // period + Period *IntOrString `json:"period,omitempty"` + + // stat + Stat string `json:"stat,omitempty"` + + // unit + Unit string `json:"unit,omitempty"` +} + +// Validate validates this rollouts cloud watch metric stat +func (m *RolloutsCloudWatchMetricStat) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetric(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePeriod(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetricStat) validateMetric(formats strfmt.Registry) error { + if swag.IsZero(m.Metric) { // not required + return nil + } + + if m.Metric != nil { + if err := m.Metric.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metric") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metric") + } + + return err + } + } + + return nil +} + +func (m *RolloutsCloudWatchMetricStat) validatePeriod(formats strfmt.Registry) error { + if swag.IsZero(m.Period) { // not required + return nil + } + + if m.Period != nil { + if err := m.Period.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("period") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("period") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts cloud watch metric stat based on the context it is used +func (m *RolloutsCloudWatchMetricStat) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetric(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePeriod(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetricStat) contextValidateMetric(ctx context.Context, formats strfmt.Registry) error { + + if m.Metric != nil { + + if swag.IsZero(m.Metric) { // not required + return nil + } + + if err := m.Metric.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metric") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metric") + } + + return err + } + } + + return nil +} + +func (m *RolloutsCloudWatchMetricStat) contextValidatePeriod(ctx context.Context, formats strfmt.Registry) error { + + if m.Period != nil { + + if swag.IsZero(m.Period) { // not required + return nil + } + + if err := m.Period.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("period") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("period") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricStat) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricStat) UnmarshalBinary(b []byte) error { + var res RolloutsCloudWatchMetricStat + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cloud_watch_metric_stat_metric.go b/pkg/client/generated/models/rollouts_cloud_watch_metric_stat_metric.go new file mode 100644 index 0000000000..e0ddd1f4d3 --- /dev/null +++ b/pkg/client/generated/models/rollouts_cloud_watch_metric_stat_metric.go @@ -0,0 +1,133 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsCloudWatchMetricStatMetric rollouts cloud watch metric stat metric +// +// swagger:model RolloutsCloudWatchMetricStatMetric +type RolloutsCloudWatchMetricStatMetric struct { + + // dimensions + Dimensions []*RolloutsCloudWatchMetricStatMetricDimension `json:"dimensions"` + + // metric name + MetricName string `json:"metricName,omitempty"` + + // namespace + Namespace string `json:"namespace,omitempty"` +} + +// Validate validates this rollouts cloud watch metric stat metric +func (m *RolloutsCloudWatchMetricStatMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateDimensions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetricStatMetric) validateDimensions(formats strfmt.Registry) error { + if swag.IsZero(m.Dimensions) { // not required + return nil + } + + for i := 0; i < len(m.Dimensions); i++ { + if swag.IsZero(m.Dimensions[i]) { // not required + continue + } + + if m.Dimensions[i] != nil { + if err := m.Dimensions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dimensions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dimensions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts cloud watch metric stat metric based on the context it is used +func (m *RolloutsCloudWatchMetricStatMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateDimensions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsCloudWatchMetricStatMetric) contextValidateDimensions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Dimensions); i++ { + + if m.Dimensions[i] != nil { + + if swag.IsZero(m.Dimensions[i]) { // not required + return nil + } + + if err := m.Dimensions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("dimensions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("dimensions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricStatMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricStatMetric) UnmarshalBinary(b []byte) error { + var res RolloutsCloudWatchMetricStatMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cloud_watch_metric_stat_metric_dimension.go b/pkg/client/generated/models/rollouts_cloud_watch_metric_stat_metric_dimension.go new file mode 100644 index 0000000000..c9fed5adde --- /dev/null +++ b/pkg/client/generated/models/rollouts_cloud_watch_metric_stat_metric_dimension.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsCloudWatchMetricStatMetricDimension rollouts cloud watch metric stat metric dimension +// +// swagger:model RolloutsCloudWatchMetricStatMetricDimension +type RolloutsCloudWatchMetricStatMetricDimension struct { + + // name + Name string `json:"name,omitempty"` + + // value + Value string `json:"value,omitempty"` +} + +// Validate validates this rollouts cloud watch metric stat metric dimension +func (m *RolloutsCloudWatchMetricStatMetricDimension) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts cloud watch metric stat metric dimension based on context it is used +func (m *RolloutsCloudWatchMetricStatMetricDimension) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricStatMetricDimension) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsCloudWatchMetricStatMetricDimension) UnmarshalBinary(b []byte) error { + var res RolloutsCloudWatchMetricStatMetricDimension + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cluster_analysis_template.go b/pkg/client/generated/models/rollouts_cluster_analysis_template.go new file mode 100644 index 0000000000..8a6259c9d4 --- /dev/null +++ b/pkg/client/generated/models/rollouts_cluster_analysis_template.go @@ -0,0 +1,189 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsClusterAnalysisTemplate rollouts cluster analysis template +// +// swagger:model RolloutsClusterAnalysisTemplate +type RolloutsClusterAnalysisTemplate struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // spec + Spec *RolloutsAnalysisTemplateSpec `json:"spec,omitempty"` +} + +// Validate validates this rollouts cluster analysis template +func (m *RolloutsClusterAnalysisTemplate) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsClusterAnalysisTemplate) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsClusterAnalysisTemplate) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + if m.Spec != nil { + if err := m.Spec.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts cluster analysis template based on the context it is used +func (m *RolloutsClusterAnalysisTemplate) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsClusterAnalysisTemplate) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsClusterAnalysisTemplate) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + if m.Spec != nil { + + if swag.IsZero(m.Spec) { // not required + return nil + } + + if err := m.Spec.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsClusterAnalysisTemplate) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsClusterAnalysisTemplate) UnmarshalBinary(b []byte) error { + var res RolloutsClusterAnalysisTemplate + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_cluster_analysis_template_list.go b/pkg/client/generated/models/rollouts_cluster_analysis_template_list.go new file mode 100644 index 0000000000..fa387b656c --- /dev/null +++ b/pkg/client/generated/models/rollouts_cluster_analysis_template_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsClusterAnalysisTemplateList rollouts cluster analysis template list +// +// swagger:model RolloutsClusterAnalysisTemplateList +type RolloutsClusterAnalysisTemplateList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*RolloutsClusterAnalysisTemplate `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this rollouts cluster analysis template list +func (m *RolloutsClusterAnalysisTemplateList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsClusterAnalysisTemplateList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsClusterAnalysisTemplateList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts cluster analysis template list based on the context it is used +func (m *RolloutsClusterAnalysisTemplateList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsClusterAnalysisTemplateList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsClusterAnalysisTemplateList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsClusterAnalysisTemplateList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsClusterAnalysisTemplateList) UnmarshalBinary(b []byte) error { + var res RolloutsClusterAnalysisTemplateList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_datadog_metric.go b/pkg/client/generated/models/rollouts_datadog_metric.go new file mode 100644 index 0000000000..733658a6ce --- /dev/null +++ b/pkg/client/generated/models/rollouts_datadog_metric.go @@ -0,0 +1,62 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsDatadogMetric rollouts datadog metric +// +// swagger:model RolloutsDatadogMetric +type RolloutsDatadogMetric struct { + + // aggregator + Aggregator string `json:"aggregator,omitempty"` + + // api version + APIVersion string `json:"apiVersion,omitempty"` + + // formula + Formula string `json:"formula,omitempty"` + + // interval + Interval string `json:"interval,omitempty"` + + // queries + Queries map[string]string `json:"queries,omitempty"` + + // query + Query string `json:"query,omitempty"` +} + +// Validate validates this rollouts datadog metric +func (m *RolloutsDatadogMetric) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts datadog metric based on context it is used +func (m *RolloutsDatadogMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsDatadogMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsDatadogMetric) UnmarshalBinary(b []byte) error { + var res RolloutsDatadogMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_dry_run.go b/pkg/client/generated/models/rollouts_dry_run.go new file mode 100644 index 0000000000..56f406d333 --- /dev/null +++ b/pkg/client/generated/models/rollouts_dry_run.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsDryRun rollouts dry run +// +// swagger:model RolloutsDryRun +type RolloutsDryRun struct { + + // metric name + MetricName string `json:"metricName,omitempty"` +} + +// Validate validates this rollouts dry run +func (m *RolloutsDryRun) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts dry run based on context it is used +func (m *RolloutsDryRun) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsDryRun) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsDryRun) UnmarshalBinary(b []byte) error { + var res RolloutsDryRun + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_field_ref.go b/pkg/client/generated/models/rollouts_field_ref.go new file mode 100644 index 0000000000..e889c5657b --- /dev/null +++ b/pkg/client/generated/models/rollouts_field_ref.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsFieldRef rollouts field ref +// +// swagger:model RolloutsFieldRef +type RolloutsFieldRef struct { + + // Required: Path of the field to select in the specified API version + FieldPath string `json:"fieldPath,omitempty"` +} + +// Validate validates this rollouts field ref +func (m *RolloutsFieldRef) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts field ref based on context it is used +func (m *RolloutsFieldRef) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsFieldRef) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsFieldRef) UnmarshalBinary(b []byte) error { + var res RolloutsFieldRef + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_graphite_metric.go b/pkg/client/generated/models/rollouts_graphite_metric.go new file mode 100644 index 0000000000..a9a1eec889 --- /dev/null +++ b/pkg/client/generated/models/rollouts_graphite_metric.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsGraphiteMetric rollouts graphite metric +// +// swagger:model RolloutsGraphiteMetric +type RolloutsGraphiteMetric struct { + + // address + Address string `json:"address,omitempty"` + + // query + Query string `json:"query,omitempty"` +} + +// Validate validates this rollouts graphite metric +func (m *RolloutsGraphiteMetric) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts graphite metric based on context it is used +func (m *RolloutsGraphiteMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsGraphiteMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsGraphiteMetric) UnmarshalBinary(b []byte) error { + var res RolloutsGraphiteMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_influxdb_metric.go b/pkg/client/generated/models/rollouts_influxdb_metric.go new file mode 100644 index 0000000000..7a972c7dea --- /dev/null +++ b/pkg/client/generated/models/rollouts_influxdb_metric.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsInfluxdbMetric rollouts influxdb metric +// +// swagger:model RolloutsInfluxdbMetric +type RolloutsInfluxdbMetric struct { + + // profile + Profile string `json:"profile,omitempty"` + + // query + Query string `json:"query,omitempty"` +} + +// Validate validates this rollouts influxdb metric +func (m *RolloutsInfluxdbMetric) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts influxdb metric based on context it is used +func (m *RolloutsInfluxdbMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsInfluxdbMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsInfluxdbMetric) UnmarshalBinary(b []byte) error { + var res RolloutsInfluxdbMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_job_metric.go b/pkg/client/generated/models/rollouts_job_metric.go new file mode 100644 index 0000000000..09793e1795 --- /dev/null +++ b/pkg/client/generated/models/rollouts_job_metric.go @@ -0,0 +1,174 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsJobMetric rollouts job metric +// +// swagger:model RolloutsJobMetric +type RolloutsJobMetric struct { + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // spec + Spec *V1JobSpec `json:"spec,omitempty"` +} + +// Validate validates this rollouts job metric +func (m *RolloutsJobMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsJobMetric) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsJobMetric) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + if m.Spec != nil { + if err := m.Spec.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts job metric based on the context it is used +func (m *RolloutsJobMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsJobMetric) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *RolloutsJobMetric) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + if m.Spec != nil { + + if swag.IsZero(m.Spec) { // not required + return nil + } + + if err := m.Spec.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("spec") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("spec") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsJobMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsJobMetric) UnmarshalBinary(b []byte) error { + var res RolloutsJobMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_kayenta_metric.go b/pkg/client/generated/models/rollouts_kayenta_metric.go new file mode 100644 index 0000000000..275ee27060 --- /dev/null +++ b/pkg/client/generated/models/rollouts_kayenta_metric.go @@ -0,0 +1,204 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsKayentaMetric rollouts kayenta metric +// +// swagger:model RolloutsKayentaMetric +type RolloutsKayentaMetric struct { + + // address + Address string `json:"address,omitempty"` + + // application + Application string `json:"application,omitempty"` + + // canary config name + CanaryConfigName string `json:"canaryConfigName,omitempty"` + + // configuration account name + ConfigurationAccountName string `json:"configurationAccountName,omitempty"` + + // metrics account name + MetricsAccountName string `json:"metricsAccountName,omitempty"` + + // scopes + Scopes []*RolloutsKayentaScope `json:"scopes"` + + // storage account name + StorageAccountName string `json:"storageAccountName,omitempty"` + + // threshold + Threshold *RolloutsKayentaThreshold `json:"threshold,omitempty"` +} + +// Validate validates this rollouts kayenta metric +func (m *RolloutsKayentaMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateScopes(formats); err != nil { + res = append(res, err) + } + + if err := m.validateThreshold(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsKayentaMetric) validateScopes(formats strfmt.Registry) error { + if swag.IsZero(m.Scopes) { // not required + return nil + } + + for i := 0; i < len(m.Scopes); i++ { + if swag.IsZero(m.Scopes[i]) { // not required + continue + } + + if m.Scopes[i] != nil { + if err := m.Scopes[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("scopes" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("scopes" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsKayentaMetric) validateThreshold(formats strfmt.Registry) error { + if swag.IsZero(m.Threshold) { // not required + return nil + } + + if m.Threshold != nil { + if err := m.Threshold.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("threshold") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("threshold") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts kayenta metric based on the context it is used +func (m *RolloutsKayentaMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateScopes(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateThreshold(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsKayentaMetric) contextValidateScopes(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Scopes); i++ { + + if m.Scopes[i] != nil { + + if swag.IsZero(m.Scopes[i]) { // not required + return nil + } + + if err := m.Scopes[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("scopes" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("scopes" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *RolloutsKayentaMetric) contextValidateThreshold(ctx context.Context, formats strfmt.Registry) error { + + if m.Threshold != nil { + + if swag.IsZero(m.Threshold) { // not required + return nil + } + + if err := m.Threshold.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("threshold") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("threshold") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsKayentaMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsKayentaMetric) UnmarshalBinary(b []byte) error { + var res RolloutsKayentaMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_kayenta_scope.go b/pkg/client/generated/models/rollouts_kayenta_scope.go new file mode 100644 index 0000000000..1ed4e8a78d --- /dev/null +++ b/pkg/client/generated/models/rollouts_kayenta_scope.go @@ -0,0 +1,177 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsKayentaScope rollouts kayenta scope +// +// swagger:model RolloutsKayentaScope +type RolloutsKayentaScope struct { + + // control scope + ControlScope *RolloutsScopeDetail `json:"controlScope,omitempty"` + + // experiment scope + ExperimentScope *RolloutsScopeDetail `json:"experimentScope,omitempty"` + + // name + Name string `json:"name,omitempty"` +} + +// Validate validates this rollouts kayenta scope +func (m *RolloutsKayentaScope) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateControlScope(formats); err != nil { + res = append(res, err) + } + + if err := m.validateExperimentScope(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsKayentaScope) validateControlScope(formats strfmt.Registry) error { + if swag.IsZero(m.ControlScope) { // not required + return nil + } + + if m.ControlScope != nil { + if err := m.ControlScope.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("controlScope") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("controlScope") + } + + return err + } + } + + return nil +} + +func (m *RolloutsKayentaScope) validateExperimentScope(formats strfmt.Registry) error { + if swag.IsZero(m.ExperimentScope) { // not required + return nil + } + + if m.ExperimentScope != nil { + if err := m.ExperimentScope.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("experimentScope") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("experimentScope") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts kayenta scope based on the context it is used +func (m *RolloutsKayentaScope) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateControlScope(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateExperimentScope(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsKayentaScope) contextValidateControlScope(ctx context.Context, formats strfmt.Registry) error { + + if m.ControlScope != nil { + + if swag.IsZero(m.ControlScope) { // not required + return nil + } + + if err := m.ControlScope.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("controlScope") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("controlScope") + } + + return err + } + } + + return nil +} + +func (m *RolloutsKayentaScope) contextValidateExperimentScope(ctx context.Context, formats strfmt.Registry) error { + + if m.ExperimentScope != nil { + + if swag.IsZero(m.ExperimentScope) { // not required + return nil + } + + if err := m.ExperimentScope.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("experimentScope") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("experimentScope") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsKayentaScope) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsKayentaScope) UnmarshalBinary(b []byte) error { + var res RolloutsKayentaScope + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_kayenta_threshold.go b/pkg/client/generated/models/rollouts_kayenta_threshold.go new file mode 100644 index 0000000000..a988b2822a --- /dev/null +++ b/pkg/client/generated/models/rollouts_kayenta_threshold.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsKayentaThreshold rollouts kayenta threshold +// +// swagger:model RolloutsKayentaThreshold +type RolloutsKayentaThreshold struct { + + // marginal + Marginal int64 `json:"marginal,omitempty"` + + // pass + Pass int64 `json:"pass,omitempty"` +} + +// Validate validates this rollouts kayenta threshold +func (m *RolloutsKayentaThreshold) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts kayenta threshold based on context it is used +func (m *RolloutsKayentaThreshold) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsKayentaThreshold) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsKayentaThreshold) UnmarshalBinary(b []byte) error { + var res RolloutsKayentaThreshold + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_measurement.go b/pkg/client/generated/models/rollouts_measurement.go new file mode 100644 index 0000000000..367cbb9058 --- /dev/null +++ b/pkg/client/generated/models/rollouts_measurement.go @@ -0,0 +1,65 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsMeasurement rollouts measurement +// +// swagger:model RolloutsMeasurement +type RolloutsMeasurement struct { + + // finished at + FinishedAt string `json:"finishedAt,omitempty"` + + // message + Message string `json:"message,omitempty"` + + // metadata + Metadata map[string]string `json:"metadata,omitempty"` + + // phase + Phase string `json:"phase,omitempty"` + + // resume at + ResumeAt string `json:"resumeAt,omitempty"` + + // started at + StartedAt string `json:"startedAt,omitempty"` + + // value + Value string `json:"value,omitempty"` +} + +// Validate validates this rollouts measurement +func (m *RolloutsMeasurement) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts measurement based on context it is used +func (m *RolloutsMeasurement) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsMeasurement) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsMeasurement) UnmarshalBinary(b []byte) error { + var res RolloutsMeasurement + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_measurement_retention.go b/pkg/client/generated/models/rollouts_measurement_retention.go new file mode 100644 index 0000000000..69396c0f62 --- /dev/null +++ b/pkg/client/generated/models/rollouts_measurement_retention.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsMeasurementRetention rollouts measurement retention +// +// swagger:model RolloutsMeasurementRetention +type RolloutsMeasurementRetention struct { + + // limit + Limit int64 `json:"limit,omitempty"` + + // metric name + MetricName string `json:"metricName,omitempty"` +} + +// Validate validates this rollouts measurement retention +func (m *RolloutsMeasurementRetention) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts measurement retention based on context it is used +func (m *RolloutsMeasurementRetention) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsMeasurementRetention) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsMeasurementRetention) UnmarshalBinary(b []byte) error { + var res RolloutsMeasurementRetention + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_metric.go b/pkg/client/generated/models/rollouts_metric.go new file mode 100644 index 0000000000..cc7d945ced --- /dev/null +++ b/pkg/client/generated/models/rollouts_metric.go @@ -0,0 +1,425 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsMetric rollouts metric +// +// swagger:model RolloutsMetric +type RolloutsMetric struct { + + // consecutive error limit + ConsecutiveErrorLimit *IntOrString `json:"consecutiveErrorLimit,omitempty"` + + // consecutive success limit + ConsecutiveSuccessLimit *IntOrString `json:"consecutiveSuccessLimit,omitempty"` + + // count + Count *IntOrString `json:"count,omitempty"` + + // failure condition + FailureCondition string `json:"failureCondition,omitempty"` + + // failure limit + FailureLimit *IntOrString `json:"failureLimit,omitempty"` + + // inconclusive limit + InconclusiveLimit *IntOrString `json:"inconclusiveLimit,omitempty"` + + // initial delay + InitialDelay string `json:"initialDelay,omitempty"` + + // interval + Interval string `json:"interval,omitempty"` + + // name + Name string `json:"name,omitempty"` + + // provider + Provider *RolloutsMetricProvider `json:"provider,omitempty"` + + // success condition + SuccessCondition string `json:"successCondition,omitempty"` +} + +// Validate validates this rollouts metric +func (m *RolloutsMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConsecutiveErrorLimit(formats); err != nil { + res = append(res, err) + } + + if err := m.validateConsecutiveSuccessLimit(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCount(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFailureLimit(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInconclusiveLimit(formats); err != nil { + res = append(res, err) + } + + if err := m.validateProvider(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsMetric) validateConsecutiveErrorLimit(formats strfmt.Registry) error { + if swag.IsZero(m.ConsecutiveErrorLimit) { // not required + return nil + } + + if m.ConsecutiveErrorLimit != nil { + if err := m.ConsecutiveErrorLimit.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("consecutiveErrorLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("consecutiveErrorLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) validateConsecutiveSuccessLimit(formats strfmt.Registry) error { + if swag.IsZero(m.ConsecutiveSuccessLimit) { // not required + return nil + } + + if m.ConsecutiveSuccessLimit != nil { + if err := m.ConsecutiveSuccessLimit.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("consecutiveSuccessLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("consecutiveSuccessLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) validateCount(formats strfmt.Registry) error { + if swag.IsZero(m.Count) { // not required + return nil + } + + if m.Count != nil { + if err := m.Count.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("count") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("count") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) validateFailureLimit(formats strfmt.Registry) error { + if swag.IsZero(m.FailureLimit) { // not required + return nil + } + + if m.FailureLimit != nil { + if err := m.FailureLimit.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("failureLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("failureLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) validateInconclusiveLimit(formats strfmt.Registry) error { + if swag.IsZero(m.InconclusiveLimit) { // not required + return nil + } + + if m.InconclusiveLimit != nil { + if err := m.InconclusiveLimit.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("inconclusiveLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("inconclusiveLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) validateProvider(formats strfmt.Registry) error { + if swag.IsZero(m.Provider) { // not required + return nil + } + + if m.Provider != nil { + if err := m.Provider.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("provider") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("provider") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts metric based on the context it is used +func (m *RolloutsMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConsecutiveErrorLimit(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateConsecutiveSuccessLimit(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCount(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFailureLimit(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateInconclusiveLimit(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateProvider(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsMetric) contextValidateConsecutiveErrorLimit(ctx context.Context, formats strfmt.Registry) error { + + if m.ConsecutiveErrorLimit != nil { + + if swag.IsZero(m.ConsecutiveErrorLimit) { // not required + return nil + } + + if err := m.ConsecutiveErrorLimit.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("consecutiveErrorLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("consecutiveErrorLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) contextValidateConsecutiveSuccessLimit(ctx context.Context, formats strfmt.Registry) error { + + if m.ConsecutiveSuccessLimit != nil { + + if swag.IsZero(m.ConsecutiveSuccessLimit) { // not required + return nil + } + + if err := m.ConsecutiveSuccessLimit.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("consecutiveSuccessLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("consecutiveSuccessLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) contextValidateCount(ctx context.Context, formats strfmt.Registry) error { + + if m.Count != nil { + + if swag.IsZero(m.Count) { // not required + return nil + } + + if err := m.Count.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("count") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("count") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) contextValidateFailureLimit(ctx context.Context, formats strfmt.Registry) error { + + if m.FailureLimit != nil { + + if swag.IsZero(m.FailureLimit) { // not required + return nil + } + + if err := m.FailureLimit.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("failureLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("failureLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) contextValidateInconclusiveLimit(ctx context.Context, formats strfmt.Registry) error { + + if m.InconclusiveLimit != nil { + + if swag.IsZero(m.InconclusiveLimit) { // not required + return nil + } + + if err := m.InconclusiveLimit.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("inconclusiveLimit") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("inconclusiveLimit") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetric) contextValidateProvider(ctx context.Context, formats strfmt.Registry) error { + + if m.Provider != nil { + + if swag.IsZero(m.Provider) { // not required + return nil + } + + if err := m.Provider.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("provider") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("provider") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsMetric) UnmarshalBinary(b []byte) error { + var res RolloutsMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_metric_provider.go b/pkg/client/generated/models/rollouts_metric_provider.go new file mode 100644 index 0000000000..2462411bdc --- /dev/null +++ b/pkg/client/generated/models/rollouts_metric_provider.go @@ -0,0 +1,708 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsMetricProvider rollouts metric provider +// +// swagger:model RolloutsMetricProvider +type RolloutsMetricProvider struct { + + // cloud watch + CloudWatch *RolloutsCloudWatchMetric `json:"cloudWatch,omitempty"` + + // datadog + Datadog *RolloutsDatadogMetric `json:"datadog,omitempty"` + + // graphite + Graphite *RolloutsGraphiteMetric `json:"graphite,omitempty"` + + // influxdb + Influxdb *RolloutsInfluxdbMetric `json:"influxdb,omitempty"` + + // job + Job *RolloutsJobMetric `json:"job,omitempty"` + + // kayenta + Kayenta *RolloutsKayentaMetric `json:"kayenta,omitempty"` + + // new relic + NewRelic *RolloutsNewRelicMetric `json:"newRelic,omitempty"` + + // plugin + Plugin map[string]strfmt.Base64 `json:"plugin,omitempty"` + + // prometheus + Prometheus *RolloutsPrometheusMetric `json:"prometheus,omitempty"` + + // skywalking + Skywalking *RolloutsSkyWalkingMetric `json:"skywalking,omitempty"` + + // wavefront + Wavefront *RolloutsWavefrontMetric `json:"wavefront,omitempty"` + + // web + Web *RolloutsWebMetric `json:"web,omitempty"` +} + +// Validate validates this rollouts metric provider +func (m *RolloutsMetricProvider) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCloudWatch(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDatadog(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGraphite(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInfluxdb(formats); err != nil { + res = append(res, err) + } + + if err := m.validateJob(formats); err != nil { + res = append(res, err) + } + + if err := m.validateKayenta(formats); err != nil { + res = append(res, err) + } + + if err := m.validateNewRelic(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePrometheus(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSkywalking(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWavefront(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWeb(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsMetricProvider) validateCloudWatch(formats strfmt.Registry) error { + if swag.IsZero(m.CloudWatch) { // not required + return nil + } + + if m.CloudWatch != nil { + if err := m.CloudWatch.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("cloudWatch") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("cloudWatch") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateDatadog(formats strfmt.Registry) error { + if swag.IsZero(m.Datadog) { // not required + return nil + } + + if m.Datadog != nil { + if err := m.Datadog.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("datadog") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("datadog") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateGraphite(formats strfmt.Registry) error { + if swag.IsZero(m.Graphite) { // not required + return nil + } + + if m.Graphite != nil { + if err := m.Graphite.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("graphite") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("graphite") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateInfluxdb(formats strfmt.Registry) error { + if swag.IsZero(m.Influxdb) { // not required + return nil + } + + if m.Influxdb != nil { + if err := m.Influxdb.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("influxdb") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("influxdb") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateJob(formats strfmt.Registry) error { + if swag.IsZero(m.Job) { // not required + return nil + } + + if m.Job != nil { + if err := m.Job.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("job") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("job") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateKayenta(formats strfmt.Registry) error { + if swag.IsZero(m.Kayenta) { // not required + return nil + } + + if m.Kayenta != nil { + if err := m.Kayenta.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("kayenta") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("kayenta") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateNewRelic(formats strfmt.Registry) error { + if swag.IsZero(m.NewRelic) { // not required + return nil + } + + if m.NewRelic != nil { + if err := m.NewRelic.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("newRelic") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("newRelic") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validatePrometheus(formats strfmt.Registry) error { + if swag.IsZero(m.Prometheus) { // not required + return nil + } + + if m.Prometheus != nil { + if err := m.Prometheus.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("prometheus") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("prometheus") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateSkywalking(formats strfmt.Registry) error { + if swag.IsZero(m.Skywalking) { // not required + return nil + } + + if m.Skywalking != nil { + if err := m.Skywalking.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("skywalking") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("skywalking") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateWavefront(formats strfmt.Registry) error { + if swag.IsZero(m.Wavefront) { // not required + return nil + } + + if m.Wavefront != nil { + if err := m.Wavefront.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("wavefront") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("wavefront") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) validateWeb(formats strfmt.Registry) error { + if swag.IsZero(m.Web) { // not required + return nil + } + + if m.Web != nil { + if err := m.Web.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("web") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("web") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts metric provider based on the context it is used +func (m *RolloutsMetricProvider) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateCloudWatch(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDatadog(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGraphite(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateInfluxdb(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateJob(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateKayenta(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateNewRelic(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePrometheus(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSkywalking(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWavefront(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWeb(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsMetricProvider) contextValidateCloudWatch(ctx context.Context, formats strfmt.Registry) error { + + if m.CloudWatch != nil { + + if swag.IsZero(m.CloudWatch) { // not required + return nil + } + + if err := m.CloudWatch.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("cloudWatch") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("cloudWatch") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateDatadog(ctx context.Context, formats strfmt.Registry) error { + + if m.Datadog != nil { + + if swag.IsZero(m.Datadog) { // not required + return nil + } + + if err := m.Datadog.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("datadog") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("datadog") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateGraphite(ctx context.Context, formats strfmt.Registry) error { + + if m.Graphite != nil { + + if swag.IsZero(m.Graphite) { // not required + return nil + } + + if err := m.Graphite.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("graphite") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("graphite") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateInfluxdb(ctx context.Context, formats strfmt.Registry) error { + + if m.Influxdb != nil { + + if swag.IsZero(m.Influxdb) { // not required + return nil + } + + if err := m.Influxdb.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("influxdb") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("influxdb") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateJob(ctx context.Context, formats strfmt.Registry) error { + + if m.Job != nil { + + if swag.IsZero(m.Job) { // not required + return nil + } + + if err := m.Job.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("job") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("job") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateKayenta(ctx context.Context, formats strfmt.Registry) error { + + if m.Kayenta != nil { + + if swag.IsZero(m.Kayenta) { // not required + return nil + } + + if err := m.Kayenta.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("kayenta") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("kayenta") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateNewRelic(ctx context.Context, formats strfmt.Registry) error { + + if m.NewRelic != nil { + + if swag.IsZero(m.NewRelic) { // not required + return nil + } + + if err := m.NewRelic.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("newRelic") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("newRelic") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidatePrometheus(ctx context.Context, formats strfmt.Registry) error { + + if m.Prometheus != nil { + + if swag.IsZero(m.Prometheus) { // not required + return nil + } + + if err := m.Prometheus.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("prometheus") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("prometheus") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateSkywalking(ctx context.Context, formats strfmt.Registry) error { + + if m.Skywalking != nil { + + if swag.IsZero(m.Skywalking) { // not required + return nil + } + + if err := m.Skywalking.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("skywalking") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("skywalking") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateWavefront(ctx context.Context, formats strfmt.Registry) error { + + if m.Wavefront != nil { + + if swag.IsZero(m.Wavefront) { // not required + return nil + } + + if err := m.Wavefront.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("wavefront") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("wavefront") + } + + return err + } + } + + return nil +} + +func (m *RolloutsMetricProvider) contextValidateWeb(ctx context.Context, formats strfmt.Registry) error { + + if m.Web != nil { + + if swag.IsZero(m.Web) { // not required + return nil + } + + if err := m.Web.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("web") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("web") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsMetricProvider) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsMetricProvider) UnmarshalBinary(b []byte) error { + var res RolloutsMetricProvider + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_metric_result.go b/pkg/client/generated/models/rollouts_metric_result.go new file mode 100644 index 0000000000..94e26f7dc3 --- /dev/null +++ b/pkg/client/generated/models/rollouts_metric_result.go @@ -0,0 +1,160 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsMetricResult rollouts metric result +// +// swagger:model RolloutsMetricResult +type RolloutsMetricResult struct { + + // consecutive error + ConsecutiveError int64 `json:"consecutiveError,omitempty"` + + // count + Count int64 `json:"count,omitempty"` + + // dry run + DryRun bool `json:"dryRun,omitempty"` + + // error + Error int64 `json:"error,omitempty"` + + // failed + Failed int64 `json:"failed,omitempty"` + + // inconclusive + Inconclusive int64 `json:"inconclusive,omitempty"` + + // measurements + Measurements []*RolloutsMeasurement `json:"measurements"` + + // message + Message string `json:"message,omitempty"` + + // metadata + Metadata map[string]string `json:"metadata,omitempty"` + + // name + Name string `json:"name,omitempty"` + + // phase + Phase string `json:"phase,omitempty"` + + // successful + Successful int64 `json:"successful,omitempty"` +} + +// Validate validates this rollouts metric result +func (m *RolloutsMetricResult) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMeasurements(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsMetricResult) validateMeasurements(formats strfmt.Registry) error { + if swag.IsZero(m.Measurements) { // not required + return nil + } + + for i := 0; i < len(m.Measurements); i++ { + if swag.IsZero(m.Measurements[i]) { // not required + continue + } + + if m.Measurements[i] != nil { + if err := m.Measurements[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("measurements" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("measurements" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts metric result based on the context it is used +func (m *RolloutsMetricResult) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMeasurements(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsMetricResult) contextValidateMeasurements(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Measurements); i++ { + + if m.Measurements[i] != nil { + + if swag.IsZero(m.Measurements[i]) { // not required + return nil + } + + if err := m.Measurements[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("measurements" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("measurements" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsMetricResult) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsMetricResult) UnmarshalBinary(b []byte) error { + var res RolloutsMetricResult + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_new_relic_metric.go b/pkg/client/generated/models/rollouts_new_relic_metric.go new file mode 100644 index 0000000000..b416c5e699 --- /dev/null +++ b/pkg/client/generated/models/rollouts_new_relic_metric.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsNewRelicMetric rollouts new relic metric +// +// swagger:model RolloutsNewRelicMetric +type RolloutsNewRelicMetric struct { + + // profile + Profile string `json:"profile,omitempty"` + + // query + Query string `json:"query,omitempty"` +} + +// Validate validates this rollouts new relic metric +func (m *RolloutsNewRelicMetric) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts new relic metric based on context it is used +func (m *RolloutsNewRelicMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsNewRelicMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsNewRelicMetric) UnmarshalBinary(b []byte) error { + var res RolloutsNewRelicMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_o_auth2_config.go b/pkg/client/generated/models/rollouts_o_auth2_config.go new file mode 100644 index 0000000000..13a0a89f46 --- /dev/null +++ b/pkg/client/generated/models/rollouts_o_auth2_config.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsOAuth2Config rollouts o auth2 config +// +// swagger:model RolloutsOAuth2Config +type RolloutsOAuth2Config struct { + + // client Id + ClientID string `json:"clientId,omitempty"` + + // client secret + ClientSecret string `json:"clientSecret,omitempty"` + + // scopes + Scopes []string `json:"scopes"` + + // token Url + TokenURL string `json:"tokenUrl,omitempty"` +} + +// Validate validates this rollouts o auth2 config +func (m *RolloutsOAuth2Config) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts o auth2 config based on context it is used +func (m *RolloutsOAuth2Config) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsOAuth2Config) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsOAuth2Config) UnmarshalBinary(b []byte) error { + var res RolloutsOAuth2Config + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_prometheus_metric.go b/pkg/client/generated/models/rollouts_prometheus_metric.go new file mode 100644 index 0000000000..8c2fb7d1dc --- /dev/null +++ b/pkg/client/generated/models/rollouts_prometheus_metric.go @@ -0,0 +1,198 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsPrometheusMetric rollouts prometheus metric +// +// swagger:model RolloutsPrometheusMetric +type RolloutsPrometheusMetric struct { + + // address + Address string `json:"address,omitempty"` + + // authentication + Authentication *RolloutsAuthentication `json:"authentication,omitempty"` + + // headers + Headers []*RolloutsWebMetricHeader `json:"headers"` + + // insecure + Insecure bool `json:"insecure,omitempty"` + + // query + Query string `json:"query,omitempty"` + + // timeout + Timeout int64 `json:"timeout,omitempty"` +} + +// Validate validates this rollouts prometheus metric +func (m *RolloutsPrometheusMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAuthentication(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHeaders(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsPrometheusMetric) validateAuthentication(formats strfmt.Registry) error { + if swag.IsZero(m.Authentication) { // not required + return nil + } + + if m.Authentication != nil { + if err := m.Authentication.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("authentication") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("authentication") + } + + return err + } + } + + return nil +} + +func (m *RolloutsPrometheusMetric) validateHeaders(formats strfmt.Registry) error { + if swag.IsZero(m.Headers) { // not required + return nil + } + + for i := 0; i < len(m.Headers); i++ { + if swag.IsZero(m.Headers[i]) { // not required + continue + } + + if m.Headers[i] != nil { + if err := m.Headers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("headers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("headers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts prometheus metric based on the context it is used +func (m *RolloutsPrometheusMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAuthentication(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHeaders(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsPrometheusMetric) contextValidateAuthentication(ctx context.Context, formats strfmt.Registry) error { + + if m.Authentication != nil { + + if swag.IsZero(m.Authentication) { // not required + return nil + } + + if err := m.Authentication.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("authentication") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("authentication") + } + + return err + } + } + + return nil +} + +func (m *RolloutsPrometheusMetric) contextValidateHeaders(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Headers); i++ { + + if m.Headers[i] != nil { + + if swag.IsZero(m.Headers[i]) { // not required + return nil + } + + if err := m.Headers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("headers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("headers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsPrometheusMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsPrometheusMetric) UnmarshalBinary(b []byte) error { + var res RolloutsPrometheusMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_run_summary.go b/pkg/client/generated/models/rollouts_run_summary.go new file mode 100644 index 0000000000..529270f5db --- /dev/null +++ b/pkg/client/generated/models/rollouts_run_summary.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsRunSummary rollouts run summary +// +// swagger:model RolloutsRunSummary +type RolloutsRunSummary struct { + + // count + Count int64 `json:"count,omitempty"` + + // error + Error int64 `json:"error,omitempty"` + + // failed + Failed int64 `json:"failed,omitempty"` + + // inconclusive + Inconclusive int64 `json:"inconclusive,omitempty"` + + // successful + Successful int64 `json:"successful,omitempty"` +} + +// Validate validates this rollouts run summary +func (m *RolloutsRunSummary) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts run summary based on context it is used +func (m *RolloutsRunSummary) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsRunSummary) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsRunSummary) UnmarshalBinary(b []byte) error { + var res RolloutsRunSummary + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_scope_detail.go b/pkg/client/generated/models/rollouts_scope_detail.go new file mode 100644 index 0000000000..072ec4047c --- /dev/null +++ b/pkg/client/generated/models/rollouts_scope_detail.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsScopeDetail rollouts scope detail +// +// swagger:model RolloutsScopeDetail +type RolloutsScopeDetail struct { + + // end + End string `json:"end,omitempty"` + + // region + Region string `json:"region,omitempty"` + + // scope + Scope string `json:"scope,omitempty"` + + // start + Start string `json:"start,omitempty"` + + // step + Step int64 `json:"step,omitempty"` +} + +// Validate validates this rollouts scope detail +func (m *RolloutsScopeDetail) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts scope detail based on context it is used +func (m *RolloutsScopeDetail) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsScopeDetail) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsScopeDetail) UnmarshalBinary(b []byte) error { + var res RolloutsScopeDetail + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_secret_key_ref.go b/pkg/client/generated/models/rollouts_secret_key_ref.go new file mode 100644 index 0000000000..75ce2dd315 --- /dev/null +++ b/pkg/client/generated/models/rollouts_secret_key_ref.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsSecretKeyRef rollouts secret key ref +// +// swagger:model RolloutsSecretKeyRef +type RolloutsSecretKeyRef struct { + + // key + Key string `json:"key,omitempty"` + + // name + Name string `json:"name,omitempty"` +} + +// Validate validates this rollouts secret key ref +func (m *RolloutsSecretKeyRef) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts secret key ref based on context it is used +func (m *RolloutsSecretKeyRef) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsSecretKeyRef) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsSecretKeyRef) UnmarshalBinary(b []byte) error { + var res RolloutsSecretKeyRef + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_sigv4_config.go b/pkg/client/generated/models/rollouts_sigv4_config.go new file mode 100644 index 0000000000..f404c21a33 --- /dev/null +++ b/pkg/client/generated/models/rollouts_sigv4_config.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsSigv4Config rollouts sigv4 config +// +// swagger:model RolloutsSigv4Config +type RolloutsSigv4Config struct { + + // profile + Profile string `json:"profile,omitempty"` + + // region + Region string `json:"region,omitempty"` + + // role arn + RoleArn string `json:"roleArn,omitempty"` +} + +// Validate validates this rollouts sigv4 config +func (m *RolloutsSigv4Config) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts sigv4 config based on context it is used +func (m *RolloutsSigv4Config) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsSigv4Config) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsSigv4Config) UnmarshalBinary(b []byte) error { + var res RolloutsSigv4Config + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_sky_walking_metric.go b/pkg/client/generated/models/rollouts_sky_walking_metric.go new file mode 100644 index 0000000000..abb200e1e7 --- /dev/null +++ b/pkg/client/generated/models/rollouts_sky_walking_metric.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsSkyWalkingMetric rollouts sky walking metric +// +// swagger:model RolloutsSkyWalkingMetric +type RolloutsSkyWalkingMetric struct { + + // address + Address string `json:"address,omitempty"` + + // interval + Interval string `json:"interval,omitempty"` + + // query + Query string `json:"query,omitempty"` +} + +// Validate validates this rollouts sky walking metric +func (m *RolloutsSkyWalkingMetric) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts sky walking metric based on context it is used +func (m *RolloutsSkyWalkingMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsSkyWalkingMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsSkyWalkingMetric) UnmarshalBinary(b []byte) error { + var res RolloutsSkyWalkingMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_value_from.go b/pkg/client/generated/models/rollouts_value_from.go new file mode 100644 index 0000000000..a43716877c --- /dev/null +++ b/pkg/client/generated/models/rollouts_value_from.go @@ -0,0 +1,174 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsValueFrom rollouts value from +// +// swagger:model RolloutsValueFrom +type RolloutsValueFrom struct { + + // field ref + FieldRef *RolloutsFieldRef `json:"fieldRef,omitempty"` + + // secret key ref + SecretKeyRef *RolloutsSecretKeyRef `json:"secretKeyRef,omitempty"` +} + +// Validate validates this rollouts value from +func (m *RolloutsValueFrom) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFieldRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecretKeyRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsValueFrom) validateFieldRef(formats strfmt.Registry) error { + if swag.IsZero(m.FieldRef) { // not required + return nil + } + + if m.FieldRef != nil { + if err := m.FieldRef.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("fieldRef") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("fieldRef") + } + + return err + } + } + + return nil +} + +func (m *RolloutsValueFrom) validateSecretKeyRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretKeyRef) { // not required + return nil + } + + if m.SecretKeyRef != nil { + if err := m.SecretKeyRef.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("secretKeyRef") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("secretKeyRef") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this rollouts value from based on the context it is used +func (m *RolloutsValueFrom) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateFieldRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecretKeyRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsValueFrom) contextValidateFieldRef(ctx context.Context, formats strfmt.Registry) error { + + if m.FieldRef != nil { + + if swag.IsZero(m.FieldRef) { // not required + return nil + } + + if err := m.FieldRef.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("fieldRef") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("fieldRef") + } + + return err + } + } + + return nil +} + +func (m *RolloutsValueFrom) contextValidateSecretKeyRef(ctx context.Context, formats strfmt.Registry) error { + + if m.SecretKeyRef != nil { + + if swag.IsZero(m.SecretKeyRef) { // not required + return nil + } + + if err := m.SecretKeyRef.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("secretKeyRef") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("secretKeyRef") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsValueFrom) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsValueFrom) UnmarshalBinary(b []byte) error { + var res RolloutsValueFrom + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_wavefront_metric.go b/pkg/client/generated/models/rollouts_wavefront_metric.go new file mode 100644 index 0000000000..b5a8bc1410 --- /dev/null +++ b/pkg/client/generated/models/rollouts_wavefront_metric.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsWavefrontMetric rollouts wavefront metric +// +// swagger:model RolloutsWavefrontMetric +type RolloutsWavefrontMetric struct { + + // address + Address string `json:"address,omitempty"` + + // query + Query string `json:"query,omitempty"` +} + +// Validate validates this rollouts wavefront metric +func (m *RolloutsWavefrontMetric) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts wavefront metric based on context it is used +func (m *RolloutsWavefrontMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsWavefrontMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsWavefrontMetric) UnmarshalBinary(b []byte) error { + var res RolloutsWavefrontMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_web_metric.go b/pkg/client/generated/models/rollouts_web_metric.go new file mode 100644 index 0000000000..f2e1c062d3 --- /dev/null +++ b/pkg/client/generated/models/rollouts_web_metric.go @@ -0,0 +1,207 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsWebMetric rollouts web metric +// +// swagger:model RolloutsWebMetric +type RolloutsWebMetric struct { + + // authentication + Authentication *RolloutsAuthentication `json:"authentication,omitempty"` + + // body + Body string `json:"body,omitempty"` + + // headers + Headers []*RolloutsWebMetricHeader `json:"headers"` + + // insecure + Insecure bool `json:"insecure,omitempty"` + + // json body + JSONBody []int64 `json:"jsonBody"` + + // json path + JSONPath string `json:"jsonPath,omitempty"` + + // method + Method string `json:"method,omitempty"` + + // timeout seconds + TimeoutSeconds int64 `json:"timeoutSeconds,omitempty"` + + // URL is the address of the web metric + URL string `json:"url,omitempty"` +} + +// Validate validates this rollouts web metric +func (m *RolloutsWebMetric) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAuthentication(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHeaders(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsWebMetric) validateAuthentication(formats strfmt.Registry) error { + if swag.IsZero(m.Authentication) { // not required + return nil + } + + if m.Authentication != nil { + if err := m.Authentication.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("authentication") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("authentication") + } + + return err + } + } + + return nil +} + +func (m *RolloutsWebMetric) validateHeaders(formats strfmt.Registry) error { + if swag.IsZero(m.Headers) { // not required + return nil + } + + for i := 0; i < len(m.Headers); i++ { + if swag.IsZero(m.Headers[i]) { // not required + continue + } + + if m.Headers[i] != nil { + if err := m.Headers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("headers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("headers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this rollouts web metric based on the context it is used +func (m *RolloutsWebMetric) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAuthentication(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHeaders(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *RolloutsWebMetric) contextValidateAuthentication(ctx context.Context, formats strfmt.Registry) error { + + if m.Authentication != nil { + + if swag.IsZero(m.Authentication) { // not required + return nil + } + + if err := m.Authentication.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("authentication") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("authentication") + } + + return err + } + } + + return nil +} + +func (m *RolloutsWebMetric) contextValidateHeaders(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Headers); i++ { + + if m.Headers[i] != nil { + + if swag.IsZero(m.Headers[i]) { // not required + return nil + } + + if err := m.Headers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("headers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("headers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsWebMetric) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsWebMetric) UnmarshalBinary(b []byte) error { + var res RolloutsWebMetric + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/rollouts_web_metric_header.go b/pkg/client/generated/models/rollouts_web_metric_header.go new file mode 100644 index 0000000000..c368a17576 --- /dev/null +++ b/pkg/client/generated/models/rollouts_web_metric_header.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// RolloutsWebMetricHeader rollouts web metric header +// +// swagger:model RolloutsWebMetricHeader +type RolloutsWebMetricHeader struct { + + // key + Key string `json:"key,omitempty"` + + // value + Value string `json:"value,omitempty"` +} + +// Validate validates this rollouts web metric header +func (m *RolloutsWebMetricHeader) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this rollouts web metric header based on context it is used +func (m *RolloutsWebMetricHeader) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *RolloutsWebMetricHeader) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *RolloutsWebMetricHeader) UnmarshalBinary(b []byte) error { + var res RolloutsWebMetricHeader + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/stage.go b/pkg/client/generated/models/stage.go new file mode 100644 index 0000000000..52646a387d --- /dev/null +++ b/pkg/client/generated/models/stage.go @@ -0,0 +1,183 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Stage stage +// +// swagger:model Stage +type Stage struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes sources of Freight used by the Stage and how to incorporate + // Freight into the Stage. + // + // +kubebuilder:validation:Required + // Required: true + Spec struct { + StageSpec + } `json:"spec"` + + // Status describes the Stage's current and recent Freight, health, and more. + Status struct { + StageStatus + } `json:"status,omitempty"` +} + +// Validate validates this stage +func (m *Stage) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Stage) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Stage) validateSpec(formats strfmt.Registry) error { + + return nil +} + +func (m *Stage) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this stage based on the context it is used +func (m *Stage) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Stage) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Stage) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *Stage) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *Stage) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Stage) UnmarshalBinary(b []byte) error { + var res Stage + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/stage_list.go b/pkg/client/generated/models/stage_list.go new file mode 100644 index 0000000000..bf8a367e78 --- /dev/null +++ b/pkg/client/generated/models/stage_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// StageList stage list +// +// swagger:model StageList +type StageList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*Stage `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this stage list +func (m *StageList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this stage list based on the context it is used +func (m *StageList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *StageList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *StageList) UnmarshalBinary(b []byte) error { + var res StageList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/stage_spec.go b/pkg/client/generated/models/stage_spec.go new file mode 100644 index 0000000000..d8c5e8885a --- /dev/null +++ b/pkg/client/generated/models/stage_spec.go @@ -0,0 +1,269 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// StageSpec stage spec +// +// swagger:model StageSpec +type StageSpec struct { + + // PromotionTemplate describes how to incorporate Freight into the Stage + // using a Promotion. + PromotionTemplate struct { + PromotionTemplate + } `json:"promotionTemplate,omitempty"` + + // RequestedFreight expresses the Stage's need for certain pieces of Freight, + // each having originated from a particular Warehouse. This list must be + // non-empty. In the common case, a Stage will request Freight having + // originated from just one specific Warehouse. In advanced cases, requesting + // Freight from multiple Warehouses provides a method of advancing new + // artifacts of different types through parallel pipelines at different + // speeds. This can be useful, for instance, if a Stage is home to multiple + // microservices that are independently versioned. + // + // +kubebuilder:validation:MinItems=1 + RequestedFreight []*FreightRequest `json:"requestedFreight"` + + // Shard is the name of the shard that this Stage belongs to. This is an + // optional field. If not specified, the Stage will belong to the default + // shard. A defaulting webhook will sync the value of the + // kargo.akuity.io/shard label with the value of this field. When this field + // is empty, the webhook will ensure that label is absent. + Shard string `json:"shard,omitempty"` + + // Vars is a list of variables that can be referenced anywhere in the + // StageSpec that supports expressions. For example, the PromotionTemplate + // and arguments of the Verification. + Vars []*ExpressionVariable `json:"vars"` + + // Verification describes how to verify a Stage's current Freight is fit for + // promotion downstream. + Verification struct { + Verification + } `json:"verification,omitempty"` +} + +// Validate validates this stage spec +func (m *StageSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePromotionTemplate(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequestedFreight(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVars(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVerification(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageSpec) validatePromotionTemplate(formats strfmt.Registry) error { + if swag.IsZero(m.PromotionTemplate) { // not required + return nil + } + + return nil +} + +func (m *StageSpec) validateRequestedFreight(formats strfmt.Registry) error { + if swag.IsZero(m.RequestedFreight) { // not required + return nil + } + + for i := 0; i < len(m.RequestedFreight); i++ { + if swag.IsZero(m.RequestedFreight[i]) { // not required + continue + } + + if m.RequestedFreight[i] != nil { + if err := m.RequestedFreight[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("requestedFreight" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("requestedFreight" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageSpec) validateVars(formats strfmt.Registry) error { + if swag.IsZero(m.Vars) { // not required + return nil + } + + for i := 0; i < len(m.Vars); i++ { + if swag.IsZero(m.Vars[i]) { // not required + continue + } + + if m.Vars[i] != nil { + if err := m.Vars[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageSpec) validateVerification(formats strfmt.Registry) error { + if swag.IsZero(m.Verification) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this stage spec based on the context it is used +func (m *StageSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePromotionTemplate(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRequestedFreight(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVars(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVerification(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageSpec) contextValidatePromotionTemplate(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *StageSpec) contextValidateRequestedFreight(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.RequestedFreight); i++ { + + if m.RequestedFreight[i] != nil { + + if swag.IsZero(m.RequestedFreight[i]) { // not required + return nil + } + + if err := m.RequestedFreight[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("requestedFreight" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("requestedFreight" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageSpec) contextValidateVars(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Vars); i++ { + + if m.Vars[i] != nil { + + if swag.IsZero(m.Vars[i]) { // not required + return nil + } + + if err := m.Vars[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("vars" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("vars" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageSpec) contextValidateVerification(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *StageSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *StageSpec) UnmarshalBinary(b []byte) error { + var res StageSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/stage_stats.go b/pkg/client/generated/models/stage_stats.go new file mode 100644 index 0000000000..ae29ce02b9 --- /dev/null +++ b/pkg/client/generated/models/stage_stats.go @@ -0,0 +1,84 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// StageStats stage stats +// +// swagger:model StageStats +type StageStats struct { + + // Count contains the total number of Stages in the Project. + Count int64 `json:"count,omitempty"` + + // Health contains a summary of the collective health of a Project's Stages. + Health struct { + HealthStats + } `json:"health,omitempty"` +} + +// Validate validates this stage stats +func (m *StageStats) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateHealth(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageStats) validateHealth(formats strfmt.Registry) error { + if swag.IsZero(m.Health) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this stage stats based on the context it is used +func (m *StageStats) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateHealth(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageStats) contextValidateHealth(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *StageStats) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *StageStats) UnmarshalBinary(b []byte) error { + var res StageStats + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/stage_status.go b/pkg/client/generated/models/stage_status.go new file mode 100644 index 0000000000..a4bebccef0 --- /dev/null +++ b/pkg/client/generated/models/stage_status.go @@ -0,0 +1,314 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// StageStatus stage status +// +// swagger:model StageStatus +type StageStatus struct { + + // AutoPromotionEnabled indicates whether automatic promotion is enabled + // for the Stage based on the ProjectConfig. + AutoPromotionEnabled bool `json:"autoPromotionEnabled,omitempty"` + + // Conditions contains the last observations of the Stage's current + // state. + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []*V1Condition `json:"conditions"` + + // CurrentPromotion is a reference to the currently Running promotion. + CurrentPromotion struct { + PromotionReference + } `json:"currentPromotion,omitempty"` + + // FreightHistory is a list of recent Freight selections that were deployed + // to the Stage. By default, the last ten Freight selections are stored. + // The first item in the list is the most recent Freight selection and + // currently deployed to the Stage, subsequent items are older selections. + FreightHistory []*FreightCollection `json:"freightHistory"` + + // FreightSummary is human-readable text maintained by the controller that + // summarizes what Freight is currently deployed to the Stage. For Stages that + // request a single piece of Freight AND the request has been fulfilled, this + // field will simply contain the name of the Freight. For Stages that request + // a single piece of Freight AND the request has NOT been fulfilled, or for + // Stages that request multiple pieces of Freight, this field will contain a + // summary of fulfilled/requested Freight. The existence of this field is a + // workaround for kubectl limitations so that this complex but valuable + // information can be displayed in a column in response to `kubectl get + // stages`. + FreightSummary string `json:"freightSummary,omitempty"` + + // Health is the Stage's last observed health. + Health struct { + Health + } `json:"health,omitempty"` + + // LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh + // annotation that was handled by the controller. This field can be used to + // determine whether the request to refresh the resource has been handled. + // +optional + LastHandledRefresh string `json:"lastHandledRefresh,omitempty"` + + // LastPromotion is a reference to the last completed promotion. + LastPromotion struct { + PromotionReference + } `json:"lastPromotion,omitempty"` + + // Metadata is a map of arbitrary metadata associated with the Stage. + // This is useful for storing additional information about the Stage + // that can be shared across promotions, verifications, or other processes. + Metadata map[string]any `json:"metadata,omitempty"` + + // ObservedGeneration represents the .metadata.generation that this Stage + // status was reconciled against. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// Validate validates this stage status +func (m *StageStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConditions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCurrentPromotion(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFreightHistory(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHealth(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLastPromotion(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageStatus) validateConditions(formats strfmt.Registry) error { + if swag.IsZero(m.Conditions) { // not required + return nil + } + + for i := 0; i < len(m.Conditions); i++ { + if swag.IsZero(m.Conditions[i]) { // not required + continue + } + + if m.Conditions[i] != nil { + if err := m.Conditions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageStatus) validateCurrentPromotion(formats strfmt.Registry) error { + if swag.IsZero(m.CurrentPromotion) { // not required + return nil + } + + return nil +} + +func (m *StageStatus) validateFreightHistory(formats strfmt.Registry) error { + if swag.IsZero(m.FreightHistory) { // not required + return nil + } + + for i := 0; i < len(m.FreightHistory); i++ { + if swag.IsZero(m.FreightHistory[i]) { // not required + continue + } + + if m.FreightHistory[i] != nil { + if err := m.FreightHistory[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freightHistory" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freightHistory" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageStatus) validateHealth(formats strfmt.Registry) error { + if swag.IsZero(m.Health) { // not required + return nil + } + + return nil +} + +func (m *StageStatus) validateLastPromotion(formats strfmt.Registry) error { + if swag.IsZero(m.LastPromotion) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this stage status based on the context it is used +func (m *StageStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConditions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCurrentPromotion(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFreightHistory(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHealth(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLastPromotion(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *StageStatus) contextValidateConditions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Conditions); i++ { + + if m.Conditions[i] != nil { + + if swag.IsZero(m.Conditions[i]) { // not required + return nil + } + + if err := m.Conditions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageStatus) contextValidateCurrentPromotion(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *StageStatus) contextValidateFreightHistory(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.FreightHistory); i++ { + + if m.FreightHistory[i] != nil { + + if swag.IsZero(m.FreightHistory[i]) { // not required + return nil + } + + if err := m.FreightHistory[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("freightHistory" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("freightHistory" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *StageStatus) contextValidateHealth(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *StageStatus) contextValidateLastPromotion(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *StageStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *StageStatus) UnmarshalBinary(b []byte) error { + var res StageStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/step_execution_metadata.go b/pkg/client/generated/models/step_execution_metadata.go new file mode 100644 index 0000000000..b8738ad298 --- /dev/null +++ b/pkg/client/generated/models/step_execution_metadata.go @@ -0,0 +1,70 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// StepExecutionMetadata step execution metadata +// +// swagger:model StepExecutionMetadata +type StepExecutionMetadata struct { + + // Alias is the alias of the step. + Alias string `json:"alias,omitempty"` + + // ContinueOnError is a boolean value that, if set to true, will cause the + // Promotion to continue executing the next step even if this step fails. It + // also will not permit this failure to impact the overall status of the + // Promotion. + ContinueOnError bool `json:"continueOnError,omitempty"` + + // ErrorCount tracks consecutive failed attempts to execute the step. + ErrorCount int64 `json:"errorCount,omitempty"` + + // FinishedAt is the time at which the final attempt to execute the step + // completed. + FinishedAt string `json:"finishedAt,omitempty"` + + // Message is a display message about the step, including any errors. + Message string `json:"message,omitempty"` + + // StartedAt is the time at which the first attempt to execute the step + // began. + StartedAt string `json:"startedAt,omitempty"` + + // Status is the high-level outcome of the step. + Status string `json:"status,omitempty"` +} + +// Validate validates this step execution metadata +func (m *StepExecutionMetadata) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this step execution metadata based on context it is used +func (m *StepExecutionMetadata) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *StepExecutionMetadata) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *StepExecutionMetadata) UnmarshalBinary(b []byte) error { + var res StepExecutionMetadata + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_a_w_s_elastic_block_store_volume_source.go b/pkg/client/generated/models/v1_a_w_s_elastic_block_store_volume_source.go new file mode 100644 index 0000000000..7254b3399d --- /dev/null +++ b/pkg/client/generated/models/v1_a_w_s_elastic_block_store_volume_source.go @@ -0,0 +1,68 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1AWSElasticBlockStoreVolumeSource v1 a w s elastic block store volume source +// +// swagger:model V1AWSElasticBlockStoreVolumeSource +type V1AWSElasticBlockStoreVolumeSource struct { + + // fsType is the filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FsType string `json:"fsType,omitempty"` + + // partition is the partition in the volume that you want to mount. + // If omitted, the default is to mount by volume name. + // Examples: For volume /dev/sda1, you specify the partition as "1". + // Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + // +optional + Partition int64 `json:"partition,omitempty"` + + // readOnly value true will force the readOnly setting in VolumeMounts. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + VolumeID string `json:"volumeID,omitempty"` +} + +// Validate validates this v1 a w s elastic block store volume source +func (m *V1AWSElasticBlockStoreVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 a w s elastic block store volume source based on context it is used +func (m *V1AWSElasticBlockStoreVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1AWSElasticBlockStoreVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1AWSElasticBlockStoreVolumeSource) UnmarshalBinary(b []byte) error { + var res V1AWSElasticBlockStoreVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_affinity.go b/pkg/client/generated/models/v1_affinity.go new file mode 100644 index 0000000000..5cbc27d826 --- /dev/null +++ b/pkg/client/generated/models/v1_affinity.go @@ -0,0 +1,136 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Affinity v1 affinity +// +// swagger:model V1Affinity +type V1Affinity struct { + + // Describes node affinity scheduling rules for the pod. + // +optional + NodeAffinity struct { + V1NodeAffinity + } `json:"nodeAffinity,omitempty"` + + // Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + // +optional + PodAffinity struct { + V1PodAffinity + } `json:"podAffinity,omitempty"` + + // Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + // +optional + PodAntiAffinity struct { + V1PodAntiAffinity + } `json:"podAntiAffinity,omitempty"` +} + +// Validate validates this v1 affinity +func (m *V1Affinity) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateNodeAffinity(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePodAffinity(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePodAntiAffinity(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Affinity) validateNodeAffinity(formats strfmt.Registry) error { + if swag.IsZero(m.NodeAffinity) { // not required + return nil + } + + return nil +} + +func (m *V1Affinity) validatePodAffinity(formats strfmt.Registry) error { + if swag.IsZero(m.PodAffinity) { // not required + return nil + } + + return nil +} + +func (m *V1Affinity) validatePodAntiAffinity(formats strfmt.Registry) error { + if swag.IsZero(m.PodAntiAffinity) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 affinity based on the context it is used +func (m *V1Affinity) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateNodeAffinity(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePodAffinity(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePodAntiAffinity(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Affinity) contextValidateNodeAffinity(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Affinity) contextValidatePodAffinity(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Affinity) contextValidatePodAntiAffinity(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Affinity) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Affinity) UnmarshalBinary(b []byte) error { + var res V1Affinity + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_app_armor_profile.go b/pkg/client/generated/models/v1_app_armor_profile.go new file mode 100644 index 0000000000..2d323baaae --- /dev/null +++ b/pkg/client/generated/models/v1_app_armor_profile.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1AppArmorProfile v1 app armor profile +// +// swagger:model V1AppArmorProfile +type V1AppArmorProfile struct { + + // localhostProfile indicates a profile loaded on the node that should be used. + // The profile must be preconfigured on the node to work. + // Must match the loaded name of the profile. + // Must be set if and only if type is "Localhost". + // +optional + LocalhostProfile string `json:"localhostProfile,omitempty"` + + // type indicates which kind of AppArmor profile will be applied. + // Valid options are: + // Localhost - a profile pre-loaded on the node. + // RuntimeDefault - the container runtime's default profile. + // Unconfined - no AppArmor enforcement. + // +unionDiscriminator + Type string `json:"type,omitempty"` +} + +// Validate validates this v1 app armor profile +func (m *V1AppArmorProfile) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 app armor profile based on context it is used +func (m *V1AppArmorProfile) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1AppArmorProfile) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1AppArmorProfile) UnmarshalBinary(b []byte) error { + var res V1AppArmorProfile + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_azure_disk_volume_source.go b/pkg/client/generated/models/v1_azure_disk_volume_source.go new file mode 100644 index 0000000000..e3a27a063e --- /dev/null +++ b/pkg/client/generated/models/v1_azure_disk_volume_source.go @@ -0,0 +1,72 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1AzureDiskVolumeSource v1 azure disk volume source +// +// swagger:model V1AzureDiskVolumeSource +type V1AzureDiskVolumeSource struct { + + // cachingMode is the Host Caching mode: None, Read Only, Read Write. + // +optional + // +default=ref(AzureDataDiskCachingReadWrite) + CachingMode string `json:"cachingMode,omitempty"` + + // diskName is the Name of the data disk in the blob storage + DiskName string `json:"diskName,omitempty"` + + // diskURI is the URI of data disk in the blob storage + DiskURI string `json:"diskURI,omitempty"` + + // fsType is Filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + // +default="ext4" + FsType string `json:"fsType,omitempty"` + + // kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared + // +default=ref(AzureSharedBlobDisk) + Kind string `json:"kind,omitempty"` + + // readOnly Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + // +default=false + ReadOnly bool `json:"readOnly,omitempty"` +} + +// Validate validates this v1 azure disk volume source +func (m *V1AzureDiskVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 azure disk volume source based on context it is used +func (m *V1AzureDiskVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1AzureDiskVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1AzureDiskVolumeSource) UnmarshalBinary(b []byte) error { + var res V1AzureDiskVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_azure_file_volume_source.go b/pkg/client/generated/models/v1_azure_file_volume_source.go new file mode 100644 index 0000000000..5b57872759 --- /dev/null +++ b/pkg/client/generated/models/v1_azure_file_volume_source.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1AzureFileVolumeSource v1 azure file volume source +// +// swagger:model V1AzureFileVolumeSource +type V1AzureFileVolumeSource struct { + + // readOnly defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretName is the name of secret that contains Azure Storage Account Name and Key + SecretName string `json:"secretName,omitempty"` + + // shareName is the azure share Name + ShareName string `json:"shareName,omitempty"` +} + +// Validate validates this v1 azure file volume source +func (m *V1AzureFileVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 azure file volume source based on context it is used +func (m *V1AzureFileVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1AzureFileVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1AzureFileVolumeSource) UnmarshalBinary(b []byte) error { + var res V1AzureFileVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_c_s_i_volume_source.go b/pkg/client/generated/models/v1_c_s_i_volume_source.go new file mode 100644 index 0000000000..c016f2b226 --- /dev/null +++ b/pkg/client/generated/models/v1_c_s_i_volume_source.go @@ -0,0 +1,106 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1CSIVolumeSource v1 c s i volume source +// +// swagger:model V1CSIVolumeSource +type V1CSIVolumeSource struct { + + // driver is the name of the CSI driver that handles this volume. + // Consult with your admin for the correct name as registered in the cluster. + Driver string `json:"driver,omitempty"` + + // fsType to mount. Ex. "ext4", "xfs", "ntfs". + // If not provided, the empty value is passed to the associated CSI driver + // which will determine the default filesystem to apply. + // +optional + FsType string `json:"fsType,omitempty"` + + // nodePublishSecretRef is a reference to the secret object containing + // sensitive information to pass to the CSI driver to complete the CSI + // NodePublishVolume and NodeUnpublishVolume calls. + // This field is optional, and may be empty if no secret is required. If the + // secret object contains more than one secret, all secret references are passed. + // +optional + NodePublishSecretRef struct { + V1LocalObjectReference + } `json:"nodePublishSecretRef,omitempty"` + + // readOnly specifies a read-only configuration for the volume. + // Defaults to false (read/write). + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // volumeAttributes stores driver-specific properties that are passed to the CSI + // driver. Consult your driver's documentation for supported values. + // +optional + VolumeAttributes map[string]string `json:"volumeAttributes,omitempty"` +} + +// Validate validates this v1 c s i volume source +func (m *V1CSIVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateNodePublishSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CSIVolumeSource) validateNodePublishSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.NodePublishSecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 c s i volume source based on the context it is used +func (m *V1CSIVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateNodePublishSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CSIVolumeSource) contextValidateNodePublishSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1CSIVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1CSIVolumeSource) UnmarshalBinary(b []byte) error { + var res V1CSIVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_capabilities.go b/pkg/client/generated/models/v1_capabilities.go new file mode 100644 index 0000000000..d57afd3183 --- /dev/null +++ b/pkg/client/generated/models/v1_capabilities.go @@ -0,0 +1,54 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Capabilities v1 capabilities +// +// swagger:model V1Capabilities +type V1Capabilities struct { + + // Added capabilities + // +optional + // +listType=atomic + Add []string `json:"add"` + + // Removed capabilities + // +optional + // +listType=atomic + Drop []string `json:"drop"` +} + +// Validate validates this v1 capabilities +func (m *V1Capabilities) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 capabilities based on context it is used +func (m *V1Capabilities) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1Capabilities) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Capabilities) UnmarshalBinary(b []byte) error { + var res V1Capabilities + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_ceph_f_s_volume_source.go b/pkg/client/generated/models/v1_ceph_f_s_volume_source.go new file mode 100644 index 0000000000..3d65e9d4c6 --- /dev/null +++ b/pkg/client/generated/models/v1_ceph_f_s_volume_source.go @@ -0,0 +1,108 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1CephFSVolumeSource v1 ceph f s volume source +// +// swagger:model V1CephFSVolumeSource +type V1CephFSVolumeSource struct { + + // monitors is Required: Monitors is a collection of Ceph monitors + // More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + // +listType=atomic + Monitors []string `json:"monitors"` + + // path is Optional: Used as the mounted root, rather than the full Ceph tree, default is / + // +optional + Path string `json:"path,omitempty"` + + // readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + // More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + // +optional + SecretFile string `json:"secretFile,omitempty"` + + // secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + // More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + // +optional + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` + + // user is optional: User is the rados user name, default is admin + // More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + // +optional + User string `json:"user,omitempty"` +} + +// Validate validates this v1 ceph f s volume source +func (m *V1CephFSVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CephFSVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 ceph f s volume source based on the context it is used +func (m *V1CephFSVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CephFSVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1CephFSVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1CephFSVolumeSource) UnmarshalBinary(b []byte) error { + var res V1CephFSVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_cinder_volume_source.go b/pkg/client/generated/models/v1_cinder_volume_source.go new file mode 100644 index 0000000000..e27f26a7a2 --- /dev/null +++ b/pkg/client/generated/models/v1_cinder_volume_source.go @@ -0,0 +1,100 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1CinderVolumeSource v1 cinder volume source +// +// swagger:model V1CinderVolumeSource +type V1CinderVolumeSource struct { + + // fsType is the filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://examples.k8s.io/mysql-cinder-pd/README.md + // +optional + FsType string `json:"fsType,omitempty"` + + // readOnly defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // More info: https://examples.k8s.io/mysql-cinder-pd/README.md + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretRef is optional: points to a secret object containing parameters used to connect + // to OpenStack. + // +optional + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` + + // volumeID used to identify the volume in cinder. + // More info: https://examples.k8s.io/mysql-cinder-pd/README.md + VolumeID string `json:"volumeID,omitempty"` +} + +// Validate validates this v1 cinder volume source +func (m *V1CinderVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CinderVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 cinder volume source based on the context it is used +func (m *V1CinderVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1CinderVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1CinderVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1CinderVolumeSource) UnmarshalBinary(b []byte) error { + var res V1CinderVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_cluster_trust_bundle_projection.go b/pkg/client/generated/models/v1_cluster_trust_bundle_projection.go new file mode 100644 index 0000000000..5cc5583a42 --- /dev/null +++ b/pkg/client/generated/models/v1_cluster_trust_bundle_projection.go @@ -0,0 +1,107 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ClusterTrustBundleProjection v1 cluster trust bundle projection +// +// swagger:model V1ClusterTrustBundleProjection +type V1ClusterTrustBundleProjection struct { + + // Select all ClusterTrustBundles that match this label selector. Only has + // effect if signerName is set. Mutually-exclusive with name. If unset, + // interpreted as "match nothing". If set but empty, interpreted as "match + // everything". + // +optional + LabelSelector struct { + V1LabelSelector + } `json:"labelSelector,omitempty"` + + // Select a single ClusterTrustBundle by object name. Mutually-exclusive + // with signerName and labelSelector. + // +optional + Name string `json:"name,omitempty"` + + // If true, don't block pod startup if the referenced ClusterTrustBundle(s) + // aren't available. If using name, then the named ClusterTrustBundle is + // allowed not to exist. If using signerName, then the combination of + // signerName and labelSelector is allowed to match zero + // ClusterTrustBundles. + // +optional + Optional bool `json:"optional,omitempty"` + + // Relative path from the volume root to write the bundle. + Path string `json:"path,omitempty"` + + // Select all ClusterTrustBundles that match this signer name. + // Mutually-exclusive with name. The contents of all selected + // ClusterTrustBundles will be unified and deduplicated. + // +optional + SignerName string `json:"signerName,omitempty"` +} + +// Validate validates this v1 cluster trust bundle projection +func (m *V1ClusterTrustBundleProjection) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLabelSelector(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ClusterTrustBundleProjection) validateLabelSelector(formats strfmt.Registry) error { + if swag.IsZero(m.LabelSelector) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 cluster trust bundle projection based on the context it is used +func (m *V1ClusterTrustBundleProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateLabelSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ClusterTrustBundleProjection) contextValidateLabelSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ClusterTrustBundleProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ClusterTrustBundleProjection) UnmarshalBinary(b []byte) error { + var res V1ClusterTrustBundleProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_completion_mode.go b/pkg/client/generated/models/v1_completion_mode.go new file mode 100644 index 0000000000..487d7c9a74 --- /dev/null +++ b/pkg/client/generated/models/v1_completion_mode.go @@ -0,0 +1,75 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// V1CompletionMode v1 completion mode +// +// swagger:model V1CompletionMode +type V1CompletionMode string + +func NewV1CompletionMode(value V1CompletionMode) *V1CompletionMode { + return &value +} + +// Pointer returns a pointer to a freshly-allocated V1CompletionMode. +func (m V1CompletionMode) Pointer() *V1CompletionMode { + return &m +} + +const ( + + // V1CompletionModeNonIndexed captures enum value "NonIndexed" + V1CompletionModeNonIndexed V1CompletionMode = "NonIndexed" + + // V1CompletionModeIndexed captures enum value "Indexed" + V1CompletionModeIndexed V1CompletionMode = "Indexed" +) + +// for schema +var v1CompletionModeEnum []any + +func init() { + var res []V1CompletionMode + if err := json.Unmarshal([]byte(`["NonIndexed","Indexed"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + v1CompletionModeEnum = append(v1CompletionModeEnum, v) + } +} + +func (m V1CompletionMode) validateV1CompletionModeEnum(path, location string, value V1CompletionMode) error { + if err := validate.EnumCase(path, location, value, v1CompletionModeEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this v1 completion mode +func (m V1CompletionMode) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateV1CompletionModeEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this v1 completion mode based on context it is used +func (m V1CompletionMode) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/pkg/client/generated/models/v1_condition.go b/pkg/client/generated/models/v1_condition.go new file mode 100644 index 0000000000..4406766394 --- /dev/null +++ b/pkg/client/generated/models/v1_condition.go @@ -0,0 +1,172 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// V1Condition v1 condition +// +// swagger:model V1Condition +type V1Condition struct { + + // lastTransitionTime is the 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. + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Format=date-time + // Required: true + LastTransitionTime *string `json:"lastTransitionTime"` + + // message is a human readable message indicating details about the transition. + // This may be an empty string. + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:MaxLength=32768 + // Required: true + Message *string `json:"message"` + + // observedGeneration represents the .metadata.generation that the condition was set based upon. + // For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + // with respect to the current state of the instance. + // +optional + // +kubebuilder:validation:Minimum=0 + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // reason contains a programmatic identifier indicating the reason for the condition's last transition. + // Producers of specific condition types may define expected values and meanings for this field, + // and whether the values are considered a guaranteed API. + // The value should be a CamelCase string. + // This field may not be empty. + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:MaxLength=1024 + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$` + // Required: true + Reason *string `json:"reason"` + + // status of the condition, one of True, False, Unknown. + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:Enum=True;False;Unknown + // Required: true + Status *string `json:"status"` + + // 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. + // The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$` + // +kubebuilder:validation:MaxLength=316 + // Required: true + Type *string `json:"type"` +} + +// Validate validates this v1 condition +func (m *V1Condition) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLastTransitionTime(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMessage(formats); err != nil { + res = append(res, err) + } + + if err := m.validateReason(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if err := m.validateType(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Condition) validateLastTransitionTime(formats strfmt.Registry) error { + + if err := validate.Required("lastTransitionTime", "body", m.LastTransitionTime); err != nil { + return err + } + + return nil +} + +func (m *V1Condition) validateMessage(formats strfmt.Registry) error { + + if err := validate.Required("message", "body", m.Message); err != nil { + return err + } + + return nil +} + +func (m *V1Condition) validateReason(formats strfmt.Registry) error { + + if err := validate.Required("reason", "body", m.Reason); err != nil { + return err + } + + return nil +} + +func (m *V1Condition) validateStatus(formats strfmt.Registry) error { + + if err := validate.Required("status", "body", m.Status); err != nil { + return err + } + + return nil +} + +func (m *V1Condition) validateType(formats strfmt.Registry) error { + + if err := validate.Required("type", "body", m.Type); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this v1 condition based on context it is used +func (m *V1Condition) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1Condition) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Condition) UnmarshalBinary(b []byte) error { + var res V1Condition + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_config_map.go b/pkg/client/generated/models/v1_config_map.go new file mode 100644 index 0000000000..4685cbf60f --- /dev/null +++ b/pkg/client/generated/models/v1_config_map.go @@ -0,0 +1,123 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ConfigMap v1 config map +// +// swagger:model V1ConfigMap +type V1ConfigMap struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // BinaryData contains the binary data. + // Each key must consist of alphanumeric characters, '-', '_' or '.'. + // BinaryData can contain byte sequences that are not in the UTF-8 range. + // The keys stored in BinaryData must not overlap with the ones in + // the Data field, this is enforced during validation process. + // Using this field will require 1.10+ apiserver and + // kubelet. + // +optional + BinaryData map[string]strfmt.Base64 `json:"binaryData,omitempty"` + + // Data contains the configuration data. + // Each key must consist of alphanumeric characters, '-', '_' or '.'. + // Values with non-UTF-8 byte sequences must use the BinaryData field. + // The keys stored in Data must not overlap with the keys in + // the BinaryData field, this is enforced during validation process. + // +optional + Data map[string]string `json:"data,omitempty"` + + // Immutable, if set to true, ensures that data stored in the ConfigMap cannot + // be updated (only object metadata can be modified). + // If not set to true, the field can be modified at any time. + // Defaulted to nil. + // +optional + Immutable bool `json:"immutable,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + Metadata struct { + V1ObjectMeta + } `json:"metadata,omitempty"` +} + +// Validate validates this v1 config map +func (m *V1ConfigMap) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMap) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 config map based on the context it is used +func (m *V1ConfigMap) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMap) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ConfigMap) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ConfigMap) UnmarshalBinary(b []byte) error { + var res V1ConfigMap + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_config_map_env_source.go b/pkg/client/generated/models/v1_config_map_env_source.go new file mode 100644 index 0000000000..3f8add81ec --- /dev/null +++ b/pkg/client/generated/models/v1_config_map_env_source.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ConfigMapEnvSource v1 config map env source +// +// swagger:model V1ConfigMapEnvSource +type V1ConfigMapEnvSource struct { + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // Specify whether the ConfigMap must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 config map env source +func (m *V1ConfigMapEnvSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 config map env source based on context it is used +func (m *V1ConfigMapEnvSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ConfigMapEnvSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ConfigMapEnvSource) UnmarshalBinary(b []byte) error { + var res V1ConfigMapEnvSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_config_map_key_selector.go b/pkg/client/generated/models/v1_config_map_key_selector.go new file mode 100644 index 0000000000..975baac47f --- /dev/null +++ b/pkg/client/generated/models/v1_config_map_key_selector.go @@ -0,0 +1,62 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ConfigMapKeySelector v1 config map key selector +// +// swagger:model V1ConfigMapKeySelector +type V1ConfigMapKeySelector struct { + + // The key to select. + Key string `json:"key,omitempty"` + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // Specify whether the ConfigMap or its key must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 config map key selector +func (m *V1ConfigMapKeySelector) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 config map key selector based on context it is used +func (m *V1ConfigMapKeySelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ConfigMapKeySelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ConfigMapKeySelector) UnmarshalBinary(b []byte) error { + var res V1ConfigMapKeySelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_config_map_list.go b/pkg/client/generated/models/v1_config_map_list.go new file mode 100644 index 0000000000..49048206b5 --- /dev/null +++ b/pkg/client/generated/models/v1_config_map_list.go @@ -0,0 +1,169 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ConfigMapList v1 config map list +// +// swagger:model V1ConfigMapList +type V1ConfigMapList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Items is the list of ConfigMaps. + Items []*V1ConfigMap `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + Metadata struct { + V1ListMeta + } `json:"metadata,omitempty"` +} + +// Validate validates this v1 config map list +func (m *V1ConfigMapList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMapList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1ConfigMapList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 config map list based on the context it is used +func (m *V1ConfigMapList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMapList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1ConfigMapList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ConfigMapList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ConfigMapList) UnmarshalBinary(b []byte) error { + var res V1ConfigMapList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_config_map_projection.go b/pkg/client/generated/models/v1_config_map_projection.go new file mode 100644 index 0000000000..f8b3f4508e --- /dev/null +++ b/pkg/client/generated/models/v1_config_map_projection.go @@ -0,0 +1,150 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ConfigMapProjection v1 config map projection +// +// swagger:model V1ConfigMapProjection +type V1ConfigMapProjection struct { + + // items if unspecified, each key-value pair in the Data field of the referenced + // ConfigMap will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the ConfigMap, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + // +listType=atomic + Items []*V1KeyToPath `json:"items"` + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // optional specify whether the ConfigMap or its keys must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 config map projection +func (m *V1ConfigMapProjection) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMapProjection) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 config map projection based on the context it is used +func (m *V1ConfigMapProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMapProjection) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ConfigMapProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ConfigMapProjection) UnmarshalBinary(b []byte) error { + var res V1ConfigMapProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_config_map_volume_source.go b/pkg/client/generated/models/v1_config_map_volume_source.go new file mode 100644 index 0000000000..0c226fe015 --- /dev/null +++ b/pkg/client/generated/models/v1_config_map_volume_source.go @@ -0,0 +1,160 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ConfigMapVolumeSource v1 config map volume source +// +// swagger:model V1ConfigMapVolumeSource +type V1ConfigMapVolumeSource struct { + + // defaultMode is optional: mode bits used to set permissions on created files by default. + // Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + // YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + // Defaults to 0644. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode int64 `json:"defaultMode,omitempty"` + + // items if unspecified, each key-value pair in the Data field of the referenced + // ConfigMap will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the ConfigMap, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + // +listType=atomic + Items []*V1KeyToPath `json:"items"` + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // optional specify whether the ConfigMap or its keys must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 config map volume source +func (m *V1ConfigMapVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMapVolumeSource) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 config map volume source based on the context it is used +func (m *V1ConfigMapVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ConfigMapVolumeSource) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ConfigMapVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ConfigMapVolumeSource) UnmarshalBinary(b []byte) error { + var res V1ConfigMapVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_container.go b/pkg/client/generated/models/v1_container.go new file mode 100644 index 0000000000..9f2dee6cf1 --- /dev/null +++ b/pkg/client/generated/models/v1_container.go @@ -0,0 +1,889 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Container v1 container +// +// swagger:model V1Container +type V1Container struct { + + // Arguments to the entrypoint. + // The container image's CMD is used if this is not provided. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. Cannot be updated. + // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + // +optional + // +listType=atomic + Args []string `json:"args"` + + // Entrypoint array. Not executed within a shell. + // The container image's ENTRYPOINT is used if this is not provided. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. Cannot be updated. + // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + // +optional + // +listType=atomic + Command []string `json:"command"` + + // List of environment variables to set in the container. + // Cannot be updated. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + Env []*V1EnvVar `json:"env"` + + // List of sources to populate environment variables in the container. + // The keys defined within a source may consist of any printable ASCII characters except '='. + // When a key exists in multiple + // sources, the value associated with the last source will take precedence. + // Values defined by an Env with a duplicate key will take precedence. + // Cannot be updated. + // +optional + // +listType=atomic + EnvFrom []*V1EnvFromSource `json:"envFrom"` + + // Container image name. + // More info: https://kubernetes.io/docs/concepts/containers/images + // This field is optional to allow higher level config management to default or override + // container images in workload controllers like Deployments and StatefulSets. + // +optional + Image string `json:"image,omitempty"` + + // Image pull policy. + // One of Always, Never, IfNotPresent. + // Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + // +optional + ImagePullPolicy string `json:"imagePullPolicy,omitempty"` + + // Actions that the management system should take in response to container lifecycle events. + // Cannot be updated. + // +optional + Lifecycle struct { + V1Lifecycle + } `json:"lifecycle,omitempty"` + + // Periodic probe of container liveness. + // Container will be restarted if the probe fails. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + LivenessProbe struct { + V1Probe + } `json:"livenessProbe,omitempty"` + + // Name of the container specified as a DNS_LABEL. + // Each container in a pod must have a unique name (DNS_LABEL). + // Cannot be updated. + Name string `json:"name,omitempty"` + + // List of ports to expose from the container. Not specifying a port here + // DOES NOT prevent that port from being exposed. Any port which is + // listening on the default "0.0.0.0" address inside a container will be + // accessible from the network. + // Modifying this array with strategic merge patch may corrupt the data. + // For more information See https://github.com/kubernetes/kubernetes/issues/108255. + // Cannot be updated. + // +optional + // +patchMergeKey=containerPort + // +patchStrategy=merge + // +listType=map + // +listMapKey=containerPort + // +listMapKey=protocol + Ports []*V1ContainerPort `json:"ports"` + + // Periodic probe of container service readiness. + // Container will be removed from service endpoints if the probe fails. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + ReadinessProbe struct { + V1Probe + } `json:"readinessProbe,omitempty"` + + // Resources resize policy for the container. + // +featureGate=InPlacePodVerticalScaling + // +optional + // +listType=atomic + ResizePolicy []*V1ContainerResizePolicy `json:"resizePolicy"` + + // Compute Resources required by this container. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // +optional + Resources struct { + V1ResourceRequirements + } `json:"resources,omitempty"` + + // RestartPolicy defines the restart behavior of individual containers in a pod. + // This overrides the pod-level restart policy. When this field is not specified, + // the restart behavior is defined by the Pod's restart policy and the container type. + // Additionally, setting the RestartPolicy as "Always" for the init container will + // have the following effect: + // this init container will be continually restarted on + // exit until all regular containers have terminated. Once all regular + // containers have completed, all init containers with restartPolicy "Always" + // will be shut down. This lifecycle differs from normal init containers and + // is often referred to as a "sidecar" container. Although this init + // container still starts in the init container sequence, it does not wait + // for the container to complete before proceeding to the next init + // container. Instead, the next init container starts immediately after this + // init container is started, or after any startupProbe has successfully + // completed. + // +featureGate=SidecarContainers + // +optional + RestartPolicy string `json:"restartPolicy,omitempty"` + + // Represents a list of rules to be checked to determine if the + // container should be restarted on exit. The rules are evaluated in + // order. Once a rule matches a container exit condition, the remaining + // rules are ignored. If no rule matches the container exit condition, + // the Container-level restart policy determines the whether the container + // is restarted or not. Constraints on the rules: + // - At most 20 rules are allowed. + // - Rules can have the same action. + // - Identical rules are not forbidden in validations. + // When rules are specified, container MUST set RestartPolicy explicitly + // even it if matches the Pod's RestartPolicy. + // +featureGate=ContainerRestartRules + // +optional + // +listType=atomic + RestartPolicyRules []*V1ContainerRestartRule `json:"restartPolicyRules"` + + // SecurityContext defines the security options the container should be run with. + // If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + // +optional + SecurityContext struct { + V1SecurityContext + } `json:"securityContext,omitempty"` + + // StartupProbe indicates that the Pod has successfully initialized. + // If specified, no other probes are executed until this completes successfully. + // If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + // This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + // when it might take a long time to load data or warm a cache, than during steady-state operation. + // This cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + StartupProbe struct { + V1Probe + } `json:"startupProbe,omitempty"` + + // Whether this container should allocate a buffer for stdin in the container runtime. If this + // is not set, reads from stdin in the container will always result in EOF. + // Default is false. + // +optional + Stdin bool `json:"stdin,omitempty"` + + // Whether the container runtime should close the stdin channel after it has been opened by + // a single attach. When stdin is true the stdin stream will remain open across multiple attach + // sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + // first client attaches to stdin, and then remains open and accepts data until the client disconnects, + // at which time stdin is closed and remains closed until the container is restarted. If this + // flag is false, a container processes that reads from stdin will never receive an EOF. + // Default is false + // +optional + StdinOnce bool `json:"stdinOnce,omitempty"` + + // Optional: Path at which the file to which the container's termination message + // will be written is mounted into the container's filesystem. + // Message written is intended to be brief final status, such as an assertion failure message. + // Will be truncated by the node if greater than 4096 bytes. The total message length across + // all containers will be limited to 12kb. + // Defaults to /dev/termination-log. + // Cannot be updated. + // +optional + TerminationMessagePath string `json:"terminationMessagePath,omitempty"` + + // Indicate how the termination message should be populated. File will use the contents of + // terminationMessagePath to populate the container status message on both success and failure. + // FallbackToLogsOnError will use the last chunk of container log output if the termination + // message file is empty and the container exited with an error. + // The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + // Defaults to File. + // Cannot be updated. + // +optional + TerminationMessagePolicy string `json:"terminationMessagePolicy,omitempty"` + + // Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + // Default is false. + // +optional + Tty bool `json:"tty,omitempty"` + + // volumeDevices is the list of block devices to be used by the container. + // +patchMergeKey=devicePath + // +patchStrategy=merge + // +listType=map + // +listMapKey=devicePath + // +optional + VolumeDevices []*V1VolumeDevice `json:"volumeDevices"` + + // Pod volumes to mount into the container's filesystem. + // Cannot be updated. + // +optional + // +patchMergeKey=mountPath + // +patchStrategy=merge + // +listType=map + // +listMapKey=mountPath + VolumeMounts []*V1VolumeMount `json:"volumeMounts"` + + // Container's working directory. + // If not specified, the container runtime's default will be used, which + // might be configured in the container image. + // Cannot be updated. + // +optional + WorkingDir string `json:"workingDir,omitempty"` +} + +// Validate validates this v1 container +func (m *V1Container) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateEnv(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEnvFrom(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLifecycle(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLivenessProbe(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePorts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateReadinessProbe(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResizePolicy(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResources(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRestartPolicyRules(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecurityContext(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStartupProbe(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVolumeDevices(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVolumeMounts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Container) validateEnv(formats strfmt.Registry) error { + if swag.IsZero(m.Env) { // not required + return nil + } + + for i := 0; i < len(m.Env); i++ { + if swag.IsZero(m.Env[i]) { // not required + continue + } + + if m.Env[i] != nil { + if err := m.Env[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("env" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("env" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) validateEnvFrom(formats strfmt.Registry) error { + if swag.IsZero(m.EnvFrom) { // not required + return nil + } + + for i := 0; i < len(m.EnvFrom); i++ { + if swag.IsZero(m.EnvFrom[i]) { // not required + continue + } + + if m.EnvFrom[i] != nil { + if err := m.EnvFrom[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) validateLifecycle(formats strfmt.Registry) error { + if swag.IsZero(m.Lifecycle) { // not required + return nil + } + + return nil +} + +func (m *V1Container) validateLivenessProbe(formats strfmt.Registry) error { + if swag.IsZero(m.LivenessProbe) { // not required + return nil + } + + return nil +} + +func (m *V1Container) validatePorts(formats strfmt.Registry) error { + if swag.IsZero(m.Ports) { // not required + return nil + } + + for i := 0; i < len(m.Ports); i++ { + if swag.IsZero(m.Ports[i]) { // not required + continue + } + + if m.Ports[i] != nil { + if err := m.Ports[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ports" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ports" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) validateReadinessProbe(formats strfmt.Registry) error { + if swag.IsZero(m.ReadinessProbe) { // not required + return nil + } + + return nil +} + +func (m *V1Container) validateResizePolicy(formats strfmt.Registry) error { + if swag.IsZero(m.ResizePolicy) { // not required + return nil + } + + for i := 0; i < len(m.ResizePolicy); i++ { + if swag.IsZero(m.ResizePolicy[i]) { // not required + continue + } + + if m.ResizePolicy[i] != nil { + if err := m.ResizePolicy[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) validateResources(formats strfmt.Registry) error { + if swag.IsZero(m.Resources) { // not required + return nil + } + + return nil +} + +func (m *V1Container) validateRestartPolicyRules(formats strfmt.Registry) error { + if swag.IsZero(m.RestartPolicyRules) { // not required + return nil + } + + for i := 0; i < len(m.RestartPolicyRules); i++ { + if swag.IsZero(m.RestartPolicyRules[i]) { // not required + continue + } + + if m.RestartPolicyRules[i] != nil { + if err := m.RestartPolicyRules[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) validateSecurityContext(formats strfmt.Registry) error { + if swag.IsZero(m.SecurityContext) { // not required + return nil + } + + return nil +} + +func (m *V1Container) validateStartupProbe(formats strfmt.Registry) error { + if swag.IsZero(m.StartupProbe) { // not required + return nil + } + + return nil +} + +func (m *V1Container) validateVolumeDevices(formats strfmt.Registry) error { + if swag.IsZero(m.VolumeDevices) { // not required + return nil + } + + for i := 0; i < len(m.VolumeDevices); i++ { + if swag.IsZero(m.VolumeDevices[i]) { // not required + continue + } + + if m.VolumeDevices[i] != nil { + if err := m.VolumeDevices[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) validateVolumeMounts(formats strfmt.Registry) error { + if swag.IsZero(m.VolumeMounts) { // not required + return nil + } + + for i := 0; i < len(m.VolumeMounts); i++ { + if swag.IsZero(m.VolumeMounts[i]) { // not required + continue + } + + if m.VolumeMounts[i] != nil { + if err := m.VolumeMounts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 container based on the context it is used +func (m *V1Container) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateEnv(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateEnvFrom(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLifecycle(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLivenessProbe(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePorts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateReadinessProbe(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResizePolicy(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResources(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRestartPolicyRules(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecurityContext(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStartupProbe(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVolumeDevices(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVolumeMounts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Container) contextValidateEnv(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Env); i++ { + + if m.Env[i] != nil { + + if swag.IsZero(m.Env[i]) { // not required + return nil + } + + if err := m.Env[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("env" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("env" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) contextValidateEnvFrom(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.EnvFrom); i++ { + + if m.EnvFrom[i] != nil { + + if swag.IsZero(m.EnvFrom[i]) { // not required + return nil + } + + if err := m.EnvFrom[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) contextValidateLifecycle(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Container) contextValidateLivenessProbe(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Container) contextValidatePorts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Ports); i++ { + + if m.Ports[i] != nil { + + if swag.IsZero(m.Ports[i]) { // not required + return nil + } + + if err := m.Ports[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ports" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ports" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) contextValidateReadinessProbe(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Container) contextValidateResizePolicy(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ResizePolicy); i++ { + + if m.ResizePolicy[i] != nil { + + if swag.IsZero(m.ResizePolicy[i]) { // not required + return nil + } + + if err := m.ResizePolicy[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) contextValidateResources(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Container) contextValidateRestartPolicyRules(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.RestartPolicyRules); i++ { + + if m.RestartPolicyRules[i] != nil { + + if swag.IsZero(m.RestartPolicyRules[i]) { // not required + return nil + } + + if err := m.RestartPolicyRules[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Container) contextValidateStartupProbe(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Container) contextValidateVolumeDevices(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.VolumeDevices); i++ { + + if m.VolumeDevices[i] != nil { + + if swag.IsZero(m.VolumeDevices[i]) { // not required + return nil + } + + if err := m.VolumeDevices[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1Container) contextValidateVolumeMounts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.VolumeMounts); i++ { + + if m.VolumeMounts[i] != nil { + + if swag.IsZero(m.VolumeMounts[i]) { // not required + return nil + } + + if err := m.VolumeMounts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Container) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Container) UnmarshalBinary(b []byte) error { + var res V1Container + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_container_port.go b/pkg/client/generated/models/v1_container_port.go new file mode 100644 index 0000000000..0705e9f2f8 --- /dev/null +++ b/pkg/client/generated/models/v1_container_port.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ContainerPort v1 container port +// +// swagger:model V1ContainerPort +type V1ContainerPort struct { + + // Number of port to expose on the pod's IP address. + // This must be a valid port number, 0 < x < 65536. + ContainerPort int64 `json:"containerPort,omitempty"` + + // What host IP to bind the external port to. + // +optional + HostIP string `json:"hostIP,omitempty"` + + // Number of port to expose on the host. + // If specified, this must be a valid port number, 0 < x < 65536. + // If HostNetwork is specified, this must match ContainerPort. + // Most containers do not need this. + // +optional + HostPort int64 `json:"hostPort,omitempty"` + + // If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + // named port in a pod must have a unique name. Name for the port that can be + // referred to by services. + // +optional + Name string `json:"name,omitempty"` + + // Protocol for port. Must be UDP, TCP, or SCTP. + // Defaults to "TCP". + // +optional + // +default="TCP" + Protocol string `json:"protocol,omitempty"` +} + +// Validate validates this v1 container port +func (m *V1ContainerPort) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 container port based on context it is used +func (m *V1ContainerPort) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ContainerPort) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ContainerPort) UnmarshalBinary(b []byte) error { + var res V1ContainerPort + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_container_resize_policy.go b/pkg/client/generated/models/v1_container_resize_policy.go new file mode 100644 index 0000000000..5de9f9df92 --- /dev/null +++ b/pkg/client/generated/models/v1_container_resize_policy.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ContainerResizePolicy v1 container resize policy +// +// swagger:model V1ContainerResizePolicy +type V1ContainerResizePolicy struct { + + // Name of the resource to which this resource resize policy applies. + // Supported values: cpu, memory. + ResourceName string `json:"resourceName,omitempty"` + + // Restart policy to apply when specified resource is resized. + // If not specified, it defaults to NotRequired. + RestartPolicy string `json:"restartPolicy,omitempty"` +} + +// Validate validates this v1 container resize policy +func (m *V1ContainerResizePolicy) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 container resize policy based on context it is used +func (m *V1ContainerResizePolicy) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ContainerResizePolicy) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ContainerResizePolicy) UnmarshalBinary(b []byte) error { + var res V1ContainerResizePolicy + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_container_restart_rule.go b/pkg/client/generated/models/v1_container_restart_rule.go new file mode 100644 index 0000000000..23a1bce237 --- /dev/null +++ b/pkg/client/generated/models/v1_container_restart_rule.go @@ -0,0 +1,89 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ContainerRestartRule v1 container restart rule +// +// swagger:model V1ContainerRestartRule +type V1ContainerRestartRule struct { + + // Specifies the action taken on a container exit if the requirements + // are satisfied. The only possible value is "Restart" to restart the + // container. + // +required + Action string `json:"action,omitempty"` + + // Represents the exit codes to check on container exits. + // +optional + // +oneOf=when + ExitCodes struct { + V1ContainerRestartRuleOnExitCodes + } `json:"exitCodes,omitempty"` +} + +// Validate validates this v1 container restart rule +func (m *V1ContainerRestartRule) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateExitCodes(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ContainerRestartRule) validateExitCodes(formats strfmt.Registry) error { + if swag.IsZero(m.ExitCodes) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 container restart rule based on the context it is used +func (m *V1ContainerRestartRule) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateExitCodes(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ContainerRestartRule) contextValidateExitCodes(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ContainerRestartRule) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ContainerRestartRule) UnmarshalBinary(b []byte) error { + var res V1ContainerRestartRule + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_container_restart_rule_on_exit_codes.go b/pkg/client/generated/models/v1_container_restart_rule_on_exit_codes.go new file mode 100644 index 0000000000..3a7a8f7ec3 --- /dev/null +++ b/pkg/client/generated/models/v1_container_restart_rule_on_exit_codes.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ContainerRestartRuleOnExitCodes v1 container restart rule on exit codes +// +// swagger:model V1ContainerRestartRuleOnExitCodes +type V1ContainerRestartRuleOnExitCodes struct { + + // Represents the relationship between the container exit code(s) and the + // specified values. Possible values are: + // - In: the requirement is satisfied if the container exit code is in the + // set of specified values. + // - NotIn: the requirement is satisfied if the container exit code is + // not in the set of specified values. + // +required + Operator string `json:"operator,omitempty"` + + // Specifies the set of values to check for container exit codes. + // At most 255 elements are allowed. + // +optional + // +listType=set + Values []int64 `json:"values"` +} + +// Validate validates this v1 container restart rule on exit codes +func (m *V1ContainerRestartRuleOnExitCodes) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 container restart rule on exit codes based on context it is used +func (m *V1ContainerRestartRuleOnExitCodes) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ContainerRestartRuleOnExitCodes) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ContainerRestartRuleOnExitCodes) UnmarshalBinary(b []byte) error { + var res V1ContainerRestartRuleOnExitCodes + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_downward_api_projection.go b/pkg/client/generated/models/v1_downward_api_projection.go new file mode 100644 index 0000000000..7efffc2d30 --- /dev/null +++ b/pkg/client/generated/models/v1_downward_api_projection.go @@ -0,0 +1,129 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1DownwardAPIProjection v1 downward API projection +// +// swagger:model V1DownwardAPIProjection +type V1DownwardAPIProjection struct { + + // Items is a list of DownwardAPIVolume file + // +optional + // +listType=atomic + Items []*V1DownwardAPIVolumeFile `json:"items"` +} + +// Validate validates this v1 downward API projection +func (m *V1DownwardAPIProjection) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1DownwardAPIProjection) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 downward API projection based on the context it is used +func (m *V1DownwardAPIProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1DownwardAPIProjection) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1DownwardAPIProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1DownwardAPIProjection) UnmarshalBinary(b []byte) error { + var res V1DownwardAPIProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_downward_api_volume_file.go b/pkg/client/generated/models/v1_downward_api_volume_file.go new file mode 100644 index 0000000000..d00c06f783 --- /dev/null +++ b/pkg/client/generated/models/v1_downward_api_volume_file.go @@ -0,0 +1,122 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1DownwardAPIVolumeFile v1 downward API volume file +// +// swagger:model V1DownwardAPIVolumeFile +type V1DownwardAPIVolumeFile struct { + + // Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported. + // +optional + FieldRef struct { + V1ObjectFieldSelector + } `json:"fieldRef,omitempty"` + + // Optional: mode bits used to set permissions on this file, must be an octal value + // between 0000 and 0777 or a decimal value between 0 and 511. + // YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + // If not specified, the volume defaultMode will be used. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + Mode int64 `json:"mode,omitempty"` + + // Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' + Path string `json:"path,omitempty"` + + // Selects a resource of the container: only resources limits and requests + // (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + // +optional + ResourceFieldRef struct { + V1ResourceFieldSelector + } `json:"resourceFieldRef,omitempty"` +} + +// Validate validates this v1 downward API volume file +func (m *V1DownwardAPIVolumeFile) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFieldRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResourceFieldRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1DownwardAPIVolumeFile) validateFieldRef(formats strfmt.Registry) error { + if swag.IsZero(m.FieldRef) { // not required + return nil + } + + return nil +} + +func (m *V1DownwardAPIVolumeFile) validateResourceFieldRef(formats strfmt.Registry) error { + if swag.IsZero(m.ResourceFieldRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 downward API volume file based on the context it is used +func (m *V1DownwardAPIVolumeFile) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateFieldRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResourceFieldRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1DownwardAPIVolumeFile) contextValidateFieldRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1DownwardAPIVolumeFile) contextValidateResourceFieldRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1DownwardAPIVolumeFile) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1DownwardAPIVolumeFile) UnmarshalBinary(b []byte) error { + var res V1DownwardAPIVolumeFile + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_downward_api_volume_source.go b/pkg/client/generated/models/v1_downward_api_volume_source.go new file mode 100644 index 0000000000..288a095e37 --- /dev/null +++ b/pkg/client/generated/models/v1_downward_api_volume_source.go @@ -0,0 +1,140 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1DownwardAPIVolumeSource v1 downward API volume source +// +// swagger:model V1DownwardAPIVolumeSource +type V1DownwardAPIVolumeSource struct { + + // Optional: mode bits to use on created files by default. Must be a + // Optional: mode bits used to set permissions on created files by default. + // Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + // YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + // Defaults to 0644. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode int64 `json:"defaultMode,omitempty"` + + // Items is a list of downward API volume file + // +optional + // +listType=atomic + Items []*V1DownwardAPIVolumeFile `json:"items"` +} + +// Validate validates this v1 downward API volume source +func (m *V1DownwardAPIVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1DownwardAPIVolumeSource) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 downward API volume source based on the context it is used +func (m *V1DownwardAPIVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1DownwardAPIVolumeSource) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1DownwardAPIVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1DownwardAPIVolumeSource) UnmarshalBinary(b []byte) error { + var res V1DownwardAPIVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_empty_dir_volume_source.go b/pkg/client/generated/models/v1_empty_dir_volume_source.go new file mode 100644 index 0000000000..fc1a2c1857 --- /dev/null +++ b/pkg/client/generated/models/v1_empty_dir_volume_source.go @@ -0,0 +1,94 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EmptyDirVolumeSource v1 empty dir volume source +// +// swagger:model V1EmptyDirVolumeSource +type V1EmptyDirVolumeSource struct { + + // medium represents what type of storage medium should back this directory. + // The default is "" which means to use the node's default medium. + // Must be an empty string (default) or Memory. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + // +optional + Medium string `json:"medium,omitempty"` + + // sizeLimit is the total amount of local storage required for this EmptyDir volume. + // The size limit is also applicable for memory medium. + // The maximum usage on memory medium EmptyDir would be the minimum value between + // the SizeLimit specified here and the sum of memory limits of all containers in a pod. + // The default is nil which means that the limit is undefined. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + // +optional + SizeLimit struct { + Quantity + } `json:"sizeLimit,omitempty"` +} + +// Validate validates this v1 empty dir volume source +func (m *V1EmptyDirVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSizeLimit(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EmptyDirVolumeSource) validateSizeLimit(formats strfmt.Registry) error { + if swag.IsZero(m.SizeLimit) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 empty dir volume source based on the context it is used +func (m *V1EmptyDirVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSizeLimit(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EmptyDirVolumeSource) contextValidateSizeLimit(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EmptyDirVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EmptyDirVolumeSource) UnmarshalBinary(b []byte) error { + var res V1EmptyDirVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_env_from_source.go b/pkg/client/generated/models/v1_env_from_source.go new file mode 100644 index 0000000000..0c876f9662 --- /dev/null +++ b/pkg/client/generated/models/v1_env_from_source.go @@ -0,0 +1,114 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EnvFromSource v1 env from source +// +// swagger:model V1EnvFromSource +type V1EnvFromSource struct { + + // The ConfigMap to select from + // +optional + ConfigMapRef struct { + V1ConfigMapEnvSource + } `json:"configMapRef,omitempty"` + + // Optional text to prepend to the name of each environment variable. + // May consist of any printable ASCII characters except '='. + // +optional + Prefix string `json:"prefix,omitempty"` + + // The Secret to select from + // +optional + SecretRef struct { + V1SecretEnvSource + } `json:"secretRef,omitempty"` +} + +// Validate validates this v1 env from source +func (m *V1EnvFromSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConfigMapRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EnvFromSource) validateConfigMapRef(formats strfmt.Registry) error { + if swag.IsZero(m.ConfigMapRef) { // not required + return nil + } + + return nil +} + +func (m *V1EnvFromSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 env from source based on the context it is used +func (m *V1EnvFromSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConfigMapRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EnvFromSource) contextValidateConfigMapRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EnvFromSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EnvFromSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EnvFromSource) UnmarshalBinary(b []byte) error { + var res V1EnvFromSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_env_var.go b/pkg/client/generated/models/v1_env_var.go new file mode 100644 index 0000000000..c147c793ab --- /dev/null +++ b/pkg/client/generated/models/v1_env_var.go @@ -0,0 +1,98 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EnvVar v1 env var +// +// swagger:model V1EnvVar +type V1EnvVar struct { + + // Name of the environment variable. + // May consist of any printable ASCII characters except '='. + Name string `json:"name,omitempty"` + + // Variable references $(VAR_NAME) are expanded + // using the previously defined environment variables in the container and + // any service environment variables. If a variable cannot be resolved, + // the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + // "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + // Escaped references will never be expanded, regardless of whether the variable + // exists or not. + // Defaults to "". + // +optional + Value string `json:"value,omitempty"` + + // Source for the environment variable's value. Cannot be used if value is not empty. + // +optional + ValueFrom struct { + V1EnvVarSource + } `json:"valueFrom,omitempty"` +} + +// Validate validates this v1 env var +func (m *V1EnvVar) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateValueFrom(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EnvVar) validateValueFrom(formats strfmt.Registry) error { + if swag.IsZero(m.ValueFrom) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 env var based on the context it is used +func (m *V1EnvVar) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateValueFrom(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EnvVar) contextValidateValueFrom(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EnvVar) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EnvVar) UnmarshalBinary(b []byte) error { + var res V1EnvVar + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_env_var_source.go b/pkg/client/generated/models/v1_env_var_source.go new file mode 100644 index 0000000000..aa18724134 --- /dev/null +++ b/pkg/client/generated/models/v1_env_var_source.go @@ -0,0 +1,195 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EnvVarSource v1 env var source +// +// swagger:model V1EnvVarSource +type V1EnvVarSource struct { + + // Selects a key of a ConfigMap. + // +optional + ConfigMapKeyRef struct { + V1ConfigMapKeySelector + } `json:"configMapKeyRef,omitempty"` + + // Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + // spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + // +optional + FieldRef struct { + V1ObjectFieldSelector + } `json:"fieldRef,omitempty"` + + // FileKeyRef selects a key of the env file. + // Requires the EnvFiles feature gate to be enabled. + // + // +featureGate=EnvFiles + // +optional + FileKeyRef struct { + V1FileKeySelector + } `json:"fileKeyRef,omitempty"` + + // Selects a resource of the container: only resources limits and requests + // (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + // +optional + ResourceFieldRef struct { + V1ResourceFieldSelector + } `json:"resourceFieldRef,omitempty"` + + // Selects a key of a secret in the pod's namespace + // +optional + SecretKeyRef struct { + V1SecretKeySelector + } `json:"secretKeyRef,omitempty"` +} + +// Validate validates this v1 env var source +func (m *V1EnvVarSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConfigMapKeyRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFieldRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFileKeyRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResourceFieldRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecretKeyRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EnvVarSource) validateConfigMapKeyRef(formats strfmt.Registry) error { + if swag.IsZero(m.ConfigMapKeyRef) { // not required + return nil + } + + return nil +} + +func (m *V1EnvVarSource) validateFieldRef(formats strfmt.Registry) error { + if swag.IsZero(m.FieldRef) { // not required + return nil + } + + return nil +} + +func (m *V1EnvVarSource) validateFileKeyRef(formats strfmt.Registry) error { + if swag.IsZero(m.FileKeyRef) { // not required + return nil + } + + return nil +} + +func (m *V1EnvVarSource) validateResourceFieldRef(formats strfmt.Registry) error { + if swag.IsZero(m.ResourceFieldRef) { // not required + return nil + } + + return nil +} + +func (m *V1EnvVarSource) validateSecretKeyRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretKeyRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 env var source based on the context it is used +func (m *V1EnvVarSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConfigMapKeyRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFieldRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFileKeyRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResourceFieldRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecretKeyRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EnvVarSource) contextValidateConfigMapKeyRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EnvVarSource) contextValidateFieldRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EnvVarSource) contextValidateFileKeyRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EnvVarSource) contextValidateResourceFieldRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EnvVarSource) contextValidateSecretKeyRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EnvVarSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EnvVarSource) UnmarshalBinary(b []byte) error { + var res V1EnvVarSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_ephemeral_container.go b/pkg/client/generated/models/v1_ephemeral_container.go new file mode 100644 index 0000000000..0a0ddc1c03 --- /dev/null +++ b/pkg/client/generated/models/v1_ephemeral_container.go @@ -0,0 +1,853 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EphemeralContainer v1 ephemeral container +// +// swagger:model V1EphemeralContainer +type V1EphemeralContainer struct { + + // Arguments to the entrypoint. + // The image's CMD is used if this is not provided. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. Cannot be updated. + // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + // +optional + // +listType=atomic + Args []string `json:"args"` + + // Entrypoint array. Not executed within a shell. + // The image's ENTRYPOINT is used if this is not provided. + // Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + // cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + // to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + // of whether the variable exists or not. Cannot be updated. + // More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + // +optional + // +listType=atomic + Command []string `json:"command"` + + // List of environment variables to set in the container. + // Cannot be updated. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + Env []*V1EnvVar `json:"env"` + + // List of sources to populate environment variables in the container. + // The keys defined within a source may consist of any printable ASCII characters except '='. + // When a key exists in multiple + // sources, the value associated with the last source will take precedence. + // Values defined by an Env with a duplicate key will take precedence. + // Cannot be updated. + // +optional + // +listType=atomic + EnvFrom []*V1EnvFromSource `json:"envFrom"` + + // Container image name. + // More info: https://kubernetes.io/docs/concepts/containers/images + Image string `json:"image,omitempty"` + + // Image pull policy. + // One of Always, Never, IfNotPresent. + // Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + // +optional + ImagePullPolicy string `json:"imagePullPolicy,omitempty"` + + // Lifecycle is not allowed for ephemeral containers. + // +optional + Lifecycle struct { + V1Lifecycle + } `json:"lifecycle,omitempty"` + + // Probes are not allowed for ephemeral containers. + // +optional + LivenessProbe struct { + V1Probe + } `json:"livenessProbe,omitempty"` + + // Name of the ephemeral container specified as a DNS_LABEL. + // This name must be unique among all containers, init containers and ephemeral containers. + Name string `json:"name,omitempty"` + + // Ports are not allowed for ephemeral containers. + // +optional + // +patchMergeKey=containerPort + // +patchStrategy=merge + // +listType=map + // +listMapKey=containerPort + // +listMapKey=protocol + Ports []*V1ContainerPort `json:"ports"` + + // Probes are not allowed for ephemeral containers. + // +optional + ReadinessProbe struct { + V1Probe + } `json:"readinessProbe,omitempty"` + + // Resources resize policy for the container. + // +featureGate=InPlacePodVerticalScaling + // +optional + // +listType=atomic + ResizePolicy []*V1ContainerResizePolicy `json:"resizePolicy"` + + // Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources + // already allocated to the pod. + // +optional + Resources struct { + V1ResourceRequirements + } `json:"resources,omitempty"` + + // Restart policy for the container to manage the restart behavior of each + // container within a pod. + // You cannot set this field on ephemeral containers. + // +featureGate=SidecarContainers + // +optional + RestartPolicy string `json:"restartPolicy,omitempty"` + + // Represents a list of rules to be checked to determine if the + // container should be restarted on exit. You cannot set this field on + // ephemeral containers. + // +featureGate=ContainerRestartRules + // +optional + // +listType=atomic + RestartPolicyRules []*V1ContainerRestartRule `json:"restartPolicyRules"` + + // Optional: SecurityContext defines the security options the ephemeral container should be run with. + // If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + // +optional + SecurityContext struct { + V1SecurityContext + } `json:"securityContext,omitempty"` + + // Probes are not allowed for ephemeral containers. + // +optional + StartupProbe struct { + V1Probe + } `json:"startupProbe,omitempty"` + + // Whether this container should allocate a buffer for stdin in the container runtime. If this + // is not set, reads from stdin in the container will always result in EOF. + // Default is false. + // +optional + Stdin bool `json:"stdin,omitempty"` + + // Whether the container runtime should close the stdin channel after it has been opened by + // a single attach. When stdin is true the stdin stream will remain open across multiple attach + // sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + // first client attaches to stdin, and then remains open and accepts data until the client disconnects, + // at which time stdin is closed and remains closed until the container is restarted. If this + // flag is false, a container processes that reads from stdin will never receive an EOF. + // Default is false + // +optional + StdinOnce bool `json:"stdinOnce,omitempty"` + + // If set, the name of the container from PodSpec that this ephemeral container targets. + // The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. + // If not set then the ephemeral container uses the namespaces configured in the Pod spec. + // + // The container runtime must implement support for this feature. If the runtime does not + // support namespace targeting then the result of setting this field is undefined. + // +optional + TargetContainerName string `json:"targetContainerName,omitempty"` + + // Optional: Path at which the file to which the container's termination message + // will be written is mounted into the container's filesystem. + // Message written is intended to be brief final status, such as an assertion failure message. + // Will be truncated by the node if greater than 4096 bytes. The total message length across + // all containers will be limited to 12kb. + // Defaults to /dev/termination-log. + // Cannot be updated. + // +optional + TerminationMessagePath string `json:"terminationMessagePath,omitempty"` + + // Indicate how the termination message should be populated. File will use the contents of + // terminationMessagePath to populate the container status message on both success and failure. + // FallbackToLogsOnError will use the last chunk of container log output if the termination + // message file is empty and the container exited with an error. + // The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + // Defaults to File. + // Cannot be updated. + // +optional + TerminationMessagePolicy string `json:"terminationMessagePolicy,omitempty"` + + // Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + // Default is false. + // +optional + Tty bool `json:"tty,omitempty"` + + // volumeDevices is the list of block devices to be used by the container. + // +patchMergeKey=devicePath + // +patchStrategy=merge + // +listType=map + // +listMapKey=devicePath + // +optional + VolumeDevices []*V1VolumeDevice `json:"volumeDevices"` + + // Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. + // Cannot be updated. + // +optional + // +patchMergeKey=mountPath + // +patchStrategy=merge + // +listType=map + // +listMapKey=mountPath + VolumeMounts []*V1VolumeMount `json:"volumeMounts"` + + // Container's working directory. + // If not specified, the container runtime's default will be used, which + // might be configured in the container image. + // Cannot be updated. + // +optional + WorkingDir string `json:"workingDir,omitempty"` +} + +// Validate validates this v1 ephemeral container +func (m *V1EphemeralContainer) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateEnv(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEnvFrom(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLifecycle(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLivenessProbe(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePorts(formats); err != nil { + res = append(res, err) + } + + if err := m.validateReadinessProbe(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResizePolicy(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResources(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRestartPolicyRules(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecurityContext(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStartupProbe(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVolumeDevices(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVolumeMounts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EphemeralContainer) validateEnv(formats strfmt.Registry) error { + if swag.IsZero(m.Env) { // not required + return nil + } + + for i := 0; i < len(m.Env); i++ { + if swag.IsZero(m.Env[i]) { // not required + continue + } + + if m.Env[i] != nil { + if err := m.Env[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("env" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("env" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) validateEnvFrom(formats strfmt.Registry) error { + if swag.IsZero(m.EnvFrom) { // not required + return nil + } + + for i := 0; i < len(m.EnvFrom); i++ { + if swag.IsZero(m.EnvFrom[i]) { // not required + continue + } + + if m.EnvFrom[i] != nil { + if err := m.EnvFrom[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) validateLifecycle(formats strfmt.Registry) error { + if swag.IsZero(m.Lifecycle) { // not required + return nil + } + + return nil +} + +func (m *V1EphemeralContainer) validateLivenessProbe(formats strfmt.Registry) error { + if swag.IsZero(m.LivenessProbe) { // not required + return nil + } + + return nil +} + +func (m *V1EphemeralContainer) validatePorts(formats strfmt.Registry) error { + if swag.IsZero(m.Ports) { // not required + return nil + } + + for i := 0; i < len(m.Ports); i++ { + if swag.IsZero(m.Ports[i]) { // not required + continue + } + + if m.Ports[i] != nil { + if err := m.Ports[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ports" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ports" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) validateReadinessProbe(formats strfmt.Registry) error { + if swag.IsZero(m.ReadinessProbe) { // not required + return nil + } + + return nil +} + +func (m *V1EphemeralContainer) validateResizePolicy(formats strfmt.Registry) error { + if swag.IsZero(m.ResizePolicy) { // not required + return nil + } + + for i := 0; i < len(m.ResizePolicy); i++ { + if swag.IsZero(m.ResizePolicy[i]) { // not required + continue + } + + if m.ResizePolicy[i] != nil { + if err := m.ResizePolicy[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) validateResources(formats strfmt.Registry) error { + if swag.IsZero(m.Resources) { // not required + return nil + } + + return nil +} + +func (m *V1EphemeralContainer) validateRestartPolicyRules(formats strfmt.Registry) error { + if swag.IsZero(m.RestartPolicyRules) { // not required + return nil + } + + for i := 0; i < len(m.RestartPolicyRules); i++ { + if swag.IsZero(m.RestartPolicyRules[i]) { // not required + continue + } + + if m.RestartPolicyRules[i] != nil { + if err := m.RestartPolicyRules[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) validateSecurityContext(formats strfmt.Registry) error { + if swag.IsZero(m.SecurityContext) { // not required + return nil + } + + return nil +} + +func (m *V1EphemeralContainer) validateStartupProbe(formats strfmt.Registry) error { + if swag.IsZero(m.StartupProbe) { // not required + return nil + } + + return nil +} + +func (m *V1EphemeralContainer) validateVolumeDevices(formats strfmt.Registry) error { + if swag.IsZero(m.VolumeDevices) { // not required + return nil + } + + for i := 0; i < len(m.VolumeDevices); i++ { + if swag.IsZero(m.VolumeDevices[i]) { // not required + continue + } + + if m.VolumeDevices[i] != nil { + if err := m.VolumeDevices[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) validateVolumeMounts(formats strfmt.Registry) error { + if swag.IsZero(m.VolumeMounts) { // not required + return nil + } + + for i := 0; i < len(m.VolumeMounts); i++ { + if swag.IsZero(m.VolumeMounts[i]) { // not required + continue + } + + if m.VolumeMounts[i] != nil { + if err := m.VolumeMounts[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 ephemeral container based on the context it is used +func (m *V1EphemeralContainer) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateEnv(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateEnvFrom(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLifecycle(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLivenessProbe(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePorts(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateReadinessProbe(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResizePolicy(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResources(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRestartPolicyRules(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecurityContext(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStartupProbe(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVolumeDevices(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVolumeMounts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EphemeralContainer) contextValidateEnv(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Env); i++ { + + if m.Env[i] != nil { + + if swag.IsZero(m.Env[i]) { // not required + return nil + } + + if err := m.Env[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("env" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("env" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) contextValidateEnvFrom(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.EnvFrom); i++ { + + if m.EnvFrom[i] != nil { + + if swag.IsZero(m.EnvFrom[i]) { // not required + return nil + } + + if err := m.EnvFrom[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("envFrom" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) contextValidateLifecycle(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EphemeralContainer) contextValidateLivenessProbe(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EphemeralContainer) contextValidatePorts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Ports); i++ { + + if m.Ports[i] != nil { + + if swag.IsZero(m.Ports[i]) { // not required + return nil + } + + if err := m.Ports[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ports" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ports" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) contextValidateReadinessProbe(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EphemeralContainer) contextValidateResizePolicy(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ResizePolicy); i++ { + + if m.ResizePolicy[i] != nil { + + if swag.IsZero(m.ResizePolicy[i]) { // not required + return nil + } + + if err := m.ResizePolicy[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("resizePolicy" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) contextValidateResources(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EphemeralContainer) contextValidateRestartPolicyRules(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.RestartPolicyRules); i++ { + + if m.RestartPolicyRules[i] != nil { + + if swag.IsZero(m.RestartPolicyRules[i]) { // not required + return nil + } + + if err := m.RestartPolicyRules[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("restartPolicyRules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EphemeralContainer) contextValidateStartupProbe(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1EphemeralContainer) contextValidateVolumeDevices(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.VolumeDevices); i++ { + + if m.VolumeDevices[i] != nil { + + if swag.IsZero(m.VolumeDevices[i]) { // not required + return nil + } + + if err := m.VolumeDevices[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeDevices" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EphemeralContainer) contextValidateVolumeMounts(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.VolumeMounts); i++ { + + if m.VolumeMounts[i] != nil { + + if swag.IsZero(m.VolumeMounts[i]) { // not required + return nil + } + + if err := m.VolumeMounts[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumeMounts" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EphemeralContainer) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EphemeralContainer) UnmarshalBinary(b []byte) error { + var res V1EphemeralContainer + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_ephemeral_volume_source.go b/pkg/client/generated/models/v1_ephemeral_volume_source.go new file mode 100644 index 0000000000..3ef71c8808 --- /dev/null +++ b/pkg/client/generated/models/v1_ephemeral_volume_source.go @@ -0,0 +1,101 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EphemeralVolumeSource v1 ephemeral volume source +// +// swagger:model V1EphemeralVolumeSource +type V1EphemeralVolumeSource struct { + + // Will be used to create a stand-alone PVC to provision the volume. + // The pod in which this EphemeralVolumeSource is embedded will be the + // owner of the PVC, i.e. the PVC will be deleted together with the + // pod. The name of the PVC will be `-` where + // `` is the name from the `PodSpec.Volumes` array + // entry. Pod validation will reject the pod if the concatenated name + // is not valid for a PVC (for example, too long). + // + // An existing PVC with that name that is not owned by the pod + // will *not* be used for the pod to avoid using an unrelated + // volume by mistake. Starting the pod is then blocked until + // the unrelated PVC is removed. If such a pre-created PVC is + // meant to be used by the pod, the PVC has to updated with an + // owner reference to the pod once the pod exists. Normally + // this should not be necessary, but it may be useful when + // manually reconstructing a broken cluster. + // + // This field is read-only and no changes will be made by Kubernetes + // to the PVC after it has been created. + // + // Required, must not be nil. + VolumeClaimTemplate struct { + V1PersistentVolumeClaimTemplate + } `json:"volumeClaimTemplate,omitempty"` +} + +// Validate validates this v1 ephemeral volume source +func (m *V1EphemeralVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateVolumeClaimTemplate(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EphemeralVolumeSource) validateVolumeClaimTemplate(formats strfmt.Registry) error { + if swag.IsZero(m.VolumeClaimTemplate) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 ephemeral volume source based on the context it is used +func (m *V1EphemeralVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateVolumeClaimTemplate(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EphemeralVolumeSource) contextValidateVolumeClaimTemplate(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EphemeralVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EphemeralVolumeSource) UnmarshalBinary(b []byte) error { + var res V1EphemeralVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_event.go b/pkg/client/generated/models/v1_event.go new file mode 100644 index 0000000000..abef769743 --- /dev/null +++ b/pkg/client/generated/models/v1_event.go @@ -0,0 +1,270 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Event v1 event +// +// swagger:model V1Event +type V1Event struct { + + // What action was taken/failed regarding to the Regarding object. + // +optional + Action string `json:"action,omitempty"` + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // The number of times this event has occurred. + // +optional + Count int64 `json:"count,omitempty"` + + // Time when this Event was first observed. + // +optional + EventTime struct { + V1MicroTime + } `json:"eventTime,omitempty"` + + // The time at which the event was first recorded. (Time of server receipt is in TypeMeta.) + // +optional + FirstTimestamp string `json:"firstTimestamp,omitempty"` + + // The object that this event is about. + InvolvedObject struct { + V1ObjectReference + } `json:"involvedObject,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // The time at which the most recent occurrence of this event was recorded. + // +optional + LastTimestamp string `json:"lastTimestamp,omitempty"` + + // A human-readable description of the status of this operation. + // TODO: decide on maximum length. + // +optional + Message string `json:"message,omitempty"` + + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + Metadata struct { + V1ObjectMeta + } `json:"metadata,omitempty"` + + // This should be a short, machine understandable string that gives the reason + // for the transition into the object's current status. + // TODO: provide exact specification for format. + // +optional + Reason string `json:"reason,omitempty"` + + // Optional secondary object for more complex actions. + // +optional + Related struct { + V1ObjectReference + } `json:"related,omitempty"` + + // Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`. + // +optional + ReportingComponent string `json:"reportingComponent,omitempty"` + + // ID of the controller instance, e.g. `kubelet-xyzf`. + // +optional + ReportingInstance string `json:"reportingInstance,omitempty"` + + // Data about the Event series this event represents or nil if it's a singleton Event. + // +optional + Series struct { + V1EventSeries + } `json:"series,omitempty"` + + // The component reporting this event. Should be a short machine understandable string. + // +optional + Source struct { + V1EventSource + } `json:"source,omitempty"` + + // Type of this event (Normal, Warning), new types could be added in the future + // +optional + Type string `json:"type,omitempty"` +} + +// Validate validates this v1 event +func (m *V1Event) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateEventTime(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInvolvedObject(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRelated(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSeries(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSource(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Event) validateEventTime(formats strfmt.Registry) error { + if swag.IsZero(m.EventTime) { // not required + return nil + } + + return nil +} + +func (m *V1Event) validateInvolvedObject(formats strfmt.Registry) error { + if swag.IsZero(m.InvolvedObject) { // not required + return nil + } + + return nil +} + +func (m *V1Event) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +func (m *V1Event) validateRelated(formats strfmt.Registry) error { + if swag.IsZero(m.Related) { // not required + return nil + } + + return nil +} + +func (m *V1Event) validateSeries(formats strfmt.Registry) error { + if swag.IsZero(m.Series) { // not required + return nil + } + + return nil +} + +func (m *V1Event) validateSource(formats strfmt.Registry) error { + if swag.IsZero(m.Source) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 event based on the context it is used +func (m *V1Event) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateEventTime(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateInvolvedObject(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRelated(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSeries(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSource(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Event) contextValidateEventTime(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Event) contextValidateInvolvedObject(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Event) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Event) contextValidateRelated(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Event) contextValidateSeries(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Event) contextValidateSource(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Event) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Event) UnmarshalBinary(b []byte) error { + var res V1Event + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_event_list.go b/pkg/client/generated/models/v1_event_list.go new file mode 100644 index 0000000000..836e676c1c --- /dev/null +++ b/pkg/client/generated/models/v1_event_list.go @@ -0,0 +1,170 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EventList v1 event list +// +// swagger:model V1EventList +type V1EventList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // List of events + Items []*V1Event `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // +optional + Metadata struct { + V1ListMeta + } `json:"metadata,omitempty"` +} + +// Validate validates this v1 event list +func (m *V1EventList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EventList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EventList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 event list based on the context it is used +func (m *V1EventList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EventList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1EventList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EventList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EventList) UnmarshalBinary(b []byte) error { + var res V1EventList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_event_series.go b/pkg/client/generated/models/v1_event_series.go new file mode 100644 index 0000000000..7b87207d21 --- /dev/null +++ b/pkg/client/generated/models/v1_event_series.go @@ -0,0 +1,84 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EventSeries v1 event series +// +// swagger:model V1EventSeries +type V1EventSeries struct { + + // Number of occurrences in this series up to the last heartbeat time + Count int64 `json:"count,omitempty"` + + // Time of the last occurrence observed + LastObservedTime struct { + V1MicroTime + } `json:"lastObservedTime,omitempty"` +} + +// Validate validates this v1 event series +func (m *V1EventSeries) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLastObservedTime(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EventSeries) validateLastObservedTime(formats strfmt.Registry) error { + if swag.IsZero(m.LastObservedTime) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 event series based on the context it is used +func (m *V1EventSeries) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateLastObservedTime(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1EventSeries) contextValidateLastObservedTime(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1EventSeries) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EventSeries) UnmarshalBinary(b []byte) error { + var res V1EventSeries + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_event_source.go b/pkg/client/generated/models/v1_event_source.go new file mode 100644 index 0000000000..39ae131a61 --- /dev/null +++ b/pkg/client/generated/models/v1_event_source.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1EventSource v1 event source +// +// swagger:model V1EventSource +type V1EventSource struct { + + // Component from which the event is generated. + // +optional + Component string `json:"component,omitempty"` + + // Node name on which the event is generated. + // +optional + Host string `json:"host,omitempty"` +} + +// Validate validates this v1 event source +func (m *V1EventSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 event source based on context it is used +func (m *V1EventSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1EventSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1EventSource) UnmarshalBinary(b []byte) error { + var res V1EventSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_exec_action.go b/pkg/client/generated/models/v1_exec_action.go new file mode 100644 index 0000000000..784e8940a1 --- /dev/null +++ b/pkg/client/generated/models/v1_exec_action.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ExecAction v1 exec action +// +// swagger:model V1ExecAction +type V1ExecAction struct { + + // Command is the command line to execute inside the container, the working directory for the + // command is root ('/') in the container's filesystem. The command is simply exec'd, it is + // not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + // a shell, you need to explicitly call out to that shell. + // Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + // +optional + // +listType=atomic + Command []string `json:"command"` +} + +// Validate validates this v1 exec action +func (m *V1ExecAction) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 exec action based on context it is used +func (m *V1ExecAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ExecAction) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ExecAction) UnmarshalBinary(b []byte) error { + var res V1ExecAction + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_f_c_volume_source.go b/pkg/client/generated/models/v1_f_c_volume_source.go new file mode 100644 index 0000000000..e7832333ec --- /dev/null +++ b/pkg/client/generated/models/v1_f_c_volume_source.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1FCVolumeSource v1 f c volume source +// +// swagger:model V1FCVolumeSource +type V1FCVolumeSource struct { + + // fsType is the filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FsType string `json:"fsType,omitempty"` + + // lun is Optional: FC target lun number + // +optional + Lun int64 `json:"lun,omitempty"` + + // readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // targetWWNs is Optional: FC target worldwide names (WWNs) + // +optional + // +listType=atomic + TargetWWNs []string `json:"targetWWNs"` + + // wwids Optional: FC volume world wide identifiers (wwids) + // Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + // +optional + // +listType=atomic + Wwids []string `json:"wwids"` +} + +// Validate validates this v1 f c volume source +func (m *V1FCVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 f c volume source based on context it is used +func (m *V1FCVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1FCVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1FCVolumeSource) UnmarshalBinary(b []byte) error { + var res V1FCVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_fields_v1.go b/pkg/client/generated/models/v1_fields_v1.go new file mode 100644 index 0000000000..dee1da3555 --- /dev/null +++ b/pkg/client/generated/models/v1_fields_v1.go @@ -0,0 +1,8 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// V1FieldsV1 v1 fields v1 +// +// swagger:model V1FieldsV1 +type V1FieldsV1 any diff --git a/pkg/client/generated/models/v1_file_key_selector.go b/pkg/client/generated/models/v1_file_key_selector.go new file mode 100644 index 0000000000..b6d9eca0ca --- /dev/null +++ b/pkg/client/generated/models/v1_file_key_selector.go @@ -0,0 +1,70 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1FileKeySelector v1 file key selector +// +// swagger:model V1FileKeySelector +type V1FileKeySelector struct { + + // The key within the env file. An invalid key will prevent the pod from starting. + // The keys defined within a source may consist of any printable ASCII characters except '='. + // During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. + // +required + Key string `json:"key,omitempty"` + + // Specify whether the file or its key must be defined. If the file or key + // does not exist, then the env var is not published. + // If optional is set to true and the specified key does not exist, + // the environment variable will not be set in the Pod's containers. + // + // If optional is set to false and the specified key does not exist, + // an error will be returned during Pod creation. + // +optional + // +default=false + Optional bool `json:"optional,omitempty"` + + // The path within the volume from which to select the file. + // Must be relative and may not contain the '..' path or start with '..'. + // +required + Path string `json:"path,omitempty"` + + // The name of the volume mount containing the env file. + // +required + VolumeName string `json:"volumeName,omitempty"` +} + +// Validate validates this v1 file key selector +func (m *V1FileKeySelector) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 file key selector based on context it is used +func (m *V1FileKeySelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1FileKeySelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1FileKeySelector) UnmarshalBinary(b []byte) error { + var res V1FileKeySelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_flex_volume_source.go b/pkg/client/generated/models/v1_flex_volume_source.go new file mode 100644 index 0000000000..96a4e9c87b --- /dev/null +++ b/pkg/client/generated/models/v1_flex_volume_source.go @@ -0,0 +1,104 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1FlexVolumeSource v1 flex volume source +// +// swagger:model V1FlexVolumeSource +type V1FlexVolumeSource struct { + + // driver is the name of the driver to use for this volume. + Driver string `json:"driver,omitempty"` + + // fsType is the filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + // +optional + FsType string `json:"fsType,omitempty"` + + // options is Optional: this field holds extra command options if any. + // +optional + Options map[string]string `json:"options,omitempty"` + + // readOnly is Optional: defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretRef is Optional: secretRef is reference to the secret object containing + // sensitive information to pass to the plugin scripts. This may be + // empty if no secret object is specified. If the secret object + // contains more than one secret, all secrets are passed to the plugin + // scripts. + // +optional + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` +} + +// Validate validates this v1 flex volume source +func (m *V1FlexVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1FlexVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 flex volume source based on the context it is used +func (m *V1FlexVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1FlexVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1FlexVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1FlexVolumeSource) UnmarshalBinary(b []byte) error { + var res V1FlexVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_flocker_volume_source.go b/pkg/client/generated/models/v1_flocker_volume_source.go new file mode 100644 index 0000000000..47924d6383 --- /dev/null +++ b/pkg/client/generated/models/v1_flocker_volume_source.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1FlockerVolumeSource v1 flocker volume source +// +// swagger:model V1FlockerVolumeSource +type V1FlockerVolumeSource struct { + + // datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + // should be considered as deprecated + // +optional + DatasetName string `json:"datasetName,omitempty"` + + // datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset + // +optional + DatasetUUID string `json:"datasetUUID,omitempty"` +} + +// Validate validates this v1 flocker volume source +func (m *V1FlockerVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 flocker volume source based on context it is used +func (m *V1FlockerVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1FlockerVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1FlockerVolumeSource) UnmarshalBinary(b []byte) error { + var res V1FlockerVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_g_c_e_persistent_disk_volume_source.go b/pkg/client/generated/models/v1_g_c_e_persistent_disk_volume_source.go new file mode 100644 index 0000000000..644eef8e55 --- /dev/null +++ b/pkg/client/generated/models/v1_g_c_e_persistent_disk_volume_source.go @@ -0,0 +1,70 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1GCEPersistentDiskVolumeSource v1 g c e persistent disk volume source +// +// swagger:model V1GCEPersistentDiskVolumeSource +type V1GCEPersistentDiskVolumeSource struct { + + // fsType is filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FsType string `json:"fsType,omitempty"` + + // partition is the partition in the volume that you want to mount. + // If omitted, the default is to mount by volume name. + // Examples: For volume /dev/sda1, you specify the partition as "1". + // Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + Partition int64 `json:"partition,omitempty"` + + // pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + PdName string `json:"pdName,omitempty"` + + // readOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + ReadOnly bool `json:"readOnly,omitempty"` +} + +// Validate validates this v1 g c e persistent disk volume source +func (m *V1GCEPersistentDiskVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 g c e persistent disk volume source based on context it is used +func (m *V1GCEPersistentDiskVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1GCEPersistentDiskVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1GCEPersistentDiskVolumeSource) UnmarshalBinary(b []byte) error { + var res V1GCEPersistentDiskVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_g_rpc_action.go b/pkg/client/generated/models/v1_g_rpc_action.go new file mode 100644 index 0000000000..807a625721 --- /dev/null +++ b/pkg/client/generated/models/v1_g_rpc_action.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1GRPCAction v1 g RPC action +// +// swagger:model V1GRPCAction +type V1GRPCAction struct { + + // Port number of the gRPC service. Number must be in the range 1 to 65535. + Port int64 `json:"port,omitempty"` + + // Service is the name of the service to place in the gRPC HealthCheckRequest + // (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + // + // If this is not specified, the default behavior is defined by gRPC. + // +optional + // +default="" + Service string `json:"service,omitempty"` +} + +// Validate validates this v1 g RPC action +func (m *V1GRPCAction) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 g RPC action based on context it is used +func (m *V1GRPCAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1GRPCAction) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1GRPCAction) UnmarshalBinary(b []byte) error { + var res V1GRPCAction + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_git_repo_volume_source.go b/pkg/client/generated/models/v1_git_repo_volume_source.go new file mode 100644 index 0000000000..d2c48514f4 --- /dev/null +++ b/pkg/client/generated/models/v1_git_repo_volume_source.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1GitRepoVolumeSource v1 git repo volume source +// +// swagger:model V1GitRepoVolumeSource +type V1GitRepoVolumeSource struct { + + // directory is the target directory name. + // Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + // git repository. Otherwise, if specified, the volume will contain the git repository in + // the subdirectory with the given name. + // +optional + Directory string `json:"directory,omitempty"` + + // repository is the URL + Repository string `json:"repository,omitempty"` + + // revision is the commit hash for the specified revision. + // +optional + Revision string `json:"revision,omitempty"` +} + +// Validate validates this v1 git repo volume source +func (m *V1GitRepoVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 git repo volume source based on context it is used +func (m *V1GitRepoVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1GitRepoVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1GitRepoVolumeSource) UnmarshalBinary(b []byte) error { + var res V1GitRepoVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_glusterfs_volume_source.go b/pkg/client/generated/models/v1_glusterfs_volume_source.go new file mode 100644 index 0000000000..628e7c851a --- /dev/null +++ b/pkg/client/generated/models/v1_glusterfs_volume_source.go @@ -0,0 +1,57 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1GlusterfsVolumeSource v1 glusterfs volume source +// +// swagger:model V1GlusterfsVolumeSource +type V1GlusterfsVolumeSource struct { + + // endpoints is the endpoint name that details Glusterfs topology. + Endpoints string `json:"endpoints,omitempty"` + + // path is the Glusterfs volume path. + // More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + Path string `json:"path,omitempty"` + + // readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + // Defaults to false. + // More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + // +optional + ReadOnly bool `json:"readOnly,omitempty"` +} + +// Validate validates this v1 glusterfs volume source +func (m *V1GlusterfsVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 glusterfs volume source based on context it is used +func (m *V1GlusterfsVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1GlusterfsVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1GlusterfsVolumeSource) UnmarshalBinary(b []byte) error { + var res V1GlusterfsVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_host_alias.go b/pkg/client/generated/models/v1_host_alias.go new file mode 100644 index 0000000000..7c860206ab --- /dev/null +++ b/pkg/client/generated/models/v1_host_alias.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1HostAlias v1 host alias +// +// swagger:model V1HostAlias +type V1HostAlias struct { + + // Hostnames for the above IP address. + // +listType=atomic + Hostnames []string `json:"hostnames"` + + // IP address of the host file entry. + // +required + IP string `json:"ip,omitempty"` +} + +// Validate validates this v1 host alias +func (m *V1HostAlias) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 host alias based on context it is used +func (m *V1HostAlias) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1HostAlias) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1HostAlias) UnmarshalBinary(b []byte) error { + var res V1HostAlias + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_host_path_volume_source.go b/pkg/client/generated/models/v1_host_path_volume_source.go new file mode 100644 index 0000000000..bc63db877b --- /dev/null +++ b/pkg/client/generated/models/v1_host_path_volume_source.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1HostPathVolumeSource v1 host path volume source +// +// swagger:model V1HostPathVolumeSource +type V1HostPathVolumeSource struct { + + // path of the directory on the host. + // If the path is a symlink, it will follow the link to the real path. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + Path string `json:"path,omitempty"` + + // type for HostPath Volume + // Defaults to "" + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + // +optional + Type string `json:"type,omitempty"` +} + +// Validate validates this v1 host path volume source +func (m *V1HostPathVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 host path volume source based on context it is used +func (m *V1HostPathVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1HostPathVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1HostPathVolumeSource) UnmarshalBinary(b []byte) error { + var res V1HostPathVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_http_get_action.go b/pkg/client/generated/models/v1_http_get_action.go new file mode 100644 index 0000000000..cdca332810 --- /dev/null +++ b/pkg/client/generated/models/v1_http_get_action.go @@ -0,0 +1,171 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1HTTPGetAction v1 HTTP get action +// +// swagger:model V1HTTPGetAction +type V1HTTPGetAction struct { + + // Host name to connect to, defaults to the pod IP. You probably want to set + // "Host" in httpHeaders instead. + // +optional + Host string `json:"host,omitempty"` + + // Custom headers to set in the request. HTTP allows repeated headers. + // +optional + // +listType=atomic + HTTPHeaders []*V1HTTPHeader `json:"httpHeaders"` + + // Path to access on the HTTP server. + // +optional + Path string `json:"path,omitempty"` + + // Name or number of the port to access on the container. + // Number must be in the range 1 to 65535. + // Name must be an IANA_SVC_NAME. + Port struct { + IntOrString + } `json:"port,omitempty"` + + // Scheme to use for connecting to the host. + // Defaults to HTTP. + // +optional + Scheme string `json:"scheme,omitempty"` +} + +// Validate validates this v1 HTTP get action +func (m *V1HTTPGetAction) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateHTTPHeaders(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePort(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1HTTPGetAction) validateHTTPHeaders(formats strfmt.Registry) error { + if swag.IsZero(m.HTTPHeaders) { // not required + return nil + } + + for i := 0; i < len(m.HTTPHeaders); i++ { + if swag.IsZero(m.HTTPHeaders[i]) { // not required + continue + } + + if m.HTTPHeaders[i] != nil { + if err := m.HTTPHeaders[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("httpHeaders" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("httpHeaders" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1HTTPGetAction) validatePort(formats strfmt.Registry) error { + if swag.IsZero(m.Port) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 HTTP get action based on the context it is used +func (m *V1HTTPGetAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateHTTPHeaders(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePort(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1HTTPGetAction) contextValidateHTTPHeaders(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.HTTPHeaders); i++ { + + if m.HTTPHeaders[i] != nil { + + if swag.IsZero(m.HTTPHeaders[i]) { // not required + return nil + } + + if err := m.HTTPHeaders[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("httpHeaders" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("httpHeaders" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1HTTPGetAction) contextValidatePort(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1HTTPGetAction) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1HTTPGetAction) UnmarshalBinary(b []byte) error { + var res V1HTTPGetAction + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_http_header.go b/pkg/client/generated/models/v1_http_header.go new file mode 100644 index 0000000000..a408434603 --- /dev/null +++ b/pkg/client/generated/models/v1_http_header.go @@ -0,0 +1,51 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1HTTPHeader v1 HTTP header +// +// swagger:model V1HTTPHeader +type V1HTTPHeader struct { + + // The header field name. + // This will be canonicalized upon output, so case-variant names will be understood as the same header. + Name string `json:"name,omitempty"` + + // The header field value + Value string `json:"value,omitempty"` +} + +// Validate validates this v1 HTTP header +func (m *V1HTTPHeader) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 HTTP header based on context it is used +func (m *V1HTTPHeader) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1HTTPHeader) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1HTTPHeader) UnmarshalBinary(b []byte) error { + var res V1HTTPHeader + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_i_s_c_s_i_volume_source.go b/pkg/client/generated/models/v1_i_s_c_s_i_volume_source.go new file mode 100644 index 0000000000..ead92a419a --- /dev/null +++ b/pkg/client/generated/models/v1_i_s_c_s_i_volume_source.go @@ -0,0 +1,131 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ISCSIVolumeSource v1 i s c s i volume source +// +// swagger:model V1ISCSIVolumeSource +type V1ISCSIVolumeSource struct { + + // chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication + // +optional + ChapAuthDiscovery bool `json:"chapAuthDiscovery,omitempty"` + + // chapAuthSession defines whether support iSCSI Session CHAP authentication + // +optional + ChapAuthSession bool `json:"chapAuthSession,omitempty"` + + // fsType is the filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FsType string `json:"fsType,omitempty"` + + // initiatorName is the custom iSCSI Initiator Name. + // If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + // : will be created for the connection. + // +optional + InitiatorName string `json:"initiatorName,omitempty"` + + // iqn is the target iSCSI Qualified Name. + Iqn string `json:"iqn,omitempty"` + + // iscsiInterface is the interface Name that uses an iSCSI transport. + // Defaults to 'default' (tcp). + // +optional + // +default="default" + IscsiInterface string `json:"iscsiInterface,omitempty"` + + // lun represents iSCSI Target Lun number. + Lun int64 `json:"lun,omitempty"` + + // portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + // is other than default (typically TCP ports 860 and 3260). + // +optional + // +listType=atomic + Portals []string `json:"portals"` + + // readOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretRef is the CHAP Secret for iSCSI target and initiator authentication + // +optional + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` + + // targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + // is other than default (typically TCP ports 860 and 3260). + TargetPortal string `json:"targetPortal,omitempty"` +} + +// Validate validates this v1 i s c s i volume source +func (m *V1ISCSIVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ISCSIVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 i s c s i volume source based on the context it is used +func (m *V1ISCSIVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ISCSIVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ISCSIVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ISCSIVolumeSource) UnmarshalBinary(b []byte) error { + var res V1ISCSIVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_image_volume_source.go b/pkg/client/generated/models/v1_image_volume_source.go new file mode 100644 index 0000000000..d9bc233393 --- /dev/null +++ b/pkg/client/generated/models/v1_image_volume_source.go @@ -0,0 +1,61 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ImageVolumeSource v1 image volume source +// +// swagger:model V1ImageVolumeSource +type V1ImageVolumeSource struct { + + // Policy for pulling OCI objects. Possible values are: + // Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + // Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + // IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + // Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + // +optional + PullPolicy string `json:"pullPolicy,omitempty"` + + // Required: Image or artifact reference to be used. + // Behaves in the same way as pod.spec.containers[*].image. + // Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. + // More info: https://kubernetes.io/docs/concepts/containers/images + // This field is optional to allow higher level config management to default or override + // container images in workload controllers like Deployments and StatefulSets. + // +optional + Reference string `json:"reference,omitempty"` +} + +// Validate validates this v1 image volume source +func (m *V1ImageVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 image volume source based on context it is used +func (m *V1ImageVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ImageVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ImageVolumeSource) UnmarshalBinary(b []byte) error { + var res V1ImageVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_job_spec.go b/pkg/client/generated/models/v1_job_spec.go new file mode 100644 index 0000000000..7676a3134e --- /dev/null +++ b/pkg/client/generated/models/v1_job_spec.go @@ -0,0 +1,361 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1JobSpec v1 job spec +// +// swagger:model V1JobSpec +type V1JobSpec struct { + + // Specifies the duration in seconds relative to the startTime that the job + // may be continuously active before the system tries to terminate it; value + // must be positive integer. If a Job is suspended (at creation or through an + // update), this timer will effectively be stopped and reset when the Job is + // resumed again. + // +optional + ActiveDeadlineSeconds int64 `json:"activeDeadlineSeconds,omitempty"` + + // Specifies the number of retries before marking this job failed. + // Defaults to 6, unless backoffLimitPerIndex (only Indexed Job) is specified. + // When backoffLimitPerIndex is specified, backoffLimit defaults to 2147483647. + // +optional + BackoffLimit int64 `json:"backoffLimit,omitempty"` + + // Specifies the limit for the number of retries within an + // index before marking this index as failed. When enabled the number of + // failures per index is kept in the pod's + // batch.kubernetes.io/job-index-failure-count annotation. It can only + // be set when Job's completionMode=Indexed, and the Pod's restart + // policy is Never. The field is immutable. + // +optional + BackoffLimitPerIndex int64 `json:"backoffLimitPerIndex,omitempty"` + + // completionMode specifies how Pod completions are tracked. It can be + // `NonIndexed` (default) or `Indexed`. + // + // `NonIndexed` means that the Job is considered complete when there have + // been .spec.completions successfully completed Pods. Each Pod completion is + // homologous to each other. + // + // `Indexed` means that the Pods of a + // Job get an associated completion index from 0 to (.spec.completions - 1), + // available in the annotation batch.kubernetes.io/job-completion-index. + // The Job is considered complete when there is one successfully completed Pod + // for each index. + // When value is `Indexed`, .spec.completions must be specified and + // `.spec.parallelism` must be less than or equal to 10^5. + // In addition, The Pod name takes the form + // `$(job-name)-$(index)-$(random-string)`, + // the Pod hostname takes the form `$(job-name)-$(index)`. + // + // More completion modes can be added in the future. + // If the Job controller observes a mode that it doesn't recognize, which + // is possible during upgrades due to version skew, the controller + // skips updates for the Job. + // +optional + CompletionMode struct { + V1CompletionMode + } `json:"completionMode,omitempty"` + + // Specifies the desired number of successfully finished pods the + // job should be run with. Setting to null means that the success of any + // pod signals the success of all pods, and allows parallelism to have any positive + // value. Setting to 1 means that parallelism is limited to 1 and the success of that + // pod signals the success of the job. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + // +optional + Completions int64 `json:"completions,omitempty"` + + // ManagedBy field indicates the controller that manages a Job. The k8s Job + // controller reconciles jobs which don't have this field at all or the field + // value is the reserved string `kubernetes.io/job-controller`, but skips + // reconciling Jobs with a custom value for this field. + // The value must be a valid domain-prefixed path (e.g. acme.io/foo) - + // all characters before the first "/" must be a valid subdomain as defined + // by RFC 1123. All characters trailing the first "/" must be valid HTTP Path + // characters as defined by RFC 3986. The value cannot exceed 63 characters. + // This field is immutable. + // + // This field is beta-level. The job controller accepts setting the field + // when the feature gate JobManagedBy is enabled (enabled by default). + // +optional + ManagedBy string `json:"managedBy,omitempty"` + + // manualSelector controls generation of pod labels and pod selectors. + // Leave `manualSelector` unset unless you are certain what you are doing. + // When false or unset, the system pick labels unique to this job + // and appends those labels to the pod template. When true, + // the user is responsible for picking unique labels and specifying + // the selector. Failure to pick a unique label may cause this + // and other jobs to not function correctly. However, You may see + // `manualSelector=true` in jobs that were created with the old `extensions/v1beta1` + // API. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector + // +optional + ManualSelector bool `json:"manualSelector,omitempty"` + + // Specifies the maximal number of failed indexes before marking the Job as + // failed, when backoffLimitPerIndex is set. Once the number of failed + // indexes exceeds this number the entire Job is marked as Failed and its + // execution is terminated. When left as null the job continues execution of + // all of its indexes and is marked with the `Complete` Job condition. + // It can only be specified when backoffLimitPerIndex is set. + // It can be null or up to completions. It is required and must be + // less than or equal to 10^4 when is completions greater than 10^5. + // +optional + MaxFailedIndexes int64 `json:"maxFailedIndexes,omitempty"` + + // Specifies the maximum desired number of pods the job should + // run at any given time. The actual number of pods running in steady state will + // be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), + // i.e. when the work left to do is less than max parallelism. + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + // +optional + Parallelism int64 `json:"parallelism,omitempty"` + + // Specifies the policy of handling failed pods. In particular, it allows to + // specify the set of actions and conditions which need to be + // satisfied to take the associated action. + // If empty, the default behaviour applies - the counter of failed pods, + // represented by the jobs's .status.failed field, is incremented and it is + // checked against the backoffLimit. This field cannot be used in combination + // with restartPolicy=OnFailure. + // + // +optional + PodFailurePolicy struct { + V1PodFailurePolicy + } `json:"podFailurePolicy,omitempty"` + + // podReplacementPolicy specifies when to create replacement Pods. + // Possible values are: + // - TerminatingOrFailed means that we recreate pods + // when they are terminating (has a metadata.deletionTimestamp) or failed. + // - Failed means to wait until a previously created Pod is fully terminated (has phase + // Failed or Succeeded) before creating a replacement Pod. + // + // When using podFailurePolicy, Failed is the the only allowed value. + // TerminatingOrFailed and Failed are allowed values when podFailurePolicy is not in use. + // +optional + PodReplacementPolicy struct { + V1PodReplacementPolicy + } `json:"podReplacementPolicy,omitempty"` + + // A label query over pods that should match the pod count. + // Normally, the system sets this field for you. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + // +optional + Selector struct { + V1LabelSelector + } `json:"selector,omitempty"` + + // successPolicy specifies the policy when the Job can be declared as succeeded. + // If empty, the default behavior applies - the Job is declared as succeeded + // only when the number of succeeded pods equals to the completions. + // When the field is specified, it must be immutable and works only for the Indexed Jobs. + // Once the Job meets the SuccessPolicy, the lingering pods are terminated. + // + // +optional + SuccessPolicy struct { + V1SuccessPolicy + } `json:"successPolicy,omitempty"` + + // suspend specifies whether the Job controller should create Pods or not. If + // a Job is created with suspend set to true, no Pods are created by the Job + // controller. If a Job is suspended after creation (i.e. the flag goes from + // false to true), the Job controller will delete all active Pods associated + // with this Job. Users must design their workload to gracefully handle this. + // Suspending a Job will reset the StartTime field of the Job, effectively + // resetting the ActiveDeadlineSeconds timer too. Defaults to false. + // + // +optional + Suspend bool `json:"suspend,omitempty"` + + // Describes the pod that will be created when executing a job. + // The only allowed template.spec.restartPolicy values are "Never" or "OnFailure". + // More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ + Template struct { + V1PodTemplateSpec + } `json:"template,omitempty"` + + // ttlSecondsAfterFinished limits the lifetime of a Job that has finished + // execution (either Complete or Failed). If this field is set, + // ttlSecondsAfterFinished after the Job finishes, it is eligible to be + // automatically deleted. When the Job is being deleted, its lifecycle + // guarantees (e.g. finalizers) will be honored. If this field is unset, + // the Job won't be automatically deleted. If this field is set to zero, + // the Job becomes eligible to be deleted immediately after it finishes. + // +optional + TTLSecondsAfterFinished int64 `json:"ttlSecondsAfterFinished,omitempty"` +} + +// Validate validates this v1 job spec +func (m *V1JobSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateCompletionMode(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePodFailurePolicy(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePodReplacementPolicy(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSelector(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSuccessPolicy(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTemplate(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1JobSpec) validateCompletionMode(formats strfmt.Registry) error { + if swag.IsZero(m.CompletionMode) { // not required + return nil + } + + return nil +} + +func (m *V1JobSpec) validatePodFailurePolicy(formats strfmt.Registry) error { + if swag.IsZero(m.PodFailurePolicy) { // not required + return nil + } + + return nil +} + +func (m *V1JobSpec) validatePodReplacementPolicy(formats strfmt.Registry) error { + if swag.IsZero(m.PodReplacementPolicy) { // not required + return nil + } + + return nil +} + +func (m *V1JobSpec) validateSelector(formats strfmt.Registry) error { + if swag.IsZero(m.Selector) { // not required + return nil + } + + return nil +} + +func (m *V1JobSpec) validateSuccessPolicy(formats strfmt.Registry) error { + if swag.IsZero(m.SuccessPolicy) { // not required + return nil + } + + return nil +} + +func (m *V1JobSpec) validateTemplate(formats strfmt.Registry) error { + if swag.IsZero(m.Template) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 job spec based on the context it is used +func (m *V1JobSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateCompletionMode(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePodFailurePolicy(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePodReplacementPolicy(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSuccessPolicy(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTemplate(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1JobSpec) contextValidateCompletionMode(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1JobSpec) contextValidatePodFailurePolicy(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1JobSpec) contextValidatePodReplacementPolicy(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1JobSpec) contextValidateSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1JobSpec) contextValidateSuccessPolicy(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1JobSpec) contextValidateTemplate(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1JobSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1JobSpec) UnmarshalBinary(b []byte) error { + var res V1JobSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_key_to_path.go b/pkg/client/generated/models/v1_key_to_path.go new file mode 100644 index 0000000000..ff6f34f05d --- /dev/null +++ b/pkg/client/generated/models/v1_key_to_path.go @@ -0,0 +1,62 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1KeyToPath v1 key to path +// +// swagger:model V1KeyToPath +type V1KeyToPath struct { + + // key is the key to project. + Key string `json:"key,omitempty"` + + // mode is Optional: mode bits used to set permissions on this file. + // Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + // YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + // If not specified, the volume defaultMode will be used. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + Mode int64 `json:"mode,omitempty"` + + // path is the relative path of the file to map the key to. + // May not be an absolute path. + // May not contain the path element '..'. + // May not start with the string '..'. + Path string `json:"path,omitempty"` +} + +// Validate validates this v1 key to path +func (m *V1KeyToPath) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 key to path based on context it is used +func (m *V1KeyToPath) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1KeyToPath) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1KeyToPath) UnmarshalBinary(b []byte) error { + var res V1KeyToPath + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_label_selector.go b/pkg/client/generated/models/v1_label_selector.go new file mode 100644 index 0000000000..e78013fb30 --- /dev/null +++ b/pkg/client/generated/models/v1_label_selector.go @@ -0,0 +1,135 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1LabelSelector v1 label selector +// +// swagger:model V1LabelSelector +type V1LabelSelector struct { + + // matchExpressions is a list of label selector requirements. The requirements are ANDed. + // +optional + // +listType=atomic + MatchExpressions []*V1LabelSelectorRequirement `json:"matchExpressions"` + + // matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + // map is equivalent to an element of matchExpressions, whose key field is "key", the + // operator is "In", and the values array contains only "value". The requirements are ANDed. + // +optional + MatchLabels map[string]string `json:"matchLabels,omitempty"` +} + +// Validate validates this v1 label selector +func (m *V1LabelSelector) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMatchExpressions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1LabelSelector) validateMatchExpressions(formats strfmt.Registry) error { + if swag.IsZero(m.MatchExpressions) { // not required + return nil + } + + for i := 0; i < len(m.MatchExpressions); i++ { + if swag.IsZero(m.MatchExpressions[i]) { // not required + continue + } + + if m.MatchExpressions[i] != nil { + if err := m.MatchExpressions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 label selector based on the context it is used +func (m *V1LabelSelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMatchExpressions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1LabelSelector) contextValidateMatchExpressions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MatchExpressions); i++ { + + if m.MatchExpressions[i] != nil { + + if swag.IsZero(m.MatchExpressions[i]) { // not required + return nil + } + + if err := m.MatchExpressions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1LabelSelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1LabelSelector) UnmarshalBinary(b []byte) error { + var res V1LabelSelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_label_selector_requirement.go b/pkg/client/generated/models/v1_label_selector_requirement.go new file mode 100644 index 0000000000..07185e9cff --- /dev/null +++ b/pkg/client/generated/models/v1_label_selector_requirement.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1LabelSelectorRequirement v1 label selector requirement +// +// swagger:model V1LabelSelectorRequirement +type V1LabelSelectorRequirement struct { + + // key is the label key that the selector applies to. + Key string `json:"key,omitempty"` + + // operator represents a key's relationship to a set of values. + // Valid operators are In, NotIn, Exists and DoesNotExist. + Operator string `json:"operator,omitempty"` + + // values is an array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. This array is replaced during a strategic + // merge patch. + // +optional + // +listType=atomic + Values []string `json:"values"` +} + +// Validate validates this v1 label selector requirement +func (m *V1LabelSelectorRequirement) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 label selector requirement based on context it is used +func (m *V1LabelSelectorRequirement) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1LabelSelectorRequirement) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1LabelSelectorRequirement) UnmarshalBinary(b []byte) error { + var res V1LabelSelectorRequirement + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_lifecycle.go b/pkg/client/generated/models/v1_lifecycle.go new file mode 100644 index 0000000000..c562ffcff0 --- /dev/null +++ b/pkg/client/generated/models/v1_lifecycle.go @@ -0,0 +1,126 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Lifecycle v1 lifecycle +// +// swagger:model V1Lifecycle +type V1Lifecycle struct { + + // PostStart is called immediately after a container is created. If the handler fails, + // the container is terminated and restarted according to its restart policy. + // Other management of the container blocks until the hook completes. + // More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + // +optional + PostStart struct { + V1LifecycleHandler + } `json:"postStart,omitempty"` + + // PreStop is called immediately before a container is terminated due to an + // API request or management event such as liveness/startup probe failure, + // preemption, resource contention, etc. The handler is not called if the + // container crashes or exits. The Pod's termination grace period countdown begins before the + // PreStop hook is executed. Regardless of the outcome of the handler, the + // container will eventually terminate within the Pod's termination grace + // period (unless delayed by finalizers). Other management of the container blocks until the hook completes + // or until the termination grace period is reached. + // More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + // +optional + PreStop struct { + V1LifecycleHandler + } `json:"preStop,omitempty"` + + // StopSignal defines which signal will be sent to a container when it is being stopped. + // If not specified, the default is defined by the container runtime in use. + // StopSignal can only be set for Pods with a non-empty .spec.os.name + // +optional + StopSignal string `json:"stopSignal,omitempty"` +} + +// Validate validates this v1 lifecycle +func (m *V1Lifecycle) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePostStart(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePreStop(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Lifecycle) validatePostStart(formats strfmt.Registry) error { + if swag.IsZero(m.PostStart) { // not required + return nil + } + + return nil +} + +func (m *V1Lifecycle) validatePreStop(formats strfmt.Registry) error { + if swag.IsZero(m.PreStop) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 lifecycle based on the context it is used +func (m *V1Lifecycle) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePostStart(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePreStop(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Lifecycle) contextValidatePostStart(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Lifecycle) contextValidatePreStop(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Lifecycle) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Lifecycle) UnmarshalBinary(b []byte) error { + var res V1Lifecycle + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_lifecycle_handler.go b/pkg/client/generated/models/v1_lifecycle_handler.go new file mode 100644 index 0000000000..d6f831ddd7 --- /dev/null +++ b/pkg/client/generated/models/v1_lifecycle_handler.go @@ -0,0 +1,166 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1LifecycleHandler v1 lifecycle handler +// +// swagger:model V1LifecycleHandler +type V1LifecycleHandler struct { + + // Exec specifies a command to execute in the container. + // +optional + Exec struct { + V1ExecAction + } `json:"exec,omitempty"` + + // HTTPGet specifies an HTTP GET request to perform. + // +optional + HTTPGet struct { + V1HTTPGetAction + } `json:"httpGet,omitempty"` + + // Sleep represents a duration that the container should sleep. + // +featureGate=PodLifecycleSleepAction + // +optional + Sleep struct { + V1SleepAction + } `json:"sleep,omitempty"` + + // Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + // for backward compatibility. There is no validation of this field and + // lifecycle hooks will fail at runtime when it is specified. + // +optional + TCPSocket struct { + V1TCPSocketAction + } `json:"tcpSocket,omitempty"` +} + +// Validate validates this v1 lifecycle handler +func (m *V1LifecycleHandler) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateExec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHTTPGet(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSleep(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTCPSocket(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1LifecycleHandler) validateExec(formats strfmt.Registry) error { + if swag.IsZero(m.Exec) { // not required + return nil + } + + return nil +} + +func (m *V1LifecycleHandler) validateHTTPGet(formats strfmt.Registry) error { + if swag.IsZero(m.HTTPGet) { // not required + return nil + } + + return nil +} + +func (m *V1LifecycleHandler) validateSleep(formats strfmt.Registry) error { + if swag.IsZero(m.Sleep) { // not required + return nil + } + + return nil +} + +func (m *V1LifecycleHandler) validateTCPSocket(formats strfmt.Registry) error { + if swag.IsZero(m.TCPSocket) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 lifecycle handler based on the context it is used +func (m *V1LifecycleHandler) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateExec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHTTPGet(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSleep(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTCPSocket(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1LifecycleHandler) contextValidateExec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1LifecycleHandler) contextValidateHTTPGet(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1LifecycleHandler) contextValidateSleep(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1LifecycleHandler) contextValidateTCPSocket(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1LifecycleHandler) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1LifecycleHandler) UnmarshalBinary(b []byte) error { + var res V1LifecycleHandler + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_list_meta.go b/pkg/client/generated/models/v1_list_meta.go new file mode 100644 index 0000000000..0db2a4d9b8 --- /dev/null +++ b/pkg/client/generated/models/v1_list_meta.go @@ -0,0 +1,78 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ListMeta v1 list meta +// +// swagger:model V1ListMeta +type V1ListMeta struct { + + // continue may be set if the user set a limit on the number of items returned, and indicates that + // the server has more data available. The value is opaque and may be used to issue another request + // to the endpoint that served this list to retrieve the next set of available objects. Continuing a + // consistent list may not be possible if the server configuration has changed or more than a few + // minutes have passed. The resourceVersion field returned when using this continue value will be + // identical to the value in the first response, unless you have received this token from an error + // message. + Continue string `json:"continue,omitempty"` + + // remainingItemCount is the number of subsequent items in the list which are not included in this + // list response. If the list request contained label or field selectors, then the number of + // remaining items is unknown and the field will be left unset and omitted during serialization. + // If the list is complete (either because it is not chunking or because this is the last chunk), + // then there are no more remaining items and this field will be left unset and omitted during + // serialization. + // Servers older than v1.15 do not set this field. + // The intended use of the remainingItemCount is *estimating* the size of a collection. Clients + // should not rely on the remainingItemCount to be set or to be exact. + // +optional + RemainingItemCount int64 `json:"remainingItemCount,omitempty"` + + // String that identifies the server's internal version of this object that + // can be used by clients to determine when objects have changed. + // Value must be treated as opaque by clients and passed unmodified back to the server. + // Populated by the system. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + // +optional + ResourceVersion string `json:"resourceVersion,omitempty"` + + // Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. + // +optional + SelfLink string `json:"selfLink,omitempty"` +} + +// Validate validates this v1 list meta +func (m *V1ListMeta) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 list meta based on context it is used +func (m *V1ListMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ListMeta) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ListMeta) UnmarshalBinary(b []byte) error { + var res V1ListMeta + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_local_object_reference.go b/pkg/client/generated/models/v1_local_object_reference.go new file mode 100644 index 0000000000..5c51839027 --- /dev/null +++ b/pkg/client/generated/models/v1_local_object_reference.go @@ -0,0 +1,55 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1LocalObjectReference v1 local object reference +// +// swagger:model V1LocalObjectReference +type V1LocalObjectReference struct { + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` +} + +// Validate validates this v1 local object reference +func (m *V1LocalObjectReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 local object reference based on context it is used +func (m *V1LocalObjectReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1LocalObjectReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1LocalObjectReference) UnmarshalBinary(b []byte) error { + var res V1LocalObjectReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_managed_fields_entry.go b/pkg/client/generated/models/v1_managed_fields_entry.go new file mode 100644 index 0000000000..27da8bfd63 --- /dev/null +++ b/pkg/client/generated/models/v1_managed_fields_entry.go @@ -0,0 +1,102 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ManagedFieldsEntry v1 managed fields entry +// +// swagger:model V1ManagedFieldsEntry +type V1ManagedFieldsEntry struct { + + // APIVersion defines the version of this resource that this field set + // applies to. The format is "group/version" just like the top-level + // APIVersion field. It is necessary to track the version of a field + // set because it cannot be automatically converted. + APIVersion string `json:"apiVersion,omitempty"` + + // FieldsType is the discriminator for the different fields format and version. + // There is currently only one possible value: "FieldsV1" + FieldsType string `json:"fieldsType,omitempty"` + + // FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. + // +optional + FieldsV1 struct { + V1FieldsV1 + } `json:"fieldsV1,omitempty"` + + // Manager is an identifier of the workflow managing these fields. + Manager string `json:"manager,omitempty"` + + // Operation is the type of operation which lead to this ManagedFieldsEntry being created. + // The only valid values for this field are 'Apply' and 'Update'. + Operation string `json:"operation,omitempty"` + + // Subresource is the name of the subresource used to update that object, or + // empty string if the object was updated through the main resource. The + // value of this field is used to distinguish between managers, even if they + // share the same name. For example, a status update will be distinct from a + // regular update using the same manager name. + // Note that the APIVersion field is not related to the Subresource field and + // it always corresponds to the version of the main resource. + Subresource string `json:"subresource,omitempty"` + + // Time is the timestamp of when the ManagedFields entry was added. The + // timestamp will also be updated if a field is added, the manager + // changes any of the owned fields value or removes a field. The + // timestamp does not update when a field is removed from the entry + // because another manager took it over. + // +optional + Time string `json:"time,omitempty"` +} + +// Validate validates this v1 managed fields entry +func (m *V1ManagedFieldsEntry) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFieldsV1(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ManagedFieldsEntry) validateFieldsV1(formats strfmt.Registry) error { + if swag.IsZero(m.FieldsV1) { // not required + return nil + } + + return nil +} + +// ContextValidate validates this v1 managed fields entry based on context it is used +func (m *V1ManagedFieldsEntry) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ManagedFieldsEntry) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ManagedFieldsEntry) UnmarshalBinary(b []byte) error { + var res V1ManagedFieldsEntry + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_micro_time.go b/pkg/client/generated/models/v1_micro_time.go new file mode 100644 index 0000000000..bdeeab7e66 --- /dev/null +++ b/pkg/client/generated/models/v1_micro_time.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1MicroTime v1 micro time +// +// swagger:model V1MicroTime +type V1MicroTime struct { + + // time time + TimeTime string `json:"time.Time,omitempty"` +} + +// Validate validates this v1 micro time +func (m *V1MicroTime) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 micro time based on context it is used +func (m *V1MicroTime) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1MicroTime) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1MicroTime) UnmarshalBinary(b []byte) error { + var res V1MicroTime + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_n_f_s_volume_source.go b/pkg/client/generated/models/v1_n_f_s_volume_source.go new file mode 100644 index 0000000000..99a36ce50c --- /dev/null +++ b/pkg/client/generated/models/v1_n_f_s_volume_source.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1NFSVolumeSource v1 n f s volume source +// +// swagger:model V1NFSVolumeSource +type V1NFSVolumeSource struct { + + // path that is exported by the NFS server. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + Path string `json:"path,omitempty"` + + // readOnly here will force the NFS export to be mounted with read-only permissions. + // Defaults to false. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // server is the hostname or IP address of the NFS server. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + Server string `json:"server,omitempty"` +} + +// Validate validates this v1 n f s volume source +func (m *V1NFSVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 n f s volume source based on context it is used +func (m *V1NFSVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1NFSVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1NFSVolumeSource) UnmarshalBinary(b []byte) error { + var res V1NFSVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_node_affinity.go b/pkg/client/generated/models/v1_node_affinity.go new file mode 100644 index 0000000000..b93a020f24 --- /dev/null +++ b/pkg/client/generated/models/v1_node_affinity.go @@ -0,0 +1,168 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1NodeAffinity v1 node affinity +// +// swagger:model V1NodeAffinity +type V1NodeAffinity struct { + + // The scheduler will prefer to schedule pods to nodes that satisfy + // the affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node matches the corresponding matchExpressions; the + // node(s) with the highest sum are the most preferred. + // +optional + // +listType=atomic + PreferredDuringSchedulingIgnoredDuringExecution []*V1PreferredSchedulingTerm `json:"preferredDuringSchedulingIgnoredDuringExecution"` + + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to an update), the system + // may or may not try to eventually evict the pod from its node. + // +optional + RequiredDuringSchedulingIgnoredDuringExecution struct { + V1NodeSelector + } `json:"requiredDuringSchedulingIgnoredDuringExecution,omitempty"` +} + +// Validate validates this v1 node affinity +func (m *V1NodeAffinity) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePreferredDuringSchedulingIgnoredDuringExecution(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequiredDuringSchedulingIgnoredDuringExecution(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1NodeAffinity) validatePreferredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error { + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution) { // not required + return nil + } + + for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ { + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required + continue + } + + if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil { + if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1NodeAffinity) validateRequiredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error { + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 node affinity based on the context it is used +func (m *V1NodeAffinity) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePreferredDuringSchedulingIgnoredDuringExecution(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRequiredDuringSchedulingIgnoredDuringExecution(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1NodeAffinity) contextValidatePreferredDuringSchedulingIgnoredDuringExecution(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ { + + if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil { + + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required + return nil + } + + if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1NodeAffinity) contextValidateRequiredDuringSchedulingIgnoredDuringExecution(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1NodeAffinity) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1NodeAffinity) UnmarshalBinary(b []byte) error { + var res V1NodeAffinity + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_node_selector.go b/pkg/client/generated/models/v1_node_selector.go new file mode 100644 index 0000000000..e9e54d1382 --- /dev/null +++ b/pkg/client/generated/models/v1_node_selector.go @@ -0,0 +1,128 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1NodeSelector v1 node selector +// +// swagger:model V1NodeSelector +type V1NodeSelector struct { + + // Required. A list of node selector terms. The terms are ORed. + // +listType=atomic + NodeSelectorTerms []*V1NodeSelectorTerm `json:"nodeSelectorTerms"` +} + +// Validate validates this v1 node selector +func (m *V1NodeSelector) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateNodeSelectorTerms(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1NodeSelector) validateNodeSelectorTerms(formats strfmt.Registry) error { + if swag.IsZero(m.NodeSelectorTerms) { // not required + return nil + } + + for i := 0; i < len(m.NodeSelectorTerms); i++ { + if swag.IsZero(m.NodeSelectorTerms[i]) { // not required + continue + } + + if m.NodeSelectorTerms[i] != nil { + if err := m.NodeSelectorTerms[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("nodeSelectorTerms" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("nodeSelectorTerms" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 node selector based on the context it is used +func (m *V1NodeSelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateNodeSelectorTerms(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1NodeSelector) contextValidateNodeSelectorTerms(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.NodeSelectorTerms); i++ { + + if m.NodeSelectorTerms[i] != nil { + + if swag.IsZero(m.NodeSelectorTerms[i]) { // not required + return nil + } + + if err := m.NodeSelectorTerms[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("nodeSelectorTerms" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("nodeSelectorTerms" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1NodeSelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1NodeSelector) UnmarshalBinary(b []byte) error { + var res V1NodeSelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_node_selector_requirement.go b/pkg/client/generated/models/v1_node_selector_requirement.go new file mode 100644 index 0000000000..c92805cb44 --- /dev/null +++ b/pkg/client/generated/models/v1_node_selector_requirement.go @@ -0,0 +1,60 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1NodeSelectorRequirement v1 node selector requirement +// +// swagger:model V1NodeSelectorRequirement +type V1NodeSelectorRequirement struct { + + // The label key that the selector applies to. + Key string `json:"key,omitempty"` + + // Represents a key's relationship to a set of values. + // Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + Operator string `json:"operator,omitempty"` + + // An array of string values. If the operator is In or NotIn, + // the values array must be non-empty. If the operator is Exists or DoesNotExist, + // the values array must be empty. If the operator is Gt or Lt, the values + // array must have a single element, which will be interpreted as an integer. + // This array is replaced during a strategic merge patch. + // +optional + // +listType=atomic + Values []string `json:"values"` +} + +// Validate validates this v1 node selector requirement +func (m *V1NodeSelectorRequirement) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 node selector requirement based on context it is used +func (m *V1NodeSelectorRequirement) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1NodeSelectorRequirement) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1NodeSelectorRequirement) UnmarshalBinary(b []byte) error { + var res V1NodeSelectorRequirement + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_node_selector_term.go b/pkg/client/generated/models/v1_node_selector_term.go new file mode 100644 index 0000000000..c43f1e383c --- /dev/null +++ b/pkg/client/generated/models/v1_node_selector_term.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1NodeSelectorTerm v1 node selector term +// +// swagger:model V1NodeSelectorTerm +type V1NodeSelectorTerm struct { + + // A list of node selector requirements by node's labels. + // +optional + // +listType=atomic + MatchExpressions []*V1NodeSelectorRequirement `json:"matchExpressions"` + + // A list of node selector requirements by node's fields. + // +optional + // +listType=atomic + MatchFields []*V1NodeSelectorRequirement `json:"matchFields"` +} + +// Validate validates this v1 node selector term +func (m *V1NodeSelectorTerm) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMatchExpressions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMatchFields(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1NodeSelectorTerm) validateMatchExpressions(formats strfmt.Registry) error { + if swag.IsZero(m.MatchExpressions) { // not required + return nil + } + + for i := 0; i < len(m.MatchExpressions); i++ { + if swag.IsZero(m.MatchExpressions[i]) { // not required + continue + } + + if m.MatchExpressions[i] != nil { + if err := m.MatchExpressions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1NodeSelectorTerm) validateMatchFields(formats strfmt.Registry) error { + if swag.IsZero(m.MatchFields) { // not required + return nil + } + + for i := 0; i < len(m.MatchFields); i++ { + if swag.IsZero(m.MatchFields[i]) { // not required + continue + } + + if m.MatchFields[i] != nil { + if err := m.MatchFields[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchFields" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchFields" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 node selector term based on the context it is used +func (m *V1NodeSelectorTerm) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMatchExpressions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMatchFields(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1NodeSelectorTerm) contextValidateMatchExpressions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MatchExpressions); i++ { + + if m.MatchExpressions[i] != nil { + + if swag.IsZero(m.MatchExpressions[i]) { // not required + return nil + } + + if err := m.MatchExpressions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchExpressions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1NodeSelectorTerm) contextValidateMatchFields(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.MatchFields); i++ { + + if m.MatchFields[i] != nil { + + if swag.IsZero(m.MatchFields[i]) { // not required + return nil + } + + if err := m.MatchFields[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("matchFields" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("matchFields" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1NodeSelectorTerm) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1NodeSelectorTerm) UnmarshalBinary(b []byte) error { + var res V1NodeSelectorTerm + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_object_field_selector.go b/pkg/client/generated/models/v1_object_field_selector.go new file mode 100644 index 0000000000..9f95e5fcf7 --- /dev/null +++ b/pkg/client/generated/models/v1_object_field_selector.go @@ -0,0 +1,51 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ObjectFieldSelector v1 object field selector +// +// swagger:model V1ObjectFieldSelector +type V1ObjectFieldSelector struct { + + // Version of the schema the FieldPath is written in terms of, defaults to "v1". + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Path of the field to select in the specified API version. + FieldPath string `json:"fieldPath,omitempty"` +} + +// Validate validates this v1 object field selector +func (m *V1ObjectFieldSelector) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 object field selector based on context it is used +func (m *V1ObjectFieldSelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ObjectFieldSelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ObjectFieldSelector) UnmarshalBinary(b []byte) error { + var res V1ObjectFieldSelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_object_meta.go b/pkg/client/generated/models/v1_object_meta.go new file mode 100644 index 0000000000..4dff538674 --- /dev/null +++ b/pkg/client/generated/models/v1_object_meta.go @@ -0,0 +1,352 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ObjectMeta v1 object meta +// +// swagger:model V1ObjectMeta +type V1ObjectMeta struct { + + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + + // CreationTimestamp is a timestamp representing the server time when this object was + // created. It is not guaranteed to be set in happens-before order across separate operations. + // Clients may not set this value. It is represented in RFC3339 form and is in UTC. + // + // Populated by the system. + // Read-only. + // Null for lists. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + CreationTimestamp string `json:"creationTimestamp,omitempty"` + + // Number of seconds allowed for this object to gracefully terminate before + // it will be removed from the system. Only set when deletionTimestamp is also set. + // May only be shortened. + // Read-only. + // +optional + DeletionGracePeriodSeconds int64 `json:"deletionGracePeriodSeconds,omitempty"` + + // DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This + // field is set by the server when a graceful deletion is requested by the user, and is not + // directly settable by a client. The resource is expected to be deleted (no longer visible + // from resource lists, and not reachable by name) after the time in this field, once the + // finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. + // Once the deletionTimestamp is set, this value may not be unset or be set further into the + // future, although it may be shortened or the resource may be deleted prior to this time. + // For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react + // by sending a graceful termination signal to the containers in the pod. After that 30 seconds, + // the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, + // remove the pod from the API. In the presence of network partitions, this object may still + // exist after this timestamp, until an administrator or automated process can determine the + // resource is fully terminated. + // If not set, graceful deletion of the object has not been requested. + // + // Populated by the system when a graceful deletion is requested. + // Read-only. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + DeletionTimestamp string `json:"deletionTimestamp,omitempty"` + + // Must be empty before the object is deleted from the registry. Each entry + // is an identifier for the responsible component that will remove the entry + // from the list. If the deletionTimestamp of the object is non-nil, entries + // in this list can only be removed. + // Finalizers may be processed and removed in any order. Order is NOT enforced + // because it introduces significant risk of stuck finalizers. + // finalizers is a shared field, any actor with permission can reorder it. + // If the finalizer list is processed in order, then this can lead to a situation + // in which the component responsible for the first finalizer in the list is + // waiting for a signal (field value, external system, or other) produced by a + // component responsible for a finalizer later in the list, resulting in a deadlock. + // Without enforced ordering finalizers are free to order amongst themselves and + // are not vulnerable to ordering changes in the list. + // +optional + // +patchStrategy=merge + // +listType=set + Finalizers []string `json:"finalizers"` + + // GenerateName is an optional prefix, used by the server, to generate a unique + // name ONLY IF the Name field has not been provided. + // If this field is used, the name returned to the client will be different + // than the name passed. This value will also be combined with a unique suffix. + // The provided value has the same validation rules as the Name field, + // and may be truncated by the length of the suffix required to make the value + // unique on the server. + // + // If this field is specified and the generated name exists, the server will return a 409. + // + // Applied only if Name is not specified. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency + // +optional + GenerateName string `json:"generateName,omitempty"` + + // A sequence number representing a specific generation of the desired state. + // Populated by the system. Read-only. + // +optional + Generation int64 `json:"generation,omitempty"` + + // Map of string keys and values that can be used to organize and categorize + // (scope and select) objects. May match selectors of replication controllers + // and services. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels + // +optional + Labels map[string]string `json:"labels,omitempty"` + + // ManagedFields maps workflow-id and version to the set of fields + // that are managed by that workflow. This is mostly for internal + // housekeeping, and users typically shouldn't need to set or + // understand this field. A workflow can be the user's name, a + // controller's name, or the name of a specific apply path like + // "ci-cd". The set of fields is always in the version that the + // workflow used when modifying the object. + // + // +optional + // +listType=atomic + ManagedFields []*V1ManagedFieldsEntry `json:"managedFields"` + + // Name must be unique within a namespace. Is required when creating resources, although + // some resources may allow a client to request the generation of an appropriate name + // automatically. Name is primarily intended for creation idempotence and configuration + // definition. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names + // +optional + Name string `json:"name,omitempty"` + + // Namespace defines the space within which each name must be unique. An empty namespace is + // equivalent to the "default" namespace, but "default" is the canonical representation. + // Not all objects are required to be scoped to a namespace - the value of this field for + // those objects will be empty. + // + // Must be a DNS_LABEL. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces + // +optional + Namespace string `json:"namespace,omitempty"` + + // List of objects depended by this object. If ALL objects in the list have + // been deleted, this object will be garbage collected. If this object is managed by a controller, + // then an entry in this list will point to this controller, with the controller field set to true. + // There cannot be more than one managing controller. + // +optional + // +patchMergeKey=uid + // +patchStrategy=merge + // +listType=map + // +listMapKey=uid + OwnerReferences []*V1OwnerReference `json:"ownerReferences"` + + // An opaque value that represents the internal version of this object that can + // be used by clients to determine when objects have changed. May be used for optimistic + // concurrency, change detection, and the watch operation on a resource or set of resources. + // Clients must treat these values as opaque and passed unmodified back to the server. + // They may only be valid for a particular resource or set of resources. + // + // Populated by the system. + // Read-only. + // Value must be treated as opaque by clients and . + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency + // +optional + ResourceVersion string `json:"resourceVersion,omitempty"` + + // Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. + // +optional + SelfLink string `json:"selfLink,omitempty"` + + // UID is the unique in time and space value for this object. It is typically generated by + // the server on successful creation of a resource and is not allowed to change on PUT + // operations. + // + // Populated by the system. + // Read-only. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids + // +optional + UID string `json:"uid,omitempty"` +} + +// Validate validates this v1 object meta +func (m *V1ObjectMeta) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateManagedFields(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOwnerReferences(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ObjectMeta) validateManagedFields(formats strfmt.Registry) error { + if swag.IsZero(m.ManagedFields) { // not required + return nil + } + + for i := 0; i < len(m.ManagedFields); i++ { + if swag.IsZero(m.ManagedFields[i]) { // not required + continue + } + + if m.ManagedFields[i] != nil { + if err := m.ManagedFields[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("managedFields" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("managedFields" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1ObjectMeta) validateOwnerReferences(formats strfmt.Registry) error { + if swag.IsZero(m.OwnerReferences) { // not required + return nil + } + + for i := 0; i < len(m.OwnerReferences); i++ { + if swag.IsZero(m.OwnerReferences[i]) { // not required + continue + } + + if m.OwnerReferences[i] != nil { + if err := m.OwnerReferences[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ownerReferences" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ownerReferences" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 object meta based on the context it is used +func (m *V1ObjectMeta) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateManagedFields(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOwnerReferences(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ObjectMeta) contextValidateManagedFields(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ManagedFields); i++ { + + if m.ManagedFields[i] != nil { + + if swag.IsZero(m.ManagedFields[i]) { // not required + return nil + } + + if err := m.ManagedFields[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("managedFields" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("managedFields" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1ObjectMeta) contextValidateOwnerReferences(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.OwnerReferences); i++ { + + if m.OwnerReferences[i] != nil { + + if swag.IsZero(m.OwnerReferences[i]) { // not required + return nil + } + + if err := m.OwnerReferences[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ownerReferences" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ownerReferences" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ObjectMeta) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ObjectMeta) UnmarshalBinary(b []byte) error { + var res V1ObjectMeta + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_object_reference.go b/pkg/client/generated/models/v1_object_reference.go new file mode 100644 index 0000000000..57e3837b81 --- /dev/null +++ b/pkg/client/generated/models/v1_object_reference.go @@ -0,0 +1,84 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ObjectReference v1 object reference +// +// swagger:model V1ObjectReference +type V1ObjectReference struct { + + // API version of the referent. + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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. + // +optional + FieldPath string `json:"fieldPath,omitempty"` + + // Kind of the referent. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // +optional + Kind string `json:"kind,omitempty"` + + // Name of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + Name string `json:"name,omitempty"` + + // Namespace of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + // +optional + Namespace string `json:"namespace,omitempty"` + + // 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 + // +optional + ResourceVersion string `json:"resourceVersion,omitempty"` + + // UID of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids + // +optional + UID string `json:"uid,omitempty"` +} + +// Validate validates this v1 object reference +func (m *V1ObjectReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 object reference based on context it is used +func (m *V1ObjectReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ObjectReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ObjectReference) UnmarshalBinary(b []byte) error { + var res V1ObjectReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_owner_reference.go b/pkg/client/generated/models/v1_owner_reference.go new file mode 100644 index 0000000000..7d3777feeb --- /dev/null +++ b/pkg/client/generated/models/v1_owner_reference.go @@ -0,0 +1,74 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1OwnerReference v1 owner reference +// +// swagger:model V1OwnerReference +type V1OwnerReference struct { + + // API version of the referent. + APIVersion string `json:"apiVersion,omitempty"` + + // If true, AND if the owner has the "foregroundDeletion" finalizer, then + // the owner cannot be deleted from the key-value store until this + // reference is removed. + // See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion + // for how the garbage collector interacts with this field and enforces the foreground deletion. + // Defaults to false. + // To set this field, a user needs "delete" permission of the owner, + // otherwise 422 (Unprocessable Entity) will be returned. + // +optional + BlockOwnerDeletion bool `json:"blockOwnerDeletion,omitempty"` + + // If true, this reference points to the managing controller. + // +optional + Controller bool `json:"controller,omitempty"` + + // Kind of the referent. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind,omitempty"` + + // Name of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names + Name string `json:"name,omitempty"` + + // UID of the referent. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids + UID string `json:"uid,omitempty"` +} + +// Validate validates this v1 owner reference +func (m *V1OwnerReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 owner reference based on context it is used +func (m *V1OwnerReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1OwnerReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1OwnerReference) UnmarshalBinary(b []byte) error { + var res V1OwnerReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_persistent_volume_claim_spec.go b/pkg/client/generated/models/v1_persistent_volume_claim_spec.go new file mode 100644 index 0000000000..5fee10c026 --- /dev/null +++ b/pkg/client/generated/models/v1_persistent_volume_claim_spec.go @@ -0,0 +1,230 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PersistentVolumeClaimSpec v1 persistent volume claim spec +// +// swagger:model V1PersistentVolumeClaimSpec +type V1PersistentVolumeClaimSpec struct { + + // accessModes contains the desired access modes the volume should have. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + // +optional + // +listType=atomic + AccessModes []string `json:"accessModes"` + + // dataSource field can be used to specify either: + // * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + // * An existing PVC (PersistentVolumeClaim) + // If the provisioner or an external controller can support the specified data source, + // it will create a new volume based on the contents of the specified data source. + // When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + // and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + // If the namespace is specified, then dataSourceRef will not be copied to dataSource. + // +optional + DataSource struct { + V1TypedLocalObjectReference + } `json:"dataSource,omitempty"` + + // dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + // volume is desired. This may be any object from a non-empty API group (non + // core object) or a PersistentVolumeClaim object. + // When this field is specified, volume binding will only succeed if the type of + // the specified object matches some installed volume populator or dynamic + // provisioner. + // This field will replace the functionality of the dataSource field and as such + // if both fields are non-empty, they must have the same value. For backwards + // compatibility, when namespace isn't specified in dataSourceRef, + // both fields (dataSource and dataSourceRef) will be set to the same + // value automatically if one of them is empty and the other is non-empty. + // When namespace is specified in dataSourceRef, + // dataSource isn't set to the same value and must be empty. + // There are three important differences between dataSource and dataSourceRef: + // * While dataSource only allows two specific types of objects, dataSourceRef + // allows any non-core object, as well as PersistentVolumeClaim objects. + // * While dataSource ignores disallowed values (dropping them), dataSourceRef + // preserves all values, and generates an error if a disallowed value is + // specified. + // * While dataSource only allows local objects, dataSourceRef allows objects + // in any namespaces. + // (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + // (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + // +optional + DataSourceRef struct { + V1TypedObjectReference + } `json:"dataSourceRef,omitempty"` + + // resources represents the minimum resources the volume should have. + // If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + // that are lower than previous value but must still be higher than capacity recorded in the + // status field of the claim. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + // +optional + Resources struct { + V1VolumeResourceRequirements + } `json:"resources,omitempty"` + + // selector is a label query over volumes to consider for binding. + // +optional + Selector struct { + V1LabelSelector + } `json:"selector,omitempty"` + + // storageClassName is the name of the StorageClass required by the claim. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + // +optional + StorageClassName string `json:"storageClassName,omitempty"` + + // volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + // If specified, the CSI driver will create or update the volume with the attributes defined + // in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + // it can be changed after the claim is created. An empty string or nil value indicates that no + // VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, + // this field can be reset to its previous value (including nil) to cancel the modification. + // If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + // set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + // exists. + // More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ + // +featureGate=VolumeAttributesClass + // +optional + VolumeAttributesClassName string `json:"volumeAttributesClassName,omitempty"` + + // volumeMode defines what type of volume is required by the claim. + // Value of Filesystem is implied when not included in claim spec. + // +optional + VolumeMode string `json:"volumeMode,omitempty"` + + // volumeName is the binding reference to the PersistentVolume backing this claim. + // +optional + VolumeName string `json:"volumeName,omitempty"` +} + +// Validate validates this v1 persistent volume claim spec +func (m *V1PersistentVolumeClaimSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateDataSource(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDataSourceRef(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResources(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSelector(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PersistentVolumeClaimSpec) validateDataSource(formats strfmt.Registry) error { + if swag.IsZero(m.DataSource) { // not required + return nil + } + + return nil +} + +func (m *V1PersistentVolumeClaimSpec) validateDataSourceRef(formats strfmt.Registry) error { + if swag.IsZero(m.DataSourceRef) { // not required + return nil + } + + return nil +} + +func (m *V1PersistentVolumeClaimSpec) validateResources(formats strfmt.Registry) error { + if swag.IsZero(m.Resources) { // not required + return nil + } + + return nil +} + +func (m *V1PersistentVolumeClaimSpec) validateSelector(formats strfmt.Registry) error { + if swag.IsZero(m.Selector) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 persistent volume claim spec based on the context it is used +func (m *V1PersistentVolumeClaimSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateDataSource(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDataSourceRef(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResources(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PersistentVolumeClaimSpec) contextValidateDataSource(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PersistentVolumeClaimSpec) contextValidateDataSourceRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PersistentVolumeClaimSpec) contextValidateResources(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PersistentVolumeClaimSpec) contextValidateSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PersistentVolumeClaimSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PersistentVolumeClaimSpec) UnmarshalBinary(b []byte) error { + var res V1PersistentVolumeClaimSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_persistent_volume_claim_template.go b/pkg/client/generated/models/v1_persistent_volume_claim_template.go new file mode 100644 index 0000000000..75c55d50e6 --- /dev/null +++ b/pkg/client/generated/models/v1_persistent_volume_claim_template.go @@ -0,0 +1,114 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PersistentVolumeClaimTemplate v1 persistent volume claim template +// +// swagger:model V1PersistentVolumeClaimTemplate +type V1PersistentVolumeClaimTemplate struct { + + // May contain labels and annotations that will be copied into the PVC + // when creating it. No other fields are allowed and will be rejected during + // validation. + // + // +optional + Metadata struct { + V1ObjectMeta + } `json:"metadata,omitempty"` + + // The specification for the PersistentVolumeClaim. The entire content is + // copied unchanged into the PVC that gets created from this + // template. The same fields as in a PersistentVolumeClaim + // are also valid here. + Spec struct { + V1PersistentVolumeClaimSpec + } `json:"spec,omitempty"` +} + +// Validate validates this v1 persistent volume claim template +func (m *V1PersistentVolumeClaimTemplate) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PersistentVolumeClaimTemplate) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +func (m *V1PersistentVolumeClaimTemplate) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 persistent volume claim template based on the context it is used +func (m *V1PersistentVolumeClaimTemplate) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PersistentVolumeClaimTemplate) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PersistentVolumeClaimTemplate) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PersistentVolumeClaimTemplate) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PersistentVolumeClaimTemplate) UnmarshalBinary(b []byte) error { + var res V1PersistentVolumeClaimTemplate + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_persistent_volume_claim_volume_source.go b/pkg/client/generated/models/v1_persistent_volume_claim_volume_source.go new file mode 100644 index 0000000000..e194a950bd --- /dev/null +++ b/pkg/client/generated/models/v1_persistent_volume_claim_volume_source.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PersistentVolumeClaimVolumeSource v1 persistent volume claim volume source +// +// swagger:model V1PersistentVolumeClaimVolumeSource +type V1PersistentVolumeClaimVolumeSource struct { + + // claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + ClaimName string `json:"claimName,omitempty"` + + // readOnly Will force the ReadOnly setting in VolumeMounts. + // Default false. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` +} + +// Validate validates this v1 persistent volume claim volume source +func (m *V1PersistentVolumeClaimVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 persistent volume claim volume source based on context it is used +func (m *V1PersistentVolumeClaimVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PersistentVolumeClaimVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PersistentVolumeClaimVolumeSource) UnmarshalBinary(b []byte) error { + var res V1PersistentVolumeClaimVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_photon_persistent_disk_volume_source.go b/pkg/client/generated/models/v1_photon_persistent_disk_volume_source.go new file mode 100644 index 0000000000..fe2a695869 --- /dev/null +++ b/pkg/client/generated/models/v1_photon_persistent_disk_volume_source.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PhotonPersistentDiskVolumeSource v1 photon persistent disk volume source +// +// swagger:model V1PhotonPersistentDiskVolumeSource +type V1PhotonPersistentDiskVolumeSource struct { + + // fsType is the filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + FsType string `json:"fsType,omitempty"` + + // pdID is the ID that identifies Photon Controller persistent disk + PdID string `json:"pdID,omitempty"` +} + +// Validate validates this v1 photon persistent disk volume source +func (m *V1PhotonPersistentDiskVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 photon persistent disk volume source based on context it is used +func (m *V1PhotonPersistentDiskVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PhotonPersistentDiskVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PhotonPersistentDiskVolumeSource) UnmarshalBinary(b []byte) error { + var res V1PhotonPersistentDiskVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_affinity.go b/pkg/client/generated/models/v1_pod_affinity.go new file mode 100644 index 0000000000..8e37ea3d14 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_affinity.go @@ -0,0 +1,215 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodAffinity v1 pod affinity +// +// swagger:model V1PodAffinity +type V1PodAffinity struct { + + // The scheduler will prefer to schedule pods to nodes that satisfy + // the affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and adding + // "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + // node(s) with the highest sum are the most preferred. + // +optional + // +listType=atomic + PreferredDuringSchedulingIgnoredDuringExecution []*V1WeightedPodAffinityTerm `json:"preferredDuringSchedulingIgnoredDuringExecution"` + + // If the affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system may or may not try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + // +listType=atomic + RequiredDuringSchedulingIgnoredDuringExecution []*V1PodAffinityTerm `json:"requiredDuringSchedulingIgnoredDuringExecution"` +} + +// Validate validates this v1 pod affinity +func (m *V1PodAffinity) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePreferredDuringSchedulingIgnoredDuringExecution(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequiredDuringSchedulingIgnoredDuringExecution(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodAffinity) validatePreferredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error { + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution) { // not required + return nil + } + + for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ { + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required + continue + } + + if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil { + if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodAffinity) validateRequiredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error { + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution) { // not required + return nil + } + + for i := 0; i < len(m.RequiredDuringSchedulingIgnoredDuringExecution); i++ { + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution[i]) { // not required + continue + } + + if m.RequiredDuringSchedulingIgnoredDuringExecution[i] != nil { + if err := m.RequiredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 pod affinity based on the context it is used +func (m *V1PodAffinity) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePreferredDuringSchedulingIgnoredDuringExecution(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRequiredDuringSchedulingIgnoredDuringExecution(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodAffinity) contextValidatePreferredDuringSchedulingIgnoredDuringExecution(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ { + + if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil { + + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required + return nil + } + + if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodAffinity) contextValidateRequiredDuringSchedulingIgnoredDuringExecution(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.RequiredDuringSchedulingIgnoredDuringExecution); i++ { + + if m.RequiredDuringSchedulingIgnoredDuringExecution[i] != nil { + + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution[i]) { // not required + return nil + } + + if err := m.RequiredDuringSchedulingIgnoredDuringExecution[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodAffinity) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodAffinity) UnmarshalBinary(b []byte) error { + var res V1PodAffinity + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_affinity_term.go b/pkg/client/generated/models/v1_pod_affinity_term.go new file mode 100644 index 0000000000..c9059eac5f --- /dev/null +++ b/pkg/client/generated/models/v1_pod_affinity_term.go @@ -0,0 +1,155 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodAffinityTerm v1 pod affinity term +// +// swagger:model V1PodAffinityTerm +type V1PodAffinityTerm struct { + + // A label query over a set of resources, in this case pods. + // If it's null, this PodAffinityTerm matches with no Pods. + // +optional + LabelSelector struct { + V1LabelSelector + } `json:"labelSelector,omitempty"` + + // MatchLabelKeys is a set of pod label keys to select which pods will + // be taken into consideration. The keys are used to lookup values from the + // incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` + // to select the group of existing pods which pods will be taken into consideration + // for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + // pod labels will be ignored. The default value is empty. + // The same key is forbidden to exist in both matchLabelKeys and labelSelector. + // Also, matchLabelKeys cannot be set when labelSelector isn't set. + // + // +listType=atomic + // +optional + MatchLabelKeys []string `json:"matchLabelKeys"` + + // MismatchLabelKeys is a set of pod label keys to select which pods will + // be taken into consideration. The keys are used to lookup values from the + // incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` + // to select the group of existing pods which pods will be taken into consideration + // for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + // pod labels will be ignored. The default value is empty. + // The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. + // Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + // + // +listType=atomic + // +optional + MismatchLabelKeys []string `json:"mismatchLabelKeys"` + + // A label query over the set of namespaces that the term applies to. + // The term is applied to the union of the namespaces selected by this field + // and the ones listed in the namespaces field. + // null selector and null or empty namespaces list means "this pod's namespace". + // An empty selector ({}) matches all namespaces. + // +optional + NamespaceSelector struct { + V1LabelSelector + } `json:"namespaceSelector,omitempty"` + + // namespaces specifies a static list of namespace names that the term applies to. + // The term is applied to the union of the namespaces listed in this field + // and the ones selected by namespaceSelector. + // null or empty namespaces list and null namespaceSelector means "this pod's namespace". + // +optional + // +listType=atomic + Namespaces []string `json:"namespaces"` + + // This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + // the labelSelector in the specified namespaces, where co-located is defined as running on a node + // whose value of the label with key topologyKey matches that of any node on which any of the + // selected pods is running. + // Empty topologyKey is not allowed. + TopologyKey string `json:"topologyKey,omitempty"` +} + +// Validate validates this v1 pod affinity term +func (m *V1PodAffinityTerm) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLabelSelector(formats); err != nil { + res = append(res, err) + } + + if err := m.validateNamespaceSelector(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodAffinityTerm) validateLabelSelector(formats strfmt.Registry) error { + if swag.IsZero(m.LabelSelector) { // not required + return nil + } + + return nil +} + +func (m *V1PodAffinityTerm) validateNamespaceSelector(formats strfmt.Registry) error { + if swag.IsZero(m.NamespaceSelector) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 pod affinity term based on the context it is used +func (m *V1PodAffinityTerm) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateLabelSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateNamespaceSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodAffinityTerm) contextValidateLabelSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodAffinityTerm) contextValidateNamespaceSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodAffinityTerm) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodAffinityTerm) UnmarshalBinary(b []byte) error { + var res V1PodAffinityTerm + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_anti_affinity.go b/pkg/client/generated/models/v1_pod_anti_affinity.go new file mode 100644 index 0000000000..2068e0b9c5 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_anti_affinity.go @@ -0,0 +1,215 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodAntiAffinity v1 pod anti affinity +// +// swagger:model V1PodAntiAffinity +type V1PodAntiAffinity struct { + + // The scheduler will prefer to schedule pods to nodes that satisfy + // the anti-affinity expressions specified by this field, but it may choose + // a node that violates one or more of the expressions. The node that is + // most preferred is the one with the greatest sum of weights, i.e. + // for each node that meets all of the scheduling requirements (resource + // request, requiredDuringScheduling anti-affinity expressions, etc.), + // compute a sum by iterating through the elements of this field and subtracting + // "weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the + // node(s) with the highest sum are the most preferred. + // +optional + // +listType=atomic + PreferredDuringSchedulingIgnoredDuringExecution []*V1WeightedPodAffinityTerm `json:"preferredDuringSchedulingIgnoredDuringExecution"` + + // If the anti-affinity requirements specified by this field are not met at + // scheduling time, the pod will not be scheduled onto the node. + // If the anti-affinity requirements specified by this field cease to be met + // at some point during pod execution (e.g. due to a pod label update), the + // system may or may not try to eventually evict the pod from its node. + // When there are multiple elements, the lists of nodes corresponding to each + // podAffinityTerm are intersected, i.e. all terms must be satisfied. + // +optional + // +listType=atomic + RequiredDuringSchedulingIgnoredDuringExecution []*V1PodAffinityTerm `json:"requiredDuringSchedulingIgnoredDuringExecution"` +} + +// Validate validates this v1 pod anti affinity +func (m *V1PodAntiAffinity) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePreferredDuringSchedulingIgnoredDuringExecution(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequiredDuringSchedulingIgnoredDuringExecution(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodAntiAffinity) validatePreferredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error { + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution) { // not required + return nil + } + + for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ { + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required + continue + } + + if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil { + if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodAntiAffinity) validateRequiredDuringSchedulingIgnoredDuringExecution(formats strfmt.Registry) error { + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution) { // not required + return nil + } + + for i := 0; i < len(m.RequiredDuringSchedulingIgnoredDuringExecution); i++ { + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution[i]) { // not required + continue + } + + if m.RequiredDuringSchedulingIgnoredDuringExecution[i] != nil { + if err := m.RequiredDuringSchedulingIgnoredDuringExecution[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 pod anti affinity based on the context it is used +func (m *V1PodAntiAffinity) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePreferredDuringSchedulingIgnoredDuringExecution(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRequiredDuringSchedulingIgnoredDuringExecution(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodAntiAffinity) contextValidatePreferredDuringSchedulingIgnoredDuringExecution(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.PreferredDuringSchedulingIgnoredDuringExecution); i++ { + + if m.PreferredDuringSchedulingIgnoredDuringExecution[i] != nil { + + if swag.IsZero(m.PreferredDuringSchedulingIgnoredDuringExecution[i]) { // not required + return nil + } + + if err := m.PreferredDuringSchedulingIgnoredDuringExecution[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("preferredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodAntiAffinity) contextValidateRequiredDuringSchedulingIgnoredDuringExecution(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.RequiredDuringSchedulingIgnoredDuringExecution); i++ { + + if m.RequiredDuringSchedulingIgnoredDuringExecution[i] != nil { + + if swag.IsZero(m.RequiredDuringSchedulingIgnoredDuringExecution[i]) { // not required + return nil + } + + if err := m.RequiredDuringSchedulingIgnoredDuringExecution[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("requiredDuringSchedulingIgnoredDuringExecution" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodAntiAffinity) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodAntiAffinity) UnmarshalBinary(b []byte) error { + var res V1PodAntiAffinity + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_certificate_projection.go b/pkg/client/generated/models/v1_pod_certificate_projection.go new file mode 100644 index 0000000000..016f9ae7cf --- /dev/null +++ b/pkg/client/generated/models/v1_pod_certificate_projection.go @@ -0,0 +1,113 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodCertificateProjection v1 pod certificate projection +// +// swagger:model V1PodCertificateProjection +type V1PodCertificateProjection struct { + + // Write the certificate chain at this path in the projected volume. + // + // Most applications should use credentialBundlePath. When using keyPath + // and certificateChainPath, your application needs to check that the key + // and leaf certificate are consistent, because it is possible to read the + // files mid-rotation. + // + // +optional + CertificateChainPath string `json:"certificateChainPath,omitempty"` + + // Write the credential bundle at this path in the projected volume. + // + // The credential bundle is a single file that contains multiple PEM blocks. + // The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private + // key. + // + // The remaining blocks are CERTIFICATE blocks, containing the issued + // certificate chain from the signer (leaf and any intermediates). + // + // Using credentialBundlePath lets your Pod's application code make a single + // atomic read that retrieves a consistent key and certificate chain. If you + // project them to separate files, your application code will need to + // additionally check that the leaf certificate was issued to the key. + // + // +optional + CredentialBundlePath string `json:"credentialBundlePath,omitempty"` + + // Write the key at this path in the projected volume. + // + // Most applications should use credentialBundlePath. When using keyPath + // and certificateChainPath, your application needs to check that the key + // and leaf certificate are consistent, because it is possible to read the + // files mid-rotation. + // + // +optional + KeyPath string `json:"keyPath,omitempty"` + + // The type of keypair Kubelet will generate for the pod. + // + // Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", + // "ECDSAP521", and "ED25519". + // + // +required + KeyType string `json:"keyType,omitempty"` + + // maxExpirationSeconds is the maximum lifetime permitted for the + // certificate. + // + // Kubelet copies this value verbatim into the PodCertificateRequests it + // generates for this projection. + // + // If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver + // will reject values shorter than 3600 (1 hour). The maximum allowable + // value is 7862400 (91 days). + // + // The signer implementation is then free to issue a certificate with any + // lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 + // seconds (1 hour). This constraint is enforced by kube-apiserver. + // `kubernetes.io` signers will never issue certificates with a lifetime + // longer than 24 hours. + // + // +optional + MaxExpirationSeconds int64 `json:"maxExpirationSeconds,omitempty"` + + // Kubelet's generated CSRs will be addressed to this signer. + // + // +required + SignerName string `json:"signerName,omitempty"` +} + +// Validate validates this v1 pod certificate projection +func (m *V1PodCertificateProjection) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod certificate projection based on context it is used +func (m *V1PodCertificateProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodCertificateProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodCertificateProjection) UnmarshalBinary(b []byte) error { + var res V1PodCertificateProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_dns_config.go b/pkg/client/generated/models/v1_pod_dns_config.go new file mode 100644 index 0000000000..dfe0af072f --- /dev/null +++ b/pkg/client/generated/models/v1_pod_dns_config.go @@ -0,0 +1,146 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodDNSConfig v1 pod DNS config +// +// swagger:model V1PodDNSConfig +type V1PodDNSConfig struct { + + // A list of DNS name server IP addresses. + // This will be appended to the base nameservers generated from DNSPolicy. + // Duplicated nameservers will be removed. + // +optional + // +listType=atomic + Nameservers []string `json:"nameservers"` + + // A list of DNS resolver options. + // This will be merged with the base options generated from DNSPolicy. + // Duplicated entries will be removed. Resolution options given in Options + // will override those that appear in the base DNSPolicy. + // +optional + // +listType=atomic + Options []*V1PodDNSConfigOption `json:"options"` + + // A list of DNS search domains for host-name lookup. + // This will be appended to the base search paths generated from DNSPolicy. + // Duplicated search paths will be removed. + // +optional + // +listType=atomic + Searches []string `json:"searches"` +} + +// Validate validates this v1 pod DNS config +func (m *V1PodDNSConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateOptions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodDNSConfig) validateOptions(formats strfmt.Registry) error { + if swag.IsZero(m.Options) { // not required + return nil + } + + for i := 0; i < len(m.Options); i++ { + if swag.IsZero(m.Options[i]) { // not required + continue + } + + if m.Options[i] != nil { + if err := m.Options[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("options" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("options" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 pod DNS config based on the context it is used +func (m *V1PodDNSConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodDNSConfig) contextValidateOptions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Options); i++ { + + if m.Options[i] != nil { + + if swag.IsZero(m.Options[i]) { // not required + return nil + } + + if err := m.Options[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("options" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("options" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodDNSConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodDNSConfig) UnmarshalBinary(b []byte) error { + var res V1PodDNSConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_dns_config_option.go b/pkg/client/generated/models/v1_pod_dns_config_option.go new file mode 100644 index 0000000000..f4d4f245a5 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_dns_config_option.go @@ -0,0 +1,52 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodDNSConfigOption v1 pod DNS config option +// +// swagger:model V1PodDNSConfigOption +type V1PodDNSConfigOption struct { + + // Name is this DNS resolver option's name. + // Required. + Name string `json:"name,omitempty"` + + // Value is this DNS resolver option's value. + // +optional + Value string `json:"value,omitempty"` +} + +// Validate validates this v1 pod DNS config option +func (m *V1PodDNSConfigOption) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod DNS config option based on context it is used +func (m *V1PodDNSConfigOption) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodDNSConfigOption) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodDNSConfigOption) UnmarshalBinary(b []byte) error { + var res V1PodDNSConfigOption + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_failure_policy.go b/pkg/client/generated/models/v1_pod_failure_policy.go new file mode 100644 index 0000000000..888731e181 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_failure_policy.go @@ -0,0 +1,132 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodFailurePolicy v1 pod failure policy +// +// swagger:model V1PodFailurePolicy +type V1PodFailurePolicy struct { + + // A list of pod failure policy rules. The rules are evaluated in order. + // Once a rule matches a Pod failure, the remaining of the rules are ignored. + // When no rule matches the Pod failure, the default handling applies - the + // counter of pod failures is incremented and it is checked against + // the backoffLimit. At most 20 elements are allowed. + // +listType=atomic + Rules []*V1PodFailurePolicyRule `json:"rules"` +} + +// Validate validates this v1 pod failure policy +func (m *V1PodFailurePolicy) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateRules(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodFailurePolicy) validateRules(formats strfmt.Registry) error { + if swag.IsZero(m.Rules) { // not required + return nil + } + + for i := 0; i < len(m.Rules); i++ { + if swag.IsZero(m.Rules[i]) { // not required + continue + } + + if m.Rules[i] != nil { + if err := m.Rules[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("rules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("rules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 pod failure policy based on the context it is used +func (m *V1PodFailurePolicy) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateRules(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodFailurePolicy) contextValidateRules(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Rules); i++ { + + if m.Rules[i] != nil { + + if swag.IsZero(m.Rules[i]) { // not required + return nil + } + + if err := m.Rules[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("rules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("rules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodFailurePolicy) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodFailurePolicy) UnmarshalBinary(b []byte) error { + var res V1PodFailurePolicy + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_failure_policy_action.go b/pkg/client/generated/models/v1_pod_failure_policy_action.go new file mode 100644 index 0000000000..dddcece6bc --- /dev/null +++ b/pkg/client/generated/models/v1_pod_failure_policy_action.go @@ -0,0 +1,81 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// V1PodFailurePolicyAction v1 pod failure policy action +// +// swagger:model V1PodFailurePolicyAction +type V1PodFailurePolicyAction string + +func NewV1PodFailurePolicyAction(value V1PodFailurePolicyAction) *V1PodFailurePolicyAction { + return &value +} + +// Pointer returns a pointer to a freshly-allocated V1PodFailurePolicyAction. +func (m V1PodFailurePolicyAction) Pointer() *V1PodFailurePolicyAction { + return &m +} + +const ( + + // V1PodFailurePolicyActionFailJob captures enum value "FailJob" + V1PodFailurePolicyActionFailJob V1PodFailurePolicyAction = "FailJob" + + // V1PodFailurePolicyActionFailIndex captures enum value "FailIndex" + V1PodFailurePolicyActionFailIndex V1PodFailurePolicyAction = "FailIndex" + + // V1PodFailurePolicyActionIgnore captures enum value "Ignore" + V1PodFailurePolicyActionIgnore V1PodFailurePolicyAction = "Ignore" + + // V1PodFailurePolicyActionCount captures enum value "Count" + V1PodFailurePolicyActionCount V1PodFailurePolicyAction = "Count" +) + +// for schema +var v1PodFailurePolicyActionEnum []any + +func init() { + var res []V1PodFailurePolicyAction + if err := json.Unmarshal([]byte(`["FailJob","FailIndex","Ignore","Count"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + v1PodFailurePolicyActionEnum = append(v1PodFailurePolicyActionEnum, v) + } +} + +func (m V1PodFailurePolicyAction) validateV1PodFailurePolicyActionEnum(path, location string, value V1PodFailurePolicyAction) error { + if err := validate.EnumCase(path, location, value, v1PodFailurePolicyActionEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this v1 pod failure policy action +func (m V1PodFailurePolicyAction) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateV1PodFailurePolicyActionEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this v1 pod failure policy action based on context it is used +func (m V1PodFailurePolicyAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/pkg/client/generated/models/v1_pod_failure_policy_on_exit_codes_operator.go b/pkg/client/generated/models/v1_pod_failure_policy_on_exit_codes_operator.go new file mode 100644 index 0000000000..7272c7f1fc --- /dev/null +++ b/pkg/client/generated/models/v1_pod_failure_policy_on_exit_codes_operator.go @@ -0,0 +1,75 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// V1PodFailurePolicyOnExitCodesOperator v1 pod failure policy on exit codes operator +// +// swagger:model V1PodFailurePolicyOnExitCodesOperator +type V1PodFailurePolicyOnExitCodesOperator string + +func NewV1PodFailurePolicyOnExitCodesOperator(value V1PodFailurePolicyOnExitCodesOperator) *V1PodFailurePolicyOnExitCodesOperator { + return &value +} + +// Pointer returns a pointer to a freshly-allocated V1PodFailurePolicyOnExitCodesOperator. +func (m V1PodFailurePolicyOnExitCodesOperator) Pointer() *V1PodFailurePolicyOnExitCodesOperator { + return &m +} + +const ( + + // V1PodFailurePolicyOnExitCodesOperatorIn captures enum value "In" + V1PodFailurePolicyOnExitCodesOperatorIn V1PodFailurePolicyOnExitCodesOperator = "In" + + // V1PodFailurePolicyOnExitCodesOperatorNotIn captures enum value "NotIn" + V1PodFailurePolicyOnExitCodesOperatorNotIn V1PodFailurePolicyOnExitCodesOperator = "NotIn" +) + +// for schema +var v1PodFailurePolicyOnExitCodesOperatorEnum []any + +func init() { + var res []V1PodFailurePolicyOnExitCodesOperator + if err := json.Unmarshal([]byte(`["In","NotIn"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + v1PodFailurePolicyOnExitCodesOperatorEnum = append(v1PodFailurePolicyOnExitCodesOperatorEnum, v) + } +} + +func (m V1PodFailurePolicyOnExitCodesOperator) validateV1PodFailurePolicyOnExitCodesOperatorEnum(path, location string, value V1PodFailurePolicyOnExitCodesOperator) error { + if err := validate.EnumCase(path, location, value, v1PodFailurePolicyOnExitCodesOperatorEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this v1 pod failure policy on exit codes operator +func (m V1PodFailurePolicyOnExitCodesOperator) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateV1PodFailurePolicyOnExitCodesOperatorEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this v1 pod failure policy on exit codes operator based on context it is used +func (m V1PodFailurePolicyOnExitCodesOperator) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/pkg/client/generated/models/v1_pod_failure_policy_on_exit_codes_requirement.go b/pkg/client/generated/models/v1_pod_failure_policy_on_exit_codes_requirement.go new file mode 100644 index 0000000000..506be70307 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_failure_policy_on_exit_codes_requirement.go @@ -0,0 +1,107 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodFailurePolicyOnExitCodesRequirement v1 pod failure policy on exit codes requirement +// +// swagger:model V1PodFailurePolicyOnExitCodesRequirement +type V1PodFailurePolicyOnExitCodesRequirement struct { + + // Restricts the check for exit codes to the container with the + // specified name. When null, the rule applies to all containers. + // When specified, it should match one the container or initContainer + // names in the pod template. + // +optional + ContainerName string `json:"containerName,omitempty"` + + // Represents the relationship between the container exit code(s) and the + // specified values. Containers completed with success (exit code 0) are + // excluded from the requirement check. Possible values are: + // + // - In: the requirement is satisfied if at least one container exit code + // (might be multiple if there are multiple containers not restricted + // by the 'containerName' field) is in the set of specified values. + // - NotIn: the requirement is satisfied if at least one container exit code + // (might be multiple if there are multiple containers not restricted + // by the 'containerName' field) is not in the set of specified values. + // Additional values are considered to be added in the future. Clients should + // react to an unknown operator by assuming the requirement is not satisfied. + Operator struct { + V1PodFailurePolicyOnExitCodesOperator + } `json:"operator,omitempty"` + + // Specifies the set of values. Each returned container exit code (might be + // multiple in case of multiple containers) is checked against this set of + // values with respect to the operator. The list of values must be ordered + // and must not contain duplicates. Value '0' cannot be used for the In operator. + // At least one element is required. At most 255 elements are allowed. + // +listType=set + Values []int64 `json:"values"` +} + +// Validate validates this v1 pod failure policy on exit codes requirement +func (m *V1PodFailurePolicyOnExitCodesRequirement) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateOperator(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodFailurePolicyOnExitCodesRequirement) validateOperator(formats strfmt.Registry) error { + if swag.IsZero(m.Operator) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 pod failure policy on exit codes requirement based on the context it is used +func (m *V1PodFailurePolicyOnExitCodesRequirement) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateOperator(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodFailurePolicyOnExitCodesRequirement) contextValidateOperator(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodFailurePolicyOnExitCodesRequirement) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodFailurePolicyOnExitCodesRequirement) UnmarshalBinary(b []byte) error { + var res V1PodFailurePolicyOnExitCodesRequirement + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_failure_policy_on_pod_conditions_pattern.go b/pkg/client/generated/models/v1_pod_failure_policy_on_pod_conditions_pattern.go new file mode 100644 index 0000000000..b372932758 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_failure_policy_on_pod_conditions_pattern.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodFailurePolicyOnPodConditionsPattern v1 pod failure policy on pod conditions pattern +// +// swagger:model V1PodFailurePolicyOnPodConditionsPattern +type V1PodFailurePolicyOnPodConditionsPattern struct { + + // Specifies the required Pod condition status. To match a pod condition + // it is required that the specified status equals the pod condition status. + // Defaults to True. + Status string `json:"status,omitempty"` + + // Specifies the required Pod condition type. To match a pod condition + // it is required that specified type equals the pod condition type. + Type string `json:"type,omitempty"` +} + +// Validate validates this v1 pod failure policy on pod conditions pattern +func (m *V1PodFailurePolicyOnPodConditionsPattern) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod failure policy on pod conditions pattern based on context it is used +func (m *V1PodFailurePolicyOnPodConditionsPattern) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodFailurePolicyOnPodConditionsPattern) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodFailurePolicyOnPodConditionsPattern) UnmarshalBinary(b []byte) error { + var res V1PodFailurePolicyOnPodConditionsPattern + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_failure_policy_rule.go b/pkg/client/generated/models/v1_pod_failure_policy_rule.go new file mode 100644 index 0000000000..ae0257b808 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_failure_policy_rule.go @@ -0,0 +1,196 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodFailurePolicyRule v1 pod failure policy rule +// +// swagger:model V1PodFailurePolicyRule +type V1PodFailurePolicyRule struct { + + // Specifies the action taken on a pod failure when the requirements are satisfied. + // Possible values are: + // + // - FailJob: indicates that the pod's job is marked as Failed and all + // running pods are terminated. + // - FailIndex: indicates that the pod's index is marked as Failed and will + // not be restarted. + // - Ignore: indicates that the counter towards the .backoffLimit is not + // incremented and a replacement pod is created. + // - Count: indicates that the pod is handled in the default way - the + // counter towards the .backoffLimit is incremented. + // Additional values are considered to be added in the future. Clients should + // react to an unknown action by skipping the rule. + Action struct { + V1PodFailurePolicyAction + } `json:"action,omitempty"` + + // Represents the requirement on the container exit codes. + // +optional + OnExitCodes struct { + V1PodFailurePolicyOnExitCodesRequirement + } `json:"onExitCodes,omitempty"` + + // Represents the requirement on the pod conditions. The requirement is represented + // as a list of pod condition patterns. The requirement is satisfied if at + // least one pattern matches an actual pod condition. At most 20 elements are allowed. + // +listType=atomic + // +optional + OnPodConditions []*V1PodFailurePolicyOnPodConditionsPattern `json:"onPodConditions"` +} + +// Validate validates this v1 pod failure policy rule +func (m *V1PodFailurePolicyRule) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAction(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOnExitCodes(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOnPodConditions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodFailurePolicyRule) validateAction(formats strfmt.Registry) error { + if swag.IsZero(m.Action) { // not required + return nil + } + + return nil +} + +func (m *V1PodFailurePolicyRule) validateOnExitCodes(formats strfmt.Registry) error { + if swag.IsZero(m.OnExitCodes) { // not required + return nil + } + + return nil +} + +func (m *V1PodFailurePolicyRule) validateOnPodConditions(formats strfmt.Registry) error { + if swag.IsZero(m.OnPodConditions) { // not required + return nil + } + + for i := 0; i < len(m.OnPodConditions); i++ { + if swag.IsZero(m.OnPodConditions[i]) { // not required + continue + } + + if m.OnPodConditions[i] != nil { + if err := m.OnPodConditions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("onPodConditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("onPodConditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 pod failure policy rule based on the context it is used +func (m *V1PodFailurePolicyRule) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAction(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOnExitCodes(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOnPodConditions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodFailurePolicyRule) contextValidateAction(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodFailurePolicyRule) contextValidateOnExitCodes(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodFailurePolicyRule) contextValidateOnPodConditions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.OnPodConditions); i++ { + + if m.OnPodConditions[i] != nil { + + if swag.IsZero(m.OnPodConditions[i]) { // not required + return nil + } + + if err := m.OnPodConditions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("onPodConditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("onPodConditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodFailurePolicyRule) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodFailurePolicyRule) UnmarshalBinary(b []byte) error { + var res V1PodFailurePolicyRule + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_o_s.go b/pkg/client/generated/models/v1_pod_o_s.go new file mode 100644 index 0000000000..973b8651cc --- /dev/null +++ b/pkg/client/generated/models/v1_pod_o_s.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodOS v1 pod o s +// +// swagger:model V1PodOS +type V1PodOS struct { + + // Name is the name of the operating system. The currently supported values are linux and windows. + // Additional value may be defined in future and can be one of: + // https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration + // Clients should expect to handle additional values and treat unrecognized values in this field as os: null + Name string `json:"name,omitempty"` +} + +// Validate validates this v1 pod o s +func (m *V1PodOS) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod o s based on context it is used +func (m *V1PodOS) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodOS) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodOS) UnmarshalBinary(b []byte) error { + var res V1PodOS + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_readiness_gate.go b/pkg/client/generated/models/v1_pod_readiness_gate.go new file mode 100644 index 0000000000..823afa7388 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_readiness_gate.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodReadinessGate v1 pod readiness gate +// +// swagger:model V1PodReadinessGate +type V1PodReadinessGate struct { + + // ConditionType refers to a condition in the pod's condition list with matching type. + ConditionType string `json:"conditionType,omitempty"` +} + +// Validate validates this v1 pod readiness gate +func (m *V1PodReadinessGate) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod readiness gate based on context it is used +func (m *V1PodReadinessGate) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodReadinessGate) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodReadinessGate) UnmarshalBinary(b []byte) error { + var res V1PodReadinessGate + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_replacement_policy.go b/pkg/client/generated/models/v1_pod_replacement_policy.go new file mode 100644 index 0000000000..ee6ae45b84 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_replacement_policy.go @@ -0,0 +1,75 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// V1PodReplacementPolicy v1 pod replacement policy +// +// swagger:model V1PodReplacementPolicy +type V1PodReplacementPolicy string + +func NewV1PodReplacementPolicy(value V1PodReplacementPolicy) *V1PodReplacementPolicy { + return &value +} + +// Pointer returns a pointer to a freshly-allocated V1PodReplacementPolicy. +func (m V1PodReplacementPolicy) Pointer() *V1PodReplacementPolicy { + return &m +} + +const ( + + // V1PodReplacementPolicyTerminatingOrFailed captures enum value "TerminatingOrFailed" + V1PodReplacementPolicyTerminatingOrFailed V1PodReplacementPolicy = "TerminatingOrFailed" + + // V1PodReplacementPolicyFailed captures enum value "Failed" + V1PodReplacementPolicyFailed V1PodReplacementPolicy = "Failed" +) + +// for schema +var v1PodReplacementPolicyEnum []any + +func init() { + var res []V1PodReplacementPolicy + if err := json.Unmarshal([]byte(`["TerminatingOrFailed","Failed"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + v1PodReplacementPolicyEnum = append(v1PodReplacementPolicyEnum, v) + } +} + +func (m V1PodReplacementPolicy) validateV1PodReplacementPolicyEnum(path, location string, value V1PodReplacementPolicy) error { + if err := validate.EnumCase(path, location, value, v1PodReplacementPolicyEnum, true); err != nil { + return err + } + return nil +} + +// Validate validates this v1 pod replacement policy +func (m V1PodReplacementPolicy) Validate(formats strfmt.Registry) error { + var res []error + + // value enum + if err := m.validateV1PodReplacementPolicyEnum("", "body", m); err != nil { + return err + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validates this v1 pod replacement policy based on context it is used +func (m V1PodReplacementPolicy) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} diff --git a/pkg/client/generated/models/v1_pod_resource_claim.go b/pkg/client/generated/models/v1_pod_resource_claim.go new file mode 100644 index 0000000000..5dcab56220 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_resource_claim.go @@ -0,0 +1,72 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodResourceClaim v1 pod resource claim +// +// swagger:model V1PodResourceClaim +type V1PodResourceClaim struct { + + // Name uniquely identifies this resource claim inside the pod. + // This must be a DNS_LABEL. + Name string `json:"name,omitempty"` + + // ResourceClaimName is the name of a ResourceClaim object in the same + // namespace as this pod. + // + // Exactly one of ResourceClaimName and ResourceClaimTemplateName must + // be set. + ResourceClaimName string `json:"resourceClaimName,omitempty"` + + // ResourceClaimTemplateName is the name of a ResourceClaimTemplate + // object in the same namespace as this pod. + // + // The template will be used to create a new ResourceClaim, which will + // be bound to this pod. When this pod is deleted, the ResourceClaim + // will also be deleted. The pod name and resource name, along with a + // generated component, will be used to form a unique name for the + // ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + // + // This field is immutable and no changes will be made to the + // corresponding ResourceClaim by the control plane after creating the + // ResourceClaim. + // + // Exactly one of ResourceClaimName and ResourceClaimTemplateName must + // be set. + ResourceClaimTemplateName string `json:"resourceClaimTemplateName,omitempty"` +} + +// Validate validates this v1 pod resource claim +func (m *V1PodResourceClaim) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod resource claim based on context it is used +func (m *V1PodResourceClaim) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodResourceClaim) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodResourceClaim) UnmarshalBinary(b []byte) error { + var res V1PodResourceClaim + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_scheduling_gate.go b/pkg/client/generated/models/v1_pod_scheduling_gate.go new file mode 100644 index 0000000000..ffd9d5c035 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_scheduling_gate.go @@ -0,0 +1,48 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodSchedulingGate v1 pod scheduling gate +// +// swagger:model V1PodSchedulingGate +type V1PodSchedulingGate struct { + + // Name of the scheduling gate. + // Each scheduling gate must have a unique name field. + Name string `json:"name,omitempty"` +} + +// Validate validates this v1 pod scheduling gate +func (m *V1PodSchedulingGate) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 pod scheduling gate based on context it is used +func (m *V1PodSchedulingGate) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodSchedulingGate) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodSchedulingGate) UnmarshalBinary(b []byte) error { + var res V1PodSchedulingGate + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_security_context.go b/pkg/client/generated/models/v1_pod_security_context.go new file mode 100644 index 0000000000..9f56c5573b --- /dev/null +++ b/pkg/client/generated/models/v1_pod_security_context.go @@ -0,0 +1,349 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodSecurityContext v1 pod security context +// +// swagger:model V1PodSecurityContext +type V1PodSecurityContext struct { + + // appArmorProfile is the AppArmor options to use by the containers in this pod. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + AppArmorProfile struct { + V1AppArmorProfile + } `json:"appArmorProfile,omitempty"` + + // A special supplemental group that applies to all containers in a pod. + // Some volume types allow the Kubelet to change the ownership of that volume + // to be owned by the pod: + // + // 1. The owning GID will be the FSGroup + // 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + // 3. The permission bits are OR'd with rw-rw---- + // + // If unset, the Kubelet will not modify the ownership and permissions of any volume. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + FsGroup int64 `json:"fsGroup,omitempty"` + + // fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + // before being exposed inside Pod. This field will only apply to + // volume types which support fsGroup based ownership(and permissions). + // It will have no effect on ephemeral volume types such as: secret, configmaps + // and emptydir. + // Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + FsGroupChangePolicy string `json:"fsGroupChangePolicy,omitempty"` + + // The GID to run the entrypoint of the container process. + // Uses runtime default if unset. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsGroup int64 `json:"runAsGroup,omitempty"` + + // Indicates that the container must run as a non-root user. + // If true, the Kubelet will validate the image at runtime to ensure that it + // does not run as UID 0 (root) and fail to start the container if it does. + // If unset or false, no such validation will be performed. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + RunAsNonRoot bool `json:"runAsNonRoot,omitempty"` + + // The UID to run the entrypoint of the container process. + // Defaults to user specified in image metadata if unspecified. + // May also be set in SecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence + // for that container. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsUser int64 `json:"runAsUser,omitempty"` + + // seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. + // It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. + // Valid values are "MountOption" and "Recursive". + // + // "Recursive" means relabeling of all files on all Pod volumes by the container runtime. + // This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. + // + // "MountOption" mounts all eligible Pod volumes with `-o context` mount option. + // This requires all Pods that share the same volume to use the same SELinux label. + // It is not possible to share the same volume among privileged and unprivileged Pods. + // Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes + // whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their + // CSIDriver instance. Other volumes are always re-labelled recursively. + // "MountOption" value is allowed only when SELinuxMount feature gate is enabled. + // + // If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. + // If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes + // and "Recursive" for all other volumes. + // + // This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. + // + // All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. + // Note that this field cannot be set when spec.os.name is windows. + // +featureGate=SELinuxChangePolicy + // +optional + SeLinuxChangePolicy string `json:"seLinuxChangePolicy,omitempty"` + + // The SELinux context to be applied to all containers. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container. May also be set in SecurityContext. If set in + // both SecurityContext and PodSecurityContext, the value specified in SecurityContext + // takes precedence for that container. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SeLinuxOptions struct { + V1SELinuxOptions + } `json:"seLinuxOptions,omitempty"` + + // The seccomp options to use by the containers in this pod. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SeccompProfile struct { + V1SeccompProfile + } `json:"seccompProfile,omitempty"` + + // A list of groups applied to the first process run in each container, in + // addition to the container's primary GID and fsGroup (if specified). If + // the SupplementalGroupsPolicy feature is enabled, the + // supplementalGroupsPolicy field determines whether these are in addition + // to or instead of any group memberships defined in the container image. + // If unspecified, no additional groups are added, though group memberships + // defined in the container image may still be used, depending on the + // supplementalGroupsPolicy field. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + // +listType=atomic + SupplementalGroups []int64 `json:"supplementalGroups"` + + // Defines how supplemental groups of the first container processes are calculated. + // Valid values are "Merge" and "Strict". If not specified, "Merge" is used. + // (Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled + // and the container runtime must implement support for this feature. + // Note that this field cannot be set when spec.os.name is windows. + // TODO: update the default value to "Merge" when spec.os.name is not windows in v1.34 + // +featureGate=SupplementalGroupsPolicy + // +optional + SupplementalGroupsPolicy string `json:"supplementalGroupsPolicy,omitempty"` + + // Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + // sysctls (by the container runtime) might fail to launch. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + // +listType=atomic + Sysctls []*V1Sysctl `json:"sysctls"` + + // The Windows specific settings applied to all containers. + // If unspecified, the options within a container's SecurityContext will be used. + // If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is linux. + // +optional + WindowsOptions struct { + V1WindowsSecurityContextOptions + } `json:"windowsOptions,omitempty"` +} + +// Validate validates this v1 pod security context +func (m *V1PodSecurityContext) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAppArmorProfile(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSeLinuxOptions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSeccompProfile(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSysctls(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWindowsOptions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodSecurityContext) validateAppArmorProfile(formats strfmt.Registry) error { + if swag.IsZero(m.AppArmorProfile) { // not required + return nil + } + + return nil +} + +func (m *V1PodSecurityContext) validateSeLinuxOptions(formats strfmt.Registry) error { + if swag.IsZero(m.SeLinuxOptions) { // not required + return nil + } + + return nil +} + +func (m *V1PodSecurityContext) validateSeccompProfile(formats strfmt.Registry) error { + if swag.IsZero(m.SeccompProfile) { // not required + return nil + } + + return nil +} + +func (m *V1PodSecurityContext) validateSysctls(formats strfmt.Registry) error { + if swag.IsZero(m.Sysctls) { // not required + return nil + } + + for i := 0; i < len(m.Sysctls); i++ { + if swag.IsZero(m.Sysctls[i]) { // not required + continue + } + + if m.Sysctls[i] != nil { + if err := m.Sysctls[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sysctls" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sysctls" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSecurityContext) validateWindowsOptions(formats strfmt.Registry) error { + if swag.IsZero(m.WindowsOptions) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 pod security context based on the context it is used +func (m *V1PodSecurityContext) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAppArmorProfile(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSeLinuxOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSeccompProfile(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSysctls(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWindowsOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodSecurityContext) contextValidateAppArmorProfile(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSecurityContext) contextValidateSeLinuxOptions(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSecurityContext) contextValidateSeccompProfile(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSecurityContext) contextValidateSysctls(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Sysctls); i++ { + + if m.Sysctls[i] != nil { + + if swag.IsZero(m.Sysctls[i]) { // not required + return nil + } + + if err := m.Sysctls[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sysctls" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sysctls" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSecurityContext) contextValidateWindowsOptions(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodSecurityContext) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodSecurityContext) UnmarshalBinary(b []byte) error { + var res V1PodSecurityContext + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_spec.go b/pkg/client/generated/models/v1_pod_spec.go new file mode 100644 index 0000000000..ff46ec0166 --- /dev/null +++ b/pkg/client/generated/models/v1_pod_spec.go @@ -0,0 +1,1311 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodSpec v1 pod spec +// +// swagger:model V1PodSpec +type V1PodSpec struct { + + // Optional duration in seconds the pod may be active on the node relative to + // StartTime before the system will actively try to mark it failed and kill associated containers. + // Value must be a positive integer. + // +optional + ActiveDeadlineSeconds int64 `json:"activeDeadlineSeconds,omitempty"` + + // If specified, the pod's scheduling constraints + // +optional + Affinity struct { + V1Affinity + } `json:"affinity,omitempty"` + + // AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. + // +optional + AutomountServiceAccountToken bool `json:"automountServiceAccountToken,omitempty"` + + // List of containers belonging to the pod. + // Containers cannot currently be added or removed. + // There must be at least one container in a Pod. + // Cannot be updated. + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + Containers []*V1Container `json:"containers"` + + // Specifies the DNS parameters of a pod. + // Parameters specified here will be merged to the generated DNS + // configuration based on DNSPolicy. + // +optional + DNSConfig struct { + V1PodDNSConfig + } `json:"dnsConfig,omitempty"` + + // Set DNS policy for the pod. + // Defaults to "ClusterFirst". + // Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. + // DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. + // To have DNS options set along with hostNetwork, you have to specify DNS policy + // explicitly to 'ClusterFirstWithHostNet'. + // +optional + DNSPolicy string `json:"dnsPolicy,omitempty"` + + // EnableServiceLinks indicates whether information about services should be injected into pod's + // environment variables, matching the syntax of Docker links. + // Optional: Defaults to true. + // +optional + EnableServiceLinks bool `json:"enableServiceLinks,omitempty"` + + // List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing + // pod to perform user-initiated actions such as debugging. This list cannot be specified when + // creating a pod, and it cannot be modified by updating the pod spec. In order to add an + // ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + EphemeralContainers []*V1EphemeralContainer `json:"ephemeralContainers"` + + // HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts + // file if specified. + // +optional + // +patchMergeKey=ip + // +patchStrategy=merge + // +listType=map + // +listMapKey=ip + HostAliases []*V1HostAlias `json:"hostAliases"` + + // Use the host's ipc namespace. + // Optional: Default to false. + // +k8s:conversion-gen=false + // +optional + HostIPC bool `json:"hostIPC,omitempty"` + + // Host networking requested for this pod. Use the host's network namespace. + // When using HostNetwork you should specify ports so the scheduler is aware. + // When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`, + // and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`. + // Default to false. + // +k8s:conversion-gen=false + // +optional + HostNetwork bool `json:"hostNetwork,omitempty"` + + // Use the host's pid namespace. + // Optional: Default to false. + // +k8s:conversion-gen=false + // +optional + HostPID bool `json:"hostPID,omitempty"` + + // Use the host's user namespace. + // Optional: Default to true. + // If set to true or not present, the pod will be run in the host user namespace, useful + // for when the pod needs a feature only available to the host user namespace, such as + // loading a kernel module with CAP_SYS_MODULE. + // When set to false, a new userns is created for the pod. Setting false is useful for + // mitigating container breakout vulnerabilities even allowing users to run their + // containers as root without actually having root privileges on the host. + // This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. + // +k8s:conversion-gen=false + // +optional + HostUsers bool `json:"hostUsers,omitempty"` + + // Specifies the hostname of the Pod + // If not specified, the pod's hostname will be set to a system-defined value. + // +optional + Hostname string `json:"hostname,omitempty"` + + // HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod. + // This field only specifies the pod's hostname and does not affect its DNS records. + // When this field is set to a non-empty string: + // - It takes precedence over the values set in `hostname` and `subdomain`. + // - The Pod's hostname will be set to this value. + // - `setHostnameAsFQDN` must be nil or set to false. + // - `hostNetwork` must be set to false. + // + // This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters. + // Requires the HostnameOverride feature gate to be enabled. + // + // +featureGate=HostnameOverride + // +optional + HostnameOverride string `json:"hostnameOverride,omitempty"` + + // ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. + // If specified, these secrets will be passed to individual puller implementations for them to use. + // More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + ImagePullSecrets []*V1LocalObjectReference `json:"imagePullSecrets"` + + // List of initialization containers belonging to the pod. + // Init containers are executed in order prior to containers being started. If any + // init container fails, the pod is considered to have failed and is handled according + // to its restartPolicy. The name for an init container or normal container must be + // unique among all containers. + // Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. + // The resourceRequirements of an init container are taken into account during scheduling + // by finding the highest request/limit for each resource type, and then using the max of + // that value or the sum of the normal containers. Limits are applied to init containers + // in a similar fashion. + // Init containers cannot currently be added or removed. + // Cannot be updated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + InitContainers []*V1Container `json:"initContainers"` + + // NodeName indicates in which node this pod is scheduled. + // If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. + // Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. + // This field should not be used to express a desire for the pod to be scheduled on a specific node. + // https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename + // +optional + NodeName string `json:"nodeName,omitempty"` + + // NodeSelector is a selector which must be true for the pod to fit on a node. + // Selector which must match a node's labels for the pod to be scheduled on that node. + // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + // +optional + // +mapType=atomic + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + + // Specifies the OS of the containers in the pod. + // Some pod and container fields are restricted if this is set. + // + // If the OS field is set to linux, the following fields must be unset: + // -securityContext.windowsOptions + // + // If the OS field is set to windows, following fields must be unset: + // - spec.hostPID + // - spec.hostIPC + // - spec.hostUsers + // - spec.resources + // - spec.securityContext.appArmorProfile + // - spec.securityContext.seLinuxOptions + // - spec.securityContext.seccompProfile + // - spec.securityContext.fsGroup + // - spec.securityContext.fsGroupChangePolicy + // - spec.securityContext.sysctls + // - spec.shareProcessNamespace + // - spec.securityContext.runAsUser + // - spec.securityContext.runAsGroup + // - spec.securityContext.supplementalGroups + // - spec.securityContext.supplementalGroupsPolicy + // - spec.containers[*].securityContext.appArmorProfile + // - spec.containers[*].securityContext.seLinuxOptions + // - spec.containers[*].securityContext.seccompProfile + // - spec.containers[*].securityContext.capabilities + // - spec.containers[*].securityContext.readOnlyRootFilesystem + // - spec.containers[*].securityContext.privileged + // - spec.containers[*].securityContext.allowPrivilegeEscalation + // - spec.containers[*].securityContext.procMount + // - spec.containers[*].securityContext.runAsUser + // - spec.containers[*].securityContext.runAsGroup + // +optional + Os struct { + V1PodOS + } `json:"os,omitempty"` + + // Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. + // This field will be autopopulated at admission time by the RuntimeClass admission controller. If + // the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. + // The RuntimeClass admission controller will reject Pod create requests which have the overhead already + // set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value + // defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. + // More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md + // +optional + Overhead struct { + V1ResourceList + } `json:"overhead,omitempty"` + + // PreemptionPolicy is the Policy for preempting pods with lower priority. + // One of Never, PreemptLowerPriority. + // Defaults to PreemptLowerPriority if unset. + // +optional + PreemptionPolicy string `json:"preemptionPolicy,omitempty"` + + // The priority value. Various system components use this field to find the + // priority of the pod. When Priority Admission Controller is enabled, it + // prevents users from setting this field. The admission controller populates + // this field from PriorityClassName. + // The higher the value, the higher the priority. + // +optional + Priority int64 `json:"priority,omitempty"` + + // If specified, indicates the pod's priority. "system-node-critical" and + // "system-cluster-critical" are two special keywords which indicate the + // highest priorities with the former being the highest priority. Any other + // name must be defined by creating a PriorityClass object with that name. + // If not specified, the pod priority will be default or zero if there is no + // default. + // +optional + PriorityClassName string `json:"priorityClassName,omitempty"` + + // If specified, all readiness gates will be evaluated for pod readiness. + // A pod is ready when all its containers are ready AND + // all conditions specified in the readiness gates have status equal to "True" + // More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates + // +optional + // +listType=atomic + ReadinessGates []*V1PodReadinessGate `json:"readinessGates"` + + // ResourceClaims defines which ResourceClaims must be allocated + // and reserved before the Pod is allowed to start. The resources + // will be made available to those containers which consume them + // by name. + // + // This is an alpha field and requires enabling the + // DynamicResourceAllocation feature gate. + // + // This field is immutable. + // + // +patchMergeKey=name + // +patchStrategy=merge,retainKeys + // +listType=map + // +listMapKey=name + // +featureGate=DynamicResourceAllocation + // +optional + ResourceClaims []*V1PodResourceClaim `json:"resourceClaims"` + + // Resources is the total amount of CPU and Memory resources required by all + // containers in the pod. It supports specifying Requests and Limits for + // "cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported. + // + // This field enables fine-grained control over resource allocation for the + // entire pod, allowing resource sharing among containers in a pod. + // TODO: For beta graduation, expand this comment with a detailed explanation. + // + // This is an alpha field and requires enabling the PodLevelResources feature + // gate. + // + // +featureGate=PodLevelResources + // +optional + Resources struct { + V1ResourceRequirements + } `json:"resources,omitempty"` + + // Restart policy for all containers within the pod. + // One of Always, OnFailure, Never. In some contexts, only a subset of those values may be permitted. + // Default to Always. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy + // +optional + RestartPolicy string `json:"restartPolicy,omitempty"` + + // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used + // to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. + // If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an + // empty definition that uses the default runtime handler. + // More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class + // +optional + RuntimeClassName string `json:"runtimeClassName,omitempty"` + + // If specified, the pod will be dispatched by specified scheduler. + // If not specified, the pod will be dispatched by default scheduler. + // +optional + SchedulerName string `json:"schedulerName,omitempty"` + + // SchedulingGates is an opaque list of values that if specified will block scheduling the pod. + // If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the + // scheduler will not attempt to schedule the pod. + // + // SchedulingGates can only be set at pod creation time, and be removed only afterwards. + // + // +patchMergeKey=name + // +patchStrategy=merge + // +listType=map + // +listMapKey=name + // +optional + SchedulingGates []*V1PodSchedulingGate `json:"schedulingGates"` + + // SecurityContext holds pod-level security attributes and common container settings. + // Optional: Defaults to empty. See type description for default values of each field. + // +optional + SecurityContext struct { + V1PodSecurityContext + } `json:"securityContext,omitempty"` + + // DeprecatedServiceAccount is a deprecated alias for ServiceAccountName. + // Deprecated: Use serviceAccountName instead. + // +k8s:conversion-gen=false + // +optional + ServiceAccount string `json:"serviceAccount,omitempty"` + + // ServiceAccountName is the name of the ServiceAccount to use to run this pod. + // More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). + // In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). + // In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. + // If a pod does not have FQDN, this has no effect. + // Default to false. + // +optional + SetHostnameAsFQDN bool `json:"setHostnameAsFQDN,omitempty"` + + // Share a single process namespace between all of the containers in a pod. + // When this is set containers will be able to view and signal processes from other containers + // in the same pod, and the first process in each container will not be assigned PID 1. + // HostPID and ShareProcessNamespace cannot both be set. + // Optional: Default to false. + // +k8s:conversion-gen=false + // +optional + ShareProcessNamespace bool `json:"shareProcessNamespace,omitempty"` + + // If specified, the fully qualified Pod hostname will be "...svc.". + // If not specified, the pod will not have a domainname at all. + // +optional + Subdomain string `json:"subdomain,omitempty"` + + // Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. + // Value must be non-negative integer. The value zero indicates stop immediately via + // the kill signal (no opportunity to shut down). + // If this value is nil, the default grace period will be used instead. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // Defaults to 30 seconds. + // +optional + TerminationGracePeriodSeconds int64 `json:"terminationGracePeriodSeconds,omitempty"` + + // If specified, the pod's tolerations. + // +optional + // +listType=atomic + Tolerations []*V1Toleration `json:"tolerations"` + + // TopologySpreadConstraints describes how a group of pods ought to spread across topology + // domains. Scheduler will schedule pods in a way which abides by the constraints. + // All topologySpreadConstraints are ANDed. + // +optional + // +patchMergeKey=topologyKey + // +patchStrategy=merge + // +listType=map + // +listMapKey=topologyKey + // +listMapKey=whenUnsatisfiable + TopologySpreadConstraints []*V1TopologySpreadConstraint `json:"topologySpreadConstraints"` + + // List of volumes that can be mounted by containers belonging to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes + // +optional + // +patchMergeKey=name + // +patchStrategy=merge,retainKeys + // +listType=map + // +listMapKey=name + Volumes []*V1Volume `json:"volumes"` +} + +// Validate validates this v1 pod spec +func (m *V1PodSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAffinity(formats); err != nil { + res = append(res, err) + } + + if err := m.validateContainers(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDNSConfig(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEphemeralContainers(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHostAliases(formats); err != nil { + res = append(res, err) + } + + if err := m.validateImagePullSecrets(formats); err != nil { + res = append(res, err) + } + + if err := m.validateInitContainers(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOs(formats); err != nil { + res = append(res, err) + } + + if err := m.validateOverhead(formats); err != nil { + res = append(res, err) + } + + if err := m.validateReadinessGates(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResourceClaims(formats); err != nil { + res = append(res, err) + } + + if err := m.validateResources(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSchedulingGates(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecurityContext(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTolerations(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTopologySpreadConstraints(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVolumes(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodSpec) validateAffinity(formats strfmt.Registry) error { + if swag.IsZero(m.Affinity) { // not required + return nil + } + + return nil +} + +func (m *V1PodSpec) validateContainers(formats strfmt.Registry) error { + if swag.IsZero(m.Containers) { // not required + return nil + } + + for i := 0; i < len(m.Containers); i++ { + if swag.IsZero(m.Containers[i]) { // not required + continue + } + + if m.Containers[i] != nil { + if err := m.Containers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("containers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("containers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateDNSConfig(formats strfmt.Registry) error { + if swag.IsZero(m.DNSConfig) { // not required + return nil + } + + return nil +} + +func (m *V1PodSpec) validateEphemeralContainers(formats strfmt.Registry) error { + if swag.IsZero(m.EphemeralContainers) { // not required + return nil + } + + for i := 0; i < len(m.EphemeralContainers); i++ { + if swag.IsZero(m.EphemeralContainers[i]) { // not required + continue + } + + if m.EphemeralContainers[i] != nil { + if err := m.EphemeralContainers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ephemeralContainers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ephemeralContainers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateHostAliases(formats strfmt.Registry) error { + if swag.IsZero(m.HostAliases) { // not required + return nil + } + + for i := 0; i < len(m.HostAliases); i++ { + if swag.IsZero(m.HostAliases[i]) { // not required + continue + } + + if m.HostAliases[i] != nil { + if err := m.HostAliases[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("hostAliases" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("hostAliases" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateImagePullSecrets(formats strfmt.Registry) error { + if swag.IsZero(m.ImagePullSecrets) { // not required + return nil + } + + for i := 0; i < len(m.ImagePullSecrets); i++ { + if swag.IsZero(m.ImagePullSecrets[i]) { // not required + continue + } + + if m.ImagePullSecrets[i] != nil { + if err := m.ImagePullSecrets[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("imagePullSecrets" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("imagePullSecrets" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateInitContainers(formats strfmt.Registry) error { + if swag.IsZero(m.InitContainers) { // not required + return nil + } + + for i := 0; i < len(m.InitContainers); i++ { + if swag.IsZero(m.InitContainers[i]) { // not required + continue + } + + if m.InitContainers[i] != nil { + if err := m.InitContainers[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("initContainers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("initContainers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateOs(formats strfmt.Registry) error { + if swag.IsZero(m.Os) { // not required + return nil + } + + return nil +} + +func (m *V1PodSpec) validateOverhead(formats strfmt.Registry) error { + if swag.IsZero(m.Overhead) { // not required + return nil + } + + return nil +} + +func (m *V1PodSpec) validateReadinessGates(formats strfmt.Registry) error { + if swag.IsZero(m.ReadinessGates) { // not required + return nil + } + + for i := 0; i < len(m.ReadinessGates); i++ { + if swag.IsZero(m.ReadinessGates[i]) { // not required + continue + } + + if m.ReadinessGates[i] != nil { + if err := m.ReadinessGates[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("readinessGates" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("readinessGates" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateResourceClaims(formats strfmt.Registry) error { + if swag.IsZero(m.ResourceClaims) { // not required + return nil + } + + for i := 0; i < len(m.ResourceClaims); i++ { + if swag.IsZero(m.ResourceClaims[i]) { // not required + continue + } + + if m.ResourceClaims[i] != nil { + if err := m.ResourceClaims[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("resourceClaims" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("resourceClaims" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateResources(formats strfmt.Registry) error { + if swag.IsZero(m.Resources) { // not required + return nil + } + + return nil +} + +func (m *V1PodSpec) validateSchedulingGates(formats strfmt.Registry) error { + if swag.IsZero(m.SchedulingGates) { // not required + return nil + } + + for i := 0; i < len(m.SchedulingGates); i++ { + if swag.IsZero(m.SchedulingGates[i]) { // not required + continue + } + + if m.SchedulingGates[i] != nil { + if err := m.SchedulingGates[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("schedulingGates" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("schedulingGates" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateSecurityContext(formats strfmt.Registry) error { + if swag.IsZero(m.SecurityContext) { // not required + return nil + } + + return nil +} + +func (m *V1PodSpec) validateTolerations(formats strfmt.Registry) error { + if swag.IsZero(m.Tolerations) { // not required + return nil + } + + for i := 0; i < len(m.Tolerations); i++ { + if swag.IsZero(m.Tolerations[i]) { // not required + continue + } + + if m.Tolerations[i] != nil { + if err := m.Tolerations[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("tolerations" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("tolerations" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateTopologySpreadConstraints(formats strfmt.Registry) error { + if swag.IsZero(m.TopologySpreadConstraints) { // not required + return nil + } + + for i := 0; i < len(m.TopologySpreadConstraints); i++ { + if swag.IsZero(m.TopologySpreadConstraints[i]) { // not required + continue + } + + if m.TopologySpreadConstraints[i] != nil { + if err := m.TopologySpreadConstraints[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("topologySpreadConstraints" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("topologySpreadConstraints" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) validateVolumes(formats strfmt.Registry) error { + if swag.IsZero(m.Volumes) { // not required + return nil + } + + for i := 0; i < len(m.Volumes); i++ { + if swag.IsZero(m.Volumes[i]) { // not required + continue + } + + if m.Volumes[i] != nil { + if err := m.Volumes[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumes" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumes" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 pod spec based on the context it is used +func (m *V1PodSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAffinity(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateContainers(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDNSConfig(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateEphemeralContainers(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHostAliases(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateImagePullSecrets(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateInitContainers(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateOverhead(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateReadinessGates(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResourceClaims(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateResources(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSchedulingGates(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecurityContext(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTolerations(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTopologySpreadConstraints(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVolumes(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodSpec) contextValidateAffinity(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSpec) contextValidateContainers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Containers); i++ { + + if m.Containers[i] != nil { + + if swag.IsZero(m.Containers[i]) { // not required + return nil + } + + if err := m.Containers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("containers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("containers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateDNSConfig(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSpec) contextValidateEphemeralContainers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.EphemeralContainers); i++ { + + if m.EphemeralContainers[i] != nil { + + if swag.IsZero(m.EphemeralContainers[i]) { // not required + return nil + } + + if err := m.EphemeralContainers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("ephemeralContainers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("ephemeralContainers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateHostAliases(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.HostAliases); i++ { + + if m.HostAliases[i] != nil { + + if swag.IsZero(m.HostAliases[i]) { // not required + return nil + } + + if err := m.HostAliases[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("hostAliases" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("hostAliases" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateImagePullSecrets(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ImagePullSecrets); i++ { + + if m.ImagePullSecrets[i] != nil { + + if swag.IsZero(m.ImagePullSecrets[i]) { // not required + return nil + } + + if err := m.ImagePullSecrets[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("imagePullSecrets" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("imagePullSecrets" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateInitContainers(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.InitContainers); i++ { + + if m.InitContainers[i] != nil { + + if swag.IsZero(m.InitContainers[i]) { // not required + return nil + } + + if err := m.InitContainers[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("initContainers" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("initContainers" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateOs(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSpec) contextValidateOverhead(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSpec) contextValidateReadinessGates(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ReadinessGates); i++ { + + if m.ReadinessGates[i] != nil { + + if swag.IsZero(m.ReadinessGates[i]) { // not required + return nil + } + + if err := m.ReadinessGates[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("readinessGates" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("readinessGates" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateResourceClaims(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.ResourceClaims); i++ { + + if m.ResourceClaims[i] != nil { + + if swag.IsZero(m.ResourceClaims[i]) { // not required + return nil + } + + if err := m.ResourceClaims[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("resourceClaims" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("resourceClaims" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateResources(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSpec) contextValidateSchedulingGates(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.SchedulingGates); i++ { + + if m.SchedulingGates[i] != nil { + + if swag.IsZero(m.SchedulingGates[i]) { // not required + return nil + } + + if err := m.SchedulingGates[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("schedulingGates" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("schedulingGates" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateSecurityContext(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodSpec) contextValidateTolerations(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Tolerations); i++ { + + if m.Tolerations[i] != nil { + + if swag.IsZero(m.Tolerations[i]) { // not required + return nil + } + + if err := m.Tolerations[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("tolerations" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("tolerations" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateTopologySpreadConstraints(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.TopologySpreadConstraints); i++ { + + if m.TopologySpreadConstraints[i] != nil { + + if swag.IsZero(m.TopologySpreadConstraints[i]) { // not required + return nil + } + + if err := m.TopologySpreadConstraints[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("topologySpreadConstraints" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("topologySpreadConstraints" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1PodSpec) contextValidateVolumes(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Volumes); i++ { + + if m.Volumes[i] != nil { + + if swag.IsZero(m.Volumes[i]) { // not required + return nil + } + + if err := m.Volumes[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("volumes" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("volumes" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodSpec) UnmarshalBinary(b []byte) error { + var res V1PodSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_pod_template_spec.go b/pkg/client/generated/models/v1_pod_template_spec.go new file mode 100644 index 0000000000..0233fa727c --- /dev/null +++ b/pkg/client/generated/models/v1_pod_template_spec.go @@ -0,0 +1,111 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PodTemplateSpec v1 pod template spec +// +// swagger:model V1PodTemplateSpec +type V1PodTemplateSpec struct { + + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + Metadata struct { + V1ObjectMeta + } `json:"metadata,omitempty"` + + // Specification of the desired behavior of the pod. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Spec struct { + V1PodSpec + } `json:"spec,omitempty"` +} + +// Validate validates this v1 pod template spec +func (m *V1PodTemplateSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodTemplateSpec) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +func (m *V1PodTemplateSpec) validateSpec(formats strfmt.Registry) error { + if swag.IsZero(m.Spec) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 pod template spec based on the context it is used +func (m *V1PodTemplateSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PodTemplateSpec) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1PodTemplateSpec) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PodTemplateSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PodTemplateSpec) UnmarshalBinary(b []byte) error { + var res V1PodTemplateSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_policy_rule.go b/pkg/client/generated/models/v1_policy_rule.go new file mode 100644 index 0000000000..24d9850b0e --- /dev/null +++ b/pkg/client/generated/models/v1_policy_rule.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PolicyRule v1 policy rule +// +// swagger:model V1PolicyRule +type V1PolicyRule struct { + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. + // +optional + // +listType=atomic + APIGroups []string `json:"apiGroups"` + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path + // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. + // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + // +optional + // +listType=atomic + NonResourceURLs []string `json:"nonResourceURLs"` + + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +optional + // +listType=atomic + ResourceNames []string `json:"resourceNames"` + + // Resources is a list of resources this rule applies to. '*' represents all resources. + // +optional + // +listType=atomic + Resources []string `json:"resources"` + + // Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs. + // +listType=atomic + Verbs []string `json:"verbs"` +} + +// Validate validates this v1 policy rule +func (m *V1PolicyRule) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 policy rule based on context it is used +func (m *V1PolicyRule) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PolicyRule) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PolicyRule) UnmarshalBinary(b []byte) error { + var res V1PolicyRule + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_portworx_volume_source.go b/pkg/client/generated/models/v1_portworx_volume_source.go new file mode 100644 index 0000000000..a72da3e71d --- /dev/null +++ b/pkg/client/generated/models/v1_portworx_volume_source.go @@ -0,0 +1,57 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PortworxVolumeSource v1 portworx volume source +// +// swagger:model V1PortworxVolumeSource +type V1PortworxVolumeSource struct { + + // fSType represents the filesystem type to mount + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + FsType string `json:"fsType,omitempty"` + + // readOnly defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // volumeID uniquely identifies a Portworx volume + VolumeID string `json:"volumeID,omitempty"` +} + +// Validate validates this v1 portworx volume source +func (m *V1PortworxVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 portworx volume source based on context it is used +func (m *V1PortworxVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1PortworxVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PortworxVolumeSource) UnmarshalBinary(b []byte) error { + var res V1PortworxVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_preferred_scheduling_term.go b/pkg/client/generated/models/v1_preferred_scheduling_term.go new file mode 100644 index 0000000000..31136467d6 --- /dev/null +++ b/pkg/client/generated/models/v1_preferred_scheduling_term.go @@ -0,0 +1,84 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1PreferredSchedulingTerm v1 preferred scheduling term +// +// swagger:model V1PreferredSchedulingTerm +type V1PreferredSchedulingTerm struct { + + // A node selector term, associated with the corresponding weight. + Preference struct { + V1NodeSelectorTerm + } `json:"preference,omitempty"` + + // Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + Weight int64 `json:"weight,omitempty"` +} + +// Validate validates this v1 preferred scheduling term +func (m *V1PreferredSchedulingTerm) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePreference(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PreferredSchedulingTerm) validatePreference(formats strfmt.Registry) error { + if swag.IsZero(m.Preference) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 preferred scheduling term based on the context it is used +func (m *V1PreferredSchedulingTerm) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePreference(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1PreferredSchedulingTerm) contextValidatePreference(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1PreferredSchedulingTerm) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1PreferredSchedulingTerm) UnmarshalBinary(b []byte) error { + var res V1PreferredSchedulingTerm + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_probe.go b/pkg/client/generated/models/v1_probe.go new file mode 100644 index 0000000000..22b5ee315f --- /dev/null +++ b/pkg/client/generated/models/v1_probe.go @@ -0,0 +1,202 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Probe v1 probe +// +// swagger:model V1Probe +type V1Probe struct { + + // Exec specifies a command to execute in the container. + // +optional + Exec struct { + V1ExecAction + } `json:"exec,omitempty"` + + // Minimum consecutive failures for the probe to be considered failed after having succeeded. + // Defaults to 3. Minimum value is 1. + // +optional + FailureThreshold int64 `json:"failureThreshold,omitempty"` + + // GRPC specifies a GRPC HealthCheckRequest. + // +optional + Grpc struct { + V1GRPCAction + } `json:"grpc,omitempty"` + + // HTTPGet specifies an HTTP GET request to perform. + // +optional + HTTPGet struct { + V1HTTPGetAction + } `json:"httpGet,omitempty"` + + // Number of seconds after the container has started before liveness probes are initiated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + InitialDelaySeconds int64 `json:"initialDelaySeconds,omitempty"` + + // How often (in seconds) to perform the probe. + // Default to 10 seconds. Minimum value is 1. + // +optional + PeriodSeconds int64 `json:"periodSeconds,omitempty"` + + // Minimum consecutive successes for the probe to be considered successful after having failed. + // Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + // +optional + SuccessThreshold int64 `json:"successThreshold,omitempty"` + + // TCPSocket specifies a connection to a TCP port. + // +optional + TCPSocket struct { + V1TCPSocketAction + } `json:"tcpSocket,omitempty"` + + // Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + // value overrides the value provided by the pod spec. + // Value must be non-negative integer. The value zero indicates stop immediately via + // the kill signal (no opportunity to shut down). + // This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + // Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + // +optional + TerminationGracePeriodSeconds int64 `json:"terminationGracePeriodSeconds,omitempty"` + + // Number of seconds after which the probe times out. + // Defaults to 1 second. Minimum value is 1. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + TimeoutSeconds int64 `json:"timeoutSeconds,omitempty"` +} + +// Validate validates this v1 probe +func (m *V1Probe) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateExec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGrpc(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHTTPGet(formats); err != nil { + res = append(res, err) + } + + if err := m.validateTCPSocket(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Probe) validateExec(formats strfmt.Registry) error { + if swag.IsZero(m.Exec) { // not required + return nil + } + + return nil +} + +func (m *V1Probe) validateGrpc(formats strfmt.Registry) error { + if swag.IsZero(m.Grpc) { // not required + return nil + } + + return nil +} + +func (m *V1Probe) validateHTTPGet(formats strfmt.Registry) error { + if swag.IsZero(m.HTTPGet) { // not required + return nil + } + + return nil +} + +func (m *V1Probe) validateTCPSocket(formats strfmt.Registry) error { + if swag.IsZero(m.TCPSocket) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 probe based on the context it is used +func (m *V1Probe) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateExec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGrpc(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHTTPGet(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateTCPSocket(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Probe) contextValidateExec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Probe) contextValidateGrpc(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Probe) contextValidateHTTPGet(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Probe) contextValidateTCPSocket(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Probe) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Probe) UnmarshalBinary(b []byte) error { + var res V1Probe + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_projected_volume_source.go b/pkg/client/generated/models/v1_projected_volume_source.go new file mode 100644 index 0000000000..83bc95e789 --- /dev/null +++ b/pkg/client/generated/models/v1_projected_volume_source.go @@ -0,0 +1,139 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ProjectedVolumeSource v1 projected volume source +// +// swagger:model V1ProjectedVolumeSource +type V1ProjectedVolumeSource struct { + + // defaultMode are the mode bits used to set permissions on created files by default. + // Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + // YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode int64 `json:"defaultMode,omitempty"` + + // sources is the list of volume projections. Each entry in this list + // handles one source. + // +optional + // +listType=atomic + Sources []*V1VolumeProjection `json:"sources"` +} + +// Validate validates this v1 projected volume source +func (m *V1ProjectedVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSources(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ProjectedVolumeSource) validateSources(formats strfmt.Registry) error { + if swag.IsZero(m.Sources) { // not required + return nil + } + + for i := 0; i < len(m.Sources); i++ { + if swag.IsZero(m.Sources[i]) { // not required + continue + } + + if m.Sources[i] != nil { + if err := m.Sources[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sources" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sources" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 projected volume source based on the context it is used +func (m *V1ProjectedVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSources(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ProjectedVolumeSource) contextValidateSources(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Sources); i++ { + + if m.Sources[i] != nil { + + if swag.IsZero(m.Sources[i]) { // not required + return nil + } + + if err := m.Sources[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("sources" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("sources" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ProjectedVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ProjectedVolumeSource) UnmarshalBinary(b []byte) error { + var res V1ProjectedVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_quobyte_volume_source.go b/pkg/client/generated/models/v1_quobyte_volume_source.go new file mode 100644 index 0000000000..e921fb764a --- /dev/null +++ b/pkg/client/generated/models/v1_quobyte_volume_source.go @@ -0,0 +1,72 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1QuobyteVolumeSource v1 quobyte volume source +// +// swagger:model V1QuobyteVolumeSource +type V1QuobyteVolumeSource struct { + + // group to map volume access to + // Default is no group + // +optional + Group string `json:"group,omitempty"` + + // readOnly here will force the Quobyte volume to be mounted with read-only permissions. + // Defaults to false. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // registry represents a single or multiple Quobyte Registry services + // specified as a string as host:port pair (multiple entries are separated with commas) + // which acts as the central registry for volumes + Registry string `json:"registry,omitempty"` + + // tenant owning the given Quobyte volume in the Backend + // Used with dynamically provisioned Quobyte volumes, value is set by the plugin + // +optional + Tenant string `json:"tenant,omitempty"` + + // user to map volume access to + // Defaults to serivceaccount user + // +optional + User string `json:"user,omitempty"` + + // volume is a string that references an already created Quobyte volume by name. + Volume string `json:"volume,omitempty"` +} + +// Validate validates this v1 quobyte volume source +func (m *V1QuobyteVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 quobyte volume source based on context it is used +func (m *V1QuobyteVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1QuobyteVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1QuobyteVolumeSource) UnmarshalBinary(b []byte) error { + var res V1QuobyteVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_r_b_d_volume_source.go b/pkg/client/generated/models/v1_r_b_d_volume_source.go new file mode 100644 index 0000000000..332ea9a2cc --- /dev/null +++ b/pkg/client/generated/models/v1_r_b_d_volume_source.go @@ -0,0 +1,129 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1RBDVolumeSource v1 r b d volume source +// +// swagger:model V1RBDVolumeSource +type V1RBDVolumeSource struct { + + // fsType is the filesystem type of the volume that you want to mount. + // Tip: Ensure that the filesystem type is supported by the host operating system. + // Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + // TODO: how do we prevent errors in the filesystem from compromising the machine + // +optional + FsType string `json:"fsType,omitempty"` + + // image is the rados image name. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + Image string `json:"image,omitempty"` + + // keyring is the path to key ring for RBDUser. + // Default is /etc/ceph/keyring. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + // +optional + // +default="/etc/ceph/keyring" + Keyring string `json:"keyring,omitempty"` + + // monitors is a collection of Ceph monitors. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + // +listType=atomic + Monitors []string `json:"monitors"` + + // pool is the rados pool name. + // Default is rbd. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + // +optional + // +default="rbd" + Pool string `json:"pool,omitempty"` + + // readOnly here will force the ReadOnly setting in VolumeMounts. + // Defaults to false. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretRef is name of the authentication secret for RBDUser. If provided + // overrides keyring. + // Default is nil. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + // +optional + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` + + // user is the rados user name. + // Default is admin. + // More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + // +optional + // +default="admin" + User string `json:"user,omitempty"` +} + +// Validate validates this v1 r b d volume source +func (m *V1RBDVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1RBDVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 r b d volume source based on the context it is used +func (m *V1RBDVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1RBDVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1RBDVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1RBDVolumeSource) UnmarshalBinary(b []byte) error { + var res V1RBDVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_resource_claim.go b/pkg/client/generated/models/v1_resource_claim.go new file mode 100644 index 0000000000..cddc028532 --- /dev/null +++ b/pkg/client/generated/models/v1_resource_claim.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ResourceClaim v1 resource claim +// +// swagger:model V1ResourceClaim +type V1ResourceClaim struct { + + // Name must match the name of one entry in pod.spec.resourceClaims of + // the Pod where this field is used. It makes that resource available + // inside a container. + Name string `json:"name,omitempty"` + + // Request is the name chosen for a request in the referenced claim. + // If empty, everything from the claim is made available, otherwise + // only the result of this request. + // + // +optional + Request string `json:"request,omitempty"` +} + +// Validate validates this v1 resource claim +func (m *V1ResourceClaim) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 resource claim based on context it is used +func (m *V1ResourceClaim) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ResourceClaim) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ResourceClaim) UnmarshalBinary(b []byte) error { + var res V1ResourceClaim + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_resource_field_selector.go b/pkg/client/generated/models/v1_resource_field_selector.go new file mode 100644 index 0000000000..1f1b973be1 --- /dev/null +++ b/pkg/client/generated/models/v1_resource_field_selector.go @@ -0,0 +1,89 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ResourceFieldSelector v1 resource field selector +// +// swagger:model V1ResourceFieldSelector +type V1ResourceFieldSelector struct { + + // Container name: required for volumes, optional for env vars + // +optional + ContainerName string `json:"containerName,omitempty"` + + // Specifies the output format of the exposed resources, defaults to "1" + // +optional + Divisor struct { + Quantity + } `json:"divisor,omitempty"` + + // Required: resource to select + Resource string `json:"resource,omitempty"` +} + +// Validate validates this v1 resource field selector +func (m *V1ResourceFieldSelector) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateDivisor(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ResourceFieldSelector) validateDivisor(formats strfmt.Registry) error { + if swag.IsZero(m.Divisor) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 resource field selector based on the context it is used +func (m *V1ResourceFieldSelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateDivisor(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ResourceFieldSelector) contextValidateDivisor(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ResourceFieldSelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ResourceFieldSelector) UnmarshalBinary(b []byte) error { + var res V1ResourceFieldSelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_resource_list.go b/pkg/client/generated/models/v1_resource_list.go new file mode 100644 index 0000000000..3cfafea50b --- /dev/null +++ b/pkg/client/generated/models/v1_resource_list.go @@ -0,0 +1,69 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/validate" +) + +// V1ResourceList v1 resource list +// +// swagger:model V1ResourceList +type V1ResourceList map[string]Quantity + +// Validate validates this v1 resource list +func (m V1ResourceList) Validate(formats strfmt.Registry) error { + var res []error + + for k := range m { + + if err := validate.Required(k, "body", m[k]); err != nil { + return err + } + if val, ok := m[k]; ok { + if err := val.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName(k) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName(k) + } + + return err + } + } + + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// ContextValidate validate this v1 resource list based on the context it is used +func (m V1ResourceList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + for k := range m { + + if val, ok := m[k]; ok { + if err := val.ContextValidate(ctx, formats); err != nil { + return err + } + } + + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/pkg/client/generated/models/v1_resource_requirements.go b/pkg/client/generated/models/v1_resource_requirements.go new file mode 100644 index 0000000000..779ab22d99 --- /dev/null +++ b/pkg/client/generated/models/v1_resource_requirements.go @@ -0,0 +1,196 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ResourceRequirements v1 resource requirements +// +// swagger:model V1ResourceRequirements +type V1ResourceRequirements struct { + + // Claims lists the names of resources, defined in spec.resourceClaims, + // that are used by this container. + // + // This field depends on the + // DynamicResourceAllocation feature gate. + // + // This field is immutable. It can only be set for containers. + // + // +listType=map + // +listMapKey=name + // +featureGate=DynamicResourceAllocation + // +optional + Claims []*V1ResourceClaim `json:"claims"` + + // Limits describes the maximum amount of compute resources allowed. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // +optional + Limits struct { + V1ResourceList + } `json:"limits,omitempty"` + + // Requests describes the minimum amount of compute resources required. + // If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + // otherwise to an implementation-defined value. Requests cannot exceed Limits. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // +optional + Requests struct { + V1ResourceList + } `json:"requests,omitempty"` +} + +// Validate validates this v1 resource requirements +func (m *V1ResourceRequirements) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateClaims(formats); err != nil { + res = append(res, err) + } + + if err := m.validateLimits(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequests(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ResourceRequirements) validateClaims(formats strfmt.Registry) error { + if swag.IsZero(m.Claims) { // not required + return nil + } + + for i := 0; i < len(m.Claims); i++ { + if swag.IsZero(m.Claims[i]) { // not required + continue + } + + if m.Claims[i] != nil { + if err := m.Claims[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("claims" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("claims" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1ResourceRequirements) validateLimits(formats strfmt.Registry) error { + if swag.IsZero(m.Limits) { // not required + return nil + } + + return nil +} + +func (m *V1ResourceRequirements) validateRequests(formats strfmt.Registry) error { + if swag.IsZero(m.Requests) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 resource requirements based on the context it is used +func (m *V1ResourceRequirements) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateClaims(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateLimits(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRequests(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ResourceRequirements) contextValidateClaims(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Claims); i++ { + + if m.Claims[i] != nil { + + if swag.IsZero(m.Claims[i]) { // not required + return nil + } + + if err := m.Claims[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("claims" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("claims" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1ResourceRequirements) contextValidateLimits(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1ResourceRequirements) contextValidateRequests(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ResourceRequirements) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ResourceRequirements) UnmarshalBinary(b []byte) error { + var res V1ResourceRequirements + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_s_e_linux_options.go b/pkg/client/generated/models/v1_s_e_linux_options.go new file mode 100644 index 0000000000..a311f89435 --- /dev/null +++ b/pkg/client/generated/models/v1_s_e_linux_options.go @@ -0,0 +1,60 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SELinuxOptions v1 s e linux options +// +// swagger:model V1SELinuxOptions +type V1SELinuxOptions struct { + + // Level is SELinux level label that applies to the container. + // +optional + Level string `json:"level,omitempty"` + + // Role is a SELinux role label that applies to the container. + // +optional + Role string `json:"role,omitempty"` + + // Type is a SELinux type label that applies to the container. + // +optional + Type string `json:"type,omitempty"` + + // User is a SELinux user label that applies to the container. + // +optional + User string `json:"user,omitempty"` +} + +// Validate validates this v1 s e linux options +func (m *V1SELinuxOptions) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 s e linux options based on context it is used +func (m *V1SELinuxOptions) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SELinuxOptions) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SELinuxOptions) UnmarshalBinary(b []byte) error { + var res V1SELinuxOptions + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_scale_i_o_volume_source.go b/pkg/client/generated/models/v1_scale_i_o_volume_source.go new file mode 100644 index 0000000000..9c36e07541 --- /dev/null +++ b/pkg/client/generated/models/v1_scale_i_o_volume_source.go @@ -0,0 +1,123 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ScaleIOVolumeSource v1 scale i o volume source +// +// swagger:model V1ScaleIOVolumeSource +type V1ScaleIOVolumeSource struct { + + // fsType is the filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". + // Default is "xfs". + // +optional + // +default="xfs" + FsType string `json:"fsType,omitempty"` + + // gateway is the host address of the ScaleIO API Gateway. + Gateway string `json:"gateway,omitempty"` + + // protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. + // +optional + ProtectionDomain string `json:"protectionDomain,omitempty"` + + // readOnly Defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretRef references to the secret for ScaleIO user and other + // sensitive information. If this is not provided, Login operation will fail. + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` + + // sslEnabled Flag enable/disable SSL communication with Gateway, default false + // +optional + SslEnabled bool `json:"sslEnabled,omitempty"` + + // storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + // Default is ThinProvisioned. + // +optional + // +default="ThinProvisioned" + StorageMode string `json:"storageMode,omitempty"` + + // storagePool is the ScaleIO Storage Pool associated with the protection domain. + // +optional + StoragePool string `json:"storagePool,omitempty"` + + // system is the name of the storage system as configured in ScaleIO. + System string `json:"system,omitempty"` + + // volumeName is the name of a volume already created in the ScaleIO system + // that is associated with this volume source. + VolumeName string `json:"volumeName,omitempty"` +} + +// Validate validates this v1 scale i o volume source +func (m *V1ScaleIOVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ScaleIOVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 scale i o volume source based on the context it is used +func (m *V1ScaleIOVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1ScaleIOVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1ScaleIOVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ScaleIOVolumeSource) UnmarshalBinary(b []byte) error { + var res V1ScaleIOVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_seccomp_profile.go b/pkg/client/generated/models/v1_seccomp_profile.go new file mode 100644 index 0000000000..1a49a30a76 --- /dev/null +++ b/pkg/client/generated/models/v1_seccomp_profile.go @@ -0,0 +1,60 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SeccompProfile v1 seccomp profile +// +// swagger:model V1SeccompProfile +type V1SeccompProfile struct { + + // localhostProfile indicates a profile defined in a file on the node should be used. + // The profile must be preconfigured on the node to work. + // Must be a descending path, relative to the kubelet's configured seccomp profile location. + // Must be set if type is "Localhost". Must NOT be set for any other type. + // +optional + LocalhostProfile string `json:"localhostProfile,omitempty"` + + // type indicates which kind of seccomp profile will be applied. + // Valid options are: + // + // Localhost - a profile defined in a file on the node should be used. + // RuntimeDefault - the container runtime default profile should be used. + // Unconfined - no profile should be applied. + // +unionDiscriminator + Type string `json:"type,omitempty"` +} + +// Validate validates this v1 seccomp profile +func (m *V1SeccompProfile) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 seccomp profile based on context it is used +func (m *V1SeccompProfile) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SeccompProfile) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SeccompProfile) UnmarshalBinary(b []byte) error { + var res V1SeccompProfile + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_secret.go b/pkg/client/generated/models/v1_secret.go new file mode 100644 index 0000000000..10cff0afd2 --- /dev/null +++ b/pkg/client/generated/models/v1_secret.go @@ -0,0 +1,125 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Secret v1 secret +// +// swagger:model V1Secret +type V1Secret struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Data contains the secret data. Each key must consist of alphanumeric + // characters, '-', '_' or '.'. The serialized form of the secret data is a + // base64 encoded string, representing the arbitrary (possibly non-string) + // data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 + // +optional + Data map[string]strfmt.Base64 `json:"data,omitempty"` + + // Immutable, if set to true, ensures that data stored in the Secret cannot + // be updated (only object metadata can be modified). + // If not set to true, the field can be modified at any time. + // Defaulted to nil. + // +optional + Immutable bool `json:"immutable,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + Metadata struct { + V1ObjectMeta + } `json:"metadata,omitempty"` + + // stringData allows specifying non-binary secret data in string form. + // It is provided as a write-only input field for convenience. + // All keys and values are merged into the data field on write, overwriting any existing values. + // The stringData field is never output when reading from the API. + // +k8s:conversion-gen=false + // +optional + StringData map[string]string `json:"stringData,omitempty"` + + // Used to facilitate programmatic handling of secret data. + // More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types + // +optional + Type string `json:"type,omitempty"` +} + +// Validate validates this v1 secret +func (m *V1Secret) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Secret) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 secret based on the context it is used +func (m *V1Secret) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Secret) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Secret) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Secret) UnmarshalBinary(b []byte) error { + var res V1Secret + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_secret_env_source.go b/pkg/client/generated/models/v1_secret_env_source.go new file mode 100644 index 0000000000..3f3d548746 --- /dev/null +++ b/pkg/client/generated/models/v1_secret_env_source.go @@ -0,0 +1,59 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SecretEnvSource v1 secret env source +// +// swagger:model V1SecretEnvSource +type V1SecretEnvSource struct { + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // Specify whether the Secret must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 secret env source +func (m *V1SecretEnvSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 secret env source based on context it is used +func (m *V1SecretEnvSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SecretEnvSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SecretEnvSource) UnmarshalBinary(b []byte) error { + var res V1SecretEnvSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_secret_key_selector.go b/pkg/client/generated/models/v1_secret_key_selector.go new file mode 100644 index 0000000000..1b9ba080e1 --- /dev/null +++ b/pkg/client/generated/models/v1_secret_key_selector.go @@ -0,0 +1,62 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SecretKeySelector v1 secret key selector +// +// swagger:model V1SecretKeySelector +type V1SecretKeySelector struct { + + // The key of the secret to select from. Must be a valid secret key. + Key string `json:"key,omitempty"` + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // Specify whether the Secret or its key must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 secret key selector +func (m *V1SecretKeySelector) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 secret key selector based on context it is used +func (m *V1SecretKeySelector) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SecretKeySelector) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SecretKeySelector) UnmarshalBinary(b []byte) error { + var res V1SecretKeySelector + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_secret_list.go b/pkg/client/generated/models/v1_secret_list.go new file mode 100644 index 0000000000..848cfd9e79 --- /dev/null +++ b/pkg/client/generated/models/v1_secret_list.go @@ -0,0 +1,171 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SecretList v1 secret list +// +// swagger:model V1SecretList +type V1SecretList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // Items is a list of secret objects. + // More info: https://kubernetes.io/docs/concepts/configuration/secret + Items []*V1Secret `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // +optional + Metadata struct { + V1ListMeta + } `json:"metadata,omitempty"` +} + +// Validate validates this v1 secret list +func (m *V1SecretList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecretList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1SecretList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 secret list based on the context it is used +func (m *V1SecretList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecretList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *V1SecretList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1SecretList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SecretList) UnmarshalBinary(b []byte) error { + var res V1SecretList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_secret_projection.go b/pkg/client/generated/models/v1_secret_projection.go new file mode 100644 index 0000000000..967fa0e667 --- /dev/null +++ b/pkg/client/generated/models/v1_secret_projection.go @@ -0,0 +1,150 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SecretProjection v1 secret projection +// +// swagger:model V1SecretProjection +type V1SecretProjection struct { + + // items if unspecified, each key-value pair in the Data field of the referenced + // Secret will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the Secret, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + // +listType=atomic + Items []*V1KeyToPath `json:"items"` + + // Name of the referent. + // This field is effectively required, but due to backwards compatibility is + // allowed to be empty. Instances of this type with an empty value here are + // almost certainly wrong. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + // +optional + // +default="" + // +kubebuilder:default="" + // TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. + Name string `json:"name,omitempty"` + + // optional field specify whether the Secret or its key must be defined + // +optional + Optional bool `json:"optional,omitempty"` +} + +// Validate validates this v1 secret projection +func (m *V1SecretProjection) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecretProjection) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 secret projection based on the context it is used +func (m *V1SecretProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecretProjection) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1SecretProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SecretProjection) UnmarshalBinary(b []byte) error { + var res V1SecretProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_secret_volume_source.go b/pkg/client/generated/models/v1_secret_volume_source.go new file mode 100644 index 0000000000..b683d6179a --- /dev/null +++ b/pkg/client/generated/models/v1_secret_volume_source.go @@ -0,0 +1,154 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SecretVolumeSource v1 secret volume source +// +// swagger:model V1SecretVolumeSource +type V1SecretVolumeSource struct { + + // defaultMode is Optional: mode bits used to set permissions on created files by default. + // Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + // YAML accepts both octal and decimal values, JSON requires decimal values + // for mode bits. Defaults to 0644. + // Directories within the path are not affected by this setting. + // This might be in conflict with other options that affect the file + // mode, like fsGroup, and the result can be other mode bits set. + // +optional + DefaultMode int64 `json:"defaultMode,omitempty"` + + // items If unspecified, each key-value pair in the Data field of the referenced + // Secret will be projected into the volume as a file whose name is the + // key and content is the value. If specified, the listed keys will be + // projected into the specified paths, and unlisted keys will not be + // present. If a key is specified which is not present in the Secret, + // the volume setup will error unless it is marked optional. Paths must be + // relative and may not contain the '..' path or start with '..'. + // +optional + // +listType=atomic + Items []*V1KeyToPath `json:"items"` + + // optional field specify whether the Secret or its keys must be defined + // +optional + Optional bool `json:"optional,omitempty"` + + // secretName is the name of the secret in the pod's namespace to use. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + // +optional + SecretName string `json:"secretName,omitempty"` +} + +// Validate validates this v1 secret volume source +func (m *V1SecretVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecretVolumeSource) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 secret volume source based on the context it is used +func (m *V1SecretVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecretVolumeSource) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1SecretVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SecretVolumeSource) UnmarshalBinary(b []byte) error { + var res V1SecretVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_security_context.go b/pkg/client/generated/models/v1_security_context.go new file mode 100644 index 0000000000..385303c417 --- /dev/null +++ b/pkg/client/generated/models/v1_security_context.go @@ -0,0 +1,260 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SecurityContext v1 security context +// +// swagger:model V1SecurityContext +type V1SecurityContext struct { + + // AllowPrivilegeEscalation controls whether a process can gain more + // privileges than its parent process. This bool directly controls if + // the no_new_privs flag will be set on the container process. + // AllowPrivilegeEscalation is true always when the container is: + // 1) run as Privileged + // 2) has CAP_SYS_ADMIN + // Note that this field cannot be set when spec.os.name is windows. + // +optional + AllowPrivilegeEscalation bool `json:"allowPrivilegeEscalation,omitempty"` + + // appArmorProfile is the AppArmor options to use by this container. If set, this profile + // overrides the pod's appArmorProfile. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + AppArmorProfile struct { + V1AppArmorProfile + } `json:"appArmorProfile,omitempty"` + + // The capabilities to add/drop when running containers. + // Defaults to the default set of capabilities granted by the container runtime. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + Capabilities struct { + V1Capabilities + } `json:"capabilities,omitempty"` + + // Run container in privileged mode. + // Processes in privileged containers are essentially equivalent to root on the host. + // Defaults to false. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + Privileged bool `json:"privileged,omitempty"` + + // procMount denotes the type of proc mount to use for the containers. + // The default value is Default which uses the container runtime defaults for + // readonly paths and masked paths. + // This requires the ProcMountType feature flag to be enabled. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + ProcMount string `json:"procMount,omitempty"` + + // Whether this container has a read-only root filesystem. + // Default is false. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + ReadOnlyRootFilesystem bool `json:"readOnlyRootFilesystem,omitempty"` + + // The GID to run the entrypoint of the container process. + // Uses runtime default if unset. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsGroup int64 `json:"runAsGroup,omitempty"` + + // Indicates that the container must run as a non-root user. + // If true, the Kubelet will validate the image at runtime to ensure that it + // does not run as UID 0 (root) and fail to start the container if it does. + // If unset or false, no such validation will be performed. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + RunAsNonRoot bool `json:"runAsNonRoot,omitempty"` + + // The UID to run the entrypoint of the container process. + // Defaults to user specified in image metadata if unspecified. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + RunAsUser int64 `json:"runAsUser,omitempty"` + + // The SELinux context to be applied to the container. + // If unspecified, the container runtime will allocate a random SELinux context for each + // container. May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SeLinuxOptions struct { + V1SELinuxOptions + } `json:"seLinuxOptions,omitempty"` + + // The seccomp options to use by this container. If seccomp options are + // provided at both the pod & container level, the container options + // override the pod options. + // Note that this field cannot be set when spec.os.name is windows. + // +optional + SeccompProfile struct { + V1SeccompProfile + } `json:"seccompProfile,omitempty"` + + // The Windows specific settings applied to all containers. + // If unspecified, the options from the PodSecurityContext will be used. + // If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + // Note that this field cannot be set when spec.os.name is linux. + // +optional + WindowsOptions struct { + V1WindowsSecurityContextOptions + } `json:"windowsOptions,omitempty"` +} + +// Validate validates this v1 security context +func (m *V1SecurityContext) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAppArmorProfile(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCapabilities(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSeLinuxOptions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSeccompProfile(formats); err != nil { + res = append(res, err) + } + + if err := m.validateWindowsOptions(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecurityContext) validateAppArmorProfile(formats strfmt.Registry) error { + if swag.IsZero(m.AppArmorProfile) { // not required + return nil + } + + return nil +} + +func (m *V1SecurityContext) validateCapabilities(formats strfmt.Registry) error { + if swag.IsZero(m.Capabilities) { // not required + return nil + } + + return nil +} + +func (m *V1SecurityContext) validateSeLinuxOptions(formats strfmt.Registry) error { + if swag.IsZero(m.SeLinuxOptions) { // not required + return nil + } + + return nil +} + +func (m *V1SecurityContext) validateSeccompProfile(formats strfmt.Registry) error { + if swag.IsZero(m.SeccompProfile) { // not required + return nil + } + + return nil +} + +func (m *V1SecurityContext) validateWindowsOptions(formats strfmt.Registry) error { + if swag.IsZero(m.WindowsOptions) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 security context based on the context it is used +func (m *V1SecurityContext) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAppArmorProfile(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCapabilities(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSeLinuxOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSeccompProfile(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateWindowsOptions(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SecurityContext) contextValidateAppArmorProfile(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1SecurityContext) contextValidateCapabilities(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1SecurityContext) contextValidateSeLinuxOptions(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1SecurityContext) contextValidateSeccompProfile(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1SecurityContext) contextValidateWindowsOptions(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1SecurityContext) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SecurityContext) UnmarshalBinary(b []byte) error { + var res V1SecurityContext + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_service_account_token_projection.go b/pkg/client/generated/models/v1_service_account_token_projection.go new file mode 100644 index 0000000000..e91cd30447 --- /dev/null +++ b/pkg/client/generated/models/v1_service_account_token_projection.go @@ -0,0 +1,64 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1ServiceAccountTokenProjection v1 service account token projection +// +// swagger:model V1ServiceAccountTokenProjection +type V1ServiceAccountTokenProjection struct { + + // audience is the intended audience of the token. A recipient of a token + // must identify itself with an identifier specified in the audience of the + // token, and otherwise should reject the token. The audience defaults to the + // identifier of the apiserver. + // +optional + Audience string `json:"audience,omitempty"` + + // expirationSeconds is the requested duration of validity of the service + // account token. As the token approaches expiration, the kubelet volume + // plugin will proactively rotate the service account token. The kubelet will + // start trying to rotate the token if the token is older than 80 percent of + // its time to live or if the token is older than 24 hours.Defaults to 1 hour + // and must be at least 10 minutes. + // +optional + ExpirationSeconds int64 `json:"expirationSeconds,omitempty"` + + // path is the path relative to the mount point of the file to project the + // token into. + Path string `json:"path,omitempty"` +} + +// Validate validates this v1 service account token projection +func (m *V1ServiceAccountTokenProjection) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 service account token projection based on context it is used +func (m *V1ServiceAccountTokenProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1ServiceAccountTokenProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1ServiceAccountTokenProjection) UnmarshalBinary(b []byte) error { + var res V1ServiceAccountTokenProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_sleep_action.go b/pkg/client/generated/models/v1_sleep_action.go new file mode 100644 index 0000000000..7ca67e2926 --- /dev/null +++ b/pkg/client/generated/models/v1_sleep_action.go @@ -0,0 +1,47 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SleepAction v1 sleep action +// +// swagger:model V1SleepAction +type V1SleepAction struct { + + // Seconds is the number of seconds to sleep. + Seconds int64 `json:"seconds,omitempty"` +} + +// Validate validates this v1 sleep action +func (m *V1SleepAction) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 sleep action based on context it is used +func (m *V1SleepAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SleepAction) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SleepAction) UnmarshalBinary(b []byte) error { + var res V1SleepAction + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_storage_o_s_volume_source.go b/pkg/client/generated/models/v1_storage_o_s_volume_source.go new file mode 100644 index 0000000000..878dca0f34 --- /dev/null +++ b/pkg/client/generated/models/v1_storage_o_s_volume_source.go @@ -0,0 +1,107 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1StorageOSVolumeSource v1 storage o s volume source +// +// swagger:model V1StorageOSVolumeSource +type V1StorageOSVolumeSource struct { + + // fsType is the filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FsType string `json:"fsType,omitempty"` + + // readOnly defaults to false (read/write). ReadOnly here will force + // the ReadOnly setting in VolumeMounts. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // secretRef specifies the secret to use for obtaining the StorageOS API + // credentials. If not specified, default values will be attempted. + // +optional + SecretRef struct { + V1LocalObjectReference + } `json:"secretRef,omitempty"` + + // volumeName is the human-readable name of the StorageOS volume. Volume + // names are only unique within a namespace. + VolumeName string `json:"volumeName,omitempty"` + + // volumeNamespace specifies the scope of the volume within StorageOS. If no + // namespace is specified then the Pod's namespace will be used. This allows the + // Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + // Set VolumeName to any name to override the default behaviour. + // Set to "default" if you are not using namespaces within StorageOS. + // Namespaces that do not pre-exist within StorageOS will be created. + // +optional + VolumeNamespace string `json:"volumeNamespace,omitempty"` +} + +// Validate validates this v1 storage o s volume source +func (m *V1StorageOSVolumeSource) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSecretRef(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1StorageOSVolumeSource) validateSecretRef(formats strfmt.Registry) error { + if swag.IsZero(m.SecretRef) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 storage o s volume source based on the context it is used +func (m *V1StorageOSVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateSecretRef(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1StorageOSVolumeSource) contextValidateSecretRef(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1StorageOSVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1StorageOSVolumeSource) UnmarshalBinary(b []byte) error { + var res V1StorageOSVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_success_policy.go b/pkg/client/generated/models/v1_success_policy.go new file mode 100644 index 0000000000..dcfe4d0937 --- /dev/null +++ b/pkg/client/generated/models/v1_success_policy.go @@ -0,0 +1,133 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SuccessPolicy v1 success policy +// +// swagger:model V1SuccessPolicy +type V1SuccessPolicy struct { + + // rules represents the list of alternative rules for the declaring the Jobs + // as successful before `.status.succeeded >= .spec.completions`. Once any of the rules are met, + // the "SuccessCriteriaMet" condition is added, and the lingering pods are removed. + // The terminal state for such a Job has the "Complete" condition. + // Additionally, these rules are evaluated in order; Once the Job meets one of the rules, + // other rules are ignored. At most 20 elements are allowed. + // +listType=atomic + Rules []*V1SuccessPolicyRule `json:"rules"` +} + +// Validate validates this v1 success policy +func (m *V1SuccessPolicy) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateRules(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SuccessPolicy) validateRules(formats strfmt.Registry) error { + if swag.IsZero(m.Rules) { // not required + return nil + } + + for i := 0; i < len(m.Rules); i++ { + if swag.IsZero(m.Rules[i]) { // not required + continue + } + + if m.Rules[i] != nil { + if err := m.Rules[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("rules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("rules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this v1 success policy based on the context it is used +func (m *V1SuccessPolicy) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateRules(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1SuccessPolicy) contextValidateRules(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Rules); i++ { + + if m.Rules[i] != nil { + + if swag.IsZero(m.Rules[i]) { // not required + return nil + } + + if err := m.Rules[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("rules" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("rules" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *V1SuccessPolicy) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SuccessPolicy) UnmarshalBinary(b []byte) error { + var res V1SuccessPolicy + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_success_policy_rule.go b/pkg/client/generated/models/v1_success_policy_rule.go new file mode 100644 index 0000000000..2aa97884aa --- /dev/null +++ b/pkg/client/generated/models/v1_success_policy_rule.go @@ -0,0 +1,73 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1SuccessPolicyRule v1 success policy rule +// +// swagger:model V1SuccessPolicyRule +type V1SuccessPolicyRule struct { + + // succeededCount specifies the minimal required size of the actual set of the succeeded indexes + // for the Job. When succeededCount is used along with succeededIndexes, the check is + // constrained only to the set of indexes specified by succeededIndexes. + // For example, given that succeededIndexes is "1-4", succeededCount is "3", + // and completed indexes are "1", "3", and "5", the Job isn't declared as succeeded + // because only "1" and "3" indexes are considered in that rules. + // When this field is null, this doesn't default to any value and + // is never evaluated at any time. + // When specified it needs to be a positive integer. + // + // +optional + SucceededCount int64 `json:"succeededCount,omitempty"` + + // succeededIndexes specifies the set of indexes + // which need to be contained in the actual set of the succeeded indexes for the Job. + // The list of indexes must be within 0 to ".spec.completions-1" and + // must not contain duplicates. At least one element is required. + // The indexes are represented as intervals separated by commas. + // The intervals can be a decimal integer or a pair of decimal integers separated by a hyphen. + // The number are listed in represented by the first and last element of the series, + // separated by a hyphen. + // For example, if the completed indexes are 1, 3, 4, 5 and 7, they are + // represented as "1,3-5,7". + // When this field is null, this field doesn't default to any value + // and is never evaluated at any time. + // + // +optional + SucceededIndexes string `json:"succeededIndexes,omitempty"` +} + +// Validate validates this v1 success policy rule +func (m *V1SuccessPolicyRule) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 success policy rule based on context it is used +func (m *V1SuccessPolicyRule) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1SuccessPolicyRule) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1SuccessPolicyRule) UnmarshalBinary(b []byte) error { + var res V1SuccessPolicyRule + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_sysctl.go b/pkg/client/generated/models/v1_sysctl.go new file mode 100644 index 0000000000..b9d2df4c67 --- /dev/null +++ b/pkg/client/generated/models/v1_sysctl.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Sysctl v1 sysctl +// +// swagger:model V1Sysctl +type V1Sysctl struct { + + // Name of a property to set + Name string `json:"name,omitempty"` + + // Value of a property to set + Value string `json:"value,omitempty"` +} + +// Validate validates this v1 sysctl +func (m *V1Sysctl) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 sysctl based on context it is used +func (m *V1Sysctl) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1Sysctl) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Sysctl) UnmarshalBinary(b []byte) error { + var res V1Sysctl + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_tcp_socket_action.go b/pkg/client/generated/models/v1_tcp_socket_action.go new file mode 100644 index 0000000000..5cd829b7ec --- /dev/null +++ b/pkg/client/generated/models/v1_tcp_socket_action.go @@ -0,0 +1,87 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1TCPSocketAction v1 TCP socket action +// +// swagger:model V1TCPSocketAction +type V1TCPSocketAction struct { + + // Optional: Host name to connect to, defaults to the pod IP. + // +optional + Host string `json:"host,omitempty"` + + // Number or name of the port to access on the container. + // Number must be in the range 1 to 65535. + // Name must be an IANA_SVC_NAME. + Port struct { + IntOrString + } `json:"port,omitempty"` +} + +// Validate validates this v1 TCP socket action +func (m *V1TCPSocketAction) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePort(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1TCPSocketAction) validatePort(formats strfmt.Registry) error { + if swag.IsZero(m.Port) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 TCP socket action based on the context it is used +func (m *V1TCPSocketAction) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePort(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1TCPSocketAction) contextValidatePort(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1TCPSocketAction) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1TCPSocketAction) UnmarshalBinary(b []byte) error { + var res V1TCPSocketAction + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_toleration.go b/pkg/client/generated/models/v1_toleration.go new file mode 100644 index 0000000000..cfeae27307 --- /dev/null +++ b/pkg/client/generated/models/v1_toleration.go @@ -0,0 +1,73 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Toleration v1 toleration +// +// swagger:model V1Toleration +type V1Toleration struct { + + // Effect indicates the taint effect to match. Empty means match all taint effects. + // When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + // +optional + Effect string `json:"effect,omitempty"` + + // Key is the taint key that the toleration applies to. Empty means match all taint keys. + // If the key is empty, operator must be Exists; this combination means to match all values and all keys. + // +optional + Key string `json:"key,omitempty"` + + // Operator represents a key's relationship to the value. + // Valid operators are Exists and Equal. Defaults to Equal. + // Exists is equivalent to wildcard for value, so that a pod can + // tolerate all taints of a particular category. + // +optional + Operator string `json:"operator,omitempty"` + + // TolerationSeconds represents the period of time the toleration (which must be + // of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + // it is not set, which means tolerate the taint forever (do not evict). Zero and + // negative values will be treated as 0 (evict immediately) by the system. + // +optional + TolerationSeconds int64 `json:"tolerationSeconds,omitempty"` + + // Value is the taint value the toleration matches to. + // If the operator is Exists, the value should be empty, otherwise just a regular string. + // +optional + Value string `json:"value,omitempty"` +} + +// Validate validates this v1 toleration +func (m *V1Toleration) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 toleration based on context it is used +func (m *V1Toleration) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1Toleration) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Toleration) UnmarshalBinary(b []byte) error { + var res V1Toleration + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_topology_spread_constraint.go b/pkg/client/generated/models/v1_topology_spread_constraint.go new file mode 100644 index 0000000000..cf051dd66d --- /dev/null +++ b/pkg/client/generated/models/v1_topology_spread_constraint.go @@ -0,0 +1,199 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1TopologySpreadConstraint v1 topology spread constraint +// +// swagger:model V1TopologySpreadConstraint +type V1TopologySpreadConstraint struct { + + // LabelSelector is used to find matching pods. + // Pods that match this label selector are counted to determine the number of pods + // in their corresponding topology domain. + // +optional + LabelSelector struct { + V1LabelSelector + } `json:"labelSelector,omitempty"` + + // MatchLabelKeys is a set of pod label keys to select the pods over which + // spreading will be calculated. The keys are used to lookup values from the + // incoming pod labels, those key-value labels are ANDed with labelSelector + // to select the group of existing pods over which spreading will be calculated + // for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + // MatchLabelKeys cannot be set when LabelSelector isn't set. + // Keys that don't exist in the incoming pod labels will + // be ignored. A null or empty list means only match against labelSelector. + // + // This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). + // +listType=atomic + // +optional + MatchLabelKeys []string `json:"matchLabelKeys"` + + // MaxSkew describes the degree to which pods may be unevenly distributed. + // When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + // between the number of matching pods in the target topology and the global minimum. + // The global minimum is the minimum number of matching pods in an eligible domain + // or zero if the number of eligible domains is less than MinDomains. + // For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + // labelSelector spread as 2/2/1: + // In this case, the global minimum is 1. + // +-------+-------+-------+ + // | zone1 | zone2 | zone3 | + // +-------+-------+-------+ + // | P P | P P | P | + // +-------+-------+-------+ + // - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + // scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + // violate MaxSkew(1). + // - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + // When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + // to topologies that satisfy it. + // It's a required field. Default value is 1 and 0 is not allowed. + MaxSkew int64 `json:"maxSkew,omitempty"` + + // MinDomains indicates a minimum number of eligible domains. + // When the number of eligible domains with matching topology keys is less than minDomains, + // Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + // And when the number of eligible domains with matching topology keys equals or greater than minDomains, + // this value has no effect on scheduling. + // As a result, when the number of eligible domains is less than minDomains, + // scheduler won't schedule more than maxSkew Pods to those domains. + // If value is nil, the constraint behaves as if MinDomains is equal to 1. + // Valid values are integers greater than 0. + // When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + // + // For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + // labelSelector spread as 2/2/2: + // +-------+-------+-------+ + // | zone1 | zone2 | zone3 | + // +-------+-------+-------+ + // | P P | P P | P P | + // +-------+-------+-------+ + // The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + // In this situation, new pod with the same labelSelector cannot be scheduled, + // because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + // it will violate MaxSkew. + // +optional + MinDomains int64 `json:"minDomains,omitempty"` + + // NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + // when calculating pod topology spread skew. Options are: + // - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + // - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. + // + // If this value is nil, the behavior is equivalent to the Honor policy. + // +optional + NodeAffinityPolicy string `json:"nodeAffinityPolicy,omitempty"` + + // NodeTaintsPolicy indicates how we will treat node taints when calculating + // pod topology spread skew. Options are: + // - Honor: nodes without taints, along with tainted nodes for which the incoming pod + // has a toleration, are included. + // - Ignore: node taints are ignored. All nodes are included. + // + // If this value is nil, the behavior is equivalent to the Ignore policy. + // +optional + NodeTaintsPolicy string `json:"nodeTaintsPolicy,omitempty"` + + // TopologyKey is the key of node labels. Nodes that have a label with this key + // and identical values are considered to be in the same topology. + // We consider each as a "bucket", and try to put balanced number + // of pods into each bucket. + // We define a domain as a particular instance of a topology. + // Also, we define an eligible domain as a domain whose nodes meet the requirements of + // nodeAffinityPolicy and nodeTaintsPolicy. + // e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + // And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + // It's a required field. + TopologyKey string `json:"topologyKey,omitempty"` + + // WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + // the spread constraint. + // - DoNotSchedule (default) tells the scheduler not to schedule it. + // - ScheduleAnyway tells the scheduler to schedule the pod in any location, + // but giving higher precedence to topologies that would help reduce the + // skew. + // A constraint is considered "Unsatisfiable" for an incoming pod + // if and only if every possible node assignment for that pod would violate + // "MaxSkew" on some topology. + // For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + // labelSelector spread as 3/1/1: + // +-------+-------+-------+ + // | zone1 | zone2 | zone3 | + // +-------+-------+-------+ + // | P P P | P | P | + // +-------+-------+-------+ + // If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + // to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + // MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + // won't make it *more* imbalanced. + // It's a required field. + WhenUnsatisfiable string `json:"whenUnsatisfiable,omitempty"` +} + +// Validate validates this v1 topology spread constraint +func (m *V1TopologySpreadConstraint) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLabelSelector(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1TopologySpreadConstraint) validateLabelSelector(formats strfmt.Registry) error { + if swag.IsZero(m.LabelSelector) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 topology spread constraint based on the context it is used +func (m *V1TopologySpreadConstraint) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateLabelSelector(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1TopologySpreadConstraint) contextValidateLabelSelector(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1TopologySpreadConstraint) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1TopologySpreadConstraint) UnmarshalBinary(b []byte) error { + var res V1TopologySpreadConstraint + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_typed_local_object_reference.go b/pkg/client/generated/models/v1_typed_local_object_reference.go new file mode 100644 index 0000000000..f5d8a4318d --- /dev/null +++ b/pkg/client/generated/models/v1_typed_local_object_reference.go @@ -0,0 +1,56 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1TypedLocalObjectReference v1 typed local object reference +// +// swagger:model V1TypedLocalObjectReference +type V1TypedLocalObjectReference struct { + + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + // +optional + APIGroup string `json:"apiGroup,omitempty"` + + // Kind is the type of resource being referenced + Kind string `json:"kind,omitempty"` + + // Name is the name of resource being referenced + Name string `json:"name,omitempty"` +} + +// Validate validates this v1 typed local object reference +func (m *V1TypedLocalObjectReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 typed local object reference based on context it is used +func (m *V1TypedLocalObjectReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1TypedLocalObjectReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1TypedLocalObjectReference) UnmarshalBinary(b []byte) error { + var res V1TypedLocalObjectReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_typed_object_reference.go b/pkg/client/generated/models/v1_typed_object_reference.go new file mode 100644 index 0000000000..5f0e2414ee --- /dev/null +++ b/pkg/client/generated/models/v1_typed_object_reference.go @@ -0,0 +1,63 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1TypedObjectReference v1 typed object reference +// +// swagger:model V1TypedObjectReference +type V1TypedObjectReference struct { + + // APIGroup is the group for the resource being referenced. + // If APIGroup is not specified, the specified Kind must be in the core API group. + // For any other third-party types, APIGroup is required. + // +optional + APIGroup string `json:"apiGroup,omitempty"` + + // Kind is the type of resource being referenced + Kind string `json:"kind,omitempty"` + + // Name is the name of resource being referenced + Name string `json:"name,omitempty"` + + // Namespace is the namespace of resource being referenced + // Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + // (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + // +featureGate=CrossNamespaceVolumeDataSource + // +optional + Namespace string `json:"namespace,omitempty"` +} + +// Validate validates this v1 typed object reference +func (m *V1TypedObjectReference) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 typed object reference based on context it is used +func (m *V1TypedObjectReference) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1TypedObjectReference) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1TypedObjectReference) UnmarshalBinary(b []byte) error { + var res V1TypedObjectReference + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_volume.go b/pkg/client/generated/models/v1_volume.go new file mode 100644 index 0000000000..35f21d80f7 --- /dev/null +++ b/pkg/client/generated/models/v1_volume.go @@ -0,0 +1,953 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1Volume v1 volume +// +// swagger:model V1Volume +type V1Volume struct { + + // awsElasticBlockStore represents an AWS Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree + // awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // +optional + AwsElasticBlockStore struct { + V1AWSElasticBlockStoreVolumeSource + } `json:"awsElasticBlockStore,omitempty"` + + // azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + // Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type + // are redirected to the disk.csi.azure.com CSI driver. + // +optional + AzureDisk struct { + V1AzureDiskVolumeSource + } `json:"azureDisk,omitempty"` + + // azureFile represents an Azure File Service mount on the host and bind mount to the pod. + // Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type + // are redirected to the file.csi.azure.com CSI driver. + // +optional + AzureFile struct { + V1AzureFileVolumeSource + } `json:"azureFile,omitempty"` + + // cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. + // Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported. + // +optional + Cephfs struct { + V1CephFSVolumeSource + } `json:"cephfs,omitempty"` + + // cinder represents a cinder volume attached and mounted on kubelets host machine. + // Deprecated: Cinder is deprecated. All operations for the in-tree cinder type + // are redirected to the cinder.csi.openstack.org CSI driver. + // More info: https://examples.k8s.io/mysql-cinder-pd/README.md + // +optional + Cinder struct { + V1CinderVolumeSource + } `json:"cinder,omitempty"` + + // configMap represents a configMap that should populate this volume + // +optional + ConfigMap struct { + V1ConfigMapVolumeSource + } `json:"configMap,omitempty"` + + // csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers. + // +optional + Csi struct { + V1CSIVolumeSource + } `json:"csi,omitempty"` + + // downwardAPI represents downward API about the pod that should populate this volume + // +optional + DownwardAPI struct { + V1DownwardAPIVolumeSource + } `json:"downwardAPI,omitempty"` + + // emptyDir represents a temporary directory that shares a pod's lifetime. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + // +optional + EmptyDir struct { + V1EmptyDirVolumeSource + } `json:"emptyDir,omitempty"` + + // ephemeral represents a volume that is handled by a cluster storage driver. + // The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + // and deleted when the pod is removed. + // + // Use this if: + // a) the volume is only needed while the pod runs, + // b) features of normal volumes like restoring from snapshot or capacity + // tracking are needed, + // c) the storage driver is specified through a storage class, and + // d) the storage driver supports dynamic volume provisioning through + // a PersistentVolumeClaim (see EphemeralVolumeSource for more + // information on the connection between this volume type + // and PersistentVolumeClaim). + // + // Use PersistentVolumeClaim or one of the vendor-specific + // APIs for volumes that persist for longer than the lifecycle + // of an individual pod. + // + // Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + // be used that way - see the documentation of the driver for + // more information. + // + // A pod can use both types of ephemeral volumes and + // persistent volumes at the same time. + // + // +optional + Ephemeral struct { + V1EphemeralVolumeSource + } `json:"ephemeral,omitempty"` + + // fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + // +optional + Fc struct { + V1FCVolumeSource + } `json:"fc,omitempty"` + + // flexVolume represents a generic volume resource that is + // provisioned/attached using an exec based plugin. + // Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead. + // +optional + FlexVolume struct { + V1FlexVolumeSource + } `json:"flexVolume,omitempty"` + + // flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running. + // Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported. + // +optional + Flocker struct { + V1FlockerVolumeSource + } `json:"flocker,omitempty"` + + // gcePersistentDisk represents a GCE Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree + // gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + // +optional + GcePersistentDisk struct { + V1GCEPersistentDiskVolumeSource + } `json:"gcePersistentDisk,omitempty"` + + // gitRepo represents a git repository at a particular revision. + // Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an + // EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + // into the Pod's container. + // +optional + GitRepo struct { + V1GitRepoVolumeSource + } `json:"gitRepo,omitempty"` + + // glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + // Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. + // +optional + Glusterfs struct { + V1GlusterfsVolumeSource + } `json:"glusterfs,omitempty"` + + // hostPath represents a pre-existing file or directory on the host + // machine that is directly exposed to the container. This is generally + // used for system agents or other privileged things that are allowed + // to see the host machine. Most containers will NOT need this. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + // --- + // TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + // mount host directories as read/write. + // +optional + HostPath struct { + V1HostPathVolumeSource + } `json:"hostPath,omitempty"` + + // image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. + // The volume is resolved at pod startup depending on which PullPolicy value is provided: + // + // - Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. + // - Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. + // - IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + // + // The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. + // A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. + // The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. + // The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. + // The volume will be mounted read-only (ro) and non-executable files (noexec). + // Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. + // The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. + // +featureGate=ImageVolume + // +optional + Image struct { + V1ImageVolumeSource + } `json:"image,omitempty"` + + // iscsi represents an ISCSI Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi + // +optional + Iscsi struct { + V1ISCSIVolumeSource + } `json:"iscsi,omitempty"` + + // name of the volume. + // Must be a DNS_LABEL and unique within the pod. + // More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + Name string `json:"name,omitempty"` + + // nfs represents an NFS mount on the host that shares a pod's lifetime + // More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + // +optional + Nfs struct { + V1NFSVolumeSource + } `json:"nfs,omitempty"` + + // persistentVolumeClaimVolumeSource represents a reference to a + // PersistentVolumeClaim in the same namespace. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + PersistentVolumeClaim struct { + V1PersistentVolumeClaimVolumeSource + } `json:"persistentVolumeClaim,omitempty"` + + // photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. + // Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported. + PhotonPersistentDisk struct { + V1PhotonPersistentDiskVolumeSource + } `json:"photonPersistentDisk,omitempty"` + + // portworxVolume represents a portworx volume attached and mounted on kubelets host machine. + // Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type + // are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate + // is on. + // +optional + PortworxVolume struct { + V1PortworxVolumeSource + } `json:"portworxVolume,omitempty"` + + // projected items for all in one resources secrets, configmaps, and downward API + Projected struct { + V1ProjectedVolumeSource + } `json:"projected,omitempty"` + + // quobyte represents a Quobyte mount on the host that shares a pod's lifetime. + // Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported. + // +optional + Quobyte struct { + V1QuobyteVolumeSource + } `json:"quobyte,omitempty"` + + // rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + // Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. + // +optional + Rbd struct { + V1RBDVolumeSource + } `json:"rbd,omitempty"` + + // scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + // Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported. + // +optional + ScaleIO struct { + V1ScaleIOVolumeSource + } `json:"scaleIO,omitempty"` + + // secret represents a secret that should populate this volume. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + // +optional + Secret struct { + V1SecretVolumeSource + } `json:"secret,omitempty"` + + // storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + // Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported. + // +optional + Storageos struct { + V1StorageOSVolumeSource + } `json:"storageos,omitempty"` + + // vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. + // Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type + // are redirected to the csi.vsphere.vmware.com CSI driver. + // +optional + VsphereVolume struct { + V1VsphereVirtualDiskVolumeSource + } `json:"vsphereVolume,omitempty"` +} + +// Validate validates this v1 volume +func (m *V1Volume) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAwsElasticBlockStore(formats); err != nil { + res = append(res, err) + } + + if err := m.validateAzureDisk(formats); err != nil { + res = append(res, err) + } + + if err := m.validateAzureFile(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCephfs(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCinder(formats); err != nil { + res = append(res, err) + } + + if err := m.validateConfigMap(formats); err != nil { + res = append(res, err) + } + + if err := m.validateCsi(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDownwardAPI(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEmptyDir(formats); err != nil { + res = append(res, err) + } + + if err := m.validateEphemeral(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFc(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFlexVolume(formats); err != nil { + res = append(res, err) + } + + if err := m.validateFlocker(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGcePersistentDisk(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGitRepo(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGlusterfs(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHostPath(formats); err != nil { + res = append(res, err) + } + + if err := m.validateImage(formats); err != nil { + res = append(res, err) + } + + if err := m.validateIscsi(formats); err != nil { + res = append(res, err) + } + + if err := m.validateNfs(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePersistentVolumeClaim(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePhotonPersistentDisk(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePortworxVolume(formats); err != nil { + res = append(res, err) + } + + if err := m.validateProjected(formats); err != nil { + res = append(res, err) + } + + if err := m.validateQuobyte(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRbd(formats); err != nil { + res = append(res, err) + } + + if err := m.validateScaleIO(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecret(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStorageos(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVsphereVolume(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Volume) validateAwsElasticBlockStore(formats strfmt.Registry) error { + if swag.IsZero(m.AwsElasticBlockStore) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateAzureDisk(formats strfmt.Registry) error { + if swag.IsZero(m.AzureDisk) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateAzureFile(formats strfmt.Registry) error { + if swag.IsZero(m.AzureFile) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateCephfs(formats strfmt.Registry) error { + if swag.IsZero(m.Cephfs) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateCinder(formats strfmt.Registry) error { + if swag.IsZero(m.Cinder) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateConfigMap(formats strfmt.Registry) error { + if swag.IsZero(m.ConfigMap) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateCsi(formats strfmt.Registry) error { + if swag.IsZero(m.Csi) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateDownwardAPI(formats strfmt.Registry) error { + if swag.IsZero(m.DownwardAPI) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateEmptyDir(formats strfmt.Registry) error { + if swag.IsZero(m.EmptyDir) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateEphemeral(formats strfmt.Registry) error { + if swag.IsZero(m.Ephemeral) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateFc(formats strfmt.Registry) error { + if swag.IsZero(m.Fc) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateFlexVolume(formats strfmt.Registry) error { + if swag.IsZero(m.FlexVolume) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateFlocker(formats strfmt.Registry) error { + if swag.IsZero(m.Flocker) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateGcePersistentDisk(formats strfmt.Registry) error { + if swag.IsZero(m.GcePersistentDisk) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateGitRepo(formats strfmt.Registry) error { + if swag.IsZero(m.GitRepo) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateGlusterfs(formats strfmt.Registry) error { + if swag.IsZero(m.Glusterfs) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateHostPath(formats strfmt.Registry) error { + if swag.IsZero(m.HostPath) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateImage(formats strfmt.Registry) error { + if swag.IsZero(m.Image) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateIscsi(formats strfmt.Registry) error { + if swag.IsZero(m.Iscsi) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateNfs(formats strfmt.Registry) error { + if swag.IsZero(m.Nfs) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validatePersistentVolumeClaim(formats strfmt.Registry) error { + if swag.IsZero(m.PersistentVolumeClaim) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validatePhotonPersistentDisk(formats strfmt.Registry) error { + if swag.IsZero(m.PhotonPersistentDisk) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validatePortworxVolume(formats strfmt.Registry) error { + if swag.IsZero(m.PortworxVolume) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateProjected(formats strfmt.Registry) error { + if swag.IsZero(m.Projected) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateQuobyte(formats strfmt.Registry) error { + if swag.IsZero(m.Quobyte) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateRbd(formats strfmt.Registry) error { + if swag.IsZero(m.Rbd) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateScaleIO(formats strfmt.Registry) error { + if swag.IsZero(m.ScaleIO) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateSecret(formats strfmt.Registry) error { + if swag.IsZero(m.Secret) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateStorageos(formats strfmt.Registry) error { + if swag.IsZero(m.Storageos) { // not required + return nil + } + + return nil +} + +func (m *V1Volume) validateVsphereVolume(formats strfmt.Registry) error { + if swag.IsZero(m.VsphereVolume) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 volume based on the context it is used +func (m *V1Volume) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAwsElasticBlockStore(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateAzureDisk(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateAzureFile(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCephfs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCinder(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateConfigMap(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateCsi(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDownwardAPI(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateEmptyDir(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateEphemeral(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFc(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFlexVolume(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateFlocker(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGcePersistentDisk(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGitRepo(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGlusterfs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHostPath(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateImage(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateIscsi(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateNfs(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePersistentVolumeClaim(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePhotonPersistentDisk(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePortworxVolume(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateProjected(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateQuobyte(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRbd(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateScaleIO(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecret(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStorageos(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateVsphereVolume(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1Volume) contextValidateAwsElasticBlockStore(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateAzureDisk(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateAzureFile(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateCephfs(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateCinder(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateConfigMap(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateCsi(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateDownwardAPI(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateEmptyDir(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateEphemeral(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateFc(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateFlexVolume(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateFlocker(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateGcePersistentDisk(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateGitRepo(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateGlusterfs(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateHostPath(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateImage(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateIscsi(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateNfs(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidatePersistentVolumeClaim(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidatePhotonPersistentDisk(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidatePortworxVolume(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateProjected(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateQuobyte(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateRbd(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateScaleIO(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateSecret(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateStorageos(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1Volume) contextValidateVsphereVolume(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1Volume) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1Volume) UnmarshalBinary(b []byte) error { + var res V1Volume + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_volume_device.go b/pkg/client/generated/models/v1_volume_device.go new file mode 100644 index 0000000000..5ec9039cc9 --- /dev/null +++ b/pkg/client/generated/models/v1_volume_device.go @@ -0,0 +1,50 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1VolumeDevice v1 volume device +// +// swagger:model V1VolumeDevice +type V1VolumeDevice struct { + + // devicePath is the path inside of the container that the device will be mapped to. + DevicePath string `json:"devicePath,omitempty"` + + // name must match the name of a persistentVolumeClaim in the pod + Name string `json:"name,omitempty"` +} + +// Validate validates this v1 volume device +func (m *V1VolumeDevice) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 volume device based on context it is used +func (m *V1VolumeDevice) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1VolumeDevice) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1VolumeDevice) UnmarshalBinary(b []byte) error { + var res V1VolumeDevice + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_volume_mount.go b/pkg/client/generated/models/v1_volume_mount.go new file mode 100644 index 0000000000..1a5d7fe0fc --- /dev/null +++ b/pkg/client/generated/models/v1_volume_mount.go @@ -0,0 +1,98 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1VolumeMount v1 volume mount +// +// swagger:model V1VolumeMount +type V1VolumeMount struct { + + // Path within the container at which the volume should be mounted. Must + // not contain ':'. + MountPath string `json:"mountPath,omitempty"` + + // mountPropagation determines how mounts are propagated from the host + // to container and the other way around. + // When not set, MountPropagationNone is used. + // This field is beta in 1.10. + // When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified + // (which defaults to None). + // +optional + MountPropagation string `json:"mountPropagation,omitempty"` + + // This must match the Name of a Volume. + Name string `json:"name,omitempty"` + + // Mounted read-only if true, read-write otherwise (false or unspecified). + // Defaults to false. + // +optional + ReadOnly bool `json:"readOnly,omitempty"` + + // RecursiveReadOnly specifies whether read-only mounts should be handled + // recursively. + // + // If ReadOnly is false, this field has no meaning and must be unspecified. + // + // If ReadOnly is true, and this field is set to Disabled, the mount is not made + // recursively read-only. If this field is set to IfPossible, the mount is made + // recursively read-only, if it is supported by the container runtime. If this + // field is set to Enabled, the mount is made recursively read-only if it is + // supported by the container runtime, otherwise the pod will not be started and + // an error will be generated to indicate the reason. + // + // If this field is set to IfPossible or Enabled, MountPropagation must be set to + // None (or be unspecified, which defaults to None). + // + // If this field is not specified, it is treated as an equivalent of Disabled. + // + // +featureGate=RecursiveReadOnlyMounts + // +optional + RecursiveReadOnly string `json:"recursiveReadOnly,omitempty"` + + // Path within the volume from which the container's volume should be mounted. + // Defaults to "" (volume's root). + // +optional + SubPath string `json:"subPath,omitempty"` + + // Expanded path within the volume from which the container's volume should be mounted. + // Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + // Defaults to "" (volume's root). + // SubPathExpr and SubPath are mutually exclusive. + // +optional + SubPathExpr string `json:"subPathExpr,omitempty"` +} + +// Validate validates this v1 volume mount +func (m *V1VolumeMount) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 volume mount based on context it is used +func (m *V1VolumeMount) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1VolumeMount) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1VolumeMount) UnmarshalBinary(b []byte) error { + var res V1VolumeMount + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_volume_projection.go b/pkg/client/generated/models/v1_volume_projection.go new file mode 100644 index 0000000000..a324b5180e --- /dev/null +++ b/pkg/client/generated/models/v1_volume_projection.go @@ -0,0 +1,265 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1VolumeProjection v1 volume projection +// +// swagger:model V1VolumeProjection +type V1VolumeProjection struct { + + // ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field + // of ClusterTrustBundle objects in an auto-updating file. + // + // Alpha, gated by the ClusterTrustBundleProjection feature gate. + // + // ClusterTrustBundle objects can either be selected by name, or by the + // combination of signer name and a label selector. + // + // Kubelet performs aggressive normalization of the PEM contents written + // into the pod filesystem. Esoteric PEM features such as inter-block + // comments and block headers are stripped. Certificates are deduplicated. + // The ordering of certificates within the file is arbitrary, and Kubelet + // may change the order over time. + // + // +featureGate=ClusterTrustBundleProjection + // +optional + ClusterTrustBundle struct { + V1ClusterTrustBundleProjection + } `json:"clusterTrustBundle,omitempty"` + + // configMap information about the configMap data to project + // +optional + ConfigMap struct { + V1ConfigMapProjection + } `json:"configMap,omitempty"` + + // downwardAPI information about the downwardAPI data to project + // +optional + DownwardAPI struct { + V1DownwardAPIProjection + } `json:"downwardAPI,omitempty"` + + // Projects an auto-rotating credential bundle (private key and certificate + // chain) that the pod can use either as a TLS client or server. + // + // Kubelet generates a private key and uses it to send a + // PodCertificateRequest to the named signer. Once the signer approves the + // request and issues a certificate chain, Kubelet writes the key and + // certificate chain to the pod filesystem. The pod does not start until + // certificates have been issued for each podCertificate projected volume + // source in its spec. + // + // Kubelet will begin trying to rotate the certificate at the time indicated + // by the signer using the PodCertificateRequest.Status.BeginRefreshAt + // timestamp. + // + // Kubelet can write a single file, indicated by the credentialBundlePath + // field, or separate files, indicated by the keyPath and + // certificateChainPath fields. + // + // The credential bundle is a single file in PEM format. The first PEM + // entry is the private key (in PKCS#8 format), and the remaining PEM + // entries are the certificate chain issued by the signer (typically, + // signers will return their certificate chain in leaf-to-root order). + // + // Prefer using the credential bundle format, since your application code + // can read it atomically. If you use keyPath and certificateChainPath, + // your application must make two separate file reads. If these coincide + // with a certificate rotation, it is possible that the private key and leaf + // certificate you read may not correspond to each other. Your application + // will need to check for this condition, and re-read until they are + // consistent. + // + // The named signer controls chooses the format of the certificate it + // issues; consult the signer implementation's documentation to learn how to + // use the certificates it issues. + // + // +featureGate=PodCertificateProjection +optional + PodCertificate struct { + V1PodCertificateProjection + } `json:"podCertificate,omitempty"` + + // secret information about the secret data to project + // +optional + Secret struct { + V1SecretProjection + } `json:"secret,omitempty"` + + // serviceAccountToken is information about the serviceAccountToken data to project + // +optional + ServiceAccountToken struct { + V1ServiceAccountTokenProjection + } `json:"serviceAccountToken,omitempty"` +} + +// Validate validates this v1 volume projection +func (m *V1VolumeProjection) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateClusterTrustBundle(formats); err != nil { + res = append(res, err) + } + + if err := m.validateConfigMap(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDownwardAPI(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePodCertificate(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSecret(formats); err != nil { + res = append(res, err) + } + + if err := m.validateServiceAccountToken(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1VolumeProjection) validateClusterTrustBundle(formats strfmt.Registry) error { + if swag.IsZero(m.ClusterTrustBundle) { // not required + return nil + } + + return nil +} + +func (m *V1VolumeProjection) validateConfigMap(formats strfmt.Registry) error { + if swag.IsZero(m.ConfigMap) { // not required + return nil + } + + return nil +} + +func (m *V1VolumeProjection) validateDownwardAPI(formats strfmt.Registry) error { + if swag.IsZero(m.DownwardAPI) { // not required + return nil + } + + return nil +} + +func (m *V1VolumeProjection) validatePodCertificate(formats strfmt.Registry) error { + if swag.IsZero(m.PodCertificate) { // not required + return nil + } + + return nil +} + +func (m *V1VolumeProjection) validateSecret(formats strfmt.Registry) error { + if swag.IsZero(m.Secret) { // not required + return nil + } + + return nil +} + +func (m *V1VolumeProjection) validateServiceAccountToken(formats strfmt.Registry) error { + if swag.IsZero(m.ServiceAccountToken) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 volume projection based on the context it is used +func (m *V1VolumeProjection) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateClusterTrustBundle(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateConfigMap(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDownwardAPI(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePodCertificate(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSecret(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateServiceAccountToken(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1VolumeProjection) contextValidateClusterTrustBundle(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1VolumeProjection) contextValidateConfigMap(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1VolumeProjection) contextValidateDownwardAPI(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1VolumeProjection) contextValidatePodCertificate(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1VolumeProjection) contextValidateSecret(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1VolumeProjection) contextValidateServiceAccountToken(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1VolumeProjection) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1VolumeProjection) UnmarshalBinary(b []byte) error { + var res V1VolumeProjection + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_volume_resource_requirements.go b/pkg/client/generated/models/v1_volume_resource_requirements.go new file mode 100644 index 0000000000..705378e544 --- /dev/null +++ b/pkg/client/generated/models/v1_volume_resource_requirements.go @@ -0,0 +1,113 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1VolumeResourceRequirements v1 volume resource requirements +// +// swagger:model V1VolumeResourceRequirements +type V1VolumeResourceRequirements struct { + + // Limits describes the maximum amount of compute resources allowed. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // +optional + Limits struct { + V1ResourceList + } `json:"limits,omitempty"` + + // Requests describes the minimum amount of compute resources required. + // If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + // otherwise to an implementation-defined value. Requests cannot exceed Limits. + // More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // +optional + Requests struct { + V1ResourceList + } `json:"requests,omitempty"` +} + +// Validate validates this v1 volume resource requirements +func (m *V1VolumeResourceRequirements) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateLimits(formats); err != nil { + res = append(res, err) + } + + if err := m.validateRequests(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1VolumeResourceRequirements) validateLimits(formats strfmt.Registry) error { + if swag.IsZero(m.Limits) { // not required + return nil + } + + return nil +} + +func (m *V1VolumeResourceRequirements) validateRequests(formats strfmt.Registry) error { + if swag.IsZero(m.Requests) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 volume resource requirements based on the context it is used +func (m *V1VolumeResourceRequirements) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateLimits(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateRequests(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1VolumeResourceRequirements) contextValidateLimits(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *V1VolumeResourceRequirements) contextValidateRequests(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1VolumeResourceRequirements) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1VolumeResourceRequirements) UnmarshalBinary(b []byte) error { + var res V1VolumeResourceRequirements + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_vsphere_virtual_disk_volume_source.go b/pkg/client/generated/models/v1_vsphere_virtual_disk_volume_source.go new file mode 100644 index 0000000000..a4be66ab49 --- /dev/null +++ b/pkg/client/generated/models/v1_vsphere_virtual_disk_volume_source.go @@ -0,0 +1,61 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1VsphereVirtualDiskVolumeSource v1 vsphere virtual disk volume source +// +// swagger:model V1VsphereVirtualDiskVolumeSource +type V1VsphereVirtualDiskVolumeSource struct { + + // fsType is filesystem type to mount. + // Must be a filesystem type supported by the host operating system. + // Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + // +optional + FsType string `json:"fsType,omitempty"` + + // storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + // +optional + StoragePolicyID string `json:"storagePolicyID,omitempty"` + + // storagePolicyName is the storage Policy Based Management (SPBM) profile name. + // +optional + StoragePolicyName string `json:"storagePolicyName,omitempty"` + + // volumePath is the path that identifies vSphere volume vmdk + VolumePath string `json:"volumePath,omitempty"` +} + +// Validate validates this v1 vsphere virtual disk volume source +func (m *V1VsphereVirtualDiskVolumeSource) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 vsphere virtual disk volume source based on context it is used +func (m *V1VsphereVirtualDiskVolumeSource) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1VsphereVirtualDiskVolumeSource) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1VsphereVirtualDiskVolumeSource) UnmarshalBinary(b []byte) error { + var res V1VsphereVirtualDiskVolumeSource + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_weighted_pod_affinity_term.go b/pkg/client/generated/models/v1_weighted_pod_affinity_term.go new file mode 100644 index 0000000000..c4e43c7920 --- /dev/null +++ b/pkg/client/generated/models/v1_weighted_pod_affinity_term.go @@ -0,0 +1,85 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1WeightedPodAffinityTerm v1 weighted pod affinity term +// +// swagger:model V1WeightedPodAffinityTerm +type V1WeightedPodAffinityTerm struct { + + // Required. A pod affinity term, associated with the corresponding weight. + PodAffinityTerm struct { + V1PodAffinityTerm + } `json:"podAffinityTerm,omitempty"` + + // weight associated with matching the corresponding podAffinityTerm, + // in the range 1-100. + Weight int64 `json:"weight,omitempty"` +} + +// Validate validates this v1 weighted pod affinity term +func (m *V1WeightedPodAffinityTerm) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validatePodAffinityTerm(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1WeightedPodAffinityTerm) validatePodAffinityTerm(formats strfmt.Registry) error { + if swag.IsZero(m.PodAffinityTerm) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this v1 weighted pod affinity term based on the context it is used +func (m *V1WeightedPodAffinityTerm) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidatePodAffinityTerm(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *V1WeightedPodAffinityTerm) contextValidatePodAffinityTerm(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *V1WeightedPodAffinityTerm) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1WeightedPodAffinityTerm) UnmarshalBinary(b []byte) error { + var res V1WeightedPodAffinityTerm + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/v1_windows_security_context_options.go b/pkg/client/generated/models/v1_windows_security_context_options.go new file mode 100644 index 0000000000..71eacd6a23 --- /dev/null +++ b/pkg/client/generated/models/v1_windows_security_context_options.go @@ -0,0 +1,68 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// V1WindowsSecurityContextOptions v1 windows security context options +// +// swagger:model V1WindowsSecurityContextOptions +type V1WindowsSecurityContextOptions struct { + + // GMSACredentialSpec is where the GMSA admission webhook + // (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + // GMSA credential spec named by the GMSACredentialSpecName field. + // +optional + GmsaCredentialSpec string `json:"gmsaCredentialSpec,omitempty"` + + // GMSACredentialSpecName is the name of the GMSA credential spec to use. + // +optional + GmsaCredentialSpecName string `json:"gmsaCredentialSpecName,omitempty"` + + // HostProcess determines if a container should be run as a 'Host Process' container. + // All of a Pod's containers must have the same effective HostProcess value + // (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + // In addition, if HostProcess is true then HostNetwork must also be set to true. + // +optional + HostProcess bool `json:"hostProcess,omitempty"` + + // The UserName in Windows to run the entrypoint of the container process. + // Defaults to the user specified in image metadata if unspecified. + // May also be set in PodSecurityContext. If set in both SecurityContext and + // PodSecurityContext, the value specified in SecurityContext takes precedence. + // +optional + RunAsUserName string `json:"runAsUserName,omitempty"` +} + +// Validate validates this v1 windows security context options +func (m *V1WindowsSecurityContextOptions) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this v1 windows security context options based on context it is used +func (m *V1WindowsSecurityContextOptions) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *V1WindowsSecurityContextOptions) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *V1WindowsSecurityContextOptions) UnmarshalBinary(b []byte) error { + var res V1WindowsSecurityContextOptions + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/verification.go b/pkg/client/generated/models/verification.go new file mode 100644 index 0000000000..4a41263c1d --- /dev/null +++ b/pkg/client/generated/models/verification.go @@ -0,0 +1,226 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Verification verification +// +// swagger:model Verification +type Verification struct { + + // AnalysisRunMetadata contains optional metadata that should be applied to + // all AnalysisRuns. + AnalysisRunMetadata struct { + AnalysisRunMetadata + } `json:"analysisRunMetadata,omitempty"` + + // AnalysisTemplates is a list of AnalysisTemplates from which AnalysisRuns + // should be created to verify a Stage's current Freight is fit to be promoted + // downstream. + AnalysisTemplates []*AnalysisTemplateReference `json:"analysisTemplates"` + + // Args lists arguments that should be added to all AnalysisRuns. + Args []*AnalysisRunArgument `json:"args"` +} + +// Validate validates this verification +func (m *Verification) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAnalysisRunMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateAnalysisTemplates(formats); err != nil { + res = append(res, err) + } + + if err := m.validateArgs(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Verification) validateAnalysisRunMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.AnalysisRunMetadata) { // not required + return nil + } + + return nil +} + +func (m *Verification) validateAnalysisTemplates(formats strfmt.Registry) error { + if swag.IsZero(m.AnalysisTemplates) { // not required + return nil + } + + for i := 0; i < len(m.AnalysisTemplates); i++ { + if swag.IsZero(m.AnalysisTemplates[i]) { // not required + continue + } + + if m.AnalysisTemplates[i] != nil { + if err := m.AnalysisTemplates[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("analysisTemplates" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("analysisTemplates" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Verification) validateArgs(formats strfmt.Registry) error { + if swag.IsZero(m.Args) { // not required + return nil + } + + for i := 0; i < len(m.Args); i++ { + if swag.IsZero(m.Args[i]) { // not required + continue + } + + if m.Args[i] != nil { + if err := m.Args[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("args" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("args" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// ContextValidate validate this verification based on the context it is used +func (m *Verification) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAnalysisRunMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateAnalysisTemplates(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateArgs(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Verification) contextValidateAnalysisRunMetadata(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *Verification) contextValidateAnalysisTemplates(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.AnalysisTemplates); i++ { + + if m.AnalysisTemplates[i] != nil { + + if swag.IsZero(m.AnalysisTemplates[i]) { // not required + return nil + } + + if err := m.AnalysisTemplates[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("analysisTemplates" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("analysisTemplates" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *Verification) contextValidateArgs(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Args); i++ { + + if m.Args[i] != nil { + + if swag.IsZero(m.Args[i]) { // not required + return nil + } + + if err := m.Args[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("args" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("args" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *Verification) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Verification) UnmarshalBinary(b []byte) error { + var res Verification + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/verification_info.go b/pkg/client/generated/models/verification_info.go new file mode 100644 index 0000000000..64b5a09766 --- /dev/null +++ b/pkg/client/generated/models/verification_info.go @@ -0,0 +1,105 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// VerificationInfo verification info +// +// swagger:model VerificationInfo +type VerificationInfo struct { + + // Actor is the name of the entity that initiated or aborted the + // Verification process. + Actor string `json:"actor,omitempty"` + + // AnalysisRun is a reference to the Argo Rollouts AnalysisRun that implements + // the Verification process. + AnalysisRun struct { + AnalysisRunReference + } `json:"analysisRun,omitempty"` + + // FinishTime is the time at which the Verification process finished. + FinishTime string `json:"finishTime,omitempty"` + + // ID is the identifier of the Verification process. + ID string `json:"id,omitempty"` + + // Message may contain additional information about why the verification + // process is in its current phase. + Message string `json:"message,omitempty"` + + // Phase describes the current phase of the Verification process. Generally, + // this will be a reflection of the underlying AnalysisRun's phase, however, + // there are exceptions to this, such as in the case where an AnalysisRun + // cannot be launched successfully. + Phase string `json:"phase,omitempty"` + + // StartTime is the time at which the Verification process was started. + StartTime string `json:"startTime,omitempty"` +} + +// Validate validates this verification info +func (m *VerificationInfo) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAnalysisRun(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *VerificationInfo) validateAnalysisRun(formats strfmt.Registry) error { + if swag.IsZero(m.AnalysisRun) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this verification info based on the context it is used +func (m *VerificationInfo) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateAnalysisRun(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *VerificationInfo) contextValidateAnalysisRun(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *VerificationInfo) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *VerificationInfo) UnmarshalBinary(b []byte) error { + var res VerificationInfo + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/verified_stage.go b/pkg/client/generated/models/verified_stage.go new file mode 100644 index 0000000000..af02dbecf2 --- /dev/null +++ b/pkg/client/generated/models/verified_stage.go @@ -0,0 +1,54 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// VerifiedStage verified stage +// +// swagger:model VerifiedStage +type VerifiedStage struct { + + // LongestCompletedSoak represents the longest definite time interval wherein + // the Freight was in CONTINUOUS use by the Stage. This value is updated as + // Freight EXITS the Stage. If the Freight is currently in use by the Stage, + // the time elapsed since the Freight ENTERED the Stage is its current soak + // time, which may exceed the value of this field. + LongestSoak string `json:"longestSoak,omitempty"` + + // VerifiedAt is the time at which the Freight was verified in the Stage. + VerifiedAt string `json:"verifiedAt,omitempty"` +} + +// Validate validates this verified stage +func (m *VerifiedStage) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this verified stage based on context it is used +func (m *VerifiedStage) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *VerifiedStage) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *VerifiedStage) UnmarshalBinary(b []byte) error { + var res VerifiedStage + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/warehouse.go b/pkg/client/generated/models/warehouse.go new file mode 100644 index 0000000000..b8db23bb44 --- /dev/null +++ b/pkg/client/generated/models/warehouse.go @@ -0,0 +1,182 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// Warehouse warehouse +// +// swagger:model Warehouse +type Warehouse struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ObjectMeta `json:"metadata,omitempty"` + + // Spec describes sources of artifacts. + // + // +kubebuilder:validation:Required + // Required: true + Spec struct { + WarehouseSpec + } `json:"spec"` + + // Status describes the Warehouse's most recently observed state. + Status struct { + WarehouseStatus + } `json:"status,omitempty"` +} + +// Validate validates this warehouse +func (m *Warehouse) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if err := m.validateStatus(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Warehouse) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Warehouse) validateSpec(formats strfmt.Registry) error { + + return nil +} + +func (m *Warehouse) validateStatus(formats strfmt.Registry) error { + if swag.IsZero(m.Status) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this warehouse based on the context it is used +func (m *Warehouse) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSpec(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateStatus(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Warehouse) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +func (m *Warehouse) contextValidateSpec(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *Warehouse) contextValidateStatus(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *Warehouse) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Warehouse) UnmarshalBinary(b []byte) error { + var res Warehouse + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/warehouse_list.go b/pkg/client/generated/models/warehouse_list.go new file mode 100644 index 0000000000..eb08532aff --- /dev/null +++ b/pkg/client/generated/models/warehouse_list.go @@ -0,0 +1,201 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WarehouseList warehouse list +// +// swagger:model WarehouseList +type WarehouseList struct { + + // 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 + // +optional + APIVersion string `json:"apiVersion,omitempty"` + + // items + Items []*Warehouse `json:"items"` + + // 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 + // +optional + Kind string `json:"kind,omitempty"` + + // metadata + Metadata *V1ListMeta `json:"metadata,omitempty"` +} + +// Validate validates this warehouse list +func (m *WarehouseList) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateItems(formats); err != nil { + res = append(res, err) + } + + if err := m.validateMetadata(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseList) validateItems(formats strfmt.Registry) error { + if swag.IsZero(m.Items) { // not required + return nil + } + + for i := 0; i < len(m.Items); i++ { + if swag.IsZero(m.Items[i]) { // not required + continue + } + + if m.Items[i] != nil { + if err := m.Items[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *WarehouseList) validateMetadata(formats strfmt.Registry) error { + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if m.Metadata != nil { + if err := m.Metadata.Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// ContextValidate validate this warehouse list based on the context it is used +func (m *WarehouseList) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateItems(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateMetadata(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseList) contextValidateItems(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Items); i++ { + + if m.Items[i] != nil { + + if swag.IsZero(m.Items[i]) { // not required + return nil + } + + if err := m.Items[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("items" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("items" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *WarehouseList) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { + + if m.Metadata != nil { + + if swag.IsZero(m.Metadata) { // not required + return nil + } + + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("metadata") + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("metadata") + } + + return err + } + } + + return nil +} + +// MarshalBinary interface implementation +func (m *WarehouseList) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WarehouseList) UnmarshalBinary(b []byte) error { + var res WarehouseList + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/warehouse_spec.go b/pkg/client/generated/models/warehouse_spec.go new file mode 100644 index 0000000000..161e52cf74 --- /dev/null +++ b/pkg/client/generated/models/warehouse_spec.go @@ -0,0 +1,126 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WarehouseSpec warehouse spec +// +// swagger:model WarehouseSpec +type WarehouseSpec struct { + + // FreightCreationCriteria defines criteria that must be satisfied for Freight + // to be created automatically from new artifacts following discovery. This + // field has no effect when the FreightCreationPolicy is `Manual`. + // + // +kubebuilder:validation:Optional + FreightCreationCriteria struct { + FreightCreationCriteria + } `json:"freightCreationCriteria,omitempty"` + + // FreightCreationPolicy describes how Freight is created by this Warehouse. + // This field is optional. When left unspecified, the field is implicitly + // treated as if its value were "Automatic". + // + // Accepted values: + // + // - "Automatic": New Freight is created automatically when any new artifact + // is discovered. + // - "Manual": New Freight is never created automatically. + // + // +kubebuilder:default=Automatic + // +kubebuilder:validation:Optional + FreightCreationPolicy string `json:"freightCreationPolicy,omitempty"` + + // Interval is the reconciliation interval for this Warehouse. On each + // reconciliation, the Warehouse will discover new artifacts and optionally + // produce new Freight. This field is optional. When left unspecified, the + // field is implicitly treated as if its value were "5m0s". + // + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern=`^([0-9]+(\.[0-9]+)?(s|m|h))+$` + // +kubebuilder:default="5m0s" + // +akuity:test-kubebuilder-pattern=Duration + Interval string `json:"interval,omitempty"` + + // Shard is the name of the shard that this Warehouse belongs to. This is an + // optional field. If not specified, the Warehouse will belong to the default + // shard. A defaulting webhook will sync this field with the value of the + // kargo.akuity.io/shard label. When the shard label is not present or differs + // from the value of this field, the defaulting webhook will set the label to + // the value of this field. If the shard label is present and this field is + // empty, the defaulting webhook will set the value of this field to the value + // of the shard label. + Shard string `json:"shard,omitempty"` + + // Subscriptions describes sources of artifacts to be included in Freight + // produced by this Warehouse. + // + // +kubebuilder:validation:MinItems=1 + Subscriptions []any `json:"subscriptions"` +} + +// Validate validates this warehouse spec +func (m *WarehouseSpec) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateFreightCreationCriteria(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseSpec) validateFreightCreationCriteria(formats strfmt.Registry) error { + if swag.IsZero(m.FreightCreationCriteria) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this warehouse spec based on the context it is used +func (m *WarehouseSpec) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateFreightCreationCriteria(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseSpec) contextValidateFreightCreationCriteria(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *WarehouseSpec) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WarehouseSpec) UnmarshalBinary(b []byte) error { + var res WarehouseSpec + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/warehouse_stats.go b/pkg/client/generated/models/warehouse_stats.go new file mode 100644 index 0000000000..c20850e577 --- /dev/null +++ b/pkg/client/generated/models/warehouse_stats.go @@ -0,0 +1,85 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WarehouseStats warehouse stats +// +// swagger:model WarehouseStats +type WarehouseStats struct { + + // Count contains the total number of Warehouses in the Project. + Count int64 `json:"count,omitempty"` + + // Health contains a summary of the collective health of a Project's + // Warehouses. + Health struct { + HealthStats + } `json:"health,omitempty"` +} + +// Validate validates this warehouse stats +func (m *WarehouseStats) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateHealth(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseStats) validateHealth(formats strfmt.Registry) error { + if swag.IsZero(m.Health) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this warehouse stats based on the context it is used +func (m *WarehouseStats) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateHealth(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseStats) contextValidateHealth(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *WarehouseStats) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WarehouseStats) UnmarshalBinary(b []byte) error { + var res WarehouseStats + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/warehouse_status.go b/pkg/client/generated/models/warehouse_status.go new file mode 100644 index 0000000000..a7ea984d31 --- /dev/null +++ b/pkg/client/generated/models/warehouse_status.go @@ -0,0 +1,172 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + stderrors "errors" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WarehouseStatus warehouse status +// +// swagger:model WarehouseStatus +type WarehouseStatus struct { + + // Conditions contains the last observations of the Warehouse's current + // state. + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []*V1Condition `json:"conditions"` + + // DiscoveredArtifacts holds the artifacts discovered by the Warehouse. + DiscoveredArtifacts struct { + DiscoveredArtifacts + } `json:"discoveredArtifacts,omitempty"` + + // LastFreightID is a reference to the system-assigned identifier (name) of + // the most recent Freight produced by the Warehouse. + LastFreightID string `json:"lastFreightID,omitempty"` + + // LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh + // annotation that was handled by the controller. This field can be used to + // determine whether the request to refresh the resource has been handled. + // +optional + LastHandledRefresh string `json:"lastHandledRefresh,omitempty"` + + // ObservedGeneration represents the .metadata.generation that this Warehouse + // was reconciled against. + ObservedGeneration int64 `json:"observedGeneration,omitempty"` +} + +// Validate validates this warehouse status +func (m *WarehouseStatus) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateConditions(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDiscoveredArtifacts(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseStatus) validateConditions(formats strfmt.Registry) error { + if swag.IsZero(m.Conditions) { // not required + return nil + } + + for i := 0; i < len(m.Conditions); i++ { + if swag.IsZero(m.Conditions[i]) { // not required + continue + } + + if m.Conditions[i] != nil { + if err := m.Conditions[i].Validate(formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *WarehouseStatus) validateDiscoveredArtifacts(formats strfmt.Registry) error { + if swag.IsZero(m.DiscoveredArtifacts) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this warehouse status based on the context it is used +func (m *WarehouseStatus) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateConditions(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDiscoveredArtifacts(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WarehouseStatus) contextValidateConditions(ctx context.Context, formats strfmt.Registry) error { + + for i := 0; i < len(m.Conditions); i++ { + + if m.Conditions[i] != nil { + + if swag.IsZero(m.Conditions[i]) { // not required + return nil + } + + if err := m.Conditions[i].ContextValidate(ctx, formats); err != nil { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName("conditions" + "." + strconv.Itoa(i)) + } + + return err + } + } + + } + + return nil +} + +func (m *WarehouseStatus) contextValidateDiscoveredArtifacts(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *WarehouseStatus) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WarehouseStatus) UnmarshalBinary(b []byte) error { + var res WarehouseStatus + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/webhook_receiver_config.go b/pkg/client/generated/models/webhook_receiver_config.go new file mode 100644 index 0000000000..ad151b282d --- /dev/null +++ b/pkg/client/generated/models/webhook_receiver_config.go @@ -0,0 +1,348 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// WebhookReceiverConfig webhook receiver config +// +// swagger:model WebhookReceiverConfig +type WebhookReceiverConfig struct { + + // Artifactory contains the configuration for a webhook receiver that is + // compatible with JFrog Artifactory payloads. + Artifactory struct { + ArtifactoryWebhookReceiverConfig + } `json:"artifactory,omitempty"` + + // Azure contains the configuration for a webhook receiver that is compatible + // with Azure Container Registry (ACR) and Azure DevOps payloads. + Azure struct { + AzureWebhookReceiverConfig + } `json:"azure,omitempty"` + + // Bitbucket contains the configuration for a webhook receiver that is + // compatible with Bitbucket payloads. + Bitbucket struct { + BitbucketWebhookReceiverConfig + } `json:"bitbucket,omitempty"` + + // DockerHub contains the configuration for a webhook receiver that is + // compatible with DockerHub payloads. + Dockerhub struct { + DockerHubWebhookReceiverConfig + } `json:"dockerhub,omitempty"` + + // Generic contains the configuration for a generic webhook receiver. + Generic struct { + GenericWebhookReceiverConfig + } `json:"generic,omitempty"` + + // Gitea contains the configuration for a webhook receiver that is compatible + // with Gitea payloads. + Gitea struct { + GiteaWebhookReceiverConfig + } `json:"gitea,omitempty"` + + // GitHub contains the configuration for a webhook receiver that is compatible + // with GitHub payloads. + Github struct { + GitHubWebhookReceiverConfig + } `json:"github,omitempty"` + + // GitLab contains the configuration for a webhook receiver that is compatible + // with GitLab payloads. + Gitlab struct { + GitLabWebhookReceiverConfig + } `json:"gitlab,omitempty"` + + // Harbor contains the configuration for a webhook receiver that is compatible + // with Harbor payloads. + Harbor struct { + HarborWebhookReceiverConfig + } `json:"harbor,omitempty"` + + // Name is the name of the webhook receiver. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` + // +akuity:test-kubebuilder-pattern=KubernetesName + // Required: true + Name *string `json:"name"` + + // Quay contains the configuration for a webhook receiver that is compatible + // with Quay payloads. + Quay struct { + QuayWebhookReceiverConfig + } `json:"quay,omitempty"` +} + +// Validate validates this webhook receiver config +func (m *WebhookReceiverConfig) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateArtifactory(formats); err != nil { + res = append(res, err) + } + + if err := m.validateAzure(formats); err != nil { + res = append(res, err) + } + + if err := m.validateBitbucket(formats); err != nil { + res = append(res, err) + } + + if err := m.validateDockerhub(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGeneric(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGitea(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGithub(formats); err != nil { + res = append(res, err) + } + + if err := m.validateGitlab(formats); err != nil { + res = append(res, err) + } + + if err := m.validateHarbor(formats); err != nil { + res = append(res, err) + } + + if err := m.validateName(formats); err != nil { + res = append(res, err) + } + + if err := m.validateQuay(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WebhookReceiverConfig) validateArtifactory(formats strfmt.Registry) error { + if swag.IsZero(m.Artifactory) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateAzure(formats strfmt.Registry) error { + if swag.IsZero(m.Azure) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateBitbucket(formats strfmt.Registry) error { + if swag.IsZero(m.Bitbucket) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateDockerhub(formats strfmt.Registry) error { + if swag.IsZero(m.Dockerhub) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateGeneric(formats strfmt.Registry) error { + if swag.IsZero(m.Generic) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateGitea(formats strfmt.Registry) error { + if swag.IsZero(m.Gitea) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateGithub(formats strfmt.Registry) error { + if swag.IsZero(m.Github) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateGitlab(formats strfmt.Registry) error { + if swag.IsZero(m.Gitlab) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateHarbor(formats strfmt.Registry) error { + if swag.IsZero(m.Harbor) { // not required + return nil + } + + return nil +} + +func (m *WebhookReceiverConfig) validateName(formats strfmt.Registry) error { + + if err := validate.Required("name", "body", m.Name); err != nil { + return err + } + + return nil +} + +func (m *WebhookReceiverConfig) validateQuay(formats strfmt.Registry) error { + if swag.IsZero(m.Quay) { // not required + return nil + } + + return nil +} + +// ContextValidate validate this webhook receiver config based on the context it is used +func (m *WebhookReceiverConfig) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateArtifactory(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateAzure(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateBitbucket(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateDockerhub(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGeneric(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGitea(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGithub(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateGitlab(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateHarbor(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateQuay(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *WebhookReceiverConfig) contextValidateArtifactory(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateAzure(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateBitbucket(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateDockerhub(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateGeneric(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateGitea(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateGithub(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateGitlab(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateHarbor(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +func (m *WebhookReceiverConfig) contextValidateQuay(ctx context.Context, formats strfmt.Registry) error { + + return nil +} + +// MarshalBinary interface implementation +func (m *WebhookReceiverConfig) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WebhookReceiverConfig) UnmarshalBinary(b []byte) error { + var res WebhookReceiverConfig + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/models/webhook_receiver_details.go b/pkg/client/generated/models/webhook_receiver_details.go new file mode 100644 index 0000000000..0b8db209b4 --- /dev/null +++ b/pkg/client/generated/models/webhook_receiver_details.go @@ -0,0 +1,53 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +import ( + "context" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" +) + +// WebhookReceiverDetails webhook receiver details +// +// swagger:model WebhookReceiverDetails +type WebhookReceiverDetails struct { + + // Name is the name of the webhook receiver. + Name string `json:"name,omitempty"` + + // Path is the path to the receiver's webhook endpoint. + Path string `json:"path,omitempty"` + + // URL includes the full address of the receiver's webhook endpoint. + URL string `json:"url,omitempty"` +} + +// Validate validates this webhook receiver details +func (m *WebhookReceiverDetails) Validate(formats strfmt.Registry) error { + return nil +} + +// ContextValidate validates this webhook receiver details based on context it is used +func (m *WebhookReceiverDetails) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *WebhookReceiverDetails) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *WebhookReceiverDetails) UnmarshalBinary(b []byte) error { + var res WebhookReceiverDetails + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/client/generated/rbac/create_project_api_token_responses.go b/pkg/client/generated/rbac/create_project_api_token_responses.go index e97af7eb64..715891a5f6 100644 --- a/pkg/client/generated/rbac/create_project_api_token_responses.go +++ b/pkg/client/generated/rbac/create_project_api_token_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateProjectAPITokenReader is a Reader for the CreateProjectAPIToken structure. @@ -42,7 +44,7 @@ CreateProjectAPITokenCreated describes a response with status code 201, with def Secret resource (k8s.io/api/core/v1.Secret) */ type CreateProjectAPITokenCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create project Api token created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateProjectAPITokenCreated) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/roles/{role}/api-tokens][%d] createProjectApiTokenCreated %s", 201, payload) } -func (o *CreateProjectAPITokenCreated) GetPayload() any { +func (o *CreateProjectAPITokenCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateProjectAPITokenCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/create_project_role_responses.go b/pkg/client/generated/rbac/create_project_role_responses.go index d5a9956d1b..aadd07650e 100644 --- a/pkg/client/generated/rbac/create_project_role_responses.go +++ b/pkg/client/generated/rbac/create_project_role_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateProjectRoleReader is a Reader for the CreateProjectRole structure. @@ -42,7 +44,7 @@ CreateProjectRoleCreated describes a response with status code 201, with default Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) */ type CreateProjectRoleCreated struct { - Payload any + Payload *models.RbacRole } // IsSuccess returns true when this create project role created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateProjectRoleCreated) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/roles][%d] createProjectRoleCreated %s", 201, payload) } -func (o *CreateProjectRoleCreated) GetPayload() any { +func (o *CreateProjectRoleCreated) GetPayload() *models.RbacRole { return o.Payload } func (o *CreateProjectRoleCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RbacRole) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/create_system_api_token_responses.go b/pkg/client/generated/rbac/create_system_api_token_responses.go index d24e5ee521..33ac3eac41 100644 --- a/pkg/client/generated/rbac/create_system_api_token_responses.go +++ b/pkg/client/generated/rbac/create_system_api_token_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // CreateSystemAPITokenReader is a Reader for the CreateSystemAPIToken structure. @@ -42,7 +44,7 @@ CreateSystemAPITokenCreated describes a response with status code 201, with defa Secret resource (k8s.io/api/core/v1.Secret) */ type CreateSystemAPITokenCreated struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this create system Api token created response has a 2xx status code @@ -85,14 +87,16 @@ func (o *CreateSystemAPITokenCreated) String() string { return fmt.Sprintf("[POST /v1beta1/system/roles/{role}/api-tokens][%d] createSystemApiTokenCreated %s", 201, payload) } -func (o *CreateSystemAPITokenCreated) GetPayload() any { +func (o *CreateSystemAPITokenCreated) GetPayload() *models.V1Secret { return o.Payload } func (o *CreateSystemAPITokenCreated) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/get_project_api_token_responses.go b/pkg/client/generated/rbac/get_project_api_token_responses.go index 107502ccd5..e79bb7641f 100644 --- a/pkg/client/generated/rbac/get_project_api_token_responses.go +++ b/pkg/client/generated/rbac/get_project_api_token_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetProjectAPITokenReader is a Reader for the GetProjectAPIToken structure. @@ -42,7 +44,7 @@ GetProjectAPITokenOK describes a response with status code 200, with default hea Secret resource (k8s.io/api/core/v1.Secret) */ type GetProjectAPITokenOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get project Api token o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetProjectAPITokenOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/api-tokens/{apitoken}][%d] getProjectApiTokenOK %s", 200, payload) } -func (o *GetProjectAPITokenOK) GetPayload() any { +func (o *GetProjectAPITokenOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetProjectAPITokenOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/get_system_api_token_responses.go b/pkg/client/generated/rbac/get_system_api_token_responses.go index 83d4474458..00c50cce52 100644 --- a/pkg/client/generated/rbac/get_system_api_token_responses.go +++ b/pkg/client/generated/rbac/get_system_api_token_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetSystemAPITokenReader is a Reader for the GetSystemAPIToken structure. @@ -42,7 +44,7 @@ GetSystemAPITokenOK describes a response with status code 200, with default head Secret resource (k8s.io/api/core/v1.Secret) */ type GetSystemAPITokenOK struct { - Payload any + Payload *models.V1Secret } // IsSuccess returns true when this get system Api token o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetSystemAPITokenOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/api-tokens/{apitoken}][%d] getSystemApiTokenOK %s", 200, payload) } -func (o *GetSystemAPITokenOK) GetPayload() any { +func (o *GetSystemAPITokenOK) GetPayload() *models.V1Secret { return o.Payload } func (o *GetSystemAPITokenOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1Secret) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/grant_responses.go b/pkg/client/generated/rbac/grant_responses.go index 6e94072fc5..25e24e3bfd 100644 --- a/pkg/client/generated/rbac/grant_responses.go +++ b/pkg/client/generated/rbac/grant_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GrantReader is a Reader for the Grant structure. @@ -42,7 +44,7 @@ GrantOK describes a response with status code 200, with default header values. Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) */ type GrantOK struct { - Payload any + Payload *models.RbacRole } // IsSuccess returns true when this grant o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GrantOK) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/roles/grants][%d] grantOK %s", 200, payload) } -func (o *GrantOK) GetPayload() any { +func (o *GrantOK) GetPayload() *models.RbacRole { return o.Payload } func (o *GrantOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RbacRole) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/list_project_api_tokens_responses.go b/pkg/client/generated/rbac/list_project_api_tokens_responses.go index 7cdb8f958e..079c5ad3f9 100644 --- a/pkg/client/generated/rbac/list_project_api_tokens_responses.go +++ b/pkg/client/generated/rbac/list_project_api_tokens_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListProjectAPITokensReader is a Reader for the ListProjectAPITokens structure. @@ -42,7 +44,7 @@ ListProjectAPITokensOK describes a response with status code 200, with default h SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListProjectAPITokensOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list project Api tokens o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListProjectAPITokensOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/api-tokens][%d] listProjectApiTokensOK %s", 200, payload) } -func (o *ListProjectAPITokensOK) GetPayload() any { +func (o *ListProjectAPITokensOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListProjectAPITokensOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/list_project_roles_responses.go b/pkg/client/generated/rbac/list_project_roles_responses.go index 928351182b..0aebb1d913 100644 --- a/pkg/client/generated/rbac/list_project_roles_responses.go +++ b/pkg/client/generated/rbac/list_project_roles_responses.go @@ -39,7 +39,7 @@ func NewListProjectRolesOK() *ListProjectRolesOK { /* ListProjectRolesOK describes a response with status code 200, with default header values. -RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList) +RoleList custom resource (rbacapi.RoleList) or underlying resources */ type ListProjectRolesOK struct { Payload any diff --git a/pkg/client/generated/rbac/list_system_api_tokens_responses.go b/pkg/client/generated/rbac/list_system_api_tokens_responses.go index e9cb2cb54e..fbf918d272 100644 --- a/pkg/client/generated/rbac/list_system_api_tokens_responses.go +++ b/pkg/client/generated/rbac/list_system_api_tokens_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListSystemAPITokensReader is a Reader for the ListSystemAPITokens structure. @@ -42,7 +44,7 @@ ListSystemAPITokensOK describes a response with status code 200, with default he SecretList resource (k8s.io/api/core/v1.SecretList) */ type ListSystemAPITokensOK struct { - Payload any + Payload *models.V1SecretList } // IsSuccess returns true when this list system Api tokens o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListSystemAPITokensOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/api-tokens][%d] listSystemApiTokensOK %s", 200, payload) } -func (o *ListSystemAPITokensOK) GetPayload() any { +func (o *ListSystemAPITokensOK) GetPayload() *models.V1SecretList { return o.Payload } func (o *ListSystemAPITokensOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.V1SecretList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/list_system_roles_responses.go b/pkg/client/generated/rbac/list_system_roles_responses.go index b5808af53f..c35e1edd1d 100644 --- a/pkg/client/generated/rbac/list_system_roles_responses.go +++ b/pkg/client/generated/rbac/list_system_roles_responses.go @@ -39,7 +39,7 @@ func NewListSystemRolesOK() *ListSystemRolesOK { /* ListSystemRolesOK describes a response with status code 200, with default header values. -RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList) +RoleList custom resource (rbacapi.RoleList) or underlying resources */ type ListSystemRolesOK struct { Payload any diff --git a/pkg/client/generated/rbac/revoke_responses.go b/pkg/client/generated/rbac/revoke_responses.go index aa5791b858..8a954c5556 100644 --- a/pkg/client/generated/rbac/revoke_responses.go +++ b/pkg/client/generated/rbac/revoke_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // RevokeReader is a Reader for the Revoke structure. @@ -42,7 +44,7 @@ RevokeOK describes a response with status code 200, with default header values. Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) */ type RevokeOK struct { - Payload any + Payload *models.RbacRole } // IsSuccess returns true when this revoke o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *RevokeOK) String() string { return fmt.Sprintf("[POST /v1beta1/projects/{project}/roles/revocations][%d] revokeOK %s", 200, payload) } -func (o *RevokeOK) GetPayload() any { +func (o *RevokeOK) GetPayload() *models.RbacRole { return o.Payload } func (o *RevokeOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RbacRole) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/rbac/update_role_responses.go b/pkg/client/generated/rbac/update_role_responses.go index 523d3d6396..4f620a9e76 100644 --- a/pkg/client/generated/rbac/update_role_responses.go +++ b/pkg/client/generated/rbac/update_role_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // UpdateRoleReader is a Reader for the UpdateRole structure. @@ -42,7 +44,7 @@ UpdateRoleOK describes a response with status code 200, with default header valu Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) */ type UpdateRoleOK struct { - Payload any + Payload *models.RbacRole } // IsSuccess returns true when this update role o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *UpdateRoleOK) String() string { return fmt.Sprintf("[PUT /v1beta1/projects/{project}/roles/{role}][%d] updateRoleOK %s", 200, payload) } -func (o *UpdateRoleOK) GetPayload() any { +func (o *UpdateRoleOK) GetPayload() *models.RbacRole { return o.Payload } func (o *UpdateRoleOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RbacRole) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/system/get_cluster_config_responses.go b/pkg/client/generated/system/get_cluster_config_responses.go index fd1a0f1d25..bf222ffb55 100644 --- a/pkg/client/generated/system/get_cluster_config_responses.go +++ b/pkg/client/generated/system/get_cluster_config_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetClusterConfigReader is a Reader for the GetClusterConfig structure. @@ -39,10 +41,10 @@ func NewGetClusterConfigOK() *GetClusterConfigOK { /* GetClusterConfigOK describes a response with status code 200, with default header values. -ClusterConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterConfig) +ClusterConfig custom resource */ type GetClusterConfigOK struct { - Payload any + Payload *models.ClusterConfig } // IsSuccess returns true when this get cluster config o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetClusterConfigOK) String() string { return fmt.Sprintf("[GET /v1beta1/system/cluster-config][%d] getClusterConfigOK %s", 200, payload) } -func (o *GetClusterConfigOK) GetPayload() any { +func (o *GetClusterConfigOK) GetPayload() *models.ClusterConfig { return o.Payload } func (o *GetClusterConfigOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.ClusterConfig) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/verifications/get_analysis_run_responses.go b/pkg/client/generated/verifications/get_analysis_run_responses.go index e314f7ab2c..fa365c46d0 100644 --- a/pkg/client/generated/verifications/get_analysis_run_responses.go +++ b/pkg/client/generated/verifications/get_analysis_run_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetAnalysisRunReader is a Reader for the GetAnalysisRun structure. @@ -42,7 +44,7 @@ GetAnalysisRunOK describes a response with status code 200, with default header AnalysisRun custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun) */ type GetAnalysisRunOK struct { - Payload any + Payload *models.RolloutsAnalysisRun } // IsSuccess returns true when this get analysis run o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetAnalysisRunOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/analysis-runs/{analysis-run}][%d] getAnalysisRunOK %s", 200, payload) } -func (o *GetAnalysisRunOK) GetPayload() any { +func (o *GetAnalysisRunOK) GetPayload() *models.RolloutsAnalysisRun { return o.Payload } func (o *GetAnalysisRunOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RolloutsAnalysisRun) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/verifications/get_analysis_template_responses.go b/pkg/client/generated/verifications/get_analysis_template_responses.go index 17cae0d21e..f133a92ecb 100644 --- a/pkg/client/generated/verifications/get_analysis_template_responses.go +++ b/pkg/client/generated/verifications/get_analysis_template_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetAnalysisTemplateReader is a Reader for the GetAnalysisTemplate structure. @@ -42,7 +44,7 @@ GetAnalysisTemplateOK describes a response with status code 200, with default he AnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplate) */ type GetAnalysisTemplateOK struct { - Payload any + Payload *models.RolloutsAnalysisTemplate } // IsSuccess returns true when this get analysis template o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetAnalysisTemplateOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/analysis-templates/{analysis-template}][%d] getAnalysisTemplateOK %s", 200, payload) } -func (o *GetAnalysisTemplateOK) GetPayload() any { +func (o *GetAnalysisTemplateOK) GetPayload() *models.RolloutsAnalysisTemplate { return o.Payload } func (o *GetAnalysisTemplateOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RolloutsAnalysisTemplate) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/verifications/get_cluster_analysis_template_responses.go b/pkg/client/generated/verifications/get_cluster_analysis_template_responses.go index 27c04c58f9..e4c05034a5 100644 --- a/pkg/client/generated/verifications/get_cluster_analysis_template_responses.go +++ b/pkg/client/generated/verifications/get_cluster_analysis_template_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // GetClusterAnalysisTemplateReader is a Reader for the GetClusterAnalysisTemplate structure. @@ -42,7 +44,7 @@ GetClusterAnalysisTemplateOK describes a response with status code 200, with def ClusterAnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate) */ type GetClusterAnalysisTemplateOK struct { - Payload any + Payload *models.RolloutsClusterAnalysisTemplate } // IsSuccess returns true when this get cluster analysis template o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *GetClusterAnalysisTemplateOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/cluster-analysis-templates/{cluster-analysis-template}][%d] getClusterAnalysisTemplateOK %s", 200, payload) } -func (o *GetClusterAnalysisTemplateOK) GetPayload() any { +func (o *GetClusterAnalysisTemplateOK) GetPayload() *models.RolloutsClusterAnalysisTemplate { return o.Payload } func (o *GetClusterAnalysisTemplateOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RolloutsClusterAnalysisTemplate) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/verifications/list_analysis_templates_responses.go b/pkg/client/generated/verifications/list_analysis_templates_responses.go index c10550d4e5..5769e41b6c 100644 --- a/pkg/client/generated/verifications/list_analysis_templates_responses.go +++ b/pkg/client/generated/verifications/list_analysis_templates_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListAnalysisTemplatesReader is a Reader for the ListAnalysisTemplates structure. @@ -42,7 +44,7 @@ ListAnalysisTemplatesOK describes a response with status code 200, with default AnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList) */ type ListAnalysisTemplatesOK struct { - Payload any + Payload *models.RolloutsAnalysisTemplateList } // IsSuccess returns true when this list analysis templates o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListAnalysisTemplatesOK) String() string { return fmt.Sprintf("[GET /v1beta1/projects/{project}/analysis-templates][%d] listAnalysisTemplatesOK %s", 200, payload) } -func (o *ListAnalysisTemplatesOK) GetPayload() any { +func (o *ListAnalysisTemplatesOK) GetPayload() *models.RolloutsAnalysisTemplateList { return o.Payload } func (o *ListAnalysisTemplatesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RolloutsAnalysisTemplateList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/generated/verifications/list_cluster_analysis_templates_responses.go b/pkg/client/generated/verifications/list_cluster_analysis_templates_responses.go index 73a8727734..eb04167936 100644 --- a/pkg/client/generated/verifications/list_cluster_analysis_templates_responses.go +++ b/pkg/client/generated/verifications/list_cluster_analysis_templates_responses.go @@ -10,6 +10,8 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" + + "github.com/akuity/kargo/pkg/client/generated/models" ) // ListClusterAnalysisTemplatesReader is a Reader for the ListClusterAnalysisTemplates structure. @@ -42,7 +44,7 @@ ListClusterAnalysisTemplatesOK describes a response with status code 200, with d ClusterAnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList) */ type ListClusterAnalysisTemplatesOK struct { - Payload any + Payload *models.RolloutsClusterAnalysisTemplateList } // IsSuccess returns true when this list cluster analysis templates o k response has a 2xx status code @@ -85,14 +87,16 @@ func (o *ListClusterAnalysisTemplatesOK) String() string { return fmt.Sprintf("[GET /v1beta1/shared/cluster-analysis-templates][%d] listClusterAnalysisTemplatesOK %s", 200, payload) } -func (o *ListClusterAnalysisTemplatesOK) GetPayload() any { +func (o *ListClusterAnalysisTemplatesOK) GetPayload() *models.RolloutsClusterAnalysisTemplateList { return o.Payload } func (o *ListClusterAnalysisTemplatesOK) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + o.Payload = new(models.RolloutsClusterAnalysisTemplateList) + // response payload - if err := consumer.Consume(response.Body(), &o.Payload); err != nil && !stderrors.Is(err, io.EOF) { + if err := consumer.Consume(response.Body(), o.Payload); err != nil && !stderrors.Is(err, io.EOF) { return err } diff --git a/pkg/client/watch/watch_test.go b/pkg/client/watch/watch_test.go index 25566e1f63..0a319ec545 100644 --- a/pkg/client/watch/watch_test.go +++ b/pkg/client/watch/watch_test.go @@ -92,7 +92,7 @@ func TestWatchStage(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchStage(ctx, "test-project", "test-stage") @@ -133,7 +133,7 @@ func TestWatchStages(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchStages(ctx, "test-project") @@ -174,7 +174,7 @@ func TestWatchWarehouse(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchWarehouse(ctx, "test-project", "test-warehouse") @@ -215,7 +215,7 @@ func TestWatchWarehouses(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchWarehouses(ctx, "test-project") @@ -256,7 +256,7 @@ func TestWatchPromotion(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchPromotion(ctx, "test-project", "test-promotion") @@ -297,7 +297,7 @@ func TestWatchPromotions(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchPromotions(ctx, "test-project") @@ -338,7 +338,7 @@ func TestWatchProjectConfig(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchProjectConfig(ctx, "test-project") @@ -378,7 +378,7 @@ func TestWatchClusterConfig(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchClusterConfig(ctx) @@ -402,7 +402,7 @@ func TestWatchResource_ErrorResponse(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "bad-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchStage(ctx, "test-project", "test-stage") @@ -428,7 +428,7 @@ func TestWatchResource_ContextCancellation(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) eventCh, errCh := client.WatchStage(ctx, "test-project", "test-stage") @@ -512,7 +512,7 @@ data: {"type":"ADDED","object":{"name":"test"}} reader := strings.NewReader(tt.input) eventCh := make(chan Event[*testObject], 1) - ctx := context.Background() + ctx := t.Context() err := readSSEStream(ctx, reader, eventCh) if tt.expectError { @@ -542,7 +542,7 @@ func TestReadSSEStream_ContextCancellation(t *testing.T) { eventCh := make(chan Event[*testObject]) - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) errCh := make(chan error, 1) go func() { @@ -624,7 +624,7 @@ func TestStreamAnalysisRunLogs(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() logCh, errCh := client.StreamAnalysisRunLogs(ctx, "test-project", "test-run", tt.metricName, tt.containerName) @@ -653,7 +653,7 @@ func TestStreamAnalysisRunLogs_Error(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() logCh, errCh := client.StreamAnalysisRunLogs(ctx, "test-project", "test-run", "", "") @@ -724,7 +724,7 @@ data: line 2 reader := strings.NewReader(tt.input) logCh := make(chan string, 10) - ctx := context.Background() + ctx := t.Context() err := readLogStream(ctx, reader, logCh) close(logCh) @@ -772,7 +772,7 @@ func TestMultipleEventsInStream(t *testing.T) { defer server.Close() client := NewClient(server.URL, server.Client(), "test-token") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) defer cancel() eventCh, errCh := client.WatchStages(ctx, "test-project") diff --git a/pkg/component/list_based_registry_test.go b/pkg/component/list_based_registry_test.go index 44e55e5adb..839016d27c 100644 --- a/pkg/component/list_based_registry_test.go +++ b/pkg/component/list_based_registry_test.go @@ -213,11 +213,11 @@ func TestListBasedRegistry_WithFunctionValues(t *testing.T) { } // Test matching predicate - reg, err := registry.Get(context.Background(), "match") + reg, err := registry.Get(t.Context(), "match") require.NoError(t, err) // Verify the factory function works - result, err := reg.Value(context.Background(), "test") + result, err := reg.Value(t.Context(), "test") require.NoError(t, err) require.Equal(t, "output-test", result) } diff --git a/pkg/component/map_based_registry_test.go b/pkg/component/map_based_registry_test.go index 8f8224937c..a173c44d1c 100644 --- a/pkg/component/map_based_registry_test.go +++ b/pkg/component/map_based_registry_test.go @@ -285,7 +285,7 @@ func TestMapBasedRegistry_WithFunctionValues(t *testing.T) { require.NoError(t, err) // Verify the factory function works - result, err := reg.Value(context.Background(), "test") + result, err := reg.Value(t.Context(), "test") require.NoError(t, err) require.Equal(t, "output-test", result) } diff --git a/pkg/controller/argocd/api/v1alpha1/application_types.go b/pkg/controller/argocd/api/v1alpha1/application_types.go index bbdc6c80f6..f0a08998a8 100644 --- a/pkg/controller/argocd/api/v1alpha1/application_types.go +++ b/pkg/controller/argocd/api/v1alpha1/application_types.go @@ -85,6 +85,7 @@ type ApplicationSourceKustomize struct { type ApplicationStatus struct { Health HealthStatus `json:"health,omitempty"` Sync SyncStatus `json:"sync,omitempty"` + ReconciledAt *metav1.Time `json:"reconciledAt,omitempty"` Conditions []ApplicationCondition `json:"conditions,omitempty"` OperationState *OperationState `json:"operationState,omitempty"` } diff --git a/pkg/controller/argocd/api/v1alpha1/zz_generated.deepcopy.go b/pkg/controller/argocd/api/v1alpha1/zz_generated.deepcopy.go index 0c8d16200b..4de1fbe99e 100644 --- a/pkg/controller/argocd/api/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/controller/argocd/api/v1alpha1/zz_generated.deepcopy.go @@ -214,6 +214,10 @@ func (in *ApplicationStatus) DeepCopyInto(out *ApplicationStatus) { *out = *in out.Health = in.Health in.Sync.DeepCopyInto(&out.Sync) + if in.ReconciledAt != nil { + in, out := &in.ReconciledAt, &out.ReconciledAt + *out = (*in).DeepCopy() + } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make([]ApplicationCondition, len(*in)) diff --git a/pkg/controller/freight/finder_test.go b/pkg/controller/freight/finder_test.go index 16535b9b5c..3e6cb748ac 100644 --- a/pkg/controller/freight/finder_test.go +++ b/pkg/controller/freight/finder_test.go @@ -1,7 +1,6 @@ package freight import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -239,7 +238,7 @@ func TestFindCommit(t *testing.T) { cl = testCase.client() } commit, err := FindCommit( - context.Background(), + t.Context(), cl, testCase.stage.Namespace, testCase.stage.Spec.RequestedFreight, @@ -473,7 +472,7 @@ func TestFindImage(t *testing.T) { cl = testCase.client() } image, err := FindImage( - context.Background(), + t.Context(), cl, testCase.stage.Namespace, testCase.stage.Spec.RequestedFreight, @@ -604,7 +603,7 @@ func TestHasAmbiguousImageRequest(t *testing.T) { cl = testCase.client() } ok, err := HasAmbiguousImageRequest( - context.Background(), + t.Context(), cl, testNamespace, testCase.freight, @@ -841,7 +840,7 @@ func TestFindChart(t *testing.T) { cl = testCase.client() } chart, err := FindChart( - context.Background(), + t.Context(), cl, testCase.stage.Namespace, testCase.stage.Spec.RequestedFreight, @@ -1096,7 +1095,7 @@ func TestFindArtifact(t *testing.T) { cl = testCase.client() } commit, err := FindArtifact( - context.Background(), + t.Context(), cl, testCase.stage.Namespace, testCase.stage.Spec.RequestedFreight, diff --git a/pkg/controller/git/base_repo.go b/pkg/controller/git/base_repo.go index 375b55b88d..b7140a1729 100644 --- a/pkg/controller/git/base_repo.go +++ b/pkg/controller/git/base_repo.go @@ -225,6 +225,7 @@ func (b *baseRepo) setupAuth(homeDir string) error { if b.creds == nil { return nil } + // TODO(v1.13.0): Remove this block when SSH support is removed. // If an SSH key was provided, use that. if b.creds.SSHPrivateKey != "" { sshPath := filepath.Join(homeDir, ".ssh") @@ -353,6 +354,7 @@ func (b *baseRepo) buildCommand(command string, arg ...string) *exec.Cmd { func (b *baseRepo) buildGitCommand(arg ...string) *exec.Cmd { cmd := b.buildCommand("git", arg...) + // TODO(v1.13.0): Remove this line when SSH support is removed. cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_SSH_COMMAND=ssh -F %s/.ssh/config", b.homeDir)) if b.creds != nil && b.creds.Password != "" { cmd.Env = append( diff --git a/pkg/controller/git/commit/lexical_selector_test.go b/pkg/controller/git/commit/lexical_selector_test.go index 61aab260c9..bccaced550 100644 --- a/pkg/controller/git/commit/lexical_selector_test.go +++ b/pkg/controller/git/commit/lexical_selector_test.go @@ -1,7 +1,6 @@ package commit import ( - "context" "errors" "regexp" "testing" @@ -361,7 +360,7 @@ func Test_lexicalSelector_Select(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - commits, err := testCase.selector.Select(context.Background()) + commits, err := testCase.selector.Select(t.Context()) testCase.assertions(t, commits, err) }) } diff --git a/pkg/controller/git/commit/newest_from_branch_selector.go b/pkg/controller/git/commit/newest_from_branch_selector.go index a6d1665c77..c892bcd58f 100644 --- a/pkg/controller/git/commit/newest_from_branch_selector.go +++ b/pkg/controller/git/commit/newest_from_branch_selector.go @@ -33,13 +33,13 @@ func init() { // kargoapi.CommitSelectionStrategyNewestFromBranch. type newestFromBranchSelector struct { *baseSelector - branch string + branch string + sinceDate *time.Time selectCommitsFn func(git.Repo) ([]git.CommitMetadata, error) listCommitsFn func( repo git.Repo, - limit uint, - skip uint, + opts *git.ListCommitsOptions, ) ([]git.CommitMetadata, error) getDiffPathsForCommitIDFn func( repo git.Repo, @@ -55,10 +55,14 @@ func newNewestFromBranchSelector( if err != nil { return nil, fmt.Errorf("error building base selector: %w", err) } + s := &newestFromBranchSelector{ baseSelector: base, branch: sub.Branch, } + if sub.Since != nil { + s.sinceDate = &sub.Since.Time + } s.selectCommitsFn = s.selectCommits s.listCommitsFn = s.listCommits s.getDiffPathsForCommitIDFn = s.getDiffPathsForCommitID @@ -128,9 +132,12 @@ func (n *newestFromBranchSelector) Select(ctx context.Context) ( func (n *newestFromBranchSelector) selectCommits( repo git.Repo, ) ([]git.CommitMetadata, error) { + opts := &git.ListCommitsOptions{Since: n.sinceDate} selectedCommits := make([]git.CommitMetadata, 0, n.discoveryLimit) for skip, batch := uint(0), uint(n.discoveryLimit); ; skip, batch = skip+batch, min(batch*2, 1000) { // nolint: gosec - commits, err := n.listCommitsFn(repo, batch, skip) // nolint: gosec + opts.Limit = batch // nolint: gosec + opts.Skip = skip // nolint: gosec + commits, err := n.listCommitsFn(repo, opts) if err != nil { return nil, fmt.Errorf("error listing commits from git repo %q: %w", n.repoURL, err) @@ -185,10 +192,9 @@ func (n *newestFromBranchSelector) selectCommits( func (n *newestFromBranchSelector) listCommits( repo git.Repo, - limit uint, - skip uint, + opts *git.ListCommitsOptions, ) ([]git.CommitMetadata, error) { - return repo.ListCommits(limit, skip) // nolint: gosec + return repo.ListCommits(opts) } func (n *newestFromBranchSelector) getDiffPathsForCommitID( diff --git a/pkg/controller/git/commit/newest_from_branch_selector_test.go b/pkg/controller/git/commit/newest_from_branch_selector_test.go index fce13ea6fd..2bb4ed844d 100644 --- a/pkg/controller/git/commit/newest_from_branch_selector_test.go +++ b/pkg/controller/git/commit/newest_from_branch_selector_test.go @@ -1,7 +1,6 @@ package commit import ( - "context" "errors" "testing" "time" @@ -9,6 +8,8 @@ import ( "github.com/expr-lang/expr" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/pkg/controller/git" @@ -30,6 +31,19 @@ func TestNewNewestFromBranchSelector(t *testing.T) { require.ErrorContains(t, err, "error building base selector") }, }, + { + name: "success with since", + sub: kargoapi.GitSubscription{ + Branch: "main", + Since: ptr.To(metav1.Now()), + }, + assertions: func(t *testing.T, s Selector, err error) { + require.NoError(t, err) + n, ok := s.(*newestFromBranchSelector) + require.True(t, ok) + require.NotNil(t, n.sinceDate) + }, + }, { name: "success", sub: kargoapi.GitSubscription{Branch: "main"}, @@ -186,7 +200,7 @@ func Test_newestFromBranchSelector_Select(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - commits, err := testCase.selector.Select(context.Background()) + commits, err := testCase.selector.Select(t.Context()) testCase.assertions(t, commits, err) }) } @@ -325,7 +339,7 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { name: "error listing commits", selector: &newestFromBranchSelector{ baseSelector: &baseSelector{}, - listCommitsFn: func(git.Repo, uint, uint) ([]git.CommitMetadata, error) { + listCommitsFn: func(git.Repo, *git.ListCommitsOptions) ([]git.CommitMetadata, error) { return nil, errors.New("something went wrong") }, }, @@ -339,7 +353,7 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { baseSelector: &baseSelector{ discoveryLimit: 3, }, - listCommitsFn: func(git.Repo, uint, uint) ([]git.CommitMetadata, error) { + listCommitsFn: func(git.Repo, *git.ListCommitsOptions) ([]git.CommitMetadata, error) { return []git.CommitMetadata{{}, {}, {}, {}, {}}, nil }, }, @@ -354,7 +368,7 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { baseSelector: &baseSelector{ filterExpression: nonBoolExpression, }, - listCommitsFn: func(git.Repo, uint, uint) ([]git.CommitMetadata, error) { + listCommitsFn: func(git.Repo, *git.ListCommitsOptions) ([]git.CommitMetadata, error) { return []git.CommitMetadata{{}}, nil }, }, @@ -368,7 +382,7 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { baseSelector: &baseSelector{ includePaths: includePaths, }, - listCommitsFn: func(git.Repo, uint, uint) ([]git.CommitMetadata, error) { + listCommitsFn: func(git.Repo, *git.ListCommitsOptions) ([]git.CommitMetadata, error) { return []git.CommitMetadata{{}}, nil }, getDiffPathsForCommitIDFn: func(git.Repo, string) ([]string, error) { @@ -386,7 +400,7 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { filterExpression: idFilterExpression, discoveryLimit: 3, }, - listCommitsFn: func(git.Repo, uint, uint) ([]git.CommitMetadata, error) { + listCommitsFn: func(git.Repo, *git.ListCommitsOptions) ([]git.CommitMetadata, error) { return []git.CommitMetadata{ {ID: "A"}, {ID: "B"}, @@ -412,7 +426,7 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { includePaths: includePaths, discoveryLimit: 3, }, - listCommitsFn: func(git.Repo, uint, uint) ([]git.CommitMetadata, error) { + listCommitsFn: func(git.Repo, *git.ListCommitsOptions) ([]git.CommitMetadata, error) { return []git.CommitMetadata{ {ID: "A"}, {ID: "B"}, @@ -440,6 +454,38 @@ func Test_newestFromBranchSelector_selectCommits(t *testing.T) { ) }, }, + { + name: "since with no filters passes option to git and uses fast path", + selector: func() *newestFromBranchSelector { + cutoff := time.Date(2024, 6, 1, 0, 0, 0, 0, time.UTC) + return &newestFromBranchSelector{ + baseSelector: &baseSelector{discoveryLimit: 5}, + sinceDate: &cutoff, + listCommitsFn: func(_ git.Repo, opts *git.ListCommitsOptions) ([]git.CommitMetadata, error) { + // Simulate git filtering by date -- only return commits after cutoff. + require.NotNil(t, opts) + require.NotNil(t, opts.Since) + return []git.CommitMetadata{ + {ID: "A", CommitDate: time.Date(2024, 9, 1, 0, 0, 0, 0, time.UTC)}, + {ID: "B", CommitDate: time.Date(2024, 8, 1, 0, 0, 0, 0, time.UTC)}, + {ID: "C", CommitDate: time.Date(2024, 7, 1, 0, 0, 0, 0, time.UTC)}, + }, nil + }, + } + }(), + assertions: func(t *testing.T, commits []git.CommitMetadata, err error) { + require.NoError(t, err) + require.Equal( + t, + []git.CommitMetadata{ + {ID: "A", CommitDate: time.Date(2024, 9, 1, 0, 0, 0, 0, time.UTC)}, + {ID: "B", CommitDate: time.Date(2024, 8, 1, 0, 0, 0, 0, time.UTC)}, + {ID: "C", CommitDate: time.Date(2024, 7, 1, 0, 0, 0, 0, time.UTC)}, + }, + commits, + ) + }, + }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { diff --git a/pkg/controller/git/commit/newest_tag_selector_test.go b/pkg/controller/git/commit/newest_tag_selector_test.go index a229ae8564..311799ddfa 100644 --- a/pkg/controller/git/commit/newest_tag_selector_test.go +++ b/pkg/controller/git/commit/newest_tag_selector_test.go @@ -1,7 +1,6 @@ package commit import ( - "context" "errors" "regexp" "testing" @@ -310,7 +309,7 @@ func Test_newestTagSelector_Select(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - commits, err := testCase.selector.Select(context.Background()) + commits, err := testCase.selector.Select(t.Context()) testCase.assertions(t, commits, err) }) } diff --git a/pkg/controller/git/commit/semver_selector_test.go b/pkg/controller/git/commit/semver_selector_test.go index 7a02f70528..367d2fc8cd 100644 --- a/pkg/controller/git/commit/semver_selector_test.go +++ b/pkg/controller/git/commit/semver_selector_test.go @@ -1,7 +1,6 @@ package commit import ( - "context" "errors" "regexp" "testing" @@ -509,7 +508,7 @@ func Test_semverSelector_Select(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - commits, err := testCase.selector.Select(context.Background()) + commits, err := testCase.selector.Select(t.Context()) testCase.assertions(t, commits, err) }) } diff --git a/pkg/controller/git/credentials.go b/pkg/controller/git/credentials.go index cac2588874..00d1dedd9f 100644 --- a/pkg/controller/git/credentials.go +++ b/pkg/controller/git/credentials.go @@ -5,6 +5,8 @@ package git type RepoCredentials struct { // SSHPrivateKey is a private key that can be used for both reading from and // writing to some remote repository. + // + // TODO(v1.13.0): Remove this field when SSH support is removed. SSHPrivateKey string // Username identifies a principal, which combined with the value of the // Password field, can be used for both reading from and writing to some diff --git a/pkg/controller/git/mock_repo.go b/pkg/controller/git/mock_repo.go index d4bdf2b7d9..963cfb01be 100644 --- a/pkg/controller/git/mock_repo.go +++ b/pkg/controller/git/mock_repo.go @@ -25,7 +25,7 @@ type MockRepo struct { IsRebasingFn func() (bool, error) LastCommitIDFn func() (string, error) ListTagsFn func() ([]TagMetadata, error) - ListCommitsFn func(limit, skip uint) ([]CommitMetadata, error) + ListCommitsFn func(opts *ListCommitsOptions) ([]CommitMetadata, error) CommitMessageFn func(id string) (string, error) PushFn func(*PushOptions) error RefsHaveDiffsFn func(commit1 string, commit2 string) (bool, error) @@ -127,8 +127,8 @@ func (m *MockRepo) ListTags() ([]TagMetadata, error) { return m.ListTagsFn() } -func (m *MockRepo) ListCommits(limit, skip uint) ([]CommitMetadata, error) { - return m.ListCommitsFn(limit, skip) +func (m *MockRepo) ListCommits(opts *ListCommitsOptions) ([]CommitMetadata, error) { + return m.ListCommitsFn(opts) } func (m *MockRepo) CommitMessage(id string) (string, error) { diff --git a/pkg/controller/git/remote_commit_integration_test.go b/pkg/controller/git/remote_commit_integration_test.go index 1aa2c774b5..153dc1cf29 100644 --- a/pkg/controller/git/remote_commit_integration_test.go +++ b/pkg/controller/git/remote_commit_integration_test.go @@ -41,7 +41,7 @@ func Test_workTree_integrateBeforePush(t *testing.T) { // A rebase produces no merge commits: // initial + remote + local = 3. - commits, err := repo.ListCommits(0, 0) + commits, err := repo.ListCommits(nil) require.NoError(t, err) require.Len(t, commits, 3) }) @@ -63,7 +63,7 @@ func Test_workTree_integrateBeforePush(t *testing.T) { // All local commits are unsigned and signing is not configured, so // rebase is safe. No merge commits: initial + remote + local = 3. - commits, err := repo.ListCommits(0, 0) + commits, err := repo.ListCommits(nil) require.NoError(t, err) require.Len(t, commits, 3) }) @@ -109,7 +109,7 @@ func Test_workTree_integrateBeforePush(t *testing.T) { require.NoError(t, err) // Rebase is safe (unsigned, signing not configured). - commits, err := repo.ListCommits(0, 0) + commits, err := repo.ListCommits(nil) require.NoError(t, err) require.Len(t, commits, 3) }) @@ -206,7 +206,7 @@ func Test_workTree_pullRebase(t *testing.T) { // The rebase should not have created any merge commits, so the commit count // should be: initial + remote + local = 3. - commits, err := repo.ListCommits(0, 0) + commits, err := repo.ListCommits(nil) require.NoError(t, err) require.Len(t, commits, 3) }) diff --git a/pkg/controller/git/work_tree.go b/pkg/controller/git/work_tree.go index 6c5349eb96..1604853936 100644 --- a/pkg/controller/git/work_tree.go +++ b/pkg/controller/git/work_tree.go @@ -76,7 +76,7 @@ type WorkTree interface { ListTags() ([]TagMetadata, error) // ListCommits returns a slice of commits in the current branch with // metadata such as commit ID, commit date, and subject. - ListCommits(limit, skip uint) ([]CommitMetadata, error) + ListCommits(opts *ListCommitsOptions) ([]CommitMetadata, error) // CommitMessage returns the text of the most recent commit message associated // with the specified commit ID. CommitMessage(id string) (string, error) @@ -95,6 +95,16 @@ type WorkTree interface { UpdateSubmodules() error } +// ListCommitsOptions contains options for listing commits. +type ListCommitsOptions struct { + // Limit is the maximum number of commits to return. 0 means no limit. + Limit uint + // Skip is the number of commits to skip before returning results. + Skip uint + // Since limits commits to those at or after this time. + Since *time.Time +} + // workTree is an implementation of the WorkTree interface for interacting with // any working tree of a Git repository. type workTree struct { @@ -416,7 +426,7 @@ func (w *workTree) Fetch(opts *FetchOptions) error { } func (w *workTree) GetDiffPathsForCommitID(commitID string) ([]string, error) { - resBytes, err := libExec.Exec(w.buildGitCommand("show", "--pretty=", "--name-only", commitID)) + resBytes, err := libExec.Exec(w.buildGitCommand("show", "--pretty=", "--name-only", "--first-parent", commitID)) if err != nil { return nil, fmt.Errorf("error getting diff paths for commit %q: %w", commitID, err) } @@ -501,9 +511,13 @@ type CommitMetadata struct { Subject string } -func (w *workTree) ListCommits(limit, skip uint) ([]CommitMetadata, error) { +func (w *workTree) ListCommits(opts *ListCommitsOptions) ([]CommitMetadata, error) { + if opts == nil { + opts = &ListCommitsOptions{} + } args := []string{ "log", + "--first-parent", // This format is designed to output the following fields, separated by // tabs (%x09): // @@ -514,14 +528,17 @@ func (w *workTree) ListCommits(limit, skip uint) ([]CommitMetadata, error) { // - subject "--pretty=format:%H%x09%ci%x09%an <%ae>%x09%cn <%ce>%x09%s", } - if limit > 0 { - args = append(args, fmt.Sprintf("--max-count=%d", limit)) + if opts.Limit > 0 { + args = append(args, fmt.Sprintf("--max-count=%d", opts.Limit)) } - if skip > 0 { - args = append(args, fmt.Sprintf("--skip=%d", skip)) + if opts.Skip > 0 { + args = append(args, fmt.Sprintf("--skip=%d", opts.Skip)) + } + if opts.Since != nil { + args = append(args, fmt.Sprintf("--since=%s", opts.Since.Format(time.RFC3339))) } - commitsBytes, err := libExec.Exec(w.buildGitCommand(args...)) + b, err := libExec.Exec(w.buildGitCommand(args...)) if err != nil { return nil, fmt.Errorf( "error listing commits for repo %q: %w", @@ -530,7 +547,7 @@ func (w *workTree) ListCommits(limit, skip uint) ([]CommitMetadata, error) { } var commits []CommitMetadata - scanner := bufio.NewScanner(bytes.NewReader(commitsBytes)) + scanner := bufio.NewScanner(bytes.NewReader(b)) for scanner.Scan() { line := scanner.Bytes() parts := bytes.SplitN(scanner.Bytes(), []byte("\t"), 5) @@ -551,7 +568,9 @@ func (w *workTree) ListCommits(limit, skip uint) ([]CommitMetadata, error) { Subject: string(parts[4]), }) } - + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("error scanning commits output: %w", err) + } return commits, nil } diff --git a/pkg/controller/git/work_tree_test.go b/pkg/controller/git/work_tree_test.go index 0d4ee26a08..a569f90e0b 100644 --- a/pkg/controller/git/work_tree_test.go +++ b/pkg/controller/git/work_tree_test.go @@ -1,6 +1,7 @@ package git import ( + "fmt" "os" "path/filepath" "testing" @@ -9,6 +10,7 @@ import ( "github.com/stretchr/testify/require" testingPkg "github.com/akuity/kargo/api/testing" + libExec "github.com/akuity/kargo/pkg/exec" ) func TestNonFastForwardRegex(t *testing.T) { @@ -126,3 +128,172 @@ func mustParseTime(s string) time.Time { t, _ := time.Parse("2006-01-02 15:04:05 -0700", s) return t } + +func TestListCommits(t *testing.T) { + testServer, testRepoURL, testRepoCreds := setupRemoteRepo(t) + defer testServer.Close() + + rep, err := Clone( + testRepoURL, + &ClientOptions{Credentials: &testRepoCreds}, + nil, + ) + require.NoError(t, err) + require.NotNil(t, rep) + defer rep.Close() + + wt := internalWorkTree(t, rep) + + // Create initial commit on main + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/file.txt", rep.Dir()), + []byte("initial"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("main: initial commit", nil)) + + // Create a feature branch from the initial commit + require.NoError(t, rep.CreateChildBranch("feature")) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/feature.txt", rep.Dir()), + []byte("feature work 1"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("feature: work 1", nil)) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/feature.txt", rep.Dir()), + []byte("feature work 2"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("feature: work 2", nil)) + + // Back to main, add another commit + require.NoError(t, rep.Checkout("main")) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/file.txt", rep.Dir()), + []byte("second"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("main: second commit", nil)) + + // Merge the feature branch into main + _, err = libExec.Exec(wt.buildGitCommand( + "merge", "feature", "--no-ff", "-m", "main: merge feature", + )) + require.NoError(t, err) + + // ListCommits should only return first-parent commits (main line), + // not the individual feature branch commits. + commits, err := rep.ListCommits(nil) + require.NoError(t, err) + + subjects := make([]string, len(commits)) + for i, c := range commits { + subjects[i] = c.Subject + } + require.Equal( + t, + []string{ + "main: merge feature", + "main: second commit", + "main: initial commit", + }, + subjects, + ) +} + +func TestGetDiffPathsForMergeCommit(t *testing.T) { + testServer, testRepoURL, testRepoCreds := setupRemoteRepo(t) + defer testServer.Close() + + rep, err := Clone( + testRepoURL, + &ClientOptions{Credentials: &testRepoCreds}, + nil, + ) + require.NoError(t, err) + require.NotNil(t, rep) + defer rep.Close() + + wt := internalWorkTree(t, rep) + + // Create initial commit on main with base files + require.NoError(t, os.MkdirAll(fmt.Sprintf("%s/foo", rep.Dir()), 0o755)) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/foo/file1.txt", rep.Dir()), + []byte("base"), + 0o600, + ), + ) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/foo/file2.txt", rep.Dir()), + []byte("base"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("initial commit", nil)) + + // Create branch-a and modify file1 + require.NoError(t, rep.CreateChildBranch("branch-a")) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/foo/file1.txt", rep.Dir()), + []byte("changed by branch-a"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("branch-a: modify file1", nil)) + + // Back to main, create branch-b, modify file2 + require.NoError(t, rep.Checkout("main")) + require.NoError(t, rep.CreateChildBranch("branch-b")) + require.NoError( + t, + os.WriteFile( + fmt.Sprintf("%s/foo/file2.txt", rep.Dir()), + []byte("changed by branch-b"), + 0o600, + ), + ) + require.NoError(t, rep.AddAllAndCommit("branch-b: modify file2", nil)) + + // Merge branch-b into main + require.NoError(t, rep.Checkout("main")) + _, err = libExec.Exec(wt.buildGitCommand( + "merge", "branch-b", "--no-ff", "-m", "merge branch-b", + )) + require.NoError(t, err) + + // Merge branch-a into main + _, err = libExec.Exec(wt.buildGitCommand( + "merge", "branch-a", "--no-ff", "-m", "merge branch-a", + )) + require.NoError(t, err) + + mergeCommitID, err := rep.LastCommitID() + require.NoError(t, err) + + // GetDiffPathsForCommitID on the merge commit should return only + // the file introduced by that merge (file1, from branch-a), not + // file2 which was already on main via the earlier merge of branch-b. + paths, err := rep.GetDiffPathsForCommitID(mergeCommitID) + require.NoError(t, err) + require.Equal(t, []string{"foo/file1.txt"}, paths) +} diff --git a/pkg/controller/management/clusterconfigs/cluster_configs_test.go b/pkg/controller/management/clusterconfigs/cluster_configs_test.go index 3f7d75e644..de2babae29 100644 --- a/pkg/controller/management/clusterconfigs/cluster_configs_test.go +++ b/pkg/controller/management/clusterconfigs/cluster_configs_test.go @@ -1,7 +1,6 @@ package clusterconfigs import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -163,7 +162,7 @@ func TestReconciler_syncWebhookReceivers(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { status, err := testCase.reconciler.syncWebhookReceivers( - context.Background(), + t.Context(), testCase.clusterCfg, ) testCase.assertions(t, status, err) diff --git a/pkg/controller/management/projects/event_handlers_test.go b/pkg/controller/management/projects/event_handlers_test.go index a76beed99e..34d602a30f 100644 --- a/pkg/controller/management/projects/event_handlers_test.go +++ b/pkg/controller/management/projects/event_handlers_test.go @@ -1,7 +1,6 @@ package projects import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -86,7 +85,7 @@ func Test_projectWarehouseHealthEnqueuer_Update(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Update( - context.Background(), + t.Context(), event.TypedUpdateEvent[*kargoapi.Warehouse]{ ObjectOld: tt.oldWarehouse, ObjectNew: tt.newWarehouse, @@ -176,7 +175,7 @@ func Test_projectStageHealthEnqueuer_Update(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Update( - context.Background(), + t.Context(), event.TypedUpdateEvent[*kargoapi.Stage]{ ObjectOld: tt.oldStage, ObjectNew: tt.newStage, diff --git a/pkg/controller/management/projects/projects_test.go b/pkg/controller/management/projects/projects_test.go index bc466b5b0e..25fc9ca88d 100644 --- a/pkg/controller/management/projects/projects_test.go +++ b/pkg/controller/management/projects/projects_test.go @@ -406,7 +406,7 @@ func TestReconciler_reconcile(t *testing.T) { WithObjects(tt.project). WithInterceptorFuncs(tt.interceptor). Build() - status, err := tt.reconciler.reconcile(context.Background(), tt.project) + status, err := tt.reconciler.reconcile(t.Context(), tt.project) tt.assertions(t, status, tt.reconciler.client, err) }) } @@ -1174,7 +1174,7 @@ func TestReconciler_syncProject(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { status, err := testCase.reconciler.syncProject( - context.Background(), + t.Context(), testCase.project, ) testCase.assertions(t, status, err) @@ -1421,7 +1421,7 @@ func TestReconciler_ensureNamespace(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { testCase.assertions( t, - testCase.reconciler.ensureNamespace(context.Background(), testCase.project), + testCase.reconciler.ensureNamespace(t.Context(), testCase.project), ) }) } @@ -1521,7 +1521,7 @@ func TestReconciler_ensureSystemPermissions(t *testing.T) { testCase.assertions( t, testCase.reconciler.ensureSystemPermissions( - context.Background(), + t.Context(), &kargoapi.Project{}, ), ) @@ -1629,7 +1629,7 @@ func TestReconciler_ensureControllerPermissions(t *testing.T) { require.NoError(t, err) sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "fake-controller", Namespace: cfg.KargoNamespace, @@ -1670,7 +1670,7 @@ func TestReconciler_ensureControllerPermissions(t *testing.T) { require.NoError(t, err) rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSA.Name), Namespace: testProject.Name, @@ -1716,7 +1716,7 @@ func TestReconciler_ensureControllerPermissions(t *testing.T) { require.NoError(t, err) rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSA.Name), Namespace: testProject.Name, @@ -1777,7 +1777,7 @@ func TestReconciler_ensureControllerPermissions(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { r := newReconciler(testCase.client, cfg) - err = r.ensureControllerPermissions(context.Background(), testProject) + err = r.ensureControllerPermissions(t.Context(), testProject) testCase.assertions(t, testCase.client, err) }) } @@ -2001,7 +2001,7 @@ func TestReconciler_ensureDefaultUserRoles(t *testing.T) { } testCase.assertions( t, - testCase.reconciler.ensureDefaultUserRoles(context.Background(), p), + testCase.reconciler.ensureDefaultUserRoles(t.Context(), p), ) }) } @@ -2070,7 +2070,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify ServiceAccount still exists sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "test-control-plane", Namespace: testProject.Name, @@ -2095,7 +2095,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify ServiceAccount was created sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "test-control-plane", Namespace: testProject.Name, @@ -2108,7 +2108,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify RoleBinding was created rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "test-control-plane", Namespace: testProject.Name, @@ -2135,7 +2135,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify ArgoCD ServiceAccount was created sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "kargo-argocd-service-account", Namespace: testProject.Name, @@ -2162,7 +2162,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify ClusterRoleBinding was created crb := &rbacv1.ClusterRoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: kubernetes.ShortenResourceName(fmt.Sprintf("kargo-argocd-%s", testProject.Name)), }, @@ -2193,7 +2193,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify ArgoCD RoleBinding was created rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: kubernetes.ShortenResourceName(fmt.Sprintf("kargo-argocd-%s", testProject.Name)), Namespace: "argocd", @@ -2227,7 +2227,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify orchestrator ServiceAccount was created sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "test-orchestrator", Namespace: testProject.Name, @@ -2239,7 +2239,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify control plane ServiceAccount was created sa = &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "test-control-plane", Namespace: testProject.Name, @@ -2259,7 +2259,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { for _, rbName := range roleBindings { rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: rbName, Namespace: testProject.Name, @@ -2286,7 +2286,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify orchestrator ServiceAccount was NOT created in project namespace sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "test-orchestrator", Namespace: testProject.Name, @@ -2313,7 +2313,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify manager RoleBinding was created rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "kargo-manager", Namespace: testProject.Name, @@ -2342,7 +2342,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify manager RoleBinding was NOT created rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: "kargo-manager", Namespace: testProject.Name, @@ -2424,7 +2424,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { // Verify it still exists crb := &rbacv1.ClusterRoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: kubernetes.ShortenResourceName(fmt.Sprintf("kargo-argocd-role-%s", testProject.Name)), }, @@ -2438,7 +2438,7 @@ func TestReconciler_ensureExtendedPermissions(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { r := newReconciler(testCase.client, testCase.cfg) - err := r.ensureExtendedPermissions(context.Background(), testProject) + err := r.ensureExtendedPermissions(t.Context(), testProject) testCase.assertions(t, testCase.client, err) }) } diff --git a/pkg/controller/management/projects/stats_test.go b/pkg/controller/management/projects/stats_test.go index 7632cb32e8..c5e961a1ca 100644 --- a/pkg/controller/management/projects/stats_test.go +++ b/pkg/controller/management/projects/stats_test.go @@ -265,7 +265,7 @@ func Test_reconciler_collectStats(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { r := &reconciler{client: tt.client} - status, err := r.collectStats(context.Background(), tt.project) + status, err := r.collectStats(t.Context(), tt.project) tt.assertions(t, status, err) }) } diff --git a/pkg/controller/management/replication/replication_test.go b/pkg/controller/management/replication/replication_test.go index ceb47d2188..1a583ac06f 100644 --- a/pkg/controller/management/replication/replication_test.go +++ b/pkg/controller/management/replication/replication_test.go @@ -905,14 +905,14 @@ func TestReconcile_SkipsReconcileWhenAdapterRetursFalse(t *testing.T) { Data: map[string][]byte{"key": []byte("value")}, Type: corev1.SecretTypeOpaque, } - require.NoError(t, fc.Create(context.Background(), nonCredentialSecret)) + require.NoError(t, fc.Create(t.Context(), nonCredentialSecret)) // Add the finalizer so it won't try to re-reconcile controllerutil.AddFinalizer(nonCredentialSecret, kargoapi.FinalizerName) - require.NoError(t, fc.Update(context.Background(), nonCredentialSecret)) + require.NoError(t, fc.Update(t.Context(), nonCredentialSecret)) // Create a test project - require.NoError(t, fc.Create(context.Background(), project("test-project"))) + require.NoError(t, fc.Create(t.Context(), project("test-project"))) r := reconcilerForTest(fc, secretFixture()) @@ -923,7 +923,7 @@ func TestReconcile_SkipsReconcileWhenAdapterRetursFalse(t *testing.T) { // Verify the Secret was not replicated to the project namespace replicatedList := &corev1.SecretList{} - require.NoError(t, fc.List(context.Background(), replicatedList, client.InNamespace("test-project"))) + require.NoError(t, fc.List(t.Context(), replicatedList, client.InNamespace("test-project"))) require.Empty(t, replicatedList.Items) } @@ -946,14 +946,14 @@ func TestReconcile_ReplicatesWhenAdapterReturnsTrue(t *testing.T) { Data: map[string][]byte{"key": []byte("value")}, Type: corev1.SecretTypeOpaque, } - require.NoError(t, fc.Create(context.Background(), credentialSecret)) + require.NoError(t, fc.Create(t.Context(), credentialSecret)) // Add the finalizer controllerutil.AddFinalizer(credentialSecret, kargoapi.FinalizerName) - require.NoError(t, fc.Update(context.Background(), credentialSecret)) + require.NoError(t, fc.Update(t.Context(), credentialSecret)) // Create a test project - require.NoError(t, fc.Create(context.Background(), project("test-project"))) + require.NoError(t, fc.Create(t.Context(), project("test-project"))) r := reconcilerForTest(fc, secretFixture()) @@ -964,7 +964,7 @@ func TestReconcile_ReplicatesWhenAdapterReturnsTrue(t *testing.T) { // Verify the Secret was replicated to the project namespace replicatedList := &corev1.SecretList{} - require.NoError(t, fc.List(context.Background(), replicatedList, client.InNamespace("test-project"))) + require.NoError(t, fc.List(t.Context(), replicatedList, client.InNamespace("test-project"))) require.Len(t, replicatedList.Items, 1) require.Equal(t, testResourceName, replicatedList.Items[0].GetName()) } diff --git a/pkg/controller/management/serviceaccounts/serviceaccounts_test.go b/pkg/controller/management/serviceaccounts/serviceaccounts_test.go index f8f5c7bf2e..e6703f6f23 100644 --- a/pkg/controller/management/serviceaccounts/serviceaccounts_test.go +++ b/pkg/controller/management/serviceaccounts/serviceaccounts_test.go @@ -120,7 +120,7 @@ func TestReconcile(t *testing.T) { // RoleBinding should be deleted rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProjectName, @@ -133,7 +133,7 @@ func TestReconcile(t *testing.T) { // Finalizer should be removed sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: testControllerSARef.Name, Namespace: testControllerSARef.Namespace, @@ -172,7 +172,7 @@ func TestReconcile(t *testing.T) { // RoleBinding should be deleted rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProjectName, @@ -185,7 +185,7 @@ func TestReconcile(t *testing.T) { // Finalizer should be removed sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: testControllerSARef.Name, Namespace: testControllerSARef.Namespace, @@ -282,7 +282,7 @@ func TestReconcile(t *testing.T) { // Finalizer should be added sa := &corev1.ServiceAccount{} err = cl.Get( - context.Background(), + t.Context(), testControllerSARef, sa, ) @@ -292,7 +292,7 @@ func TestReconcile(t *testing.T) { // RoleBinding should be created rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProjectName, @@ -307,7 +307,7 @@ func TestReconcile(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { r := newReconciler(testCase.client, cfg) _, err := r.Reconcile( - context.Background(), + t.Context(), ctrl.Request{ NamespacedName: testControllerSARef, }, @@ -391,7 +391,7 @@ func TestEnsureControllerPermissions(t *testing.T) { require.NoError(t, err) rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProject.Name, @@ -437,7 +437,7 @@ func TestEnsureControllerPermissions(t *testing.T) { require.NoError(t, err) rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProject.Name, @@ -498,7 +498,7 @@ func TestEnsureControllerPermissions(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { r := newReconciler(testCase.client, cfg) - err = r.ensureControllerPermissions(context.Background(), testControllerSARef) + err = r.ensureControllerPermissions(t.Context(), testControllerSARef) testCase.assertions(t, testCase.client, err) }) } @@ -586,7 +586,7 @@ func TestRemoveControllerPermissions(t *testing.T) { require.NoError(t, err) rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProject.Name, @@ -607,7 +607,7 @@ func TestRemoveControllerPermissions(t *testing.T) { require.NoError(t, err) rb := &rbacv1.RoleBinding{} err = cl.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: getRoleBindingName(testControllerSARef.Name), Namespace: testProject.Name, @@ -622,7 +622,7 @@ func TestRemoveControllerPermissions(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { r := newReconciler(testCase.client, cfg) - err = r.removeControllerPermissions(context.Background(), testControllerSARef) + err = r.removeControllerPermissions(t.Context(), testControllerSARef) testCase.assertions(t, testCase.client, err) }) } diff --git a/pkg/controller/promotions/predicates.go b/pkg/controller/promotions/predicates.go index 924e1e6f74..0a04d0b1e2 100644 --- a/pkg/controller/promotions/predicates.go +++ b/pkg/controller/promotions/predicates.go @@ -55,3 +55,122 @@ func (p ArgoCDAppOperationCompleted[T]) Delete(event.TypedDeleteEvent[T]) bool { func (p ArgoCDAppOperationCompleted[T]) Generic(event.TypedGenericEvent[T]) bool { return false } + +// ArgoCDAppHealthChanged is a predicate that fires when an ArgoCD +// Application's health status changes (e.g. Progressing → Healthy). This +// enables the Promotion reconciler to react promptly to health transitions +// instead of waiting for a polling interval. +type ArgoCDAppHealthChanged[T any] struct { + logger *logging.Logger +} + +func (p ArgoCDAppHealthChanged[T]) Create(event.TypedCreateEvent[T]) bool { + return false +} + +func (p ArgoCDAppHealthChanged[T]) Update(e event.TypedUpdateEvent[T]) bool { + oldApp := any(e.ObjectOld).(*argocd.Application) // nolint: forcetypeassert + newApp := any(e.ObjectNew).(*argocd.Application) // nolint: forcetypeassert + if oldApp == nil || newApp == nil { + p.logger.Error( + nil, "Update event has no new or old object", + "event", e, + ) + return false + } + return newApp.Status.Health.Status != oldApp.Status.Health.Status +} + +func (p ArgoCDAppHealthChanged[T]) Delete(event.TypedDeleteEvent[T]) bool { + return false +} + +func (p ArgoCDAppHealthChanged[T]) Generic(event.TypedGenericEvent[T]) bool { + return false +} + +// ArgoCDAppSyncChanged is a predicate that fires when an ArgoCD Application's +// sync status changes (e.g. OutOfSync → Synced). This enables the Promotion +// reconciler to react promptly to sync transitions instead of waiting for a +// polling interval. +type ArgoCDAppSyncChanged[T any] struct { + logger *logging.Logger +} + +func (p ArgoCDAppSyncChanged[T]) Create(event.TypedCreateEvent[T]) bool { + return false +} + +func (p ArgoCDAppSyncChanged[T]) Update(e event.TypedUpdateEvent[T]) bool { + oldApp := any(e.ObjectOld).(*argocd.Application) // nolint: forcetypeassert + newApp := any(e.ObjectNew).(*argocd.Application) // nolint: forcetypeassert + if oldApp == nil || newApp == nil { + p.logger.Error( + nil, "Update event has no new or old object", + "event", e, + ) + return false + } + return newApp.Status.Sync.Status != oldApp.Status.Sync.Status +} + +func (p ArgoCDAppSyncChanged[T]) Delete(event.TypedDeleteEvent[T]) bool { + return false +} + +func (p ArgoCDAppSyncChanged[T]) Generic(event.TypedGenericEvent[T]) bool { + return false +} + +// ArgoCDAppReconciledAfterOperation is a predicate that fires when an Argo CD +// Application's reconciledAt advances from a stale value (nil or before +// finishedAt) to a newer value. This is the signal that Argo CD has +// re-assessed health after a completed operation, making the health status +// trustworthy again. It enables the Promotion reconciler to react promptly +// when a hard refresh completes rather than waiting for the next polling +// interval. +type ArgoCDAppReconciledAfterOperation[T any] struct { + logger *logging.Logger +} + +func (p ArgoCDAppReconciledAfterOperation[T]) Create(event.TypedCreateEvent[T]) bool { + return false +} + +func (p ArgoCDAppReconciledAfterOperation[T]) Update(e event.TypedUpdateEvent[T]) bool { + oldApp := any(e.ObjectOld).(*argocd.Application) // nolint: forcetypeassert + newApp := any(e.ObjectNew).(*argocd.Application) // nolint: forcetypeassert + if oldApp == nil || newApp == nil { + p.logger.Error( + nil, "Update event has no new or old object", + "event", e, + ) + return false + } + + // Only relevant when there is a completed operation with a known finish time. + if newApp.Status.OperationState == nil || newApp.Status.OperationState.FinishedAt == nil { + return false + } + finishedAt := newApp.Status.OperationState.FinishedAt + + // reconciledAt must have changed. + if oldApp.Status.ReconciledAt.Equal(newApp.Status.ReconciledAt) { + return false + } + + // Only fire if the old reconciledAt was stale (nil or before finishedAt). + // Once reconciledAt is already trusted (>= finishedAt), subsequent + // advances are routine Argo CD refreshes that do not need to wake the + // Promotion reconciler. + return oldApp.Status.ReconciledAt == nil || + oldApp.Status.ReconciledAt.Before(finishedAt) +} + +func (p ArgoCDAppReconciledAfterOperation[T]) Delete(event.TypedDeleteEvent[T]) bool { + return false +} + +func (p ArgoCDAppReconciledAfterOperation[T]) Generic(event.TypedGenericEvent[T]) bool { + return false +} diff --git a/pkg/controller/promotions/predicates_test.go b/pkg/controller/promotions/predicates_test.go index e24f1ae787..62e536ac8f 100644 --- a/pkg/controller/promotions/predicates_test.go +++ b/pkg/controller/promotions/predicates_test.go @@ -2,8 +2,10 @@ package promotions import ( "testing" + "time" "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/event" argocd "github.com/akuity/kargo/pkg/controller/argocd/api/v1alpha1" @@ -97,3 +99,278 @@ func TestArgoCDAppOperationCompleted_Update(t *testing.T) { }) } } + +func TestArgoCDAppHealthChanged_Update(t *testing.T) { + testCases := []struct { + name string + e event.TypedUpdateEvent[*argocd.Application] + want bool + }{ + { + name: "ObjectOld is nil", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectNew: &argocd.Application{}, + }, + want: false, + }, + { + name: "ObjectNew is nil", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{}, + }, + want: false, + }, + { + name: "Health unchanged", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{ + Status: argocd.HealthStatusHealthy, + }, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{ + Status: argocd.HealthStatusHealthy, + }, + }, + }, + }, + want: false, + }, + { + name: "Health changed", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{ + Status: argocd.HealthStatusProgressing, + }, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{ + Status: argocd.HealthStatusHealthy, + }, + }, + }, + }, + want: true, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + p := ArgoCDAppHealthChanged[*argocd.Application]{ + logger: logging.NewDiscardLoggerOrDie(), + } + require.Equal(t, testCase.want, p.Update(testCase.e)) + }) + } +} + +func TestArgoCDAppSyncChanged_Update(t *testing.T) { + testCases := []struct { + name string + e event.TypedUpdateEvent[*argocd.Application] + want bool + }{ + { + name: "ObjectOld is nil", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectNew: &argocd.Application{}, + }, + want: false, + }, + { + name: "ObjectNew is nil", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{}, + }, + want: false, + }, + { + name: "Sync unchanged", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Status: argocd.SyncStatusCodeSynced, + }, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Status: argocd.SyncStatusCodeSynced, + }, + }, + }, + }, + want: false, + }, + { + name: "Sync changed", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Status: argocd.SyncStatusCodeOutOfSync, + }, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Status: argocd.SyncStatusCodeSynced, + }, + }, + }, + }, + want: true, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + p := ArgoCDAppSyncChanged[*argocd.Application]{ + logger: logging.NewDiscardLoggerOrDie(), + } + require.Equal(t, testCase.want, p.Update(testCase.e)) + }) + } +} + +func TestArgoCDAppReconciledAfterOperation_Update(t *testing.T) { + t0 := metav1.Now() + t1 := metav1.NewTime(t0.Add(5 * time.Second)) + t2 := metav1.NewTime(t0.Add(10 * time.Second)) + + testCases := []struct { + name string + e event.TypedUpdateEvent[*argocd.Application] + want bool + }{ + { + name: "ObjectOld is nil", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectNew: &argocd.Application{}, + }, + want: false, + }, + { + name: "ObjectNew is nil", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{}, + }, + want: false, + }, + { + name: "No operation state", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{}, + ObjectNew: &argocd.Application{}, + }, + want: false, + }, + { + name: "Operation state has no finishedAt", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{}, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + OperationState: &argocd.OperationState{ + Phase: argocd.OperationRunning, + }, + }, + }, + }, + want: false, + }, + { + name: "reconciledAt unchanged", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: &t1, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: &t1, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &t2, + }, + }, + }, + }, + want: false, + }, + { + name: "reconciledAt was nil, now advanced past finishedAt", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{}, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: &t2, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &t1, + }, + }, + }, + }, + want: true, + }, + { + name: "reconciledAt advanced from before finishedAt to after", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: &t0, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: &t2, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &t1, + }, + }, + }, + }, + want: true, + }, + { + name: "reconciledAt already past finishedAt (trusted), advances further", + e: event.TypedUpdateEvent[*argocd.Application]{ + ObjectOld: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: &t2, + }, + }, + ObjectNew: &argocd.Application{ + Status: argocd.ApplicationStatus{ + ReconciledAt: func() *metav1.Time { t := metav1.NewTime(t2.Add(time.Second)); return &t }(), + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &t1, + }, + }, + }, + }, + want: false, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + p := ArgoCDAppReconciledAfterOperation[*argocd.Application]{ + logger: logging.NewDiscardLoggerOrDie(), + } + require.Equal(t, testCase.want, p.Update(testCase.e)) + }) + } +} diff --git a/pkg/controller/promotions/promotions.go b/pkg/controller/promotions/promotions.go index 0ed6a119a3..d1f84f6cb1 100644 --- a/pkg/controller/promotions/promotions.go +++ b/pkg/controller/promotions/promotions.go @@ -63,6 +63,7 @@ func ReconcilerConfigFromEnv() ReconcilerConfig { type reconciler struct { kargoClient client.Client promoEngine promotion.Engine + apiReader client.Reader shardPredicate controller.ResponsibleFor[kargoapi.Promotion] cfg ReconcilerConfig @@ -120,6 +121,7 @@ func SetupReconcilerWithManager( reconciler := newReconciler( kargoMgr.GetClient(), + kargoMgr.GetAPIReader(), k8sevent.NewEventSender( libEvent.NewRecorder(ctx, kargoMgr.GetScheme(), kargoMgr.GetClient(), cfg.Name()), ), @@ -180,9 +182,20 @@ func SetupReconcilerWithManager( &UpdatedArgoCDAppHandler[*argocd.Application]{ kargoClient: kargoMgr.GetClient(), }, - ArgoCDAppOperationCompleted[*argocd.Application]{ - logger: logger, - }, + predicate.Or( + ArgoCDAppOperationCompleted[*argocd.Application]{ + logger: logger, + }, + ArgoCDAppHealthChanged[*argocd.Application]{ + logger: logger, + }, + ArgoCDAppSyncChanged[*argocd.Application]{ + logger: logger, + }, + ArgoCDAppReconciledAfterOperation[*argocd.Application]{ + logger: logger, + }, + ), ), ); err != nil { return fmt.Errorf("unable to watch Applications: %w", err) @@ -199,12 +212,14 @@ func SetupReconcilerWithManager( func newReconciler( kargoClient client.Client, + apiReader client.Reader, sender event.Sender, promoEngine promotion.Engine, cfg ReconcilerConfig, ) *reconciler { r := &reconciler{ kargoClient: kargoClient, + apiReader: apiReader, promoEngine: promoEngine, sender: sender, cfg: cfg, @@ -233,22 +248,36 @@ func (r *reconciler) Reconcile( ctx = logging.ContextWithLogger(ctx, logger) logger.Debug("reconciling Promotion") - // Find the Promotion - promo, err := api.GetPromotion(ctx, r.kargoClient, req.NamespacedName) + // Use the cache for cheap early exits — no API server call needed for + // promotions that are already finished or not assigned to this shard. + cachedPromo, err := api.GetPromotion(ctx, r.kargoClient, req.NamespacedName) if err != nil { return ctrl.Result{}, err } - if promo == nil || promo.Status.Phase.IsTerminal() { - // Ignore if not found or already finished. Promo might be nil if the - // Promotion was deleted after the current reconciliation request was issued. + if cachedPromo == nil || cachedPromo.Status.Phase.IsTerminal() { + // Ignore if not found or already finished. cachedPromo might be nil if + // the Promotion was deleted after the reconciliation request was issued. return ctrl.Result{}, nil } - - if !r.shardPredicate.IsResponsible(promo) { + if !r.shardPredicate.IsResponsible(cachedPromo) { logger.Debug("ignoring Promotion because it is not assigned to this shard") return ctrl.Result{}, nil } + // Use a direct API read (bypassing the cache) to ensure we see the latest + // status. This avoids a race condition where the informer cache hasn't yet + // reflected a recently-patched status, which would cause the reconciler to + // re-execute already-completed steps. + promo := &kargoapi.Promotion{} + if err = r.apiReader.Get(ctx, req.NamespacedName, promo); err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + if promo.Status.Phase.IsTerminal() { + // The Promotion reached a terminal state between the cache read above + // and the direct API read. Nothing left to do. + return ctrl.Result{}, nil + } + // Best-effort cleanup if the Promotion is being deleted (e.g. another // controller's finalizer is keeping the object alive). if !promo.DeletionTimestamp.IsZero() { diff --git a/pkg/controller/promotions/promotions_test.go b/pkg/controller/promotions/promotions_test.go index 98baf42e4c..5ddb2714fa 100644 --- a/pkg/controller/promotions/promotions_test.go +++ b/pkg/controller/promotions/promotions_test.go @@ -3,6 +3,7 @@ package promotions import ( "context" "errors" + "fmt" "testing" "time" @@ -31,6 +32,7 @@ var ( func TestNewPromotionReconciler(t *testing.T) { kubeClient := fake.NewClientBuilder().Build() r := newReconciler( + kubeClient, kubeClient, k8sevent.NewEventSender(&fakeevent.EventRecorder{}), &promotion.MockEngine{}, @@ -54,6 +56,7 @@ func newFakeReconciler( kargoClient := fake.NewClientBuilder().WithScheme(scheme). WithObjects(objects...).WithStatusSubresource(objects...).Build() return newReconciler( + kargoClient, kargoClient, k8sevent.NewEventSender(recorder), &promotion.MockEngine{}, @@ -63,8 +66,12 @@ func newFakeReconciler( func TestReconcile(t *testing.T) { testCases := []struct { - name string - promos []client.Object + name string + promos []client.Object + // apiReader, if set, overrides the reconciler's direct API reader. Use + // this to simulate cache/API divergence or to assert the reader is not + // called (e.g. wrap with an interceptor that calls t.Error on Get). + apiReader client.Reader promoteFn func( context.Context, kargoapi.Promotion, @@ -103,6 +110,7 @@ func TestReconcile(t *testing.T) { { name: "promo doesn't exist", promoToReconcile: &types.NamespacedName{Namespace: "fake-namespace", Name: "fake-promo"}, + apiReader: assertNotCalledReader(t), expectPromoteFnCalled: false, }, { @@ -114,6 +122,7 @@ func TestReconcile(t *testing.T) { promos: []client.Object{ newPromo("fake-namespace", "fake-promo", "fake-stage", kargoapi.PromotionPhaseErrored, now), }, + apiReader: assertNotCalledReader(t), }, { name: "Promotion doesn't belong to shard", @@ -134,6 +143,7 @@ func TestReconcile(t *testing.T) { }, }, }, + apiReader: assertNotCalledReader(t), }, { name: "promo already running", @@ -280,6 +290,71 @@ func TestReconcile(t *testing.T) { return nil, nil, errors.New("expected error") }, }, + { + // issue-5282: the cache holds a stale Running promotion with no step + // metadata (as it was just before any steps ran), while the API has + // the authoritative state reflecting steps already completed. The + // reconciler must use the API data so it resumes from the correct + // step rather than re-executing from step 0. + name: "stale cache: cache has no step metadata, API has current state", + expectPromoteFnCalled: true, + expectedPhase: kargoapi.PromotionPhaseSucceeded, + expectedEventRecorded: true, + expectedEventType: kargoapi.EventTypePromotionSucceeded, + promos: []client.Object{ + &kargoapi.Stage{ + ObjectMeta: metav1.ObjectMeta{ + Name: "fake-stage", + Namespace: "fake-namespace", + }, + Status: kargoapi.StageStatus{ + CurrentPromotion: &kargoapi.PromotionReference{ + Name: "fake-promo", + }, + }, + }, + // Stale cached copy: Running but no step metadata. + newPromo("fake-namespace", "fake-promo", "fake-stage", kargoapi.PromotionPhaseRunning, now), + }, + apiReader: fakeReaderWithObjects(t, func() *kargoapi.Promotion { + // Fresh API copy: Running with step metadata showing progress. + p := newPromo("fake-namespace", "fake-promo", "fake-stage", kargoapi.PromotionPhaseRunning, now) + p.Status.CurrentStep = 1 + p.Status.StepExecutionMetadata = kargoapi.StepExecutionMetadataList{{ + Alias: "step-0", + Status: kargoapi.PromotionStepStatusSucceeded, + }} + return p + }()), + promoToReconcile: &types.NamespacedName{Namespace: "fake-namespace", Name: "fake-promo"}, + promoteFn: func( + _ context.Context, + p kargoapi.Promotion, + _ *kargoapi.Freight, + ) (*kargoapi.PromotionStatus, *time.Duration, error) { + // Assert the reconciler is using the API's authoritative state, + // not the stale cached copy. + if len(p.Status.StepExecutionMetadata) == 0 { + return nil, nil, fmt.Errorf( + "expected step execution metadata from API reader, got none (stale cache used)", + ) + } + return &kargoapi.PromotionStatus{Phase: kargoapi.PromotionPhaseSucceeded}, nil, nil + }, + }, + { + // The cache shows the Promotion as active, but the direct API read + // (apiReader) returns a terminal state — the Promotion completed + // between the two reads. The reconciler must not proceed. + name: "promo terminal in API but active in cache", + expectPromoteFnCalled: false, + promos: []client.Object{ + newPromo("fake-namespace", "fake-promo", "fake-stage", kargoapi.PromotionPhaseRunning, now), + }, + apiReader: fakeReaderWithObjects(t, + newPromo("fake-namespace", "fake-promo", "fake-stage", kargoapi.PromotionPhaseSucceeded, now), + ), + }, { name: "terminates promotion on request", promos: []client.Object{ @@ -303,9 +378,12 @@ func TestReconcile(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - ctx := context.TODO() + ctx := t.Context() recorder := fakeevent.NewEventRecorder(1) r := newFakeReconciler(t, recorder, tc.promos...) + if tc.apiReader != nil { + r.apiReader = tc.apiReader + } promoteWasCalled := false r.promoteFn = func( @@ -530,7 +608,7 @@ func Test_reconciler_terminatePromotion(t *testing.T) { } req := tt.req - err := r.terminatePromotion(context.Background(), &req, tt.promo, tt.freight) + err := r.terminatePromotion(t.Context(), &req, tt.promo, tt.freight) tt.assertions(t, recorder, tt.promo, err) }) } @@ -626,7 +704,7 @@ func Test_reconciler_handleDeletion(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() recorder := fakeevent.NewEventRecorder(1) r := newFakeReconciler(t, recorder, tc.objects...) @@ -664,13 +742,13 @@ func Test_reconciler_terminatePromotion_cleansUpWorkDir(t *testing.T) { } req := kargoapi.AbortPromotionRequest{Action: kargoapi.AbortActionTerminate} - err := r.terminatePromotion(context.Background(), &req, promo, nil) + err := r.terminatePromotion(t.Context(), &req, promo, nil) require.NoError(t, err) require.True(t, cleanupCalled) var updated kargoapi.Promotion - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "fake-ns", Name: "fake-promo", }, &updated)) @@ -1110,3 +1188,36 @@ func Test_buildTargetFreightCollection(t *testing.T) { }) } } + +// assertNotCalledReader returns a client.Reader that fails the test if Get is +// called. Use it to verify that a code path exits before reaching the direct +// API read. +func assertNotCalledReader(t *testing.T) client.Reader { + t.Helper() + return interceptor.NewClient( + fake.NewClientBuilder().Build(), + interceptor.Funcs{ + Get: func( + _ context.Context, + _ client.WithWatch, + _ client.ObjectKey, + _ client.Object, + _ ...client.GetOption, + ) error { + t.Error("apiReader.Get was called but should not have been") + return nil + }, + }, + ) +} + +// fakeReaderWithObjects returns a client.Reader backed by a fake client +// pre-populated with the given objects. Use it to simulate a direct API read +// returning data that differs from the informer cache. +func fakeReaderWithObjects(t *testing.T, objs ...client.Object) client.Reader { + t.Helper() + scheme := k8sruntime.NewScheme() + require.NoError(t, kargoapi.SchemeBuilder.AddToScheme(scheme)) + return fake.NewClientBuilder().WithScheme(scheme). + WithObjects(objs...).WithStatusSubresource(objs...).Build() +} diff --git a/pkg/controller/promotions/watches_test.go b/pkg/controller/promotions/watches_test.go index 1e806893fe..69dc418507 100644 --- a/pkg/controller/promotions/watches_test.go +++ b/pkg/controller/promotions/watches_test.go @@ -238,7 +238,7 @@ func TestUpdatedArgoCDAppHandler_Update(t *testing.T) { } wq := workqueue.NewTypedRateLimitingQueue(workqueue.DefaultTypedControllerRateLimiter[reconcile.Request]()) - u.Update(context.TODO(), tt.e, wq) + u.Update(t.Context(), tt.e, wq) tt.assertions(t, wq) }) @@ -376,7 +376,7 @@ func TestPromotionAcknowledgedByStageHandler_Update(t *testing.T) { wq := workqueue.NewTypedRateLimitingQueue( workqueue.DefaultTypedControllerRateLimiter[reconcile.Request](), ) - p.Update(context.Background(), testCase.e, wq) + p.Update(t.Context(), testCase.e, wq) testCase.assertions(t, wq) }) diff --git a/pkg/controller/stages/control_flow_stages_test.go b/pkg/controller/stages/control_flow_stages_test.go index 3604b247b3..2cd010ea0c 100644 --- a/pkg/controller/stages/control_flow_stages_test.go +++ b/pkg/controller/stages/control_flow_stages_test.go @@ -173,7 +173,7 @@ func TestControlFlowStageReconciler_Reconcile(t *testing.T) { // Verify finalizer was added stage := &kargoapi.Stage{} - err = c.Get(context.Background(), testStage, stage) + err = c.Get(t.Context(), testStage, stage) require.NoError(t, err) assert.Contains(t, stage.Finalizers, kargoapi.FinalizerName) }, @@ -200,7 +200,7 @@ func TestControlFlowStageReconciler_Reconcile(t *testing.T) { // Verify annotation was removed stage := &kargoapi.Stage{} - err = c.Get(context.Background(), testStage, stage) + err = c.Get(t.Context(), testStage, stage) require.NoError(t, err) assert.NotContains(t, stage.Annotations, kargoapi.AnnotationKeyArgoCDContext) }, @@ -230,7 +230,7 @@ func TestControlFlowStageReconciler_Reconcile(t *testing.T) { // Verify error is recorded in status stage := &kargoapi.Stage{} - err = c.Get(context.Background(), testStage, stage) + err = c.Get(t.Context(), testStage, stage) require.NoError(t, err) }, }, @@ -302,7 +302,7 @@ func TestControlFlowStageReconciler_Reconcile(t *testing.T) { // Verify status was updated stage := &kargoapi.Stage{} - err = c.Get(context.Background(), testStage, stage) + err = c.Get(t.Context(), testStage, stage) require.NoError(t, err) }, }, @@ -349,7 +349,7 @@ func TestControlFlowStageReconciler_Reconcile(t *testing.T) { }, } - result, err := r.Reconcile(context.Background(), tt.req) + result, err := r.Reconcile(t.Context(), tt.req) tt.assertions(t, c, result, err) }) } @@ -430,7 +430,7 @@ func TestControlFlowStageReconciler_reconcile(t *testing.T) { require.NoError(t, err) updatedFreight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{ Namespace: testProject, Name: "fake-freight", @@ -675,7 +675,7 @@ func TestControlFlowStageReconciler_reconcile(t *testing.T) { }, } - status, err := r.reconcile(context.Background(), tt.stage, time.Now()) + status, err := r.reconcile(t.Context(), tt.stage, time.Now()) tt.assertions(t, status, c, err) }) } @@ -861,7 +861,7 @@ func TestControlFlowStageReconciler_markFreightVerifiedForStage(t *testing.T) { assert.Len(t, recorder.Events, 2) freight1 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-1", }, freight1)) @@ -873,7 +873,7 @@ func TestControlFlowStageReconciler_markFreightVerifiedForStage(t *testing.T) { ) freight2 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-2", }, freight2)) @@ -990,28 +990,28 @@ func TestControlFlowStageReconciler_markFreightVerifiedForStage(t *testing.T) { assert.Len(t, recorder.Events, 2) freight1 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-1", }, freight1)) assert.Contains(t, freight1.Status.VerifiedIn, "test-stage") freight2 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-2", }, freight2)) assert.NotContains(t, freight2.Status.VerifiedIn, "test-stage") freight3 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-3", }, freight3)) assert.Contains(t, freight3.Status.VerifiedIn, "test-stage") freight4 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-4", }, freight4)) @@ -1035,7 +1035,7 @@ func TestControlFlowStageReconciler_markFreightVerifiedForStage(t *testing.T) { eventSender: k8sevent.NewEventSender(recorder), } - _, err := r.markFreightVerifiedForStage(context.Background(), tt.stage, tt.freight, tt.startTime, tt.finishTime) + _, err := r.markFreightVerifiedForStage(t.Context(), tt.stage, tt.freight, tt.startTime, tt.finishTime) tt.assertions(t, c, recorder, err) }) } @@ -1164,7 +1164,7 @@ func TestControlFlowStageReconciler_handleDelete(t *testing.T) { client: c, } - err := r.handleDelete(context.Background(), tt.stage) + err := r.handleDelete(t.Context(), tt.stage) tt.assertions(t, tt.stage, err) }) } @@ -1230,7 +1230,7 @@ func TestControlFlowStageReconciler_clearVerifications(t *testing.T) { require.NoError(t, err) freight1 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-1", }, freight1)) @@ -1238,7 +1238,7 @@ func TestControlFlowStageReconciler_clearVerifications(t *testing.T) { assert.Contains(t, freight1.Status.VerifiedIn, "another-stage") freight2 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-2", }, freight2)) @@ -1359,7 +1359,7 @@ func TestControlFlowStageReconciler_clearVerifications(t *testing.T) { client: c, } - tt.assertions(t, c, r.clearVerifications(context.Background(), tt.stage)) + tt.assertions(t, c, r.clearVerifications(t.Context(), tt.stage)) }) } } @@ -1424,7 +1424,7 @@ func TestControlFlowStageReconciler_clearApprovals(t *testing.T) { require.NoError(t, err) freight1 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-1", }, freight1)) @@ -1432,7 +1432,7 @@ func TestControlFlowStageReconciler_clearApprovals(t *testing.T) { assert.Contains(t, freight1.Status.ApprovedFor, "another-stage") freight2 := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "freight-2", }, freight2)) @@ -1553,7 +1553,7 @@ func TestControlFlowStageReconciler_clearApprovals(t *testing.T) { client: c, } - tt.assertions(t, c, r.clearApprovals(context.Background(), tt.stage)) + tt.assertions(t, c, r.clearApprovals(t.Context(), tt.stage)) }) } } @@ -1631,7 +1631,7 @@ func TestControlFlowStageReconciler_clearAnalysisRuns(t *testing.T) { // Verify analysis runs for test-stage are deleted var runs rollouts.AnalysisRunList - err = c.List(context.Background(), &runs, + err = c.List(t.Context(), &runs, client.InNamespace("default"), client.MatchingLabels{kargoapi.LabelKeyStage: "test-stage"}, ) @@ -1639,7 +1639,7 @@ func TestControlFlowStageReconciler_clearAnalysisRuns(t *testing.T) { assert.Empty(t, runs.Items) // Verify other analysis runs still exist - err = c.List(context.Background(), &runs, + err = c.List(t.Context(), &runs, client.InNamespace("default"), client.MatchingLabels{kargoapi.LabelKeyStage: "other-stage"}, ) @@ -1694,7 +1694,7 @@ func TestControlFlowStageReconciler_clearAnalysisRuns(t *testing.T) { require.NoError(t, err) var runs rollouts.AnalysisRunList - err = c.List(context.Background(), &runs, client.InNamespace("default")) + err = c.List(t.Context(), &runs, client.InNamespace("default")) require.NoError(t, err) assert.Empty(t, runs.Items) }, @@ -1714,7 +1714,7 @@ func TestControlFlowStageReconciler_clearAnalysisRuns(t *testing.T) { cfg: tt.cfg, } - tt.assertions(t, c, r.clearAnalysisRuns(context.Background(), tt.stage)) + tt.assertions(t, c, r.clearAnalysisRuns(t.Context(), tt.stage)) }) } } diff --git a/pkg/controller/stages/event_handlers.go b/pkg/controller/stages/event_handlers.go index 169ba17615..b7cb9d68ee 100644 --- a/pkg/controller/stages/event_handlers.go +++ b/pkg/controller/stages/event_handlers.go @@ -460,16 +460,103 @@ func appHealthOrSyncStatusChanged[T any](ctx context.Context, e event.TypedUpdat "app", oldApp, ) } - oldHealth, _, _ := unstructured.NestedString(oldUn, "status", "health", "status") - newHealth, _, _ := unstructured.NestedString(newUn, "status", "health", "status") - // TODO: switch from checking sync status to whether or not operation is complete - oldSync, _, _ := unstructured.NestedString(oldUn, "status", "sync", "status") - newSync, _, _ := unstructured.NestedString(newUn, "status", "sync", "status") - //_, oldOp := oldUn["operation"] - //_, newOp := newUn["operation"] - oldRev, _, _ := unstructured.NestedString(oldUn, "status", "sync", "revision") - newRev, _, _ := unstructured.NestedString(newUn, "status", "sync", "revision") - return newHealth != oldHealth || oldSync != newSync || oldRev != newRev + // The Kargo health checker for Argo CD Applications evaluates several + // fields from the Application status. We watch for changes to each of + // these so that Stages are re-enqueued promptly when the health + // checker's output might change. + + // 1. Health status: The health checker maps this directly to Stage + // health (Progressing, Healthy, Degraded, etc.). A change here + // almost always means the health checker will produce a different + // result. + oldHealth, _, _ := unstructured.NestedString( + oldUn, "status", "health", "status", + ) + newHealth, _, _ := unstructured.NestedString( + newUn, "status", "health", "status", + ) + if newHealth != oldHealth { + return true + } + + // 2. Operation phase: The health checker returns Unknown whenever the + // last operation has not succeeded (e.g. it is still Running or has + // Failed). Watching for phase changes lets us detect both operation + // start (health becomes Unknown) and completion (health can be + // reassessed). + oldPhase, _, _ := unstructured.NestedString( + oldUn, "status", "operationState", "phase", + ) + newPhase, _, _ := unstructured.NestedString( + newUn, "status", "operationState", "phase", + ) + if oldPhase != newPhase { + return true + } + + // 3. Sync revision(s): The health checker compares observed revisions + // against the desired revisions from the last Promotion. If the + // Application syncs to a new revision, the comparison result may + // change. We check both the single-source revision field and the + // multi-source revisions array. + oldRev, _, _ := unstructured.NestedString( + oldUn, "status", "sync", "revision", + ) + newRev, _, _ := unstructured.NestedString( + newUn, "status", "sync", "revision", + ) + if oldRev != newRev { + return true + } + oldRevs, _, _ := unstructured.NestedSlice( + oldUn, "status", "sync", "revisions", + ) + newRevs, _, _ := unstructured.NestedSlice( + newUn, "status", "sync", "revisions", + ) + if fmt.Sprint(oldRevs) != fmt.Sprint(newRevs) { + return true + } + + // 4. reconciledAt vs finishedAt: Argo CD uses separate reconciliation + // loops for syncing (operations) and assessing health. After an + // operation completes, the health status may be stale -- still + // reflecting pre-operation state. The health checker handles this + // by not trusting health until reconciledAt (set by Argo CD's + // health/status loop) is after finishedAt (set when the operation + // completed). + // + // The checks above (health, revision) catch cases where the fresh + // post-operation values differ from the stale ones. But when the + // fresh values are the SAME as the stale values (e.g. the app was + // Healthy before the sync and is still Healthy after), those checks + // see no diff and don't fire. Yet the health checker's output DOES + // change: from Unknown (untrusted) to the now-trusted value. + // + // To handle this, we check whether reconciledAt just crossed the + // finishedAt threshold. We only trigger when the OLD reconciledAt + // was stale (absent or before finishedAt) and has now advanced. Once + // reconciledAt is at or past finishedAt, subsequent advances are + // routine Argo CD refreshes and do not need to trigger + // re-reconciliation. + oldReconciledAt, _, _ := unstructured.NestedString( + oldUn, "status", "reconciledAt", + ) + newReconciledAt, _, _ := unstructured.NestedString( + newUn, "status", "reconciledAt", + ) + if oldReconciledAt == newReconciledAt { + return false + } + finishedAt, _, _ := unstructured.NestedString( + newUn, "status", "operationState", "finishedAt", + ) + if finishedAt == "" { + return false + } + // RFC3339 timestamps are lexicographically orderable, so string + // comparison preserves chronological order. + return oldReconciledAt == "" || oldReconciledAt < finishedAt } // stageEnqueuerForAnalysisRuns triggers reconciliation of Stages when their diff --git a/pkg/controller/stages/event_handlers_test.go b/pkg/controller/stages/event_handlers_test.go index 9879cef843..5345339cd6 100644 --- a/pkg/controller/stages/event_handlers_test.go +++ b/pkg/controller/stages/event_handlers_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -306,7 +307,7 @@ func Test_downstreamStageEnqueuer_Update(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Update( - context.Background(), + t.Context(), event.TypedUpdateEvent[*kargoapi.Freight]{ ObjectOld: tt.oldFreight, ObjectNew: tt.newFreight, @@ -412,7 +413,7 @@ func Test_stageEnqueuerForApprovedFreight_Update(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Update( - context.Background(), + t.Context(), event.TypedUpdateEvent[*kargoapi.Freight]{ ObjectOld: tt.oldFreight, ObjectNew: tt.newFreight, @@ -678,7 +679,7 @@ func Test_warehouseStageEnqueuer_Create(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Create( - context.Background(), + t.Context(), event.TypedCreateEvent[*kargoapi.Freight]{ Object: tt.freight, }, @@ -799,7 +800,7 @@ func Test_stageEnqueuerForArgoCDChanges_Update(t *testing.T) { }, }, { - name: "sync status changed", + name: "operation phase changed", oldApp: &argocd.Application{ ObjectMeta: metav1.ObjectMeta{ Name: "test-app", @@ -808,8 +809,8 @@ func Test_stageEnqueuerForArgoCDChanges_Update(t *testing.T) { }, }, Status: argocd.ApplicationStatus{ - Sync: argocd.SyncStatus{ - Status: "OutOfSync", + OperationState: &argocd.OperationState{ + Phase: "Running", }, }, }, @@ -821,8 +822,8 @@ func Test_stageEnqueuerForArgoCDChanges_Update(t *testing.T) { }, }, Status: argocd.ApplicationStatus{ - Sync: argocd.SyncStatus{ - Status: "Synced", + OperationState: &argocd.OperationState{ + Phase: "Succeeded", }, }, }, @@ -1053,7 +1054,7 @@ func Test_stageEnqueuerForArgoCDChanges_Update(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Update( - context.Background(), + t.Context(), event.TypedUpdateEvent[*argocd.Application]{ ObjectOld: tt.oldApp, ObjectNew: tt.newApp, @@ -1350,7 +1351,7 @@ func Test_stageEnqueuerForAnalysisRuns_Update(t *testing.T) { queue := &controllertest.Queue{TypedInterface: workqueue.NewTyped[reconcile.Request]()} enqueuer.Update( - context.Background(), + t.Context(), event.TypedUpdateEvent[*rollouts.AnalysisRun]{ ObjectOld: tt.oldAnalysisRun, ObjectNew: tt.newAnalysisRun, @@ -1414,36 +1415,36 @@ func Test_appHealthOrSyncStatusChanged(t *testing.T) { updated: false, }, { - name: "sync status changed", + name: "operation phase changed", old: &argocd.Application{ Status: argocd.ApplicationStatus{ - Sync: argocd.SyncStatus{ - Status: "", + OperationState: &argocd.OperationState{ + Phase: "Running", }, }, }, new: &argocd.Application{ Status: argocd.ApplicationStatus{ - Sync: argocd.SyncStatus{ - Status: "Synced", + OperationState: &argocd.OperationState{ + Phase: "Succeeded", }, }, }, updated: true, }, { - name: "sync status did not change", + name: "operation phase did not change", old: &argocd.Application{ Status: argocd.ApplicationStatus{ - Sync: argocd.SyncStatus{ - Status: "Synced", + OperationState: &argocd.OperationState{ + Phase: "Succeeded", }, }, }, new: &argocd.Application{ Status: argocd.ApplicationStatus{ - Sync: argocd.SyncStatus{ - Status: "Synced", + OperationState: &argocd.OperationState{ + Phase: "Succeeded", }, }, }, @@ -1485,6 +1486,176 @@ func Test_appHealthOrSyncStatusChanged(t *testing.T) { }, updated: false, }, + { + name: "multi-source revisions changed", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Revisions: []string{"rev-a", "rev-b"}, + }, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Revisions: []string{"rev-a", "rev-c"}, + }, + }, + }, + updated: true, + }, + { + name: "multi-source revisions did not change", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Revisions: []string{"rev-a", "rev-b"}, + }, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Sync: argocd.SyncStatus{ + Revisions: []string{"rev-a", "rev-b"}, + }, + }, + }, + updated: false, + }, + { + name: "reconciledAt transitioned from stale to fresh", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 11, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + updated: true, + }, + { + name: "reconciledAt equal to finishedAt is already fresh", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 11, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + updated: false, + }, + { + name: "reconciledAt changed but was already fresh", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 11, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 12, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + updated: false, + }, + { + name: "reconciledAt changed but no finishedAt", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 11, 0, time.UTC), + }, + }, + }, + updated: false, + }, + { + name: "reconciledAt did not change", + old: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 5, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + new: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: "Healthy"}, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 5, 0, time.UTC), + }, + OperationState: &argocd.OperationState{ + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + }, + }, + updated: false, + }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { @@ -1495,7 +1666,7 @@ func Test_appHealthOrSyncStatusChanged(t *testing.T) { require.Equal( t, testCase.updated, - appHealthOrSyncStatusChanged(context.Background(), e), + appHealthOrSyncStatusChanged(t.Context(), e), ) }) } @@ -1546,7 +1717,7 @@ func Test_analysisRunPhaseChanged(t *testing.T) { require.Equal( t, testCase.updated, - analysisRunPhaseChanged(context.Background(), e), + analysisRunPhaseChanged(t.Context(), e), ) }) } diff --git a/pkg/controller/stages/regular_stages.go b/pkg/controller/stages/regular_stages.go index a84731cec6..2ab8db2e24 100644 --- a/pkg/controller/stages/regular_stages.go +++ b/pkg/controller/stages/regular_stages.go @@ -2,7 +2,6 @@ package stages import ( "context" - "errors" "fmt" "slices" "strings" @@ -448,39 +447,11 @@ func (r *RegularStageReconciler) reconcile( name: "assessing health", reconcile: func() (kargoapi.StageStatus, error) { status := r.assessHealth(ctx, stage) - if status.Health != nil && status.Health.Status == kargoapi.HealthStateUnknown { - // If Stage health has evaluated to Unknown, there are two specific - // scenarios between which we must distinguish and handle differently - // from one another: - // - // 1. If Stage health is unknown specifically because the last - // Promotion did not succeed, we know we cannot obtain a more - // definitive assessment of Stage health until a new Promotion has - // restored the Stage to a consistent state by executing to - // completion. In such a case, we're DONE reconciling the Stage, - // for now. We would like the Stage's conditions to reflect that - // and for the next reconciliation attempt to occur after the - // usual interval. This can be accomplished by returning a nil - // error. - // - // 2. If Stage health is unknown for any other reason, we MAY - // possibly obtain a more definitive assessment simply by - // re-attempting reconciliation. In such a case, we would like - // the Stage's conditions to reflect that we're still trying to - // reconcile, with subsequent attempts observing a progressive - // backoff. This can be accomplished by returning an error. - if lastPromo := status.LastPromotion; lastPromo == nil || - lastPromo.Status == nil || - !lastPromo.Status.Phase.IsTerminal() || - lastPromo.Status.Phase == kargoapi.PromotionPhaseSucceeded { - // Scenario 2: There was no last Promotion or there was and it was - // successful. Whatever the reason the Stage health evaluated to - // Unknown, an unsuccessful Promotion wasn't it. - return status, errors.New("Stage health evaluated to Unknown") // nolint: staticcheck - } - } - // Health assessment was definitive OR scenario 1: Stage health is - // unknown specifically because the last Promotion did not succeed. + // Unknown health is a normal, expected transient state (e.g. waiting + // for Argo CD to reconcile after an operation). The Application watcher + // will re-enqueue the Stage when the relevant condition changes, so + // there is no longer a need to return an error here just for the sake + // of triggering progressive backoff, as we did once upon a time. return status, nil }, }, diff --git a/pkg/controller/stages/regular_stages_test.go b/pkg/controller/stages/regular_stages_test.go index b1a91f756e..28c5b3a2f0 100644 --- a/pkg/controller/stages/regular_stages_test.go +++ b/pkg/controller/stages/regular_stages_test.go @@ -195,7 +195,7 @@ func TestRegularStageReconciler_Reconcile(t *testing.T) { // Verify finalizer was added stage := &kargoapi.Stage{} - err = c.Get(context.Background(), types.NamespacedName{ + err = c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "test-stage", }, stage) @@ -238,7 +238,7 @@ func TestRegularStageReconciler_Reconcile(t *testing.T) { // Verify error is recorded in status stage := &kargoapi.Stage{} - err = c.Get(context.Background(), types.NamespacedName{ + err = c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "test-stage", }, stage) @@ -361,7 +361,7 @@ func TestRegularStageReconciler_Reconcile(t *testing.T) { // Verify status was updated stage := &kargoapi.Stage{} - err = c.Get(context.Background(), types.NamespacedName{ + err = c.Get(t.Context(), types.NamespacedName{ Namespace: "default", Name: "test-stage", }, stage) @@ -423,7 +423,7 @@ func TestRegularStageReconciler_Reconcile(t *testing.T) { eventSender: k8sevent.NewEventSender(fakeevent.NewEventRecorder(10)), } - result, err := r.Reconcile(context.Background(), tt.req) + result, err := r.Reconcile(t.Context(), tt.req) tt.assertions(t, c, result, err) }) } @@ -563,7 +563,7 @@ func TestRegularStagesReconciler_reconcile(t *testing.T) { healthChecker: &health.MockAggregatingChecker{}, } - status, requeue, err := r.reconcile(context.Background(), tt.stage, now) + status, requeue, err := r.reconcile(t.Context(), tt.stage, now) tt.assertions(t, status, requeue, err) }) } @@ -1325,7 +1325,7 @@ func TestRegularStageReconciler_syncPromotions(t *testing.T) { client: c, } - status, requeue, err := r.syncPromotions(context.Background(), tt.stage) + status, requeue, err := r.syncPromotions(t.Context(), tt.stage) tt.assertions(t, status, requeue, err) }) } @@ -1419,28 +1419,28 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { require.NoError(t, err) freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-1"}, freight, ) require.NoError(t, err) require.Contains(t, freight.Status.CurrentlyIn, testStage.Name) err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-2"}, freight, ) require.NoError(t, err) require.Contains(t, freight.Status.CurrentlyIn, testStage.Name) err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-3"}, freight, ) require.NoError(t, err) require.NotContains(t, freight.Status.CurrentlyIn, testStage.Name) err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-4"}, freight, ) @@ -1494,7 +1494,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Check that expected freight remain in CurrentlyIn (they're in the stage's FreightHistory) freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-1"}, freight, ) @@ -1502,7 +1502,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { require.Contains(t, freight.Status.CurrentlyIn, testStage.Name) err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-2"}, freight, ) @@ -1511,7 +1511,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Check verified freight - should be removed from CurrentlyIn and soak time updated err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "verified-freight"}, freight, ) @@ -1564,7 +1564,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Check unverified freight - should just be removed from CurrentlyIn freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "unverified-freight"}, freight, ) @@ -1619,7 +1619,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Check longer soak freight - should be removed but soak time should not be updated freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "longer-soak-freight"}, freight, ) @@ -1684,7 +1684,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Check that expected freight remains in CurrentlyIn (they're in the stage's FreightHistory) freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-1"}, freight, ) @@ -1692,7 +1692,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { require.Contains(t, freight.Status.CurrentlyIn, testStage.Name) err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-2"}, freight, ) @@ -1701,7 +1701,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Should handle nil Since field gracefully without panic err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "nil-since-freight"}, freight, ) @@ -1766,7 +1766,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Check that expected freight remains in CurrentlyIn (they're in the stage's FreightHistory) freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-1"}, freight, ) @@ -1774,7 +1774,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { require.Contains(t, freight.Status.CurrentlyIn, testStage.Name) err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "fake-freight-2"}, freight, ) @@ -1783,7 +1783,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { // Should handle nil LongestCompletedSoak gracefully err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{Namespace: testProject, Name: "nil-soak-freight"}, freight, ) @@ -1816,7 +1816,7 @@ func TestRegularStageReconciler_syncFreight(t *testing.T) { r := &RegularStageReconciler{client: c} - err := r.syncFreight(context.Background(), testStage) + err := r.syncFreight(t.Context(), testStage) testCase.assertions(t, c, err) }) } @@ -2062,7 +2062,7 @@ func TestRegularStageReconciler_assessHealth(t *testing.T) { }, } - status := r.assessHealth(context.Background(), tt.stage) + status := r.assessHealth(t.Context(), tt.stage) tt.assertions(t, status) }) } @@ -2428,7 +2428,7 @@ func TestRegularStageReconciler_verifyStageFreight(t *testing.T) { // Verify AnalysisRun was patched to terminate ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Name: "test-analysis-run", Namespace: "fake-project", }, ar)) @@ -2508,7 +2508,7 @@ func TestRegularStageReconciler_verifyStageFreight(t *testing.T) { // Verify new AnalysisRun was created ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Name: lastVerification.AnalysisRun.Name, Namespace: lastVerification.AnalysisRun.Namespace, }, ar)) @@ -2914,7 +2914,7 @@ func TestRegularStageReconciler_verifyStageFreight(t *testing.T) { }, } - status, err := r.verifyStageFreight(context.Background(), tt.stage, startTime, fixedEndTime) + status, err := r.verifyStageFreight(t.Context(), tt.stage, startTime, fixedEndTime) tt.assertions(t, c, recorder, status, err) }) } @@ -3111,7 +3111,7 @@ func TestRegularStageReconciler_markFreightVerifiedForStage(t *testing.T) { // Check if freight was properly marked as verified freight := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), client.ObjectKey{ + require.NoError(t, c.Get(t.Context(), client.ObjectKey{ Namespace: "fake-project", Name: "test-freight", }, freight)) @@ -3165,7 +3165,7 @@ func TestRegularStageReconciler_markFreightVerifiedForStage(t *testing.T) { // Verify no changes were made to the freight freight := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), client.ObjectKey{ + require.NoError(t, c.Get(t.Context(), client.ObjectKey{ Namespace: "fake-project", Name: "test-freight", }, freight)) @@ -3222,7 +3222,7 @@ func TestRegularStageReconciler_markFreightVerifiedForStage(t *testing.T) { // Check both freight objects were marked as verified for _, name := range []string{"freight-1", "freight-2"} { freight := &kargoapi.Freight{} - require.NoError(t, c.Get(context.Background(), client.ObjectKey{ + require.NoError(t, c.Get(t.Context(), client.ObjectKey{ Namespace: "fake-project", Name: name, }, freight)) @@ -3342,7 +3342,7 @@ func TestRegularStageReconciler_markFreightVerifiedForStage(t *testing.T) { healthChecker: &health.MockAggregatingChecker{}, } - status, err := r.markFreightVerifiedForStage(context.Background(), tt.stage) + status, err := r.markFreightVerifiedForStage(t.Context(), tt.stage) tt.assertions(t, c, status, err) }) } @@ -3774,7 +3774,7 @@ func TestRegularStageReconciler_startVerification(t *testing.T) { // Verify analysis run was created ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: vi.AnalysisRun.Namespace, Name: vi.AnalysisRun.Name, }, ar)) @@ -3822,7 +3822,7 @@ func TestRegularStageReconciler_startVerification(t *testing.T) { // Verify analysis run was created ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: vi.AnalysisRun.Namespace, Name: vi.AnalysisRun.Name, }, ar)) @@ -3893,7 +3893,7 @@ func TestRegularStageReconciler_startVerification(t *testing.T) { // Verify promotion annotation was added ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: vi.AnalysisRun.Namespace, Name: vi.AnalysisRun.Name, }, ar)) @@ -3953,7 +3953,7 @@ func TestRegularStageReconciler_startVerification(t *testing.T) { // Verify analysis run was created ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: vi.AnalysisRun.Namespace, Name: vi.AnalysisRun.Name, }, ar)) @@ -4021,7 +4021,7 @@ func TestRegularStageReconciler_startVerification(t *testing.T) { }, } - vi, err := r.startVerification(context.Background(), tt.stage, tt.freightCol, tt.req, now) + vi, err := r.startVerification(t.Context(), tt.stage, tt.freightCol, tt.req, now) tt.assertions(t, c, vi, err) }) } @@ -4352,7 +4352,7 @@ func TestRegularStageReconciler_getVerificationResult(t *testing.T) { }, } - vi, err := r.getVerificationResult(context.Background(), tt.freight) + vi, err := r.getVerificationResult(t.Context(), tt.freight) tt.assertions(t, vi, err) }) } @@ -4552,7 +4552,7 @@ func TestRegularStageReconciler_abortVerification(t *testing.T) { // Verify analysis run was patched with terminate = true ar := &rolloutsapi.AnalysisRun{} - require.NoError(t, c.Get(context.Background(), types.NamespacedName{ + require.NoError(t, c.Get(t.Context(), types.NamespacedName{ Namespace: "fake-project", Name: "test-analysis", }, ar)) @@ -4696,7 +4696,7 @@ func TestRegularStageReconciler_abortVerification(t *testing.T) { }, } - vi, err := r.abortVerification(context.Background(), tt.freightCol, tt.req) + vi, err := r.abortVerification(t.Context(), tt.freightCol, tt.req) tt.assertions(t, c, vi, err) }) } @@ -4958,7 +4958,7 @@ func TestRegularStageReconciler_findExistingAnalysisRun(t *testing.T) { client: c, } - ar, err := r.findExistingAnalysisRun(context.Background(), tt.stage, tt.freightColID) + ar, err := r.findExistingAnalysisRun(t.Context(), tt.stage, tt.freightColID) tt.assertions(t, ar, err) }) } @@ -5000,7 +5000,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify no promotions were created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Empty(t, promoList.Items) }, }, @@ -5051,7 +5051,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify no promotions were created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Empty(t, promoList.Items) }, }, @@ -5086,7 +5086,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify no promotions were created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Empty(t, promoList.Items) }, }, @@ -5177,7 +5177,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify promotion was created for newest freight promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) require.Len(t, promoList.Items, 1) assert.Equal(t, "test-freight-1", promoList.Items[0].Spec.Freight) }, @@ -5258,7 +5258,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify no promotions were created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Empty(t, promoList.Items) }, }, @@ -5342,7 +5342,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify no new promotions were created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Len(t, promoList.Items, 1) assert.Equal(t, "existing-promotion", promoList.Items[0].Name) }, @@ -5430,7 +5430,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify no new promotions were created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Len(t, promoList.Items, 1) assert.Equal(t, "existing-promotion", promoList.Items[0].Name) }, @@ -5516,7 +5516,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify promotion was created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) require.Len(t, promoList.Items, 1) assert.Equal(t, "test-freight-1", promoList.Items[0].Spec.Freight) }, @@ -5636,7 +5636,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify promotion was created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) require.Len(t, promoList.Items, 1) assert.Equal(t, "test-freight-2", promoList.Items[0].Spec.Freight) }, @@ -5717,7 +5717,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify promotion was created promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) require.Len(t, promoList.Items, 1) assert.Equal(t, "test-freight-1", promoList.Items[0].Spec.Freight) }, @@ -5824,7 +5824,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify promotions were created for both freight items promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) require.Len(t, promoList.Items, 2) // Verify they're for different freight @@ -6000,7 +6000,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { // Verify only one promotion was created despite multiple sources promoList := &kargoapi.PromotionList{} - require.NoError(t, c.List(context.Background(), promoList, client.InNamespace("fake-project"))) + require.NoError(t, c.List(t.Context(), promoList, client.InNamespace("fake-project"))) assert.Len(t, promoList.Items, 1) }, }, @@ -6193,7 +6193,7 @@ func TestRegularStageReconciler_autoPromoteFreight(t *testing.T) { eventSender: k8sevent.NewEventSender(recorder), } - status, err := r.autoPromoteFreight(context.Background(), tt.stage) + status, err := r.autoPromoteFreight(t.Context(), tt.stage) tt.assertions(t, recorder, c, status, err) }) } @@ -6474,7 +6474,7 @@ func TestRegularStageReconciler_autoPromotionAllowed(t *testing.T) { client: c, } - allowed, err := r.autoPromotionAllowed(context.Background(), tt.stage) + allowed, err := r.autoPromotionAllowed(t.Context(), tt.stage) tt.assertions(t, allowed, err) }) } diff --git a/pkg/controller/warehouses/warehouses_test.go b/pkg/controller/warehouses/warehouses_test.go index b98a53e907..4c34576dd2 100644 --- a/pkg/controller/warehouses/warehouses_test.go +++ b/pkg/controller/warehouses/warehouses_test.go @@ -636,7 +636,7 @@ func TestSyncWarehouse(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - status, err := testCase.reconciler.syncWarehouse(context.TODO(), testCase.warehouse) + status, err := testCase.reconciler.syncWarehouse(t.Context(), testCase.warehouse) testCase.assertions(t, status, err) }) } @@ -837,7 +837,7 @@ func TestDiscoverArtifacts(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { discoveredArtifacts, err := testCase.reconciler.discoverArtifacts( - context.TODO(), + t.Context(), "fake-project", []kargoapi.RepoSubscription{{}}, ) diff --git a/pkg/credentials/credentials.go b/pkg/credentials/credentials.go index 3f30490113..90557af482 100644 --- a/pkg/credentials/credentials.go +++ b/pkg/credentials/credentials.go @@ -49,6 +49,8 @@ type Credentials struct { Password string // SSHPrivateKey is a private key that can be used for access to some remote // repository. This is primarily applicable for Git repositories. + // + // TODO(v1.13.0): Remove this field when SSH support is removed. SSHPrivateKey string } diff --git a/pkg/credentials/ssh/ssh.go b/pkg/credentials/ssh/ssh.go index 0ebe7069af..1455dec2b8 100644 --- a/pkg/credentials/ssh/ssh.go +++ b/pkg/credentials/ssh/ssh.go @@ -1,3 +1,4 @@ +// TODO(v1.13.0): Remove this package when SSH support is removed. package ssh import ( diff --git a/pkg/event/kubernetes/kubernetes_test.go b/pkg/event/kubernetes/kubernetes_test.go index 03b7a0fa49..adfe7773a1 100644 --- a/pkg/event/kubernetes/kubernetes_test.go +++ b/pkg/event/kubernetes/kubernetes_test.go @@ -1,7 +1,6 @@ package kubernetes import ( - "context" "testing" "time" @@ -345,7 +344,7 @@ func TestEventSender_Send(t *testing.T) { recorder := &mockEventRecorder{} sender := NewEventSender(recorder) - err := sender.Send(context.Background(), tc.event) + err := sender.Send(t.Context(), tc.event) if tc.expectError { require.Error(t, err) diff --git a/pkg/expressions/function/functions_test.go b/pkg/expressions/function/functions_test.go index b5d0aa9334..2cd7946cd6 100644 --- a/pkg/expressions/function/functions_test.go +++ b/pkg/expressions/function/functions_test.go @@ -1,7 +1,6 @@ package function import ( - "context" "testing" "time" @@ -214,7 +213,7 @@ func Test_getCommitFromFreight(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -448,7 +447,7 @@ func Test_getImageFromFreight(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -775,7 +774,7 @@ func Test_getChartFromFreight(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -1031,7 +1030,7 @@ func Test_getArtifactFromFreight(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). WithObjects(testCase.objects...). @@ -1255,7 +1254,7 @@ func Test_getConfigMap(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -1445,7 +1444,7 @@ func Test_getSecret(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -1513,7 +1512,7 @@ func Test_getConfigMap_getSecret_no_cache_key_collision(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -1765,7 +1764,7 @@ func Test_freightMetadata(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). @@ -1889,7 +1888,7 @@ func Test_stageMetadata(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() c := fake.NewClientBuilder(). WithScheme(scheme). diff --git a/pkg/fmt/bytes.go b/pkg/fmt/bytes.go new file mode 100644 index 0000000000..445fe7fc01 --- /dev/null +++ b/pkg/fmt/bytes.go @@ -0,0 +1,18 @@ +package fmt + +import "fmt" + +// FormatByteCount formats a byte count using the largest appropriate IEC +// binary unit (KiB, MiB, GiB). +func FormatByteCount(b int64) string { + switch { + case b >= 1<<30: + return fmt.Sprintf("%.1f GiB", float64(b)/(1<<30)) + case b >= 1<<20: + return fmt.Sprintf("%.1f MiB", float64(b)/(1<<20)) + case b >= 1<<10: + return fmt.Sprintf("%.1f KiB", float64(b)/(1<<10)) + default: + return fmt.Sprintf("%d bytes", b) + } +} diff --git a/pkg/fmt/bytes_test.go b/pkg/fmt/bytes_test.go new file mode 100644 index 0000000000..3338f42367 --- /dev/null +++ b/pkg/fmt/bytes_test.go @@ -0,0 +1,63 @@ +package fmt + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFormatByteCount(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + input int64 + expect string + }{ + { + name: "zero bytes", + input: 0, + expect: "0 bytes", + }, + { + name: "small byte count", + input: 512, + expect: "512 bytes", + }, + { + name: "exactly 1 KiB", + input: 1 << 10, + expect: "1.0 KiB", + }, + { + name: "fractional KiB", + input: 1536, // 1.5 KiB + expect: "1.5 KiB", + }, + { + name: "exactly 1 MiB", + input: 1 << 20, + expect: "1.0 MiB", + }, + { + name: "fractional MiB", + input: 3 * (1 << 19), // 1.5 MiB + expect: "1.5 MiB", + }, + { + name: "exactly 1 GiB", + input: 1 << 30, + expect: "1.0 GiB", + }, + { + name: "large GiB value", + input: 6 * (1 << 30), // 6 GiB + expect: "6.0 GiB", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + require.Equal(t, tc.expect, FormatByteCount(tc.input)) + }) + } +} diff --git a/pkg/garbage/collector_test.go b/pkg/garbage/collector_test.go index 3489cd2816..ec57aff7f2 100644 --- a/pkg/garbage/collector_test.go +++ b/pkg/garbage/collector_test.go @@ -142,7 +142,7 @@ func TestRun(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) defer cancel() c := &collector{ cfg: CollectorConfig{ diff --git a/pkg/garbage/freight_test.go b/pkg/garbage/freight_test.go index 12b3da50aa..15d84d4c6f 100644 --- a/pkg/garbage/freight_test.go +++ b/pkg/garbage/freight_test.go @@ -85,7 +85,7 @@ func TestCleanProjectFreight(t *testing.T) { testCase.assertions( t, testCase.collector.cleanProjectFreight( - context.Background(), + t.Context(), "fake-project", ), ) @@ -271,7 +271,7 @@ func TestCleanWarehouseFreight(t *testing.T) { testCase.assertions( t, testCase.collector.cleanWarehouseFreight( - context.Background(), + t.Context(), "fake-project", "fake-warehouse", ), diff --git a/pkg/garbage/projects_test.go b/pkg/garbage/projects_test.go index 05119382ea..fb6860df48 100644 --- a/pkg/garbage/projects_test.go +++ b/pkg/garbage/projects_test.go @@ -64,7 +64,7 @@ func TestCleanProjects(t *testing.T) { } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) defer cancel() projectCh := make(chan string) @@ -125,7 +125,7 @@ func TestCleanProject(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { testCase.assertions( t, - testCase.collector.cleanProject(context.Background(), "fake-project"), + testCase.collector.cleanProject(t.Context(), "fake-project"), ) }) } diff --git a/pkg/garbage/promotions_test.go b/pkg/garbage/promotions_test.go index ce04dc251e..c29470bdde 100644 --- a/pkg/garbage/promotions_test.go +++ b/pkg/garbage/promotions_test.go @@ -86,7 +86,7 @@ func TestCleanProjectPromotions(t *testing.T) { testCase.assertions( t, testCase.collector.cleanProjectPromotions( - context.Background(), + t.Context(), "fake-project", ), ) @@ -237,7 +237,7 @@ func TestCleanStagePromotions(t *testing.T) { testCase.assertions( t, testCase.collector.cleanStagePromotions( - context.Background(), + t.Context(), "fake-project", "fake-stage", ), diff --git a/pkg/gitprovider/azure/azure.go b/pkg/gitprovider/azure/azure.go index d5afaed3cd..9b313cd7c5 100644 --- a/pkg/gitprovider/azure/azure.go +++ b/pkg/gitprovider/azure/azure.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "strings" + "time" "github.com/microsoft/azure-devops-go-api/azuredevops/v7" adocore "github.com/microsoft/azure-devops-go-api/azuredevops/v7/core" @@ -17,6 +18,15 @@ import ( const ProviderName = "azure" +// validMergeMethods is the set of merge strategies supported by Azure DevOps. +// Azure does not validate this server-side, so we validate client-side. +var validMergeMethods = map[string]struct{}{ + "noFastForward": {}, + "rebase": {}, + "rebaseMerge": {}, + "squash": {}, +} + // Azure DevOps URLs can be of two different forms: // // - https://dev.azure.com/org//_git/ @@ -48,11 +58,35 @@ func init() { gitprovider.Register(ProviderName, registration) } +// azureGitClient is the subset of adogit.Client methods used by the provider. +type azureGitClient interface { + GetRepository( + context.Context, + adogit.GetRepositoryArgs, + ) (*adogit.GitRepository, error) + CreatePullRequest( + context.Context, + adogit.CreatePullRequestArgs, + ) (*adogit.GitPullRequest, error) + GetPullRequest( + context.Context, + adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) + GetPullRequests( + context.Context, + adogit.GetPullRequestsArgs, + ) (*[]adogit.GitPullRequest, error) + UpdatePullRequest( + context.Context, + adogit.UpdatePullRequestArgs, + ) (*adogit.GitPullRequest, error) +} + type provider struct { - org string - project string - repo string - connection *azuredevops.Connection + org string + project string + repo string + client azureGitClient } // NewProvider returns an Azure DevOps-based implementation of gitprovider.Interface. @@ -68,13 +102,23 @@ func NewProvider( return nil, err } organizationUrl := fmt.Sprintf("https://%s/%s", modernHostSuffix, org) - connection := azuredevops.NewPatConnection(organizationUrl, opts.Token) + client, err := adogit.NewClient( + // The Azure SDK's NewClient performs a one-time service discovery HTTP call + // to resolve the git resource area endpoint. Given it's limited use, using + // background context is preferable here to refactoring all provider + // registrations to be context-aware. + context.Background(), + azuredevops.NewPatConnection(organizationUrl, opts.Token), + ) + if err != nil { + return nil, fmt.Errorf("error creating Azure DevOps client: %w", err) + } return &provider{ - org: org, - project: project, - repo: repo, - connection: connection, + org: org, + project: project, + repo: repo, + client: client, }, nil } @@ -83,37 +127,37 @@ func (p *provider) CreatePullRequest( ctx context.Context, opts *gitprovider.CreatePullRequestOpts, ) (*gitprovider.PullRequest, error) { - gitClient, err := adogit.NewClient(ctx, p.connection) - if err != nil { - return nil, fmt.Errorf("error creating Azure DevOps client: %w", err) - } - repository, err := gitClient.GetRepository(ctx, adogit.GetRepositoryArgs{ - Project: &p.project, - RepositoryId: &p.repo, - }) + repository, err := p.client.GetRepository( + ctx, + adogit.GetRepositoryArgs{ + Project: &p.project, + RepositoryId: &p.repo, + }, + ) if err != nil { return nil, fmt.Errorf("error getting repository %q: %w", p.repo, err) } repoID := ptr.To(repository.Id.String()) labels := make([]adocore.WebApiTagDefinition, 0, len(opts.Labels)) for _, label := range opts.Labels { - labels = append(labels, adocore.WebApiTagDefinition{ - Name: &label, - }) + labels = append(labels, adocore.WebApiTagDefinition{Name: &label}) } sourceRefName := ptr.To(fmt.Sprintf("refs/heads/%s", opts.Head)) targetRefName := ptr.To(fmt.Sprintf("refs/heads/%s", opts.Base)) - adoPR, err := gitClient.CreatePullRequest(ctx, adogit.CreatePullRequestArgs{ - Project: &p.project, - RepositoryId: repoID, - GitPullRequestToCreate: &adogit.GitPullRequest{ - Title: &opts.Title, - Description: &opts.Description, - Labels: &labels, - SourceRefName: sourceRefName, - TargetRefName: targetRefName, + adoPR, err := p.client.CreatePullRequest( + ctx, + adogit.CreatePullRequestArgs{ + Project: &p.project, + RepositoryId: repoID, + GitPullRequestToCreate: &adogit.GitPullRequest{ + Title: &opts.Title, + Description: &opts.Description, + Labels: &labels, + SourceRefName: sourceRefName, + TargetRefName: targetRefName, + }, }, - }) + ) if err != nil { return nil, fmt.Errorf("error creating pull request from %q to %q: %w", opts.Head, opts.Base, err) } @@ -129,15 +173,14 @@ func (p *provider) GetPullRequest( ctx context.Context, id int64, ) (*gitprovider.PullRequest, error) { - gitClient, err := adogit.NewClient(ctx, p.connection) - if err != nil { - return nil, err - } - adoPR, err := gitClient.GetPullRequest(ctx, adogit.GetPullRequestArgs{ - Project: &p.project, - RepositoryId: &p.repo, - PullRequestId: ptr.To(int(id)), - }) + adoPR, err := p.client.GetPullRequest( + ctx, + adogit.GetPullRequestArgs{ + Project: &p.project, + RepositoryId: &p.repo, + PullRequestId: ptr.To(int(id)), + }, + ) if err != nil { return nil, err } @@ -153,19 +196,18 @@ func (p *provider) ListPullRequests( ctx context.Context, opts *gitprovider.ListPullRequestOptions, ) ([]gitprovider.PullRequest, error) { - gitClient, err := adogit.NewClient(ctx, p.connection) - if err != nil { - return nil, err - } - adoPRs, err := gitClient.GetPullRequests(ctx, adogit.GetPullRequestsArgs{ - Project: &p.project, - RepositoryId: &p.repo, - SearchCriteria: &adogit.GitPullRequestSearchCriteria{ - Status: ptr.To(mapADOPrState(opts.State)), - SourceRefName: ptr.To(opts.HeadBranch), - TargetRefName: ptr.To(opts.BaseBranch), + adoPRs, err := p.client.GetPullRequests( + ctx, + adogit.GetPullRequestsArgs{ + Project: &p.project, + RepositoryId: &p.repo, + SearchCriteria: &adogit.GitPullRequestSearchCriteria{ + Status: ptr.To(mapADOPrState(opts.State)), + SourceRefName: ptr.To(opts.HeadBranch), + TargetRefName: ptr.To(opts.BaseBranch), + }, }, - }) + ) if err != nil { return nil, err } @@ -185,20 +227,21 @@ func (p *provider) ListPullRequests( func (p *provider) MergePullRequest( ctx context.Context, id int64, + opts *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { - var pr *gitprovider.PullRequest - - gitClient, err := adogit.NewClient(ctx, p.connection) - if err != nil { - return nil, false, fmt.Errorf("error creating Azure DevOps client: %w", err) + if opts == nil { + opts = &gitprovider.MergePullRequestOpts{} } // Get the current PR to check its status and get the last merge source commit - adoPR, err := gitClient.GetPullRequest(ctx, adogit.GetPullRequestArgs{ - Project: &p.project, - RepositoryId: &p.repo, - PullRequestId: ptr.To(int(id)), - }) + adoPR, err := p.client.GetPullRequest( + ctx, + adogit.GetPullRequestArgs{ + Project: &p.project, + RepositoryId: &p.repo, + PullRequestId: ptr.To(int(id)), + }, + ) if err != nil { return nil, false, fmt.Errorf("error getting pull request %d: %w", id, err) } @@ -211,8 +254,8 @@ func (p *provider) MergePullRequest( switch status { case adogit.PullRequestStatusValues.Completed: - pr, err = convertADOPullRequest(adoPR) - if err != nil { + var pr *gitprovider.PullRequest + if pr, err = convertADOPullRequest(adoPR); err != nil { return nil, false, fmt.Errorf("error converting pull request %d: %w", id, err) } return pr, true, nil @@ -232,19 +275,32 @@ func (p *provider) MergePullRequest( return nil, false, nil } - // Try to merge - updatedPR, err := gitClient.UpdatePullRequest(ctx, adogit.UpdatePullRequestArgs{ - Project: &p.project, - RepositoryId: &p.repo, - PullRequestId: ptr.To(int(id)), - GitPullRequestToUpdate: &adogit.GitPullRequest{ - Status: ptr.To(adogit.PullRequestStatusValues.Completed), - // LastMergeSourceCommit ensures merge is based on the exact commit we validated. - // If the PR was amended between our validation and merge attempt, Azure DevOps - // will reject the merge operation, preventing race conditions. - LastMergeSourceCommit: adoPR.LastMergeSourceCommit, + var completionOptions *adogit.GitPullRequestCompletionOptions + if opts.MergeMethod != "" { + if _, ok := validMergeMethods[opts.MergeMethod]; !ok { + return nil, false, + fmt.Errorf("unsupported merge method %q", opts.MergeMethod) + } + completionOptions = &adogit.GitPullRequestCompletionOptions{ + MergeStrategy: ptr.To(adogit.GitPullRequestMergeStrategy(opts.MergeMethod)), + } + } + updatedPR, err := p.client.UpdatePullRequest( + ctx, + adogit.UpdatePullRequestArgs{ + Project: &p.project, + RepositoryId: &p.repo, + PullRequestId: ptr.To(int(id)), + GitPullRequestToUpdate: &adogit.GitPullRequest{ + Status: ptr.To(adogit.PullRequestStatusValues.Completed), + // LastMergeSourceCommit ensures merge is based on the exact commit we validated. + // If the PR was amended between our validation and merge attempt, Azure DevOps + // will reject the merge operation, preventing race conditions. + LastMergeSourceCommit: adoPR.LastMergeSourceCommit, + CompletionOptions: completionOptions, + }, }, - }) + ) if err != nil { return nil, false, fmt.Errorf("error merging pull request %d: %w", id, err) } @@ -252,7 +308,50 @@ func (p *provider) MergePullRequest( return nil, false, fmt.Errorf("unexpected nil response after merging pull request %d", id) } - pr, err = convertADOPullRequest(updatedPR) + // Azure DevOps processes merges asynchronously. Poll until the PR reaches + // Completed status so we can return the merge commit information. This is + // deliberately a simple polling loop with a fixed number of attempts and + // short delay between attempts instead of a progressive backoff strategy + // because, knowing how this code is used, contextually (by the git-merge-pr + // promotion step), we really don't want this call to block for too long. + var completedPR *adogit.GitPullRequest + for range 10 { + completedPR, err = p.client.GetPullRequest( + ctx, + adogit.GetPullRequestArgs{ + Project: &p.project, + RepositoryId: &p.repo, + PullRequestId: ptr.To(int(id)), + }, + ) + if err != nil { + return nil, false, + fmt.Errorf("error getting pull request %d after merge: %w", id, err) + } + if completedPR == nil { + return nil, false, + fmt.Errorf("unexpected nil pull request after merge of %d", id) + } + if ptr.Deref(completedPR.Status, "") == + adogit.PullRequestStatusValues.Completed { + break + } + select { + case <-ctx.Done(): + return nil, false, ctx.Err() + case <-time.After(time.Second): + } + } + // If the PR hasn't reached Completed after polling, return false without an + // error so the caller can retry on a future reconciliation — at which point + // the PR will either be Completed (caught by the early return at the top of + // this function) or still Active with a fresh state. + if ptr.Deref(completedPR.Status, "") != + adogit.PullRequestStatusValues.Completed { + return nil, false, nil + } + + pr, err := convertADOPullRequest(completedPR) if err != nil { return nil, false, fmt.Errorf("error converting merged pull request %d: %w", id, err) } diff --git a/pkg/gitprovider/azure/azure_test.go b/pkg/gitprovider/azure/azure_test.go index 4683939f10..9e5895cf45 100644 --- a/pkg/gitprovider/azure/azure_test.go +++ b/pkg/gitprovider/azure/azure_test.go @@ -1,11 +1,405 @@ package azure import ( + "context" + "errors" "testing" + adogit "github.com/microsoft/azure-devops-go-api/azuredevops/v7/git" "github.com/stretchr/testify/require" + "k8s.io/utils/ptr" + + "github.com/akuity/kargo/pkg/gitprovider" ) +type mockAzureGitClient struct { + getRepositoryFn func( + context.Context, + adogit.GetRepositoryArgs, + ) (*adogit.GitRepository, error) + createPullRequestFn func( + context.Context, adogit.CreatePullRequestArgs, + ) (*adogit.GitPullRequest, error) + getPullRequestFn func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) + getPullRequestsFn func( + context.Context, adogit.GetPullRequestsArgs, + ) (*[]adogit.GitPullRequest, error) + updatePullRequestFn func( + context.Context, adogit.UpdatePullRequestArgs, + ) (*adogit.GitPullRequest, error) +} + +func (m *mockAzureGitClient) GetRepository( + ctx context.Context, args adogit.GetRepositoryArgs, +) (*adogit.GitRepository, error) { + return m.getRepositoryFn(ctx, args) +} + +func (m *mockAzureGitClient) CreatePullRequest( + ctx context.Context, args adogit.CreatePullRequestArgs, +) (*adogit.GitPullRequest, error) { + return m.createPullRequestFn(ctx, args) +} + +func (m *mockAzureGitClient) GetPullRequest( + ctx context.Context, args adogit.GetPullRequestArgs, +) (*adogit.GitPullRequest, error) { + return m.getPullRequestFn(ctx, args) +} + +func (m *mockAzureGitClient) GetPullRequests( + ctx context.Context, args adogit.GetPullRequestsArgs, +) (*[]adogit.GitPullRequest, error) { + return m.getPullRequestsFn(ctx, args) +} + +func (m *mockAzureGitClient) UpdatePullRequest( + ctx context.Context, args adogit.UpdatePullRequestArgs, +) (*adogit.GitPullRequest, error) { + return m.updatePullRequestFn(ctx, args) +} + +func TestMergePullRequest(t *testing.T) { + testCases := []struct { + name string + prNumber int64 + mergeOpts *gitprovider.MergePullRequestOpts + mockClient *mockAzureGitClient + expectedMerged bool + expectError bool + errorContains string + }{ + { + name: "error getting PR", + prNumber: 999, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return nil, errors.New("get PR failed") + }, + }, + expectError: true, + errorContains: "error getting pull request", + }, + { + name: "nil PR returned", + prNumber: 404, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return nil, nil + }, + }, + expectError: true, + errorContains: "pull request 404 not found", + }, + { + name: "PR already completed", + prNumber: 123, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(123), + Status: ptr.To(adogit.PullRequestStatusValues.Completed), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/123"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + LastMergeCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("merge_sha"), + }, + }, nil + }, + }, + expectedMerged: true, + }, + { + name: "PR abandoned", + prNumber: 456, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(456), + Status: ptr.To(adogit.PullRequestStatusValues.Abandoned), + }, nil + }, + }, + expectError: true, + errorContains: "is abandoned", + }, + { + name: "PR is draft", + prNumber: 333, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(333), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + IsDraft: ptr.To(true), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Succeeded, + ), + }, nil + }, + }, + }, + { + name: "PR not ready to merge", + prNumber: 444, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(444), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Conflicts, + ), + }, nil + }, + }, + }, + { + name: "unknown status", + prNumber: 555, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(555), + Status: ptr.To(adogit.PullRequestStatusValues.NotSet), + }, nil + }, + }, + }, + { + name: "unsupported merge method", + prNumber: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "bogus"}, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + _ context.Context, _ adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(100), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Succeeded, + ), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + }, + }, + expectError: true, + errorContains: `unsupported merge method "bogus"`, + }, + { + name: "merge operation fails", + prNumber: 888, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(888), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Succeeded, + ), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + }, + updatePullRequestFn: func( + context.Context, adogit.UpdatePullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return nil, errors.New("merge failed") + }, + }, + expectError: true, + errorContains: "error merging pull request", + }, + { + name: "nil response after merge", + prNumber: 777, + mockClient: &mockAzureGitClient{ + getPullRequestFn: func( + context.Context, adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(777), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Succeeded, + ), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + }, + updatePullRequestFn: func( + context.Context, adogit.UpdatePullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return nil, nil + }, + }, + expectError: true, + errorContains: "unexpected nil response after merging", + }, + { + name: "successful merge", + prNumber: 1234, + mockClient: func() *mockAzureGitClient { + calls := 0 + return &mockAzureGitClient{ + getPullRequestFn: func( + _ context.Context, _ adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + calls++ + if calls == 1 { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(1234), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Succeeded, + ), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/1234"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + } + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(1234), + Status: ptr.To(adogit.PullRequestStatusValues.Completed), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/1234"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + LastMergeCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("merge_sha"), + }, + }, nil + }, + updatePullRequestFn: func( + context.Context, adogit.UpdatePullRequestArgs, + ) (*adogit.GitPullRequest, error) { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(1234), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/1234"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + }, + } + }(), + expectedMerged: true, + }, + { + name: "successful merge with explicit method", + prNumber: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"}, + mockClient: func() *mockAzureGitClient { + calls := 0 + return &mockAzureGitClient{ + getPullRequestFn: func( + _ context.Context, _ adogit.GetPullRequestArgs, + ) (*adogit.GitPullRequest, error) { + calls++ + if calls == 1 { + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(100), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + MergeStatus: ptr.To( + adogit.PullRequestAsyncStatusValues.Succeeded, + ), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/100"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + } + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(100), + Status: ptr.To(adogit.PullRequestStatusValues.Completed), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/100"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + LastMergeCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("squash_sha"), + }, + }, nil + }, + updatePullRequestFn: func( + _ context.Context, args adogit.UpdatePullRequestArgs, + ) (*adogit.GitPullRequest, error) { + require.NotNil(t, args.GitPullRequestToUpdate.CompletionOptions) + require.Equal(t, + adogit.GitPullRequestMergeStrategyValues.Squash, + *args.GitPullRequestToUpdate.CompletionOptions.MergeStrategy, + ) + return &adogit.GitPullRequest{ + PullRequestId: ptr.To(100), + Status: ptr.To(adogit.PullRequestStatusValues.Active), + Url: ptr.To("https://dev.azure.com/org/project/_git/repo/pullrequest/100"), + LastMergeSourceCommit: &adogit.GitCommitRef{ + CommitId: ptr.To("head_sha"), + }, + }, nil + }, + } + }(), + expectedMerged: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + p := &provider{ + org: "org", + project: "project", + repo: "repo", + client: tc.mockClient, + } + + pr, merged, err := p.MergePullRequest(t.Context(), tc.prNumber, tc.mergeOpts) + + if tc.expectError { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errorContains) + require.False(t, merged) + require.Nil(t, pr) + return + } + + require.NoError(t, err) + require.Equal(t, tc.expectedMerged, merged) + if tc.expectedMerged { + require.NotNil(t, pr) + require.Equal(t, tc.prNumber, pr.Number) + } + }) + } +} + func TestParseRepoURL(t *testing.T) { testCases := []struct { name string diff --git a/pkg/gitprovider/azure/pr_integration_test.go b/pkg/gitprovider/azure/pr_integration_test.go new file mode 100644 index 0000000000..59e95a5f57 --- /dev/null +++ b/pkg/gitprovider/azure/pr_integration_test.go @@ -0,0 +1,59 @@ +//go:build integration && azure + +package azure + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/gitprovider" + gptest "github.com/akuity/kargo/pkg/gitprovider/testing" +) + +func TestCreateAndMergePullRequest(t *testing.T) { + repoURL := gptest.RequireEnv(t, "TEST_AZURE_REPO_URL") + token := gptest.RequireEnv(t, "TEST_AZURE_TOKEN") + gitUsername := gptest.RequireEnv(t, "TEST_AZURE_USERNAME") + + repoCfg := gptest.RepoConfig{ + RepoURL: repoURL, + Token: token, + GitUsername: gitUsername, + } + + prov, err := NewProvider(repoURL, &gitprovider.Options{Token: token}) + require.NoError(t, err) + + gptest.RunPRTests(t, repoCfg, prov, []gptest.PRTestCase{ + { + Name: "unspecified merge method", + ExpectedParents: 2, // Default is noFastForward (merge commit) + }, + { + Name: "noFastForward", + MergeMethod: "noFastForward", + ExpectedParents: 2, + }, + { + Name: "rebase", + MergeMethod: "rebase", + ExpectedParents: 1, + }, + { + Name: "rebaseMerge", + MergeMethod: "rebaseMerge", + ExpectedParents: 2, + }, + { + Name: "squash", + MergeMethod: "squash", + ExpectedParents: 1, + }, + { + Name: "invalid merge method", + MergeMethod: "bogus", + ExpectMergeErr: true, + }, + }) +} diff --git a/pkg/gitprovider/bitbucket/bitbucket.go b/pkg/gitprovider/bitbucket/bitbucket.go index f0eebd795c..9c8e2dec1f 100644 --- a/pkg/gitprovider/bitbucket/bitbucket.go +++ b/pkg/gitprovider/bitbucket/bitbucket.go @@ -3,6 +3,7 @@ package bitbucket import ( "context" "encoding/json" + "errors" "fmt" "net/url" "strconv" @@ -58,11 +59,11 @@ func init() { // pullRequestClient defines the interface for pull request operations. type pullRequestClient interface { - CreatePullRequest(opt *bitbucket.PullRequestsOptions) (any, error) - ListPullRequests(opt *bitbucket.PullRequestsOptions) (any, error) - GetPullRequest(opt *bitbucket.PullRequestsOptions) (any, error) - GetCommit(opt *bitbucket.CommitsOptions) (any, error) - MergePullRequest(opt *bitbucket.PullRequestsOptions) (any, error) + Create(*bitbucket.PullRequestsOptions) (any, error) + Gets(*bitbucket.PullRequestsOptions) (any, error) + Get(*bitbucket.PullRequestsOptions) (any, error) + GetCommit(*bitbucket.CommitsOptions) (any, error) + Merge(*bitbucket.PullRequestsOptions) (any, error) } // provider is a Bitbucket-based implementation of gitprovider.Interface. @@ -107,43 +108,17 @@ func NewProvider( return &provider{ owner: owner, repoSlug: repoSlug, - client: &clientWrapper{client}, + client: &clientWrapper{ + Commits: client.Repositories.Commits, + PullRequests: client.Repositories.PullRequests, + }, }, nil } // clientWrapper wraps a bitbucket.Client to implement the prClient interface type clientWrapper struct { - client *bitbucket.Client -} - -func (w *clientWrapper) CreatePullRequest( - opt *bitbucket.PullRequestsOptions, -) (any, error) { - return w.client.Repositories.PullRequests.Create(opt) -} - -func (w *clientWrapper) ListPullRequests( - opt *bitbucket.PullRequestsOptions, -) (any, error) { - return w.client.Repositories.PullRequests.Gets(opt) -} - -func (w *clientWrapper) GetPullRequest( - opt *bitbucket.PullRequestsOptions, -) (any, error) { - return w.client.Repositories.PullRequests.Get(opt) -} - -func (w *clientWrapper) GetCommit( - opt *bitbucket.CommitsOptions, -) (any, error) { - return w.client.Repositories.Commits.GetCommit(opt) -} - -func (w *clientWrapper) MergePullRequest( - opt *bitbucket.PullRequestsOptions, -) (any, error) { - return w.client.Repositories.PullRequests.Merge(opt) + *bitbucket.Commits + *bitbucket.PullRequests } // CreatePullRequest implements gitprovider.Interface. @@ -165,7 +140,7 @@ func (p *provider) CreatePullRequest( } createOpts.WithContext(ctx) - resp, err := p.client.CreatePullRequest(createOpts) + resp, err := p.client.Create(createOpts) if err != nil { return nil, err } @@ -198,7 +173,7 @@ func (p *provider) GetPullRequest( } getOpts.WithContext(ctx) - resp, err := p.client.GetPullRequest(getOpts) + resp, err := p.client.Get(getOpts) if err != nil { return nil, err } @@ -248,7 +223,7 @@ func (p *provider) ListPullRequests( return nil, fmt.Errorf("unknown pull request state %q", opts.State) } - resp, err := p.client.ListPullRequests(listOpts) + resp, err := p.client.Gets(listOpts) if err != nil { return nil, err } @@ -309,7 +284,12 @@ func (p *provider) ListPullRequests( func (p *provider) MergePullRequest( _ context.Context, id int64, + opts *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { + if opts == nil { + opts = &gitprovider.MergePullRequestOpts{} + } + // Get the PR to check its state prOpts := &bitbucket.PullRequestsOptions{ Owner: p.owner, @@ -317,7 +297,7 @@ func (p *provider) MergePullRequest( ID: strconv.FormatInt(id, 10), } - prResp, err := p.client.GetPullRequest(prOpts) + prResp, err := p.client.Get(prOpts) if err != nil { return nil, false, fmt.Errorf("error getting pull request %d: %w", id, err) } @@ -355,15 +335,31 @@ func (p *provider) MergePullRequest( // This limitation makes the "wait" option unreliable for Bitbucket // repositories. - // Attempt to merge the PR + // TODO(krancour): go-bitbucket does not expose the merge method/strategy as + // an option. The merge will always use the repository's default merge + // strategy, so simply fail if any merge strategy was specified. This is + // strictly a limitation of the go-bitbucket library and not the Bitbucket API + // itself, so this can be revisited in the future if the library adds support + // for this or if we decide to implement this API call ourselves instead of + // using the library. + if opts.MergeMethod != "" { + return nil, false, errors.New( // nolint: staticcheck + "Kargo's Bitbucket client does not yet support specifying a merge method", + ) + } mergeOpts := &bitbucket.PullRequestsOptions{ Owner: p.owner, RepoSlug: p.repoSlug, ID: strconv.FormatInt(id, 10), } - // Perform the merge - mergeResp, err := p.client.MergePullRequest(mergeOpts) + // TODO(krancour): The Bitbucket merge endpoint can return 202 for async + // merges. The go-bitbucket library treats 202 as success (no error), but the + // response body would be a polling URL, not a PR object. This would cause + // toBitbucketPR to fail or produce incorrect results. If async merges are + // encountered in practice, we'll need to detect the 202 and poll for + // completion. + mergeResp, err := p.client.Merge(mergeOpts) if err != nil { return nil, false, fmt.Errorf("error merging pull request %d: %w", id, err) } @@ -374,6 +370,14 @@ func (p *provider) MergePullRequest( return nil, false, fmt.Errorf("error parsing merged pull request response: %w", err) } + // Per the Bitbucket API docs, the merge endpoint returns 200 only on + // success (409 for conflicts, 555 for timeout — both surfaced as errors + // above). A 200 response with a non-merged state would be unexpected. + if mergedBBPR.State != prStateMerged { + return nil, false, + fmt.Errorf("unexpected state %q after merging pull request %d", mergedBBPR.State, id) + } + return toProviderPR(mergedBBPR, mergeResp), true, nil } diff --git a/pkg/gitprovider/bitbucket/bitbucket_test.go b/pkg/gitprovider/bitbucket/bitbucket_test.go index ca1e4175bc..2b58f9794c 100644 --- a/pkg/gitprovider/bitbucket/bitbucket_test.go +++ b/pkg/gitprovider/bitbucket/bitbucket_test.go @@ -1,7 +1,6 @@ package bitbucket import ( - "context" "errors" "testing" @@ -13,31 +12,39 @@ import ( ) type mockPullRequestClient struct { - createPullRequestFunc func(opt *bitbucket.PullRequestsOptions) (any, error) - listPullRequestsFunc func(opt *bitbucket.PullRequestsOptions) (any, error) - getPullRequestFunc func(opt *bitbucket.PullRequestsOptions) (any, error) - getCommitFunc func(opt *bitbucket.CommitsOptions) (any, error) - mergePullRequestFunc func(opt *bitbucket.PullRequestsOptions) (any, error) + createFunc func(opt *bitbucket.PullRequestsOptions) (any, error) + getsFunc func(opt *bitbucket.PullRequestsOptions) (any, error) + getFunc func(opt *bitbucket.PullRequestsOptions) (any, error) + getCommitFunc func(opt *bitbucket.CommitsOptions) (any, error) + mergeFunc func(opt *bitbucket.PullRequestsOptions) (any, error) } -func (m *mockPullRequestClient) CreatePullRequest(opt *bitbucket.PullRequestsOptions) (any, error) { - return m.createPullRequestFunc(opt) +func (m *mockPullRequestClient) Create( + opt *bitbucket.PullRequestsOptions, +) (any, error) { + return m.createFunc(opt) } -func (m *mockPullRequestClient) ListPullRequests(opt *bitbucket.PullRequestsOptions) (any, error) { - return m.listPullRequestsFunc(opt) +func (m *mockPullRequestClient) Gets( + opt *bitbucket.PullRequestsOptions, +) (any, error) { + return m.getsFunc(opt) } -func (m *mockPullRequestClient) GetPullRequest(opt *bitbucket.PullRequestsOptions) (any, error) { - return m.getPullRequestFunc(opt) +func (m *mockPullRequestClient) Get( + opt *bitbucket.PullRequestsOptions, +) (any, error) { + return m.getFunc(opt) } func (m *mockPullRequestClient) GetCommit(opt *bitbucket.CommitsOptions) (any, error) { return m.getCommitFunc(opt) } -func (m *mockPullRequestClient) MergePullRequest(opt *bitbucket.PullRequestsOptions) (any, error) { - return m.mergePullRequestFunc(opt) +func (m *mockPullRequestClient) Merge( + opt *bitbucket.PullRequestsOptions, +) (any, error) { + return m.mergeFunc(opt) } func TestNewProvider(t *testing.T) { @@ -75,7 +82,7 @@ func TestNewProvider(t *testing.T) { func TestCreatePullRequest(t *testing.T) { t.Run("successful creation", func(t *testing.T) { mockClient := &mockPullRequestClient{ - createPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + createFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{ "id": int64(1), "state": prStateOpen, @@ -107,7 +114,7 @@ func TestCreatePullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() opts := &gitprovider.CreatePullRequestOpts{ Title: "Test PR", Description: "PR description", @@ -126,7 +133,7 @@ func TestCreatePullRequest(t *testing.T) { t.Run("successful creation with nil options", func(t *testing.T) { mockClient := &mockPullRequestClient{ - createPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + createFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{ "id": int64(1), "state": prStateOpen, @@ -139,7 +146,7 @@ func TestCreatePullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.CreatePullRequest(ctx, nil) assert.NoError(t, err) assert.NotNil(t, pr) @@ -148,7 +155,7 @@ func TestCreatePullRequest(t *testing.T) { t.Run("creation with merge commit", func(t *testing.T) { mockClient := &mockPullRequestClient{ - createPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + createFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{ "id": int64(1), "state": prStateOpen, @@ -169,7 +176,7 @@ func TestCreatePullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.CreatePullRequest(ctx, nil) assert.NoError(t, err) assert.NotNil(t, pr) @@ -178,7 +185,7 @@ func TestCreatePullRequest(t *testing.T) { t.Run("error during creation", func(t *testing.T) { mockClient := &mockPullRequestClient{ - createPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + createFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return nil, errors.New("creation failed") }, } @@ -188,7 +195,7 @@ func TestCreatePullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.CreatePullRequest(ctx, nil) assert.Error(t, err) assert.Nil(t, pr) @@ -196,7 +203,7 @@ func TestCreatePullRequest(t *testing.T) { t.Run("error converting PR response", func(t *testing.T) { mockClient := &mockPullRequestClient{ - createPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + createFunc: func(*bitbucket.PullRequestsOptions) (any, error) { // Return something that can't be properly unmarshaled return make(chan int), nil }, @@ -207,7 +214,7 @@ func TestCreatePullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.CreatePullRequest(ctx, nil) assert.Error(t, err) assert.Nil(t, pr) @@ -215,7 +222,7 @@ func TestCreatePullRequest(t *testing.T) { t.Run("error getting full commit SHA", func(t *testing.T) { mockClient := &mockPullRequestClient{ - createPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + createFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{ "id": int64(1), "state": prStateOpen, @@ -234,7 +241,7 @@ func TestCreatePullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.CreatePullRequest(ctx, nil) assert.Error(t, err) assert.Nil(t, pr) @@ -244,7 +251,7 @@ func TestCreatePullRequest(t *testing.T) { func TestGetPullRequest(t *testing.T) { t.Run("successful retrieval", func(t *testing.T) { mockClient := &mockPullRequestClient{ - getPullRequestFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { + getFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { assert.Equal(t, "1", opt.ID) return map[string]any{ "id": int64(1), @@ -277,7 +284,7 @@ func TestGetPullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.GetPullRequest(ctx, 1) assert.NoError(t, err) assert.NotNil(t, pr) @@ -291,7 +298,7 @@ func TestGetPullRequest(t *testing.T) { t.Run("retrieval of merged PR", func(t *testing.T) { mockClient := &mockPullRequestClient{ - getPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{ "id": int64(1), "state": prStateMerged, @@ -312,7 +319,7 @@ func TestGetPullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.GetPullRequest(ctx, 1) assert.NoError(t, err) assert.NotNil(t, pr) @@ -323,7 +330,7 @@ func TestGetPullRequest(t *testing.T) { t.Run("error during retrieval", func(t *testing.T) { mockClient := &mockPullRequestClient{ - getPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return nil, errors.New("retrieval failed") }, } @@ -333,7 +340,7 @@ func TestGetPullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.GetPullRequest(ctx, 1) assert.Error(t, err) assert.Nil(t, pr) @@ -341,7 +348,7 @@ func TestGetPullRequest(t *testing.T) { t.Run("error converting PR response", func(t *testing.T) { mockClient := &mockPullRequestClient{ - getPullRequestFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { // Return something that can't be properly unmarshaled return make(chan int), nil }, @@ -352,7 +359,7 @@ func TestGetPullRequest(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() pr, err := provider.GetPullRequest(ctx, 1) assert.Error(t, err) assert.Nil(t, pr) @@ -362,7 +369,7 @@ func TestGetPullRequest(t *testing.T) { func TestListPullRequests(t *testing.T) { t.Run("list open PRs by default", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { assert.Equal(t, []string{prStateOpen}, opt.States) return map[string]any{"values": []any{ map[string]any{"id": int64(1), "state": prStateOpen}, @@ -376,7 +383,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, nil) assert.NoError(t, err) assert.Len(t, prs, 2) @@ -384,7 +391,7 @@ func TestListPullRequests(t *testing.T) { t.Run("list all PRs", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { assert.Contains(t, opt.States, prStateOpen) assert.Contains(t, opt.States, prStateMerged) assert.Contains(t, opt.States, prStateDeclined) @@ -403,7 +410,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{ State: gitprovider.PullRequestStateAny, }) @@ -413,7 +420,7 @@ func TestListPullRequests(t *testing.T) { t.Run("list closed PRs", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(opt *bitbucket.PullRequestsOptions) (any, error) { assert.Contains(t, opt.States, prStateMerged) assert.Contains(t, opt.States, prStateDeclined) assert.Contains(t, opt.States, prStateSuperseded) @@ -431,7 +438,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{ State: gitprovider.PullRequestStateClosed, }) @@ -441,7 +448,7 @@ func TestListPullRequests(t *testing.T) { t.Run("filter by head branch", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{"values": []any{ map[string]any{ "id": int64(1), @@ -486,7 +493,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{ HeadBranch: "feature-1", }) @@ -497,7 +504,7 @@ func TestListPullRequests(t *testing.T) { t.Run("filter by base branch", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{"values": []any{ map[string]any{ "id": int64(1), @@ -542,7 +549,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{ BaseBranch: "dev", }) @@ -553,7 +560,7 @@ func TestListPullRequests(t *testing.T) { t.Run("filter by head commit", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{"values": []any{ map[string]any{ "id": int64(1), @@ -588,7 +595,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{ HeadCommit: "specific-hash", }) @@ -599,7 +606,7 @@ func TestListPullRequests(t *testing.T) { t.Run("PR with merge commit", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{"values": []any{ map[string]any{ "id": int64(1), @@ -622,7 +629,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, nil) assert.NoError(t, err) assert.Len(t, prs, 1) @@ -631,7 +638,7 @@ func TestListPullRequests(t *testing.T) { t.Run("error during list", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return nil, errors.New("list failed") }, } @@ -641,7 +648,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, nil) assert.Error(t, err) assert.Nil(t, prs) @@ -649,7 +656,7 @@ func TestListPullRequests(t *testing.T) { t.Run("invalid response format", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return "not a map", nil }, } @@ -659,7 +666,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, nil) assert.Error(t, err) assert.Nil(t, prs) @@ -667,7 +674,7 @@ func TestListPullRequests(t *testing.T) { t.Run("missing values field", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{}, nil }, } @@ -677,7 +684,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, nil) assert.Error(t, err) assert.Nil(t, prs) @@ -685,7 +692,7 @@ func TestListPullRequests(t *testing.T) { t.Run("invalid values type", func(t *testing.T) { mockClient := &mockPullRequestClient{ - listPullRequestsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + getsFunc: func(*bitbucket.PullRequestsOptions) (any, error) { return map[string]any{"values": "not an array"}, nil }, } @@ -695,7 +702,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, nil) assert.Error(t, err) assert.Nil(t, prs) @@ -707,7 +714,7 @@ func TestListPullRequests(t *testing.T) { repoSlug: "repo", } - ctx := context.Background() + ctx := t.Context() prs, err := provider.ListPullRequests(ctx, &gitprovider.ListPullRequestOptions{ State: "invalid-state", }) @@ -716,6 +723,212 @@ func TestListPullRequests(t *testing.T) { }) } +func TestMergePullRequest(t *testing.T) { + testCases := []struct { + name string + prNumber int64 + mergeOpts *gitprovider.MergePullRequestOpts + mockClient *mockPullRequestClient + expectedMerged bool + expectError bool + errorContains string + }{ + { + name: "error getting PR", + prNumber: 999, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return nil, errors.New("get PR failed") + }, + }, + expectError: true, + errorContains: "error getting pull request", + }, + { + name: "error parsing PR response", + prNumber: 999, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return "not a valid response", nil + }, + }, + expectError: true, + errorContains: "error parsing pull request response", + }, + { + name: "PR already merged", + prNumber: 123, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(123), + "state": prStateMerged, + "links": map[string]any{ + "html": map[string]any{ + "href": "https://bitbucket.org/owner/repo/pull-requests/123", + }, + }, + "merge_commit": map[string]any{ + "hash": "merge_sha", + }, + "source": map[string]any{ + "commit": map[string]any{ + "hash": "head_sha", + }, + }, + }, nil + }, + }, + expectedMerged: true, + }, + { + name: "PR declined", + prNumber: 456, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(456), + "state": prStateDeclined, + }, nil + }, + }, + expectError: true, + errorContains: "closed but not merged", + }, + { + name: "PR is draft", + prNumber: 333, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(333), + "state": prStateOpen, + "draft": true, + }, nil + }, + }, + }, + { + name: "merge method specified", + prNumber: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"}, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(100), + "state": prStateOpen, + }, nil + }, + }, + expectError: true, + errorContains: "does not yet support specifying a merge method", + }, + { + name: "merge operation fails", + prNumber: 888, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(888), + "state": prStateOpen, + }, nil + }, + mergeFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return nil, errors.New("merge failed") + }, + }, + expectError: true, + errorContains: "error merging pull request", + }, + { + name: "error parsing merge response", + prNumber: 777, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(777), + "state": prStateOpen, + }, nil + }, + mergeFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return "not a valid response", nil + }, + }, + expectError: true, + errorContains: "error parsing merged pull request response", + }, + { + name: "successful merge", + prNumber: 1234, + mockClient: &mockPullRequestClient{ + getFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(1234), + "state": prStateOpen, + "links": map[string]any{ + "html": map[string]any{ + "href": "https://bitbucket.org/owner/repo/pull-requests/1234", + }, + }, + "source": map[string]any{ + "commit": map[string]any{ + "hash": "head_sha", + }, + }, + }, nil + }, + mergeFunc: func(*bitbucket.PullRequestsOptions) (any, error) { + return map[string]any{ + "id": int64(1234), + "state": prStateMerged, + "links": map[string]any{ + "html": map[string]any{ + "href": "https://bitbucket.org/owner/repo/pull-requests/1234", + }, + }, + "merge_commit": map[string]any{ + "hash": "merge_sha", + }, + "source": map[string]any{ + "commit": map[string]any{ + "hash": "head_sha", + }, + }, + }, nil + }, + }, + expectedMerged: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + p := &provider{ + owner: "owner", + repoSlug: "repo", + client: tc.mockClient, + } + + pr, merged, err := p.MergePullRequest(t.Context(), tc.prNumber, tc.mergeOpts) + + if tc.expectError { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errorContains) + require.False(t, merged) + require.Nil(t, pr) + return + } + + require.NoError(t, err) + require.Equal(t, tc.expectedMerged, merged) + if tc.expectedMerged { + require.NotNil(t, pr) + require.Equal(t, tc.prNumber, pr.Number) + } + }) + } +} + func TestGetFullCommitSHA(t *testing.T) { t.Run("successful retrieval", func(t *testing.T) { mockClient := &mockPullRequestClient{ @@ -732,7 +945,7 @@ func TestGetFullCommitSHA(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() sha, err := provider.getFullCommitSHA(ctx, "short123") assert.NoError(t, err) assert.Equal(t, "full1234567890abcdef", sha) @@ -744,7 +957,7 @@ func TestGetFullCommitSHA(t *testing.T) { repoSlug: "repo", } - ctx := context.Background() + ctx := t.Context() sha, err := provider.getFullCommitSHA(ctx, "") assert.NoError(t, err) assert.Equal(t, "", sha) @@ -762,7 +975,7 @@ func TestGetFullCommitSHA(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() sha, err := provider.getFullCommitSHA(ctx, "short123") assert.Error(t, err) assert.Equal(t, "", sha) @@ -780,7 +993,7 @@ func TestGetFullCommitSHA(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() sha, err := provider.getFullCommitSHA(ctx, "short123") assert.Error(t, err) assert.Equal(t, "", sha) @@ -798,7 +1011,7 @@ func TestGetFullCommitSHA(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() sha, err := provider.getFullCommitSHA(ctx, "short123") assert.Error(t, err) assert.Equal(t, "", sha) @@ -818,7 +1031,7 @@ func TestGetFullCommitSHA(t *testing.T) { client: mockClient, } - ctx := context.Background() + ctx := t.Context() sha, err := provider.getFullCommitSHA(ctx, "short123") assert.Error(t, err) assert.Equal(t, "", sha) diff --git a/pkg/gitprovider/bitbucket/pr_integration_test.go b/pkg/gitprovider/bitbucket/pr_integration_test.go new file mode 100644 index 0000000000..334b44fc91 --- /dev/null +++ b/pkg/gitprovider/bitbucket/pr_integration_test.go @@ -0,0 +1,38 @@ +//go:build integration && bitbucket + +package bitbucket + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/gitprovider" + gptest "github.com/akuity/kargo/pkg/gitprovider/testing" +) + +func TestCreateAndMergePullRequest(t *testing.T) { + repoURL := gptest.RequireEnv(t, "TEST_BITBUCKET_REPO_URL") + token := gptest.RequireEnv(t, "TEST_BITBUCKET_TOKEN") + + repoCfg := gptest.RepoConfig{ + RepoURL: repoURL, + Token: token, + GitUsername: gptest.RequireEnv(t, "TEST_BITBUCKET_USERNAME"), + } + + prov, err := NewProvider(repoURL, &gitprovider.Options{Token: token}) + require.NoError(t, err) + + gptest.RunPRTests(t, repoCfg, prov, []gptest.PRTestCase{ + { + Name: "unspecified merge method", + ExpectedParents: 2, // Repo default is merge commit + }, + { + Name: "explicit merge method", + MergeMethod: "squash", + ExpectMergeErr: true, // Library limitation + }, + }) +} diff --git a/pkg/gitprovider/gitea/gitea.go b/pkg/gitprovider/gitea/gitea.go index 4f48c29388..35aecffe7c 100644 --- a/pkg/gitprovider/gitea/gitea.go +++ b/pkg/gitprovider/gitea/gitea.go @@ -16,6 +16,17 @@ import ( const ProviderName = "gitea" +// validMergeMethods is the set of merge methods supported by Gitea's API. Gitea +// does not seem to validate this server-side, so we validate client-side. +var validMergeMethods = map[string]struct{}{ + "fast-forward-only": {}, + "manually-merged": {}, + "merge": {}, + "rebase": {}, + "rebase-merge": {}, + "squash": {}, +} + var registration = gitprovider.Registration{ Predicate: func(repoURL string) bool { u, err := url.Parse(repoURL) @@ -40,41 +51,29 @@ func init() { type giteaClient interface { CreatePullRequest( - ctx context.Context, owner string, repo string, - opts *gitea.CreatePullRequestOption, + opts gitea.CreatePullRequestOption, ) (*gitea.PullRequest, *gitea.Response, error) - ListPullRequests( - ctx context.Context, + ListRepoPullRequests( owner string, repo string, - opts *gitea.ListPullRequestsOptions, + opts gitea.ListPullRequestsOptions, ) ([]*gitea.PullRequest, *gitea.Response, error) - GetPullRequests( - ctx context.Context, + GetPullRequest( owner string, repo string, - number int, + number int64, ) (*gitea.PullRequest, *gitea.Response, error) MergePullRequest( - ctx context.Context, - owner string, - repo string, - number int, - opts *gitea.MergePullRequestOption, - ) (*gitea.Response, error) - - AddLabelsToIssue( - ctx context.Context, owner string, repo string, - number int, - labels []string, - ) ([]*gitea.Label, *gitea.Response, error) + number int64, + opts gitea.MergePullRequestOption, + ) (bool, *gitea.Response, error) } // provider is a Gitea implementation of gitprovider.Interface. @@ -122,74 +121,22 @@ func NewProvider( return &provider{ owner: owner, repo: repo, - client: &giteaClientWrapper{client}, + client: client, }, nil } -type giteaClientWrapper struct { - client *gitea.Client -} - -func (g giteaClientWrapper) CreatePullRequest( - _ context.Context, - owner string, - repo string, - opts *gitea.CreatePullRequestOption, -) (*gitea.PullRequest, *gitea.Response, error) { - return g.client.CreatePullRequest(owner, repo, *opts) -} - -func (g giteaClientWrapper) ListPullRequests( - _ context.Context, - owner string, - repo string, - opts *gitea.ListPullRequestsOptions, -) ([]*gitea.PullRequest, *gitea.Response, error) { - return g.client.ListRepoPullRequests(owner, repo, *opts) -} - -func (g giteaClientWrapper) GetPullRequests( - _ context.Context, - owner string, - repo string, - number int, -) (*gitea.PullRequest, *gitea.Response, error) { - return g.client.GetPullRequest(owner, repo, int64(number)) -} - -func (g giteaClientWrapper) MergePullRequest( - _ context.Context, - owner string, - repo string, - number int, - opts *gitea.MergePullRequestOption, -) (*gitea.Response, error) { - _, resp, err := g.client.MergePullRequest(owner, repo, int64(number), *opts) - return resp, err -} - -func (g giteaClientWrapper) AddLabelsToIssue( - _ context.Context, - owner string, - repo string, - number int, - _ []string, -) ([]*gitea.Label, *gitea.Response, error) { - return g.client.AddIssueLabels(owner, repo, int64(number), gitea.IssueLabelsOption{}) -} - // CreatePullRequest implements gitprovider.Interface. func (p *provider) CreatePullRequest( - ctx context.Context, + _ context.Context, opts *gitprovider.CreatePullRequestOpts, ) (*gitprovider.PullRequest, error) { if opts == nil { opts = &gitprovider.CreatePullRequestOpts{} } - giteaPR, _, err := p.client.CreatePullRequest(ctx, + giteaPR, _, err := p.client.CreatePullRequest( p.owner, p.repo, - &gitea.CreatePullRequestOption{ + gitea.CreatePullRequestOption{ Title: opts.Title, Head: opts.Head, Base: opts.Base, @@ -202,26 +149,21 @@ func (p *provider) CreatePullRequest( if giteaPR == nil { return nil, fmt.Errorf("unexpected nil pull request") } + // TODO(krancour): Add label support. The Gitea SDK's AddIssueLabels expects + // label IDs ([]int64), but Kargo's CreatePullRequestOpts.Labels are names + // ([]string). A previous implementation attempted this but silently discarded + // the labels entirely. To fix properly: list repo labels, match by name to + // get IDs, then call AddIssueLabels. pr := convertGiteaPR(*giteaPR) - if len(opts.Labels) > 0 { - if _, _, err = p.client.AddLabelsToIssue(ctx, - p.owner, - p.repo, - int(pr.Number), - opts.Labels, - ); err != nil { - return nil, err - } - } return &pr, nil } // GetPullRequest implements gitprovider.Interface. func (p *provider) GetPullRequest( - ctx context.Context, + _ context.Context, id int64, ) (*gitprovider.PullRequest, error) { - ghPR, _, err := p.client.GetPullRequests(ctx, p.owner, p.repo, int(id)) + ghPR, _, err := p.client.GetPullRequest(p.owner, p.repo, id) if err != nil { return nil, err } @@ -234,7 +176,7 @@ func (p *provider) GetPullRequest( // ListPullRequests implements gitprovider.Interface. func (p *provider) ListPullRequests( - ctx context.Context, + _ context.Context, opts *gitprovider.ListPullRequestOptions, ) ([]gitprovider.PullRequest, error) { if opts == nil { @@ -258,7 +200,7 @@ func (p *provider) ListPullRequests( } var prs []gitprovider.PullRequest for { - giteaPRs, res, err := p.client.ListPullRequests(ctx, p.owner, p.repo, &listOpts) + giteaPRs, res, err := p.client.ListRepoPullRequests(p.owner, p.repo, listOpts) if err != nil { return nil, err } @@ -278,10 +220,15 @@ func (p *provider) ListPullRequests( // MergePullRequest implements gitprovider.Interface. func (p *provider) MergePullRequest( - ctx context.Context, + _ context.Context, id int64, + opts *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { - giteaPR, _, err := p.client.GetPullRequests(ctx, p.owner, p.repo, int(id)) + if opts == nil { + opts = &gitprovider.MergePullRequestOpts{} + } + + giteaPR, _, err := p.client.GetPullRequest(p.owner, p.repo, id) if err != nil { return nil, false, fmt.Errorf("error getting pull request %d: %w", id, err) } @@ -301,14 +248,29 @@ func (p *provider) MergePullRequest( return nil, false, nil } - // Merge the PR - if _, err = p.client.MergePullRequest( - ctx, p.owner, p.repo, int(id), &gitea.MergePullRequestOption{}, - ); err != nil { + mergeMethod := opts.MergeMethod + if mergeMethod == "" { + mergeMethod = "merge" + } + if _, ok := validMergeMethods[mergeMethod]; !ok { + return nil, false, + fmt.Errorf("unsupported merge method %q", mergeMethod) + } + + merged, _, err := p.client.MergePullRequest( + p.owner, + p.repo, + id, + gitea.MergePullRequestOption{Style: gitea.MergeStyle(mergeMethod)}, + ) + if err != nil { return nil, false, fmt.Errorf("error merging pull request %d: %w", id, err) } + if !merged { + return nil, false, fmt.Errorf("merge rejected for pull request %d", id) + } - updatedPR, _, err := p.client.GetPullRequests(ctx, p.owner, p.repo, int(id)) + updatedPR, _, err := p.client.GetPullRequest(p.owner, p.repo, id) if err != nil { return nil, false, fmt.Errorf("error fetching PR %d after merge: %w", id, err) } diff --git a/pkg/gitprovider/gitea/gitea_test.go b/pkg/gitprovider/gitea/gitea_test.go index 504c85f845..0c5795c946 100644 --- a/pkg/gitprovider/gitea/gitea_test.go +++ b/pkg/gitprovider/gitea/gitea_test.go @@ -1,7 +1,6 @@ package gitea import ( - "context" "errors" "testing" "time" @@ -81,21 +80,20 @@ func TestParseGiteaURL(t *testing.T) { type mockGiteaClient struct { mock.Mock - newPr *gitea.CreatePullRequestOption - pr *gitea.PullRequest - owner string - repo string - labels []string - listOpts *gitea.ListPullRequestsOptions + newPr gitea.CreatePullRequestOption + pr *gitea.PullRequest + owner string + repo string + issueLabelsOptions gitea.IssueLabelsOption + listOpts gitea.ListPullRequestsOptions } -func (m *mockGiteaClient) ListPullRequests( - ctx context.Context, +func (m *mockGiteaClient) ListRepoPullRequests( owner string, repo string, - opts *gitea.ListPullRequestsOptions, + opts gitea.ListPullRequestsOptions, ) ([]*gitea.PullRequest, *gitea.Response, error) { - args := m.Called(ctx, owner, repo, opts) + args := m.Called(owner, repo, opts) m.owner = owner m.repo = repo m.listOpts = opts @@ -110,13 +108,12 @@ func (m *mockGiteaClient) ListPullRequests( return prs, resp, args.Error(2) } -func (m *mockGiteaClient) GetPullRequests( - ctx context.Context, +func (m *mockGiteaClient) GetPullRequest( owner string, repo string, - number int, + number int64, ) (*gitea.PullRequest, *gitea.Response, error) { - args := m.Called(ctx, owner, repo, number) + args := m.Called(owner, repo, number) m.owner = owner m.repo = repo pr, ok := args.Get(0).(*gitea.PullRequest) @@ -130,15 +127,14 @@ func (m *mockGiteaClient) GetPullRequests( return pr, resp, args.Error(2) } -func (m *mockGiteaClient) AddLabelsToIssue( - ctx context.Context, +func (m *mockGiteaClient) AddIssueLabels( owner string, repo string, - number int, - labels []string, + number int64, + opts gitea.IssueLabelsOption, ) ([]*gitea.Label, *gitea.Response, error) { - args := m.Called(ctx, owner, repo, number, labels) - m.labels = labels + args := m.Called(owner, repo, number, opts) + m.issueLabelsOptions = opts labelsResp, ok := args.Get(0).([]*gitea.Label) if !ok { return nil, nil, args.Error(2) @@ -151,27 +147,22 @@ func (m *mockGiteaClient) AddLabelsToIssue( } func (m *mockGiteaClient) MergePullRequest( - ctx context.Context, owner string, repo string, - number int, - opts *gitea.MergePullRequestOption, -) (*gitea.Response, error) { - args := m.Called(ctx, owner, repo, number, opts) - resp, ok := args.Get(0).(*gitea.Response) - if !ok { - return nil, args.Error(1) - } - return resp, args.Error(1) + number int64, + opts gitea.MergePullRequestOption, +) (bool, *gitea.Response, error) { + args := m.Called(owner, repo, number, opts) + resp, _ := args.Get(1).(*gitea.Response) + return args.Bool(0), resp, args.Error(2) } func (m *mockGiteaClient) CreatePullRequest( - ctx context.Context, owner string, repo string, - opts *gitea.CreatePullRequestOption, + opts gitea.CreatePullRequestOption, ) (*gitea.PullRequest, *gitea.Response, error) { - args := m.Called(ctx, owner, repo, opts) + args := m.Called(owner, repo, opts) m.owner = owner m.repo = repo m.newPr = opts @@ -187,13 +178,12 @@ func (m *mockGiteaClient) CreatePullRequest( return pr, resp, args.Error(2) } -func TestCreatePullRequestWithLabels(t *testing.T) { +func TestCreatePullRequest(t *testing.T) { opts := gitprovider.CreatePullRequestOpts{ Head: "feature-branch", Base: "main", Title: "title", Description: "desc", - Labels: []string{"label1", "label2"}, } // set up mock @@ -213,7 +203,7 @@ func TestCreatePullRequestWithLabels(t *testing.T) { }, } mockClient. - On("CreatePullRequest", context.Background(), testRepoOwner, testRepoName, mock.Anything). + On("CreatePullRequest", testRepoOwner, testRepoName, mock.Anything). Return( &gitea.PullRequest{ Index: int64(42), @@ -232,13 +222,6 @@ func TestCreatePullRequestWithLabels(t *testing.T) { &gitea.Response{}, nil, ) - mockClient. - On("AddLabelsToIssue", context.Background(), testRepoOwner, testRepoName, int(mockClient.pr.Index), mock.Anything). - Return( - []*gitea.Label{}, - &gitea.Response{}, - nil, - ) // call the code we are testing g := provider{ @@ -246,7 +229,7 @@ func TestCreatePullRequestWithLabels(t *testing.T) { repo: testRepoName, client: mockClient, } - pr, err := g.CreatePullRequest(context.Background(), &opts) + pr, err := g.CreatePullRequest(t.Context(), &opts) // assert that the expectations were met mockClient.AssertExpectations(t) @@ -261,8 +244,6 @@ func TestCreatePullRequestWithLabels(t *testing.T) { "Expected title in new PR request to match title from options") require.Equal(t, opts.Description, mockClient.newPr.Body, "Expected body in new PR request to match description from options") - require.ElementsMatch(t, opts.Labels, mockClient.labels, - "Expected labels passed to gitea client to match labels from options") require.Equal(t, mockClient.pr.Index, pr.Number, "Expected PR number in returned object to match what was returned by gitea") @@ -291,7 +272,7 @@ func TestGetPullRequest(t *testing.T) { } mockClient. - On("GetPullRequests", context.Background(), testRepoOwner, testRepoName, int(mockClient.pr.Index)). + On("GetPullRequest", testRepoOwner, testRepoName, mockClient.pr.Index). Return( &gitea.PullRequest{ Index: int64(42), @@ -316,7 +297,7 @@ func TestGetPullRequest(t *testing.T) { repo: testRepoName, client: mockClient, } - pr, err := g.GetPullRequest(context.Background(), 42) + pr, err := g.GetPullRequest(t.Context(), 42) // assert that the expectations were met mockClient.AssertExpectations(t) @@ -356,7 +337,7 @@ func TestListPullRequests(t *testing.T) { }, } mockClient. - On("ListPullRequests", context.Background(), testRepoOwner, testRepoName, &gitea.ListPullRequestsOptions{ + On("ListRepoPullRequests", testRepoOwner, testRepoName, gitea.ListPullRequestsOptions{ State: "all", ListOptions: gitea.ListOptions{ Page: 0, @@ -388,7 +369,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - prs, err := g.ListPullRequests(context.Background(), &opts) + prs, err := g.ListPullRequests(t.Context(), &opts) require.NoError(t, err) require.Equal(t, testRepoOwner, mockClient.owner) @@ -404,6 +385,7 @@ func TestMergePullRequest(t *testing.T) { tests := []struct { name string prNumber int64 + mergeOpts *gitprovider.MergePullRequestOpts setupMock func(*mockGiteaClient) expectedMerged bool expectError bool @@ -413,7 +395,7 @@ func TestMergePullRequest(t *testing.T) { name: "error getting initial PR state", prNumber: 999, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(999)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(999)). Return(nil, nil, errors.New("get PR failed")) }, expectError: true, @@ -423,7 +405,7 @@ func TestMergePullRequest(t *testing.T) { name: "nil PR returned from initial get", prNumber: 404, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(404)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(404)). Return(nil, &gitea.Response{}, nil) }, expectError: true, @@ -433,7 +415,7 @@ func TestMergePullRequest(t *testing.T) { name: "PR already merged", prNumber: 123, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(123)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(123)). Return(&gitea.PullRequest{ Index: 123, State: gitea.StateClosed, @@ -448,7 +430,7 @@ func TestMergePullRequest(t *testing.T) { name: "PR not in open state", prNumber: 456, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(456)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(456)). Return(&gitea.PullRequest{ Index: 456, State: gitea.StateClosed, @@ -462,7 +444,7 @@ func TestMergePullRequest(t *testing.T) { name: "PR not mergeable", prNumber: 333, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(333)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(333)). Return(&gitea.PullRequest{ Index: 333, State: gitea.StateOpen, @@ -474,36 +456,54 @@ func TestMergePullRequest(t *testing.T) { name: "merge operation fails", prNumber: 888, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(888)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(888)). Return(&gitea.PullRequest{ Index: 888, State: gitea.StateOpen, Mergeable: true, }, &gitea.Response{}, nil).Once() - m.On("MergePullRequest", mock.Anything, testRepoOwner, testRepoName, 888, - mock.AnythingOfType("*gitea.MergePullRequestOption")). - Return(nil, errors.New("merge failed")) + m.On("MergePullRequest", testRepoOwner, testRepoName, int64(888), + mock.AnythingOfType("gitea.MergePullRequestOption")). + Return(false, nil, errors.New("merge failed")) }, expectError: true, errorContains: "error merging pull request", }, + { + name: "merge rejected", + prNumber: 555, + setupMock: func(m *mockGiteaClient) { + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(555)). + Return(&gitea.PullRequest{ + Index: 555, + State: gitea.StateOpen, + Mergeable: true, + }, &gitea.Response{}, nil).Once() + + m.On("MergePullRequest", testRepoOwner, testRepoName, int64(555), + mock.AnythingOfType("gitea.MergePullRequestOption")). + Return(false, &gitea.Response{}, nil) + }, + expectError: true, + errorContains: "merge rejected", + }, { name: "get PR after merge fails", prNumber: 777, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(777)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(777)). Return(&gitea.PullRequest{ Index: 777, State: gitea.StateOpen, Mergeable: true, }, &gitea.Response{}, nil).Once() - m.On("MergePullRequest", mock.Anything, testRepoOwner, testRepoName, 777, - mock.AnythingOfType("*gitea.MergePullRequestOption")). - Return(&gitea.Response{}, nil) + m.On("MergePullRequest", testRepoOwner, testRepoName, int64(777), + mock.AnythingOfType("gitea.MergePullRequestOption")). + Return(true, &gitea.Response{}, nil) - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(777)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(777)). Return(nil, nil, errors.New("get PR failed")).Once() }, expectError: true, @@ -513,28 +513,76 @@ func TestMergePullRequest(t *testing.T) { name: "nil PR returned after merge", prNumber: 666, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(666)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(666)). Return(&gitea.PullRequest{ Index: 666, State: gitea.StateOpen, Mergeable: true, }, &gitea.Response{}, nil).Once() - m.On("MergePullRequest", mock.Anything, testRepoOwner, testRepoName, 666, - mock.AnythingOfType("*gitea.MergePullRequestOption")). - Return(&gitea.Response{}, nil) + m.On("MergePullRequest", testRepoOwner, testRepoName, int64(666), + mock.AnythingOfType("gitea.MergePullRequestOption")). + Return(true, &gitea.Response{}, nil) - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(666)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(666)). Return(nil, &gitea.Response{}, nil).Once() }, expectError: true, errorContains: "unexpected nil PR after merge", }, + { + name: "successful merge with explicit method", + prNumber: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"}, + setupMock: func(m *mockGiteaClient) { + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(100)). + Return(&gitea.PullRequest{ + Index: 100, + State: gitea.StateOpen, + Mergeable: true, + Head: &gitea.PRBranchInfo{Sha: "head_sha"}, + URL: "https://gitea.com/akuity/kargo/pulls/100", + }, &gitea.Response{}, nil).Once() + + m.On("MergePullRequest", testRepoOwner, testRepoName, int64(100), + mock.MatchedBy(func(opts gitea.MergePullRequestOption) bool { + return opts.Style == gitea.MergeStyleSquash + })). + Return(true, &gitea.Response{}, nil) + + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(100)). + Return(&gitea.PullRequest{ + Index: 100, + State: gitea.StateClosed, + HasMerged: true, + Head: &gitea.PRBranchInfo{Sha: "head_sha"}, + URL: "https://gitea.com/akuity/kargo/pulls/100", + }, &gitea.Response{}, nil).Once() + }, + expectedMerged: true, + }, + { + name: "unsupported merge method", + prNumber: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "bogus"}, + setupMock: func(m *mockGiteaClient) { + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(100)). + Return(&gitea.PullRequest{ + Index: 100, + State: gitea.StateOpen, + Mergeable: true, + Head: &gitea.PRBranchInfo{Sha: "head_sha"}, + URL: "https://gitea.com/akuity/kargo/pulls/100", + }, &gitea.Response{}, nil).Once() + }, + expectError: true, + errorContains: `unsupported merge method "bogus"`, + }, { name: "successful merge", prNumber: 1234, setupMock: func(m *mockGiteaClient) { - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(1234)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(1234)). Return(&gitea.PullRequest{ Index: 1234, State: gitea.StateOpen, @@ -543,11 +591,11 @@ func TestMergePullRequest(t *testing.T) { URL: "https://gitea.com/akuity/kargo/pulls/1234", }, &gitea.Response{}, nil).Once() - m.On("MergePullRequest", mock.Anything, testRepoOwner, testRepoName, - 1234, mock.AnythingOfType("*gitea.MergePullRequestOption")). - Return(&gitea.Response{}, nil) + m.On("MergePullRequest", testRepoOwner, testRepoName, + int64(1234), mock.AnythingOfType("gitea.MergePullRequestOption")). + Return(true, &gitea.Response{}, nil) - m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(1234)). + m.On("GetPullRequest", testRepoOwner, testRepoName, int64(1234)). Return(&gitea.PullRequest{ Index: 1234, State: gitea.StateClosed, @@ -571,7 +619,7 @@ func TestMergePullRequest(t *testing.T) { tt.setupMock(mockClient) - pr, merged, err := p.MergePullRequest(context.Background(), tt.prNumber) + pr, merged, err := p.MergePullRequest(t.Context(), tt.prNumber, tt.mergeOpts) if tt.expectError { require.Error(t, err) diff --git a/pkg/gitprovider/gitea/pr_integration_test.go b/pkg/gitprovider/gitea/pr_integration_test.go new file mode 100644 index 0000000000..e462fdf444 --- /dev/null +++ b/pkg/gitprovider/gitea/pr_integration_test.go @@ -0,0 +1,63 @@ +//go:build integration && gitea + +package gitea + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/gitprovider" + gptest "github.com/akuity/kargo/pkg/gitprovider/testing" +) + +func TestCreateAndMergePullRequest(t *testing.T) { + repoURL := gptest.RequireEnv(t, "TEST_GITEA_REPO_URL") + token := gptest.RequireEnv(t, "TEST_GITEA_TOKEN") + + repoCfg := gptest.RepoConfig{ + RepoURL: repoURL, + Token: token, + GitUsername: gptest.RequireEnv(t, "TEST_GITEA_USERNAME"), + } + + prov, err := NewProvider(repoURL, &gitprovider.Options{Token: token}) + require.NoError(t, err) + + gptest.RunPRTests(t, repoCfg, prov, []gptest.PRTestCase{ + { + Name: "unspecified merge method", + ExpectedParents: 2, // Kargo defaults to "merge" + }, + { + Name: "fast-forward-only", + MergeMethod: "fast-forward-only", + ExpectedParents: 1, + }, + { + Name: "merge", + MergeMethod: "merge", + ExpectedParents: 2, + }, + { + Name: "rebase", + MergeMethod: "rebase", + ExpectedParents: 1, + }, + { + Name: "rebase-merge", + MergeMethod: "rebase-merge", + ExpectedParents: 2, + }, + { + Name: "squash", + MergeMethod: "squash", + ExpectedParents: 1, + }, + { + Name: "invalid merge method", + MergeMethod: "bogus", + ExpectMergeErr: true, + }, + }) +} diff --git a/pkg/gitprovider/github/github.go b/pkg/gitprovider/github/github.go index df1d767c34..804ebe6ddc 100644 --- a/pkg/gitprovider/github/github.go +++ b/pkg/gitprovider/github/github.go @@ -299,7 +299,12 @@ func (p *provider) ListPullRequests( func (p *provider) MergePullRequest( ctx context.Context, id int64, + opts *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { + if opts == nil { + opts = &gitprovider.MergePullRequestOpts{} + } + ghPR, _, err := p.client.GetPullRequests(ctx, p.owner, p.repo, int(id)) if err != nil { return nil, false, fmt.Errorf("error getting pull request %d: %w", id, err) @@ -326,8 +331,8 @@ func (p *provider) MergePullRequest( p.owner, p.repo, int(id), - "", // Use default commit message - &github.PullRequestOptions{}, + "", // Use default commit message. + &github.PullRequestOptions{MergeMethod: opts.MergeMethod}, ) if err != nil { return nil, false, fmt.Errorf("error merging pull request %d: %w", id, err) @@ -335,6 +340,10 @@ func (p *provider) MergePullRequest( if mergeResult == nil { return nil, false, fmt.Errorf("unexpected nil merge result") } + if !ptr.Deref(mergeResult.Merged, false) { + return nil, false, + fmt.Errorf("merge rejected for pull request %d", id) + } updatedPR, _, err := p.client.GetPullRequests(ctx, p.owner, p.repo, int(id)) if err != nil { diff --git a/pkg/gitprovider/github/github_test.go b/pkg/gitprovider/github/github_test.go index 49ab76fd36..12edb9e561 100644 --- a/pkg/gitprovider/github/github_test.go +++ b/pkg/gitprovider/github/github_test.go @@ -258,7 +258,7 @@ func TestCreatePullRequestWithLabels(t *testing.T) { }, } mockClient. - On("CreatePullRequest", context.Background(), testRepoOwner, testRepoName, mock.Anything). + On("CreatePullRequest", t.Context(), testRepoOwner, testRepoName, mock.Anything). Return( &github.PullRequest{ Number: mockClient.pr.Number, @@ -278,7 +278,7 @@ func TestCreatePullRequestWithLabels(t *testing.T) { nil, ) mockClient. - On("AddLabelsToIssue", context.Background(), testRepoOwner, testRepoName, *mockClient.pr.Number, mock.Anything). + On("AddLabelsToIssue", t.Context(), testRepoOwner, testRepoName, *mockClient.pr.Number, mock.Anything). Return( []*github.Label{}, &github.Response{}, @@ -291,7 +291,7 @@ func TestCreatePullRequestWithLabels(t *testing.T) { repo: testRepoName, client: mockClient, } - pr, err := g.CreatePullRequest(context.Background(), &opts) + pr, err := g.CreatePullRequest(t.Context(), &opts) // assert that the expectations were met mockClient.AssertExpectations(t) @@ -327,7 +327,7 @@ func TestGetPullRequest(t *testing.T) { }, } mockClient. - On("GetPullRequests", context.Background(), testRepoOwner, testRepoName, *mockClient.pr.Number). + On("GetPullRequests", t.Context(), testRepoOwner, testRepoName, *mockClient.pr.Number). Return( &github.PullRequest{ Number: mockClient.pr.Number, @@ -348,7 +348,7 @@ func TestGetPullRequest(t *testing.T) { repo: testRepoName, client: mockClient, } - pr, err := g.GetPullRequest(context.Background(), 42) + pr, err := g.GetPullRequest(t.Context(), 42) // assert that the expectations were met mockClient.AssertExpectations(t) @@ -381,7 +381,7 @@ func TestListPullRequests(t *testing.T) { }, } mockClient. - On("ListPullRequests", context.Background(), testRepoOwner, testRepoName, &github.PullRequestListOptions{ + On("ListPullRequests", t.Context(), testRepoOwner, testRepoName, &github.PullRequestListOptions{ State: "all", Head: opts.HeadBranch, Base: opts.BaseBranch, @@ -413,7 +413,7 @@ func TestListPullRequests(t *testing.T) { client: mockClient, } - prs, err := g.ListPullRequests(context.Background(), &opts) + prs, err := g.ListPullRequests(t.Context(), &opts) require.NoError(t, err) require.Equal(t, testRepoOwner, mockClient.owner) @@ -429,12 +429,14 @@ func TestListPullRequests(t *testing.T) { func TestMergePullRequest(t *testing.T) { tests := []struct { - name string - prNumber int64 - setupMock func(*mockGithubClient) - expectedMerged bool - expectError bool - errorContains string + name string + prNumber int64 + mergeOpts *gitprovider.MergePullRequestOpts + setupMock func(*mockGithubClient) + expectedMerged bool + expectError bool + errorContains string + expectMergeOptions *github.PullRequestOptions }{ { name: "error getting initial PR state", @@ -668,6 +670,44 @@ func TestMergePullRequest(t *testing.T) { }, expectedMerged: true, }, + { + name: "successful merge with explicit method", + prNumber: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"}, + setupMock: func(m *mockGithubClient) { + m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(100)). + Return(&github.PullRequest{ + Number: github.Ptr(100), + State: github.Ptr("open"), + Merged: github.Ptr(false), + Mergeable: github.Ptr(true), + Head: &github.PullRequestBranch{SHA: github.Ptr("head_sha")}, + HTMLURL: github.Ptr("https://github.com/akuity/kargo/pull/100"), + }, &github.Response{}, nil).Once() + + m.On("MergePullRequest", mock.Anything, testRepoOwner, testRepoName, int(100), "", + mock.MatchedBy(func(opts *github.PullRequestOptions) bool { + return opts.MergeMethod == "squash" + })). + Return(&github.PullRequestMergeResult{ + SHA: github.Ptr("squash_sha"), + Merged: github.Ptr(true), + Message: github.Ptr("Pull Request successfully merged"), + }, &github.Response{}, nil) + + m.On("GetPullRequests", mock.Anything, testRepoOwner, testRepoName, int(100)). + Return(&github.PullRequest{ + Number: github.Ptr(100), + State: github.Ptr("closed"), + Merged: github.Ptr(true), + MergeCommitSHA: github.Ptr("squash_sha"), + Head: &github.PullRequestBranch{SHA: github.Ptr("head_sha")}, + HTMLURL: github.Ptr("https://github.com/akuity/kargo/pull/100"), + MergedAt: &github.Timestamp{Time: time.Now()}, + }, &github.Response{}, nil).Once() + }, + expectedMerged: true, + }, } for _, tt := range tests { @@ -681,8 +721,11 @@ func TestMergePullRequest(t *testing.T) { tt.setupMock(mockClient) - pr, merged, err := p.MergePullRequest(context.Background(), tt.prNumber) - + pr, merged, err := p.MergePullRequest( + t.Context(), + tt.prNumber, + tt.mergeOpts, + ) if tt.expectError { require.Error(t, err) require.Contains(t, err.Error(), tt.errorContains) diff --git a/pkg/gitprovider/github/pr_integration_test.go b/pkg/gitprovider/github/pr_integration_test.go new file mode 100644 index 0000000000..890b044399 --- /dev/null +++ b/pkg/gitprovider/github/pr_integration_test.go @@ -0,0 +1,53 @@ +//go:build integration && github + +package github + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/gitprovider" + gptest "github.com/akuity/kargo/pkg/gitprovider/testing" +) + +func TestCreateAndMergePullRequest(t *testing.T) { + repoURL := gptest.RequireEnv(t, "TEST_GITHUB_REPO_URL") + token := gptest.RequireEnv(t, "TEST_GITHUB_TOKEN") + + repoCfg := gptest.RepoConfig{ + RepoURL: repoURL, + Token: token, + GitUsername: gptest.RequireEnv(t, "TEST_GITHUB_USERNAME"), + } + + prov, err := NewProvider(repoURL, &gitprovider.Options{Token: token}) + require.NoError(t, err) + + gptest.RunPRTests(t, repoCfg, prov, []gptest.PRTestCase{ + { + Name: "unspecified merge method", + ExpectedParents: 2, // Default is merge commit + }, + { + Name: "merge", + MergeMethod: "merge", + ExpectedParents: 2, + }, + { + Name: "rebase", + MergeMethod: "rebase", + ExpectedParents: 1, + }, + { + Name: "squash", + MergeMethod: "squash", + ExpectedParents: 1, + }, + { + Name: "invalid merge method", + MergeMethod: "bogus", + ExpectMergeErr: true, + }, + }) +} diff --git a/pkg/gitprovider/gitlab/gitlab.go b/pkg/gitprovider/gitlab/gitlab.go index ca7f984cc6..0d8160517e 100644 --- a/pkg/gitprovider/gitlab/gitlab.go +++ b/pkg/gitprovider/gitlab/gitlab.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/go-cleanhttp" gitlab "gitlab.com/gitlab-org/api/client-go" + "k8s.io/utils/ptr" "github.com/akuity/kargo/pkg/gitprovider" "github.com/akuity/kargo/pkg/urls" @@ -209,7 +210,12 @@ func (p *provider) ListPullRequests( func (p *provider) MergePullRequest( _ context.Context, id int64, + opts *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { + if opts == nil { + opts = &gitprovider.MergePullRequestOpts{} + } + glMR, _, err := p.client.GetMergeRequest(p.projectName, id, nil) if err != nil { return nil, false, fmt.Errorf("error getting merge request %d: %w", id, err) @@ -230,9 +236,20 @@ func (p *provider) MergePullRequest( return nil, false, nil } - // Merge the MR + // GitLab's AcceptMergeRequest API only supports "merge" (default) and + // "squash" (via a boolean flag). Other strategies are not available through + // this endpoint. + var squash *bool + switch opts.MergeMethod { + case "", "merge": + // Accept API's default merge method (merge commit) + case "squash": + squash = ptr.To(true) // Opt-in to a squash merge + default: + return nil, false, fmt.Errorf("unsupported merge method %q", opts.MergeMethod) + } updatedMR, _, err := p.client.AcceptMergeRequest( - p.projectName, id, &gitlab.AcceptMergeRequestOptions{}, + p.projectName, id, &gitlab.AcceptMergeRequestOptions{Squash: squash}, ) if err != nil { return nil, false, fmt.Errorf("error merging merge request %d: %w", id, err) diff --git a/pkg/gitprovider/gitlab/gitlab_test.go b/pkg/gitprovider/gitlab/gitlab_test.go index 503a832dd0..2ab50e807b 100644 --- a/pkg/gitprovider/gitlab/gitlab_test.go +++ b/pkg/gitprovider/gitlab/gitlab_test.go @@ -1,7 +1,6 @@ package gitlab import ( - "context" "errors" "testing" @@ -95,7 +94,7 @@ func TestCreatePullRequest(t *testing.T) { Title: "title", Description: "desc", } - pr, err := g.CreatePullRequest(context.Background(), &opts) + pr, err := g.CreatePullRequest(t.Context(), &opts) require.NoError(t, err) require.Equal(t, testProjectName, mockClient.pid) @@ -126,7 +125,7 @@ func TestGetPullRequest(t *testing.T) { client: mockClient, } - pr, err := g.GetPullRequest(context.Background(), 1) + pr, err := g.GetPullRequest(t.Context(), 1) require.NoError(t, err) require.Equal(t, testProjectName, mockClient.pid) @@ -157,7 +156,7 @@ func TestListPullRequests(t *testing.T) { HeadBranch: "head", BaseBranch: "base", } - prs, err := g.ListPullRequests(context.Background(), &opts) + prs, err := g.ListPullRequests(t.Context(), &opts) require.NoError(t, err) require.Equal(t, testProjectName, mockClient.pid) @@ -175,6 +174,7 @@ func TestMergePullRequest(t *testing.T) { name string mockClient *mockGitLabClient id int64 + mergeOpts *gitprovider.MergePullRequestOpts expectErr bool expectMerged bool expectPR bool @@ -350,6 +350,67 @@ func TestMergePullRequest(t *testing.T) { expectMerged: true, expectPR: true, }, + { + name: "successful squash merge", + mockClient: func() *mockGitLabClient { + mc := &mockGitLabClient{} + mc.getMRFunc = func(_ any, _ int64, _ *gitlab.GetMergeRequestsOptions, + _ ...gitlab.RequestOptionFunc, + ) (*gitlab.MergeRequest, *gitlab.Response, error) { + return &gitlab.MergeRequest{ + BasicMergeRequest: gitlab.BasicMergeRequest{ + IID: 100, + State: "opened", + DetailedMergeStatus: "mergeable", + WebURL: "https://gitlab.com/group/project/-/merge_requests/100", + }, + }, &gitlab.Response{}, nil + } + mc.acceptMRFunc = func(_ any, _ int64, opts *gitlab.AcceptMergeRequestOptions, + _ ...gitlab.RequestOptionFunc, + ) (*gitlab.MergeRequest, *gitlab.Response, error) { + // Verify squash merge method is passed correctly + require.NotNil(t, opts.Squash) + require.Equal(t, true, *opts.Squash) + return &gitlab.MergeRequest{ + BasicMergeRequest: gitlab.BasicMergeRequest{ + IID: 100, + MergeCommitSHA: "squash_sha100", + State: "merged", + WebURL: "https://gitlab.com/group/project/-/merge_requests/100", + }, + }, &gitlab.Response{}, nil + } + return mc + }(), + id: 100, + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "squash"}, + expectMerged: true, + expectPR: true, + }, + { + name: "unsupported merge method", + id: 101, + mockClient: func() *mockGitLabClient { + mc := &mockGitLabClient{} + mc.getMRFunc = func(_ any, _ int64, _ *gitlab.GetMergeRequestsOptions, + _ ...gitlab.RequestOptionFunc, + ) (*gitlab.MergeRequest, *gitlab.Response, error) { + return &gitlab.MergeRequest{ + BasicMergeRequest: gitlab.BasicMergeRequest{ + IID: 101, + State: "opened", + DetailedMergeStatus: "mergeable", + WebURL: "https://gitlab.com/group/project/-/merge_requests/101", + }, + }, &gitlab.Response{}, nil + } + return mc + }(), + expectErr: true, + errContains: "unsupported merge method", + mergeOpts: &gitprovider.MergePullRequestOpts{MergeMethod: "rebase"}, + }, } for _, tc := range testCases { @@ -359,7 +420,10 @@ func TestMergePullRequest(t *testing.T) { client: tc.mockClient, } - pr, merged, err := g.MergePullRequest(context.Background(), tc.id) + pr, merged, err := g.MergePullRequest( + t.Context(), tc.id, + tc.mergeOpts, + ) if tc.expectErr { require.Error(t, err) diff --git a/pkg/gitprovider/gitlab/pr_integration_test.go b/pkg/gitprovider/gitlab/pr_integration_test.go new file mode 100644 index 0000000000..c7763dedfb --- /dev/null +++ b/pkg/gitprovider/gitlab/pr_integration_test.go @@ -0,0 +1,50 @@ +//go:build integration && gitlab + +package gitlab + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/gitprovider" + gptest "github.com/akuity/kargo/pkg/gitprovider/testing" +) + +func TestCreateAndMergePullRequest(t *testing.T) { + repoURL := gptest.RequireEnv(t, "TEST_GITLAB_REPO_URL") + token := gptest.RequireEnv(t, "TEST_GITLAB_TOKEN") + + repoCfg := gptest.RepoConfig{ + RepoURL: repoURL, + Token: token, + GitUsername: gptest.RequireEnv(t, "TEST_GITLAB_USERNAME"), + MergeWaitDuration: 10 * time.Second, + } + + prov, err := NewProvider(repoURL, &gitprovider.Options{Token: token}) + require.NoError(t, err) + + gptest.RunPRTests(t, repoCfg, prov, []gptest.PRTestCase{ + { + Name: "unspecified merge method", + ExpectedParents: 2, + }, + { + Name: "merge", + MergeMethod: "merge", + ExpectedParents: 2, + }, + { + Name: "squash", + MergeMethod: "squash", + ExpectedParents: 2, // GitLab squash still produces a merge commit + }, + { + Name: "unsupported merge method", + MergeMethod: "rebase", + ExpectMergeErr: true, + }, + }) +} diff --git a/pkg/gitprovider/gitprovider.go b/pkg/gitprovider/gitprovider.go index 202c371808..66d269ed49 100644 --- a/pkg/gitprovider/gitprovider.go +++ b/pkg/gitprovider/gitprovider.go @@ -57,7 +57,7 @@ type Interface interface { // - *PullRequest: the merged PR if successful // - bool: true if merge was performed, false if PR is not ready to merge // - error: only for actual errors (auth, network, invalid PR, etc.) - MergePullRequest(context.Context, int64) (*PullRequest, bool, error) + MergePullRequest(context.Context, int64, *MergePullRequestOpts) (*PullRequest, bool, error) // GetCommitURL returns a commit URL inferred from the provided repository URL // and commit ID. @@ -96,6 +96,14 @@ type ListPullRequestOptions struct { BaseBranch string } +// MergePullRequestOpts encapsulates the options used when merging a pull +// request. +type MergePullRequestOpts struct { + // MergeMethod is the method to use when merging. If empty, the provider's + // API uses the repository's configured default merge method. + MergeMethod string +} + // PullRequest is an abstracted representation of a Git hosting provider's pull // request object (or equivalent; e.g. a GitLab merge request). type PullRequest struct { @@ -138,7 +146,7 @@ type Fake struct { *ListPullRequestOptions, ) ([]PullRequest, error) // MergePullRequestFn defines the functionality of the MergePullRequest method. - MergePullRequestFn func(context.Context, int64) (*PullRequest, bool, error) + MergePullRequestFn func(context.Context, int64, *MergePullRequestOpts) (*PullRequest, bool, error) // GetCommitURLFn defines the functionality of the GetCommitURL method. GetCommitURLFn func(repoURL string, commitID string) (string, error) } @@ -170,9 +178,10 @@ func (f *Fake) ListPullRequests( // MergePullRequest implements gitprovider.Interface. func (f *Fake) MergePullRequest( ctx context.Context, - number int64, + id int64, + opts *MergePullRequestOpts, ) (*PullRequest, bool, error) { - return f.MergePullRequestFn(ctx, number) + return f.MergePullRequestFn(ctx, id, opts) } // GetCommitURL implements gitprovider.Interface. diff --git a/pkg/gitprovider/testing/helpers.go b/pkg/gitprovider/testing/helpers.go new file mode 100644 index 0000000000..ec3f2b0602 --- /dev/null +++ b/pkg/gitprovider/testing/helpers.go @@ -0,0 +1,276 @@ +//go:build integration + +// Package testing provides shared helpers for gitprovider integration tests. +package testing + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/controller/git" + "github.com/akuity/kargo/pkg/gitprovider" +) + +// RequireEnv returns the value of the named environment variable, or skips the +// test if it is not set. +func RequireEnv(t *testing.T, name string) string { + t.Helper() + v := os.Getenv(name) + if v == "" { + t.Skipf("%s must be set", name) + } + return v +} + +// RepoConfig holds the provider-specific constants needed by the shared test +// helpers. +type RepoConfig struct { + RepoURL string + Token string + GitUsername string + // AuthedRepoURL is the clone URL with credentials embedded. Providers that + // embed credentials differently (e.g. Azure DevOps) must set this + // explicitly. If empty, it is derived as + // https://:@/. + AuthedRepoURL string + // MergeWaitDuration is how long to wait after creating a PR before + // attempting to merge. Some providers (e.g. GitLab) need longer to compute + // mergeability. Defaults to 5 seconds if zero. + MergeWaitDuration time.Duration +} + +func (c RepoConfig) clientOpts() *git.ClientOptions { + return &git.ClientOptions{ + Credentials: &git.RepoCredentials{ + Username: c.GitUsername, + Password: c.Token, + }, + User: &git.User{ + Name: "Kargo Integration Test", + Email: "test@kargo.io", + }, + } +} + +func (c RepoConfig) authedRepoURL() string { + if c.AuthedRepoURL != "" { + return c.AuthedRepoURL + } + const prefix = "https://" + if !strings.HasPrefix(c.RepoURL, prefix) { + return c.RepoURL + } + return fmt.Sprintf( + "%s%s:%s@%s", + prefix, c.GitUsername, c.Token, + c.RepoURL[len(prefix):], + ) +} + +func (c RepoConfig) mergeWait() time.Duration { + if c.MergeWaitDuration > 0 { + return c.MergeWaitDuration + } + return 5 * time.Second +} + +// PRTestCase defines a single test case for the PR integration test. +type PRTestCase struct { + Name string + MergeMethod string + ExpectedParents int + ExpectMergeErr bool +} + +// RunPRTests is the shared test runner for gitprovider integration tests. It +// exercises CreatePullRequest and MergePullRequest for each test case. +func RunPRTests( + t *testing.T, + cfg RepoConfig, + prov gitprovider.Interface, + testCases []PRTestCase, +) { + t.Helper() + ensureMainBranch(t, cfg) + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + branchName := uniqueBranchName(tc.Name) + repo := cloneAndPush(t, cfg, branchName) + defer cleanupBranch(repo, branchName) + + pr, err := prov.CreatePullRequest( + t.Context(), + &gitprovider.CreatePullRequestOpts{ + Title: fmt.Sprintf("integration test: %s", tc.Name), + Head: branchName, + Base: "main", + }, + ) + require.NoError(t, err) + require.NotNil(t, pr) + require.True(t, pr.Open) + + // Give the provider time to compute mergeability -- most of them + // do so asynchronously. + time.Sleep(cfg.mergeWait()) + + var mergeOpts *gitprovider.MergePullRequestOpts + if tc.MergeMethod != "" { + mergeOpts = &gitprovider.MergePullRequestOpts{ + MergeMethod: tc.MergeMethod, + } + } + + mergedPR, merged, mergeErr := prov.MergePullRequest( + t.Context(), pr.Number, mergeOpts, + ) + if tc.ExpectMergeErr { + require.Error(t, mergeErr) + require.False(t, merged) + return + } + require.NoError(t, mergeErr) + require.True(t, merged) + + fetchMain(t, cfg, repo) + requireParentCount( + t, repo, mergedPR.MergeCommitSHA, tc.ExpectedParents, + ) + }) + } +} + +// ensureMainBranch ensures the test repo has a main branch with at least one +// commit. This is idempotent — it's a no-op if main already exists. +func ensureMainBranch(t *testing.T, cfg RepoConfig) { + t.Helper() + if _, err := git.Clone( + cfg.RepoURL, + cfg.clientOpts(), + &git.CloneOptions{Branch: "main", SingleBranch: true}, + ); err == nil { + return // main exists + } + // Empty repo — initialize main. + dir := t.TempDir() + for _, args := range [][]string{ + {"init", "--initial-branch", "main"}, + {"config", "user.name", "Test"}, + {"config", "user.email", "test@test.com"}, + } { + runGit(t, dir, args...) + } + require.NoError(t, os.WriteFile( + filepath.Join(dir, "README.md"), []byte("# test-repo\n"), 0600, + )) + runGit(t, dir, "add", ".") + runGit(t, dir, "commit", "--no-gpg-sign", "-m", "initial commit") + runGit(t, dir, "remote", "add", "origin", cfg.authedRepoURL()) + runGit(t, dir, "push", "-u", "origin", "main") +} + +// uniqueBranchName returns a branch name that is unique and safe for use as a +// git ref. +func uniqueBranchName(testName string) string { + safeName := strings.ReplaceAll(testName, " ", "-") + return fmt.Sprintf( + "integration-test-%s-%d", safeName, time.Now().UnixNano(), + ) +} + +// cloneAndPush clones the test repo, creates a feature branch with a trivial +// commit, and pushes it. +func cloneAndPush( + t *testing.T, cfg RepoConfig, branchName string, +) git.Repo { + t.Helper() + repo, err := git.Clone( + cfg.RepoURL, + cfg.clientOpts(), + &git.CloneOptions{Branch: "main", SingleBranch: true}, + ) + require.NoError(t, err) + require.NoError(t, repo.CreateChildBranch(branchName)) + require.NoError(t, os.WriteFile( + filepath.Join(repo.Dir(), fmt.Sprintf("test-%s.txt", branchName)), + []byte(fmt.Sprintf("test content %d", time.Now().UnixNano())), + 0600, + )) + require.NoError(t, repo.AddAllAndCommit( + fmt.Sprintf("test commit for %s", branchName), nil, + )) + require.NoError(t, repo.Push(nil)) + return repo +} + +// fetchMain fetches the latest main branch from the remote. +func fetchMain(t *testing.T, cfg RepoConfig, repo git.Repo) { + t.Helper() + cmd := exec.Command("git", "fetch", "origin", "main") + cmd.Dir = repo.Dir() + cmd.Env = append( + os.Environ(), + fmt.Sprintf("HOME=%s", repo.HomeDir()), + "GIT_ASKPASS=/usr/local/bin/credential-helper", + fmt.Sprintf("GIT_PASSWORD=%s", cfg.Token), + ) + out, err := cmd.CombinedOutput() + require.NoError(t, err, string(out)) +} + +// requireParentCount asserts that the given commit has the expected number of +// parents. This is used to perform some minimal validation of the merge method +// that was actually used. Two parents indicates a merge commit, while one +// parent indicates a rebase or squash. Note that this is not a perfect test — +// for example, a rebase could produce multiple commits if there are multiple +// commits on the branch, and a merge commit could have only one parent if the +// source branch had only one commit. However, in the context of these tests +// where we create a single commit on the feature branch, it should be +// sufficient to distinguish between merge vs. rebase/squash. +func requireParentCount( + t *testing.T, repo git.Repo, sha string, expected int, +) { + t.Helper() + require.NotEmpty(t, sha, "merge commit SHA must not be empty") + cmd := exec.Command("git", "cat-file", "-p", sha) + cmd.Dir = repo.Dir() + out, err := cmd.CombinedOutput() + require.NoError(t, err, string(out)) + parentCount := 0 + for _, line := range strings.Split(string(out), "\n") { + if strings.HasPrefix(line, "parent ") { + parentCount++ + } + } + require.Equal(t, expected, parentCount, + "commit %s: expected %d parent(s), got %d", sha, expected, parentCount, + ) +} + +// cleanupBranch deletes the remote branch and closes the repo. Best-effort. +func cleanupBranch(repo git.Repo, branchName string) { + cmd := exec.Command("git", "push", "origin", "--delete", branchName) + cmd.Dir = repo.Dir() + cmd.Env = append( + os.Environ(), fmt.Sprintf("HOME=%s", repo.HomeDir()), + ) + _ = cmd.Run() + repo.Close() // nolint: errcheck +} + +// runGit runs a git command in the given directory and fails the test on error. +func runGit(t *testing.T, dir string, args ...string) { + t.Helper() + cmd := exec.Command("git", args...) + cmd.Dir = dir + out, err := cmd.CombinedOutput() + require.NoError(t, err, string(out)) +} diff --git a/pkg/health/aggregating_checker_test.go b/pkg/health/aggregating_checker_test.go index fa1d99550c..5f4c007eeb 100644 --- a/pkg/health/aggregating_checker_test.go +++ b/pkg/health/aggregating_checker_test.go @@ -66,7 +66,7 @@ func TestAggregatingChecker_Check(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() testRegistry := checkerRegistry{} @@ -162,7 +162,7 @@ func TestAggregatingChecker_executeHealthChecks(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() testRegistry := checkerRegistry{} @@ -256,7 +256,7 @@ func TestAggregatingChecker_executeHealthCheck(t *testing.T) { } result := checker.executeHealthCheck( - context.Background(), + t.Context(), "fake-project", "fake-stage", tt.criteria, diff --git a/pkg/health/checker/builtin/argocd.go b/pkg/health/checker/builtin/argocd.go index 139c229809..8866ffa96a 100644 --- a/pkg/health/checker/builtin/argocd.go +++ b/pkg/health/checker/builtin/argocd.go @@ -6,7 +6,6 @@ import ( "fmt" "slices" "strings" - "time" apierrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" @@ -19,8 +18,6 @@ import ( const applicationStatusesKey = "applicationStatuses" -var appHealthCooldownDuration = 10 * time.Second - // ArgoCDHealthInput is the input for a health check associated with the the // argocd-update step. type ArgoCDHealthInput struct { @@ -202,57 +199,46 @@ func (a *argocdChecker) getApplicationHealth( // Reflect the health and sync status of the Argo CD Application. appStatus.ApplicationStatus = app.Status - if appStatus.OperationState != nil && appStatus.OperationState.Phase != argocd.OperationSucceeded { - // This App is in a transitional state. By Kargo Standards, the Stage cannot - // be Healthy. + // Argo CD has separate reconciliation loops for operations (like syncing) and + // assessing App health. This means that immediately following a completed + // operation, App health may reflect state from PRIOR to the operation. If + // that status indicates the App is Healthy, but would have indicated + // otherwise had it not been stale, it creates the possibility of an + // overly-optimistic assessment of Stage health. + // + // Describing Argo CD behavior in greater detail: When an operation completes + // on an App, Argo CD enqueues that App for reconciliation, which will + // reassess health and update the App's status.reconciledAt field. + // + // For our purposes, if reconciledAt is at or after operation completion, we + // can infer that health was assessed after the operation completed and can + // be trusted. Equal timestamps are acceptable because Argo CD always + // enqueues reconciliation after setting finishedAt, so a same-second + // reconciledAt means the health loop ran after the operation completed. + // If reconciledAt is before finishedAt, the health assessment may be + // stale and we need to consider the health status to be unknown. + if app.Status.OperationState != nil && + app.Status.OperationState.FinishedAt != nil && + (app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Before(app.Status.OperationState.FinishedAt)) { + // Request a hard refresh to ensure Argo CD persists its status + // (including reconciledAt) even if nothing else changed. Without + // this, Argo CD may skip the status write after reconciliation + // if health/sync are identical to before the operation, leaving + // reconciledAt stale indefinitely until the next periodic refresh. + libargocd.RequestAppRefresh(ctx, a.argocdClient, app) + // nolint:staticcheck return kargoapi.HealthStateUnknown, appStatus, fmt.Errorf( - "last operation of Argo CD Application %q in namespace %q has "+ - "status %q; Application health status not trusted", + "Argo CD Application %q in namespace %q was not reconciled "+ + "after its most recent operation completed; "+ + "Application health status not trusted", appKey.Name, appKey.Namespace, - appStatus.OperationState.Phase, ) } - // Argo CD has separate reconciliation loops for operations (like syncing) and - // assessing App health. This means that in the moments immediately following - // a completed operation, App health may reflect state from PRIOR to the - // operation. If that status indicates the App is in a Healthy state, but - // would have indicated otherwise had it not been stale, it creates the - // possibility of an overly-optimistic assessment of Stage health. If that - // occurs following a Promotion, it can prompt a verification process to kick - // of prematurely. - // - // To work around this, we will not immediately trust App health if the most - // recently completed operation completed fewer than ten seconds ago. In such - // a case, we will deem Stage health Unknown and return an error. This will - // cause the Stage to be queued for re-reconciliation with a progressive - // backoff. This will continue until the App's health status is considered - // reliable. - // - // TODO(krancour): This workaround can be revisited if/when - // https://github.com/argoproj/argo-cd/pull/21120 is merged, as (for newer - // versions of Argo CD, at least) it will allow us to accurately determine - // whether an App's health was last assessed before or after its most recent - // operation completed. - if app.Status.OperationState != nil && app.Status.OperationState.FinishedAt != nil { - if time.Since(app.Status.OperationState.FinishedAt.Time) < appHealthCooldownDuration { - return kargoapi.HealthStateUnknown, - appStatus, - fmt.Errorf( - "last operation of Argo CD Application %q in namespace %q completed "+ - "less than %s ago; Application health status not trusted", - appKey.Name, - appKey.Namespace, - appHealthCooldownDuration, - ) - } - } - - // If we get to here, we assume the Argo CD Application's health state is - // reliable. + // If we get to here, we can trust the Argo CD Application's status. // Check for any error conditions. If these are found, the application is // considered unhealthy as they may indicate a problem which can result in @@ -272,17 +258,15 @@ func (a *argocdChecker) getApplicationHealth( return kargoapi.HealthStateUnhealthy, appStatus, errors.Join(issues...) } - stageHealth, err := a.stageHealthForAppHealth(app) - if err != nil || stageHealth != kargoapi.HealthStateHealthy { - // If there was an error or the App is not Healthy, we're done. + // Check sync status before health status. After an operation completes, the + // sync revision is updated immediately by the operation, while health may + // still reflect pre-operation state. By checking sync first, a wrong + // revision is caught before we even consider health. + if stageHealth, err := a.stageHealthForAppSync(app, desiredRevisions); err != nil { return stageHealth, appStatus, err } - // If we get to here, the App is Healthy and, so far, the Stage appears to be - // as well. If desiredRevisions are known, however, this needs to be factored - // into Stage health. Assess how App sources being synced to the correct or - // incorrect revisions affects overall Stage health: - stageHealth, err = a.stageHealthForAppSync(app, desiredRevisions) + stageHealth, err := a.stageHealthForAppHealth(app) return stageHealth, appStatus, err } diff --git a/pkg/health/checker/builtin/argocd_test.go b/pkg/health/checker/builtin/argocd_test.go index 4149c6a6a6..e2f13c875e 100644 --- a/pkg/health/checker/builtin/argocd_test.go +++ b/pkg/health/checker/builtin/argocd_test.go @@ -59,9 +59,12 @@ func Test_argocdUpdater_check(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusHealthy, }, @@ -80,9 +83,12 @@ func Test_argocdUpdater_check(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Conditions: []argocd.ApplicationCondition{ {Type: argocd.ApplicationConditionComparisonError}, {Type: argocd.ApplicationConditionInvalidSpecError}, @@ -118,9 +124,12 @@ func Test_argocdUpdater_check(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusHealthy, }, @@ -142,9 +151,12 @@ func Test_argocdUpdater_check(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusHealthy, }, @@ -172,7 +184,7 @@ func Test_argocdUpdater_check(t *testing.T) { testCase.assertions( t, runner.check( - context.Background(), + t.Context(), ArgoCDHealthInput{ Apps: []ArgoCDAppHealthCheck{ { @@ -223,7 +235,13 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { appStatus argocd.ApplicationStatus interceptor interceptor.Funcs desiredRevisions []string - assertions func(*testing.T, kargoapi.HealthState, ArgoCDAppStatus, error) + assertions func( + *testing.T, + kargoapi.HealthState, + ArgoCDAppStatus, + client.Client, + error, + ) }{ { name: "Application not found", @@ -243,6 +261,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.ErrorContains(t, err, "unable to find Argo CD Application") @@ -268,6 +287,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.ErrorContains(t, err, "error finding Argo CD Application") @@ -278,52 +298,90 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { }, }, { - name: "Application has an in-progress operation", + name: "Application not reconciled after last operation", appStatus: argocd.ApplicationStatus{ - OperationState: &argocd.OperationState{Phase: argocd.OperationRunning}, - Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), + }, + }, + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, }, assertions: func( t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + c client.Client, err error, ) { require.Error(t, err) - require.ErrorContains(t, err, "last operation of Argo CD Application") - require.ErrorContains(t, err, string(argocd.OperationRunning)) + require.ErrorContains(t, err, "was not reconciled after") require.ErrorContains(t, err, "Application health status not trusted") require.Equal(t, kargoapi.HealthStateUnknown, stageHealth) require.Equal(t, testApp.Namespace, appStatus.Namespace) require.Equal(t, testApp.Name, appStatus.Name) require.Equal(t, argocd.HealthStatusHealthy, appStatus.Health.Status) + // Verify hard refresh was requested + app := &argocd.Application{} + require.NoError(t, c.Get( + context.Background(), + client.ObjectKey{ + Namespace: testApp.Namespace, + Name: testApp.Name, + }, + app, + )) + require.Equal( + t, + string(argocd.RefreshTypeHard), + app.Annotations[argocd.AnnotationKeyRefresh], + ) }, }, { - name: "Application's last operation completed recently", + name: "Application reconciled before last operation completed", appStatus: argocd.ApplicationStatus{ OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1*appHealthCooldownDuration + appHealthCooldownDuration/2), + Time: time.Date(2024, 1, 1, 0, 0, 10, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 5, 0, time.UTC), + }, Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, }, assertions: func( t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + c client.Client, err error, ) { require.Error(t, err) - require.ErrorContains(t, err, "last operation of Argo CD Application") - require.ErrorContains(t, err, "completed less than") + require.ErrorContains(t, err, "was not reconciled after") require.ErrorContains(t, err, "Application health status not trusted") require.Equal(t, kargoapi.HealthStateUnknown, stageHealth) require.Equal(t, testApp.Namespace, appStatus.Namespace) require.Equal(t, testApp.Name, appStatus.Name) require.Equal(t, argocd.HealthStatusHealthy, appStatus.Health.Status) + // Verify hard refresh was requested + app := &argocd.Application{} + require.NoError(t, c.Get( + context.Background(), + client.ObjectKey{ + Namespace: testApp.Namespace, + Name: testApp.Name, + }, + app, + )) + require.Equal( + t, + string(argocd.RefreshTypeHard), + app.Annotations[argocd.AnnotationKeyRefresh], + ) }, }, { @@ -332,9 +390,12 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Conditions: []argocd.ApplicationCondition{ { Type: argocd.ApplicationConditionComparisonError, @@ -357,6 +418,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.Error(t, err) @@ -378,9 +440,12 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusDegraded, Message: "fake-message", @@ -393,6 +458,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.ErrorContains(t, err, "Argo CD Application") @@ -411,9 +477,12 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusHealthy, Message: "fake-message", @@ -426,6 +495,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.NoError(t, err) @@ -442,9 +512,12 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusHealthy, }, @@ -458,6 +531,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.ErrorContains(t, err, "Not all sources of Application") @@ -476,9 +550,12 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { OperationState: &argocd.OperationState{ Phase: argocd.OperationSucceeded, FinishedAt: &metav1.Time{ - Time: time.Now().Add(-1 * appHealthCooldownDuration), + Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), }, }, + ReconciledAt: &metav1.Time{ + Time: time.Date(2024, 1, 1, 0, 0, 1, 0, time.UTC), + }, Health: argocd.HealthStatus{ Status: argocd.HealthStatusHealthy, }, @@ -492,6 +569,7 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t *testing.T, stageHealth kargoapi.HealthState, appStatus ArgoCDAppStatus, + _ client.Client, err error, ) { require.NoError(t, err) @@ -508,22 +586,21 @@ func Test_argocdUpdater_getApplicationHealth(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { app := testApp.DeepCopy() app.Status = testCase.appStatus - runner := &argocdChecker{ - argocdClient: fake.NewClientBuilder(). - WithScheme(scheme). - WithObjects(app). - WithInterceptorFuncs(testCase.interceptor). - Build(), - } + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(app). + WithInterceptorFuncs(testCase.interceptor). + Build() + runner := &argocdChecker{argocdClient: fakeClient} stageHealth, appStatus, err := runner.getApplicationHealth( - context.Background(), + t.Context(), client.ObjectKey{ Namespace: app.Namespace, Name: app.Name, }, testCase.desiredRevisions, ) - testCase.assertions(t, stageHealth, appStatus, err) + testCase.assertions(t, stageHealth, appStatus, fakeClient, err) }) } } diff --git a/pkg/health/mock_aggregating_checker_test.go b/pkg/health/mock_aggregating_checker_test.go index bef5bc6fc0..8a676c21fa 100644 --- a/pkg/health/mock_aggregating_checker_test.go +++ b/pkg/health/mock_aggregating_checker_test.go @@ -12,12 +12,12 @@ import ( func TestMockAggregatingChecker_Check(t *testing.T) { t.Run("without function injection", func(t *testing.T) { checker := &MockAggregatingChecker{} - res := checker.Check(context.Background(), "fake-project", "fake-stage", nil) + res := checker.Check(t.Context(), "fake-project", "fake-stage", nil) assert.Equal(t, kargoapi.HealthStateHealthy, res.Status) }) t.Run("with function injection", func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() const testProject = "fake-project" const testStage = "fake-stage" criteria := []Criteria{{Kind: "mock"}} diff --git a/pkg/helm/chart/base_selector.go b/pkg/helm/chart/base_selector.go index 7a7ab597b0..7dd99ebf36 100644 --- a/pkg/helm/chart/base_selector.go +++ b/pkg/helm/chart/base_selector.go @@ -14,17 +14,19 @@ import ( // functionality for all Selector implementations. It is not intended to be used // directly. type baseSelector struct { - repoURL string - constraint *semver.Constraints - discoveryLimit int + repoURL string + constraint *semver.Constraints + discoveryLimit int + insecureSkipTLSVerify bool } func newBaseSelector( sub kargoapi.ChartSubscription, ) (*baseSelector, error) { s := &baseSelector{ - repoURL: sub.RepoURL, - discoveryLimit: int(sub.DiscoveryLimit), + repoURL: sub.RepoURL, + discoveryLimit: int(sub.DiscoveryLimit), + insecureSkipTLSVerify: sub.InsecureSkipTLSVerify, } if sub.SemverConstraint != "" { var err error diff --git a/pkg/helm/chart/http_selector.go b/pkg/helm/chart/http_selector.go index 0aa80e9d1e..0d462b6cfc 100644 --- a/pkg/helm/chart/http_selector.go +++ b/pkg/helm/chart/http_selector.go @@ -2,12 +2,14 @@ package chart import ( "context" + "crypto/tls" "fmt" "io" "net/http" "strings" "github.com/Masterminds/semver/v3" + "github.com/hashicorp/go-cleanhttp" "gopkg.in/yaml.v3" kargoapi "github.com/akuity/kargo/api/v1alpha1" @@ -52,11 +54,15 @@ func (h *httpSelector) Select(context.Context) ([]string, error) { if h.creds != nil { req.SetBasicAuth(h.creds.Username, h.creds.Password) } - // #nosec G704 -- Despite the user-specified URL, the possibility of SSRF here - // is mitigated by many factors, including the user's inability to specify an - // HTTP method or request headers, and the fact of the user having no access - // to the response. - res, err := http.DefaultClient.Do(req) + httpClient := http.DefaultClient + if h.insecureSkipTLSVerify { + httpTransport := cleanhttp.DefaultTransport() + httpTransport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, // #nosec G402 -- explicitly allowed by insecureSkipTLSVerify + } + httpClient = &http.Client{Transport: httpTransport} + } + res, err := httpClient.Do(req) // #nosec G704 -- SSRF mitigated: no method/header control, no response access if err != nil { return nil, fmt.Errorf("error querying repository index at %q: %w", h.indexURL, err) diff --git a/pkg/helm/chart/http_selector_test.go b/pkg/helm/chart/http_selector_test.go index baa7336c2a..b94014245a 100644 --- a/pkg/helm/chart/http_selector_test.go +++ b/pkg/helm/chart/http_selector_test.go @@ -1,7 +1,6 @@ package chart import ( - "context" "fmt" "net/http" "net/http/httptest" @@ -69,6 +68,60 @@ func TestNewHTTPSelector(t *testing.T) { } } +func Test_httpSelector_Select_insecureTLS(t *testing.T) { + // Use a TLS test server with a self-signed certificate to verify that + // insecureSkipTLSVerify controls whether TLS errors are ignored. + tlsServer := httptest.NewTLSServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte(`entries: + fake-chart: + - version: 1.0.0 +`)) + require.NoError(t, err) + }), + ) + defer tlsServer.Close() + + testCases := []struct { + name string + insecureSkipTLSVerify bool + assertions func(t *testing.T, versions []string, err error) + }{ + { + name: "TLS error when insecureSkipTLSVerify is false", + insecureSkipTLSVerify: false, + assertions: func(t *testing.T, _ []string, err error) { + require.ErrorContains(t, err, "error querying repository index") + }, + }, + { + name: "success when insecureSkipTLSVerify is true", + insecureSkipTLSVerify: true, + assertions: func(t *testing.T, versions []string, err error) { + require.NoError(t, err) + require.Equal(t, []string{"1.0.0"}, versions) + }, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + repoURL := fmt.Sprintf("%s/fake-repo", tlsServer.URL) + s := &httpSelector{ + baseSelector: &baseSelector{ + repoURL: repoURL, + insecureSkipTLSVerify: testCase.insecureSkipTLSVerify, + }, + indexURL: fmt.Sprintf("%s/index.yaml", repoURL), + chartName: "fake-chart", + } + versions, err := s.Select(t.Context()) + testCase.assertions(t, versions, err) + }) + } +} + func Test_httpSelector_Select(t *testing.T) { // This is a mock registry. Depending on the request path, it returns a 404, // invalid YAML, or valid YAML. @@ -147,7 +200,7 @@ func Test_httpSelector_Select(t *testing.T) { ), chartName: testCase.chart, } - versions, err := s.Select(context.Background()) + versions, err := s.Select(t.Context()) testCase.assertions(t, versions, err) }) } diff --git a/pkg/helm/chart/oci_selector.go b/pkg/helm/chart/oci_selector.go index 45f789e823..9e291e7e6e 100644 --- a/pkg/helm/chart/oci_selector.go +++ b/pkg/helm/chart/oci_selector.go @@ -35,7 +35,7 @@ func newOCISelector( fmt.Errorf("error parsing repository URL %q: %w", sub.RepoURL, err) } - authorizer := helm.NewEphemeralAuthorizer() + authorizer := helm.NewEphemeralAuthorizer(sub.InsecureSkipTLSVerify) if creds != nil { if err = authorizer.Login(context.Background(), ref.Host(), creds.Username, creds.Password); err != nil { return nil, fmt.Errorf( diff --git a/pkg/helm/chart/oci_selector_test.go b/pkg/helm/chart/oci_selector_test.go index 273afddb5b..47870cca37 100644 --- a/pkg/helm/chart/oci_selector_test.go +++ b/pkg/helm/chart/oci_selector_test.go @@ -1,7 +1,6 @@ package chart import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -47,6 +46,19 @@ func TestNewOCISelector(t *testing.T) { require.NotNil(t, o.repo) }, }, + { + name: "insecureSkipTLSVerify propagated to authorizer", + sub: kargoapi.ChartSubscription{ + RepoURL: "oci://charts.example.com/repo", + InsecureSkipTLSVerify: true, + }, + assertions: func(t *testing.T, s Selector, err error) { + require.NoError(t, err) + o, ok := s.(*ociSelector) + require.True(t, ok) + require.True(t, o.insecureSkipTLSVerify) + }, + }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { @@ -66,7 +78,7 @@ func Test_ociSelector_Select(t *testing.T) { nil, ) require.NoError(t, err) - versions, err := s.Select(context.Background()) + versions, err := s.Select(t.Context()) require.NoError(t, err) require.NotEmpty(t, versions) } diff --git a/pkg/helm/dependency_manager.go b/pkg/helm/dependency_manager.go index 3610c5ac5d..8abeea4c20 100644 --- a/pkg/helm/dependency_manager.go +++ b/pkg/helm/dependency_manager.go @@ -62,7 +62,7 @@ func NewEphemeralDependencyManager( return &EphemeralDependencyManager{ credsDB: credsDB, - authorizer: NewEphemeralAuthorizer(), + authorizer: NewEphemeralAuthorizer(false), helmHome: home, project: project, workDir: workDir, diff --git a/pkg/helm/dependency_manager_test.go b/pkg/helm/dependency_manager_test.go index 8e42e9f242..8c2953b43c 100644 --- a/pkg/helm/dependency_manager_test.go +++ b/pkg/helm/dependency_manager_test.go @@ -110,7 +110,7 @@ func TestEphemeralDependencyManager_update(t *testing.T) { b, err := os.ReadFile("testdata/charts/demo-0.1.0.tgz") require.NoError(t, err) - client, err := NewRegistryClient(NewEphemeralAuthorizer().Client) + client, err := NewRegistryClient(NewEphemeralAuthorizer(false).Client) require.NoError(t, err) _, err = client.Push(b, hostForRepositoryURL(server.URL)+"/demo:0.1.0") require.NoError(t, err) @@ -236,7 +236,7 @@ generated: "2023-01-01T00:00:00Z" t.Run(tt.name, func(t *testing.T) { em := &EphemeralDependencyManager{ credsDB: &credentials.FakeDB{}, - authorizer: NewEphemeralAuthorizer(), + authorizer: NewEphemeralAuthorizer(false), workDir: absoluteTempDir(t), helmHome: absoluteTempDir(t), } @@ -292,7 +292,7 @@ generated: "2023-01-01T00:00:00Z" Version: dep.Version, } } - require.NoError(t, em.setupRepositories(context.Background(), dependencies)) + require.NoError(t, em.setupRepositories(t.Context(), dependencies)) } updates, err := em.update(chartDir) @@ -728,7 +728,7 @@ func TestEphemeralDependencyManager_setupRepositories(t *testing.T) { // Verify an entry exists for the OCI host ociHost := hostForRepositoryURL(ociServer) - entry, err := em.authorizer.Get(context.Background(), ociHost) + entry, err := em.authorizer.Get(t.Context(), ociHost) assert.NoError(t, err) assert.NotNil(t, entry) }, @@ -819,7 +819,7 @@ func TestEphemeralDependencyManager_setupRepositories(t *testing.T) { // Verify an entry exists for the OCI host ociHost := hostForRepositoryURL(ociServer) - entry, err := em.authorizer.Get(context.Background(), ociHost) + entry, err := em.authorizer.Get(t.Context(), ociHost) assert.NoError(t, err) assert.NotNil(t, entry) }, @@ -832,7 +832,7 @@ func TestEphemeralDependencyManager_setupRepositories(t *testing.T) { em := &EphemeralDependencyManager{ helmHome: tempDir, - authorizer: NewEphemeralAuthorizer(), + authorizer: NewEphemeralAuthorizer(false), credsDB: tt.credsDB, } @@ -852,7 +852,7 @@ func TestEphemeralDependencyManager_setupRepositories(t *testing.T) { } } - err := em.setupRepositories(context.Background(), dependencies) + err := em.setupRepositories(t.Context(), dependencies) tt.assertions(t, registryURL, em, err) }) } diff --git a/pkg/helm/registry.go b/pkg/helm/registry.go index 3cb2eb0b34..604fa64dc1 100644 --- a/pkg/helm/registry.go +++ b/pkg/helm/registry.go @@ -48,10 +48,18 @@ type EphemeralAuthorizer struct { // NewEphemeralAuthorizer creates a new EphemeralAuthorizer with an in-memory // credentials store. This authorizer does not persist credentials to disk and // is suitable for temporary operations where you do not want to store -// credentials permanently. -func NewEphemeralAuthorizer() *EphemeralAuthorizer { - httpClient := cleanhttp.DefaultClient() - httpClient.Transport = retry.NewTransport(newTransport(httpClient.Transport)) +// credentials permanently. When insecure is true, TLS certificate verification +// errors are ignored. This should be enabled only with great caution. +func NewEphemeralAuthorizer(insecure bool) *EphemeralAuthorizer { + transport := cleanhttp.DefaultTransport() + if insecure { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, // #nosec G402 -- explicitly allowed by insecureSkipTLSVerify + } + } + httpClient := &http.Client{ + Transport: retry.NewTransport(newTransport(transport)), + } store := credentials.NewMemoryStore() diff --git a/pkg/helm/registry_test.go b/pkg/helm/registry_test.go index 9d3a0218e7..806881f5b7 100644 --- a/pkg/helm/registry_test.go +++ b/pkg/helm/registry_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras-go/v2/registry/remote/credentials" + "oras.land/oras-go/v2/registry/remote/retry" "github.com/akuity/kargo/pkg/x/version" ) @@ -19,7 +20,7 @@ func TestNewRegistryClient(t *testing.T) { }{ { name: "successful creation with ephemeral authorizer", - authorizer: NewEphemeralAuthorizer().Client, + authorizer: NewEphemeralAuthorizer(false).Client, assertions: func(t *testing.T, client any, err error) { assert.NoError(t, err) assert.NotNil(t, client) @@ -48,16 +49,42 @@ func TestNewRegistryClient(t *testing.T) { } func TestNewEphemeralAuthorizer(t *testing.T) { - authorizer := NewEphemeralAuthorizer() - - assert.NotNil(t, authorizer) - assert.NotNil(t, authorizer.Client) - assert.NotNil(t, authorizer.Store) - assert.NotNil(t, authorizer.Client.Client) - assert.NotNil(t, authorizer.Cache) - assert.NotNil(t, authorizer.Credential) - - // Verify the user agent is set correctly - expectedUserAgent := "Kargo/" + version.GetVersion().Version - assert.Contains(t, authorizer.Header.Get("User-Agent"), expectedUserAgent) + t.Run("skipping tls cert verification", func(t *testing.T) { + authorizer := NewEphemeralAuthorizer(false) + + assert.NotNil(t, authorizer) + assert.NotNil(t, authorizer.Client) + assert.NotNil(t, authorizer.Store) + assert.NotNil(t, authorizer.Client.Client) + assert.NotNil(t, authorizer.Cache) + assert.NotNil(t, authorizer.Credential) + + // Verify the user agent is set correctly + expectedUserAgent := "Kargo/" + version.GetVersion().Version + assert.Contains(t, authorizer.Header.Get("User-Agent"), expectedUserAgent) + }) + + t.Run("insecure", func(t *testing.T) { + authorizer := NewEphemeralAuthorizer(true) + + assert.NotNil(t, authorizer) + assert.NotNil(t, authorizer.Client.Client) + + // Unwrap the transport chain: retry.Transport -> fallbackTransport -> + // *http.Transport to verify InsecureSkipVerify is set. + retryT, ok := authorizer.Client.Client.Transport.(*retry.Transport) + assert.True(t, ok, "expected outermost transport to be *retry.Transport") + if ok { + fallbackT, ok := retryT.Base.(*fallbackTransport) + assert.True(t, ok, "expected inner transport to be *fallbackTransport") + if ok { + httpT, ok := fallbackT.Base.(*http.Transport) + assert.True(t, ok, "expected base transport to be *http.Transport") + if ok { + assert.NotNil(t, httpT.TLSClientConfig) + assert.True(t, httpT.TLSClientConfig.InsecureSkipVerify) + } + } + } + }) } diff --git a/pkg/image/mutate/mutate.go b/pkg/image/mutate/mutate.go new file mode 100644 index 0000000000..abbff2d417 --- /dev/null +++ b/pkg/image/mutate/mutate.go @@ -0,0 +1,295 @@ +package mutate + +import ( + "encoding/json" + "fmt" + "maps" + "sync" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/types" +) + +// Annotations wraps an OCI artifact to overlay annotations on its manifest. +// The input must be a v1.Image or v1.ImageIndex. +// +// For a v1.Image, only manifestAnnotations are applied; indexAnnotations +// are ignored. For a v1.ImageIndex, indexAnnotations are applied to the +// index manifest and manifestAnnotations to each child image manifest. +// +// This function exists because go-containerregistry's mutate.Annotations has +// a Layers() implementation that enumerates layers via +// ConfigFile().RootFS.DiffIDs, which is empty for non-Docker OCI artifacts +// (e.g. Helm charts). This causes layers to be omitted from the push, leading +// to MANIFEST_BLOB_UNKNOWN errors on cross-repository pushes. The wrappers +// here delegate Layers() and all other methods to the base artifact, overriding +// only the manifest to include annotations. +func Annotations( + f partial.WithRawManifest, + indexAnnotations, manifestAnnotations map[string]string, +) (partial.WithRawManifest, error) { + switch v := f.(type) { + case v1.Image: + if len(manifestAnnotations) == 0 { + return v, nil + } + return &image{base: v, annotations: manifestAnnotations}, nil + case v1.ImageIndex: + if len(indexAnnotations) == 0 && len(manifestAnnotations) == 0 { + return v, nil + } + return newIndex(v, indexAnnotations, manifestAnnotations) + default: + return nil, fmt.Errorf("unsupported type for annotation: %T", f) + } +} + +// image wraps a v1.Image to overlay annotations on its manifest. All methods +// delegate to the base image; only the manifest is modified. +type image struct { + base v1.Image + annotations map[string]string + + computed bool + manifest *v1.Manifest + sync.Mutex +} + +var _ v1.Image = (*image)(nil) + +func (i *image) compute() error { + i.Lock() + defer i.Unlock() + if i.computed { + return nil + } + m, err := i.base.Manifest() + if err != nil { + return err + } + manifest := m.DeepCopy() + if manifest.Annotations == nil { + manifest.Annotations = map[string]string{} + } + maps.Copy(manifest.Annotations, i.annotations) + i.manifest = manifest + i.computed = true + return nil +} + +func (i *image) MediaType() (types.MediaType, error) { + return i.base.MediaType() +} + +func (i *image) Layers() ([]v1.Layer, error) { + return i.base.Layers() +} + +func (i *image) ConfigName() (v1.Hash, error) { + return i.base.ConfigName() +} + +func (i *image) ConfigFile() (*v1.ConfigFile, error) { + return i.base.ConfigFile() +} + +func (i *image) RawConfigFile() ([]byte, error) { + return i.base.RawConfigFile() +} + +func (i *image) LayerByDigest(h v1.Hash) (v1.Layer, error) { + return i.base.LayerByDigest(h) +} + +func (i *image) LayerByDiffID(h v1.Hash) (v1.Layer, error) { + return i.base.LayerByDiffID(h) +} + +func (i *image) Manifest() (*v1.Manifest, error) { + if err := i.compute(); err != nil { + return nil, err + } + return i.manifest.DeepCopy(), nil +} + +func (i *image) RawManifest() ([]byte, error) { + if err := i.compute(); err != nil { + return nil, err + } + return json.Marshal(i.manifest) +} + +func (i *image) Digest() (v1.Hash, error) { + if err := i.compute(); err != nil { + return v1.Hash{}, err + } + return partial.Digest(i) +} + +func (i *image) Size() (int64, error) { + if err := i.compute(); err != nil { + return -1, err + } + return partial.Size(i) +} + +// annotatedChild holds the precomputed digest and size of an annotated child +// image, used to rewrite index manifest descriptors. +type annotatedChild struct { + digest v1.Hash + size int64 +} + +// index wraps a v1.ImageIndex to overlay scoped annotations. Index-scoped +// annotations are applied to the index manifest; manifest-scoped annotations +// are applied to each child image manifest via Image(). When manifest +// annotations are present, child descriptors are rewritten with updated +// digests/sizes to stay consistent with the annotated content. +type index struct { + base v1.ImageIndex + indexAnnotations map[string]string + manifestAnnotations map[string]string + // childMap maps original child digest → annotated digest/size. + // Populated eagerly by newIndex when manifestAnnotations is non-empty. + childMap map[v1.Hash]annotatedChild + + computed bool + manifest *v1.IndexManifest + sync.Mutex +} + +var _ v1.ImageIndex = (*index)(nil) + +// newIndex creates an index wrapper. When manifest annotations are provided, +// it eagerly computes the annotated digest and size for each child image so +// that IndexManifest() and Image() stay consistent. +func newIndex( + base v1.ImageIndex, + indexAnnotations, manifestAnnotations map[string]string, +) (*index, error) { + idx := &index{ + base: base, + indexAnnotations: indexAnnotations, + manifestAnnotations: manifestAnnotations, + childMap: make(map[v1.Hash]annotatedChild), + } + if len(manifestAnnotations) > 0 { + m, err := base.IndexManifest() + if err != nil { + return nil, fmt.Errorf("failed to get index manifest: %w", err) + } + for _, desc := range m.Manifests { + if !desc.MediaType.IsImage() { + continue + } + img, err := base.Image(desc.Digest) + if err != nil { + return nil, fmt.Errorf( + "failed to resolve child image %s: %w", desc.Digest, err, + ) + } + wrapped := &image{base: img, annotations: manifestAnnotations} + d, err := wrapped.Digest() + if err != nil { + return nil, fmt.Errorf( + "failed to compute annotated digest for %s: %w", + desc.Digest, err, + ) + } + s, err := wrapped.Size() + if err != nil { + return nil, fmt.Errorf( + "failed to compute annotated size for %s: %w", + desc.Digest, err, + ) + } + idx.childMap[desc.Digest] = annotatedChild{digest: d, size: s} + } + } + return idx, nil +} + +func (a *index) compute() error { + a.Lock() + defer a.Unlock() + if a.computed { + return nil + } + m, err := a.base.IndexManifest() + if err != nil { + return err + } + manifest := m.DeepCopy() + if len(a.indexAnnotations) > 0 { + if manifest.Annotations == nil { + manifest.Annotations = map[string]string{} + } + maps.Copy(manifest.Annotations, a.indexAnnotations) + } + // Rewrite child descriptors with annotated digests/sizes. + for i, desc := range manifest.Manifests { + if child, ok := a.childMap[desc.Digest]; ok { + manifest.Manifests[i].Digest = child.digest + manifest.Manifests[i].Size = child.size + } + } + a.manifest = manifest + a.computed = true + return nil +} + +func (a *index) MediaType() (types.MediaType, error) { + return a.base.MediaType() +} + +func (a *index) IndexManifest() (*v1.IndexManifest, error) { + if err := a.compute(); err != nil { + return nil, err + } + return a.manifest.DeepCopy(), nil +} + +func (a *index) RawManifest() ([]byte, error) { + if err := a.compute(); err != nil { + return nil, err + } + return json.Marshal(a.manifest) +} + +func (a *index) Digest() (v1.Hash, error) { + if err := a.compute(); err != nil { + return v1.Hash{}, err + } + return partial.Digest(a) +} + +func (a *index) Size() (int64, error) { + if err := a.compute(); err != nil { + return -1, err + } + return partial.Size(a) +} + +func (a *index) Image(h v1.Hash) (v1.Image, error) { + // Reverse-map: if h is an annotated digest, find the original. + origHash := h + for orig, child := range a.childMap { + if child.digest == h { + origHash = orig + break + } + } + img, err := a.base.Image(origHash) + if err != nil { + return nil, err + } + if len(a.manifestAnnotations) > 0 { + return &image{base: img, annotations: a.manifestAnnotations}, nil + } + return img, nil +} + +func (a *index) ImageIndex(h v1.Hash) (v1.ImageIndex, error) { + return a.base.ImageIndex(h) +} diff --git a/pkg/image/mutate/mutate_test.go b/pkg/image/mutate/mutate_test.go new file mode 100644 index 0000000000..5940ef631d --- /dev/null +++ b/pkg/image/mutate/mutate_test.go @@ -0,0 +1,266 @@ +package mutate + +import ( + "testing" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/random" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestAnnotations_dockerImage verifies that Annotations merges annotations onto +// a Docker-format image manifest, changes the digest, and does not mutate the +// base image. +func TestAnnotations_dockerImage(t *testing.T) { + base, err := random.Image(256, 2) + require.NoError(t, err) + + baseManifest, err := base.Manifest() + require.NoError(t, err) + baseDigest, err := base.Digest() + require.NoError(t, err) + + annotations := map[string]string{ + "io.kargo.test": "true", + "org.example": "value", + } + + result, err := Annotations(base, nil, annotations) + require.NoError(t, err) + img, ok := result.(v1.Image) + require.True(t, ok, "expected v1.Image") + + // Annotations appear on the annotated manifest. + m, err := img.Manifest() + require.NoError(t, err) + assert.Equal(t, "true", m.Annotations["io.kargo.test"]) + assert.Equal(t, "value", m.Annotations["org.example"]) + + // Digest changes. + d, err := img.Digest() + require.NoError(t, err) + assert.NotEqual(t, baseDigest, d) + + // Digest is stable across calls (compute-once). + d2, err := img.Digest() + require.NoError(t, err) + assert.Equal(t, d, d2) + + // Base manifest is not mutated. + baseAfter, err := base.Manifest() + require.NoError(t, err) + assert.Equal(t, baseManifest.Annotations, baseAfter.Annotations) +} + +// TestAnnotations_ociImage verifies that Annotations works on an OCI-format +// image with empty DiffIDs (e.g. Helm charts), a regression case for +// go-containerregistry's mutate.Annotations which would cause +// MANIFEST_BLOB_UNKNOWN errors on cross-repo pushes. +func TestAnnotations_ociImage(t *testing.T) { + base := empty.Image + + annotations := map[string]string{ + "io.kargo.helm": "chart", + } + + result, err := Annotations(base, nil, annotations) + require.NoError(t, err) + img := result.(v1.Image) //nolint:forcetypeassert + + m, err := img.Manifest() + require.NoError(t, err) + assert.Equal(t, "chart", m.Annotations["io.kargo.helm"]) + + // Layers should delegate to base and not break. + layers, err := img.Layers() + require.NoError(t, err) + assert.Empty(t, layers) +} + +// TestAnnotations_imageLayers verifies that Layers() delegates to the base +// image rather than enumerating via ConfigFile.RootFS.DiffIDs. This ensures +// all layers are preserved during cross-repository pushes. +func TestAnnotations_imageLayers(t *testing.T) { + base, err := random.Image(256, 3) + require.NoError(t, err) + + baseLayers, err := base.Layers() + require.NoError(t, err) + require.Len(t, baseLayers, 3) + + result, err := Annotations(base, nil, map[string]string{"k": "v"}) + require.NoError(t, err) + img := result.(v1.Image) //nolint:forcetypeassert + + layers, err := img.Layers() + require.NoError(t, err) + require.Len(t, layers, 3) + + // Verify layer digests match the base. + for i, l := range layers { + d, dErr := l.Digest() + require.NoError(t, dErr) + bd, bdErr := baseLayers[i].Digest() + require.NoError(t, bdErr) + assert.Equal(t, bd, d) + } +} + +// TestAnnotations_index verifies that Annotations applies index annotations to +// the index manifest and manifest annotations to each child image, rewriting +// child descriptors with updated digests. +func TestAnnotations_index(t *testing.T) { + base, err := random.Index(256, 1, 2) + require.NoError(t, err) + + idxAnns := map[string]string{"io.kargo.idx": "index-val"} + mfstAnns := map[string]string{"io.kargo.mfst": "manifest-val"} + + result, err := Annotations(base, idxAnns, mfstAnns) + require.NoError(t, err) + idx, ok := result.(v1.ImageIndex) + require.True(t, ok, "expected v1.ImageIndex") + + // Index annotations appear on the index manifest. + im, err := idx.IndexManifest() + require.NoError(t, err) + assert.Equal(t, "index-val", im.Annotations["io.kargo.idx"]) + assert.Empty(t, im.Annotations["io.kargo.mfst"]) + + // Child manifests have manifest annotations. + for _, desc := range im.Manifests { + img, imgErr := idx.Image(desc.Digest) + require.NoError(t, imgErr) + m, mErr := img.Manifest() + require.NoError(t, mErr) + assert.Equal(t, "manifest-val", m.Annotations["io.kargo.mfst"]) + assert.Empty(t, m.Annotations["io.kargo.idx"]) + } + + // Digest is stable (compute-once). + d1, err := idx.Digest() + require.NoError(t, err) + d2, err := idx.Digest() + require.NoError(t, err) + assert.Equal(t, d1, d2) +} + +// TestAnnotations_indexOnly verifies that when only index annotations are +// provided, child image digests remain unchanged. +func TestAnnotations_indexOnly(t *testing.T) { + base, err := random.Index(256, 1, 2) + require.NoError(t, err) + + result, err := Annotations(base, map[string]string{"k": "v"}, nil) + require.NoError(t, err) + idx := result.(v1.ImageIndex) //nolint:forcetypeassert + + im, err := idx.IndexManifest() + require.NoError(t, err) + assert.Equal(t, "v", im.Annotations["k"]) + + // Children should not have extra annotations. + baseIM, err := base.IndexManifest() + require.NoError(t, err) + for _, desc := range baseIM.Manifests { + // Descriptor digests should be unchanged (no manifest annotations applied). + found := false + for _, d := range im.Manifests { + if d.Digest == desc.Digest { + found = true + break + } + } + assert.True(t, found, "child digest %s should be unchanged", desc.Digest) + } +} + +// TestAnnotations_indexManifestOnly verifies that when only manifest +// annotations are provided, no index-level annotations are added and child +// images receive the annotations. +func TestAnnotations_indexManifestOnly(t *testing.T) { + base, err := random.Index(256, 1, 2) + require.NoError(t, err) + + result, err := Annotations(base, nil, map[string]string{"k": "v"}) + require.NoError(t, err) + idx := result.(v1.ImageIndex) //nolint:forcetypeassert + + im, err := idx.IndexManifest() + require.NoError(t, err) + + // No index-level annotations added. + assert.Empty(t, im.Annotations["k"]) + + // Children should have the annotation. + for _, desc := range im.Manifests { + img, imgErr := idx.Image(desc.Digest) + require.NoError(t, imgErr) + m, mErr := img.Manifest() + require.NoError(t, mErr) + assert.Equal(t, "v", m.Annotations["k"]) + } +} + +// TestAnnotations_typeCheck verifies that the unified entrypoint returns the +// correct concrete type for images and indexes, and returns an error for +// unsupported types. +func TestAnnotations_typeCheck(t *testing.T) { + t.Run("image returns v1.Image", func(t *testing.T) { + img, err := random.Image(256, 1) + require.NoError(t, err) + result, err := Annotations(img, nil, map[string]string{"k": "v"}) + require.NoError(t, err) + _, ok := result.(v1.Image) + assert.True(t, ok) + }) + + t.Run("index returns v1.ImageIndex", func(t *testing.T) { + idx, err := random.Index(256, 1, 1) + require.NoError(t, err) + result, err := Annotations(idx, map[string]string{"k": "v"}, nil) + require.NoError(t, err) + _, ok := result.(v1.ImageIndex) + assert.True(t, ok) + }) + + t.Run("unsupported type returns error", func(t *testing.T) { + raw := &fakeRawManifest{} + _, err := Annotations(raw, nil, map[string]string{"k": "v"}) + require.Error(t, err) + assert.Contains(t, err.Error(), "unsupported type") + }) +} + +// TestAnnotations_noAnnotations verifies that when both annotation maps are +// empty, the base artifact is returned unchanged (no wrapping). +func TestAnnotations_noAnnotations(t *testing.T) { + t.Run("image returned unchanged", func(t *testing.T) { + img, err := random.Image(256, 1) + require.NoError(t, err) + result, err := Annotations(img, nil, nil) + require.NoError(t, err) + assert.Equal(t, img, result, "should return base image unchanged") + }) + + t.Run("index returned unchanged", func(t *testing.T) { + idx, err := random.Index(256, 1, 1) + require.NoError(t, err) + result, err := Annotations(idx, nil, nil) + require.NoError(t, err) + assert.Equal(t, idx, result, "should return base index unchanged") + }) +} + +// fakeRawManifest is a type that implements partial.WithRawManifest but is +// neither a v1.Image nor a v1.ImageIndex, used to test the type check error. +type fakeRawManifest struct{} + +var _ partial.WithRawManifest = (*fakeRawManifest)(nil) + +func (f *fakeRawManifest) RawManifest() ([]byte, error) { + return []byte(`{}`), nil +} diff --git a/pkg/image/repository_client_docker_hub_test.go b/pkg/image/repository_client_docker_hub_test.go index e34ab804b1..7a103989f4 100644 --- a/pkg/image/repository_client_docker_hub_test.go +++ b/pkg/image/repository_client_docker_hub_test.go @@ -3,7 +3,6 @@ package image import ( - "context" "os" "testing" @@ -22,7 +21,7 @@ func TestGetTags(t *testing.T) { client, err := newRepositoryClient("debian", false, getDockerHubCreds(), true) require.NoError(t, err) require.NotNil(t, client) - tags, err := client.getTags(context.Background()) + tags, err := client.getTags(t.Context()) require.NoError(t, err) require.NotEmpty(t, tags) } diff --git a/pkg/image/repository_client_test.go b/pkg/image/repository_client_test.go index 6c42abcf89..e2cf89915d 100644 --- a/pkg/image/repository_client_test.go +++ b/pkg/image/repository_client_test.go @@ -230,7 +230,7 @@ func Test_repositoryClient_getImageByTag(t *testing.T) { testCase.setupCache(t, testCase.client.imageCache) } img, err := testCase.client.getImageByTag( - context.Background(), + t.Context(), testTag, testCase.platformConstraint, ) @@ -336,7 +336,7 @@ func Test_repositoryClient_getImageByDigest(t *testing.T) { require.NoError(t, err) } img, err := testCase.client.getImageByDigest( - context.Background(), + t.Context(), testDigest, ) testCase.assertions(t, img, err) @@ -370,7 +370,7 @@ func Test_repositoryClient_getImageFromRemoteDesc(t *testing.T) { for _, mediaType := range mediaTypes { t.Run(string(mediaType), func(t *testing.T) { img, err := testClient.getImageFromRemoteDesc( - context.Background(), + t.Context(), &remote.Descriptor{ Descriptor: v1.Descriptor{ MediaType: mediaType, @@ -413,7 +413,7 @@ func Test_repositoryClient_getImageFromRemoteDesc(t *testing.T) { } img, err := testClientWithAnnotations.getImageFromRemoteDesc( - context.Background(), + t.Context(), remoteDesc, ) require.NoError(t, err) @@ -535,7 +535,7 @@ func Test_repositoryClient_getImageFromV1ImageIndex(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { image, err := testCase.client.getImageFromV1ImageIndex( - context.Background(), + t.Context(), testDigest, testCase.idx, ) diff --git a/pkg/image/selector_docker_hub_test.go b/pkg/image/selector_docker_hub_test.go index a920b84663..be150153c2 100644 --- a/pkg/image/selector_docker_hub_test.go +++ b/pkg/image/selector_docker_hub_test.go @@ -3,7 +3,6 @@ package image import ( - "context" "testing" "github.com/Masterminds/semver/v3" @@ -28,7 +27,7 @@ func TestSelectImageDockerHub(t *testing.T) { logger, err := logging.NewLogger(logging.TraceLevel, logging.DefaultFormat) require.NoError(t, err) - ctx := logging.ContextWithLogger(context.Background(), logger) + ctx := logging.ContextWithLogger(t.Context(), logger) t.Run("digest strategy", func(t *testing.T) { diff --git a/pkg/image/selector_ghcr_test.go b/pkg/image/selector_ghcr_test.go index ecb1dbad48..11255f3ae2 100644 --- a/pkg/image/selector_ghcr_test.go +++ b/pkg/image/selector_ghcr_test.go @@ -3,7 +3,6 @@ package image import ( - "context" "testing" "github.com/Masterminds/semver/v3" @@ -21,7 +20,7 @@ func TestSelectImageGHCR(t *testing.T) { const platform = "linux/amd64" ctx := logging.ContextWithLogger( - context.Background(), + t.Context(), logging.NewLoggerOrDie(logging.TraceLevel, logging.DefaultFormat), ) diff --git a/pkg/indexer/indexer.go b/pkg/indexer/indexer.go index 813a4ec10c..49dd09d4d9 100644 --- a/pkg/indexer/indexer.go +++ b/pkg/indexer/indexer.go @@ -172,7 +172,7 @@ func RunningPromotionsByArgoCDApplications( } // Build just enough context to extract the relevant config from the - // argocd-update promotion step. + // argocd-update and argocd-wait promotion steps. promoCtx := promotion.NewContext(promo, stage) // Extract the Argo CD Applications from the promotion steps. @@ -187,7 +187,8 @@ func RunningPromotionsByArgoCDApplications( // are about to be. break } - if step.Uses != "argocd-update" || step.Config == nil { + if (step.Uses != "argocd-update" && step.Uses != "argocd-wait") || + step.Config == nil { continue } diff --git a/pkg/indexer/indexer_test.go b/pkg/indexer/indexer_test.go index 8dd4e17c0f..d3b5e87fab 100644 --- a/pkg/indexer/indexer_test.go +++ b/pkg/indexer/indexer_test.go @@ -1,7 +1,6 @@ package indexer import ( - "context" "fmt" "slices" "testing" @@ -489,6 +488,54 @@ func TestRunningPromotionsByArgoCDApplications(t *testing.T) { fmt.Sprintf("%s:%s", argocd.Namespace(), "fake-app-from-task"), }, }, + { + name: "Promotion has argocd-wait step with app name", + obj: &kargoapi.Promotion{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + }, + Spec: kargoapi.PromotionSpec{ + Stage: fakeStage.Name, + Steps: []kargoapi.PromotionStep{ + { + Uses: "argocd-wait", + Config: &apiextensionsv1.JSON{ + Raw: []byte(`{"apps":[{"namespace":"fake-namespace","name":"fake-app"}]}`), + }, + }, + }, + }, + Status: kargoapi.PromotionStatus{ + Phase: kargoapi.PromotionPhaseRunning, + CurrentStep: 0, + }, + }, + expected: []string{"fake-namespace:fake-app"}, + }, + { + name: "Promotion has argocd-wait step with selector (not indexed)", + obj: &kargoapi.Promotion{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-namespace", + }, + Spec: kargoapi.PromotionSpec{ + Stage: fakeStage.Name, + Steps: []kargoapi.PromotionStep{ + { + Uses: "argocd-wait", + Config: &apiextensionsv1.JSON{ + Raw: []byte(`{"apps":[{"selector":{"matchLabels":{"env":"prod"}}}]}`), + }, + }, + }, + }, + Status: kargoapi.PromotionStatus{ + Phase: kargoapi.PromotionPhaseRunning, + CurrentStep: 0, + }, + }, + expected: nil, + }, { name: "Promotion has directive steps without Applications", obj: &kargoapi.Promotion{ @@ -528,7 +575,7 @@ func TestRunningPromotionsByArgoCDApplications(t *testing.T) { t, testCase.expected, RunningPromotionsByArgoCDApplications( - context.TODO(), + t.Context(), c, testCase.shardName, false, diff --git a/pkg/indexer/shared_field_indexer_test.go b/pkg/indexer/shared_field_indexer_test.go index 9b945b6d11..aba681be5f 100644 --- a/pkg/indexer/shared_field_indexer_test.go +++ b/pkg/indexer/shared_field_indexer_test.go @@ -101,7 +101,7 @@ func TestIndexField(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { index := NewSharedFieldIndexer(tt.internalIndex) - err := index.IndexField(context.Background(), &mockObject{}, "metadata.name", nil) + err := index.IndexField(t.Context(), &mockObject{}, "metadata.name", nil) tt.assertions(t, index, tt.key, err) }) } diff --git a/pkg/kargo/promotion_builder_test.go b/pkg/kargo/promotion_builder_test.go index 60281bc0ff..4d10e8500b 100644 --- a/pkg/kargo/promotion_builder_test.go +++ b/pkg/kargo/promotion_builder_test.go @@ -173,7 +173,7 @@ func TestPromotionBuilder_Build(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx := user.ContextWithInfo(context.Background(), tt.userInfo) + ctx := user.ContextWithInfo(t.Context(), tt.userInfo) c := fake.NewClientBuilder(). WithScheme(s). @@ -395,7 +395,7 @@ func TestPromotionBuilder_InflateSteps(t *testing.T) { b := NewPromotionBuilder(c) p := tt.promo.DeepCopy() - err := b.InflateSteps(context.Background(), p) + err := b.InflateSteps(t.Context(), p) tt.assertions(t, p.Spec.Steps, err) }) } @@ -611,7 +611,7 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Build() b := NewPromotionBuilder(c) - steps, err := b.inflateTaskSteps(context.Background(), tt.project, tt.taskAlias, tt.promoVars, tt.taskStep) + steps, err := b.inflateTaskSteps(t.Context(), tt.project, tt.taskAlias, tt.promoVars, tt.taskStep) tt.assertions(t, steps, err) }) } @@ -793,7 +793,7 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { Build() b := NewPromotionBuilder(c) - result, err := b.getTaskSpec(context.Background(), tt.project, tt.ref) + result, err := b.getTaskSpec(t.Context(), tt.project, tt.ref) tt.assertions(t, result, err) }) } diff --git a/pkg/kubeclient/transport_test.go b/pkg/kubeclient/transport_test.go index c158bc235f..f6604578ea 100644 --- a/pkg/kubeclient/transport_test.go +++ b/pkg/kubeclient/transport_test.go @@ -1,7 +1,6 @@ package kubeclient import ( - "context" "net/http" "net/http/httptest" "testing" @@ -39,7 +38,7 @@ func Test_credentialHook(t *testing.T) { if ts.credential != "" { req.Header.Set("Authorization", ts.credential) } - res, err := hc.Do(req.WithContext(context.Background())) + res, err := hc.Do(req.WithContext(t.Context())) defer func() { _ = res.Body.Close() }() diff --git a/pkg/kubernetes/event/event_test.go b/pkg/kubernetes/event/event_test.go index 805b4f21b9..3de8ad1793 100644 --- a/pkg/kubernetes/event/event_test.go +++ b/pkg/kubernetes/event/event_test.go @@ -1,7 +1,6 @@ package event import ( - "context" "errors" "net/http" "testing" @@ -17,7 +16,7 @@ import ( ) func Test_newRecorder(t *testing.T) { - ctx := context.TODO() + ctx := t.Context() client := fake.NewClientBuilder().Build() logger := logging.LoggerFromContext(ctx) r := newRecorder(ctx, client, logger) @@ -74,7 +73,7 @@ func Test_retryDecider(t *testing.T) { func Test_newSink(t *testing.T) { s := newSink( - context.TODO(), + t.Context(), fake.NewClientBuilder().Build(), ) require.NotNil(t, s.client) diff --git a/pkg/promotion/evaluator_test.go b/pkg/promotion/evaluator_test.go index f53e361dd0..f652b2828e 100644 --- a/pkg/promotion/evaluator_test.go +++ b/pkg/promotion/evaluator_test.go @@ -1,7 +1,6 @@ package promotion import ( - "context" "testing" "github.com/stretchr/testify/assert" @@ -791,7 +790,7 @@ func TestStepEvaluator_Vars(t *testing.T) { t.Run(tt.name, func(t *testing.T) { evaluator := NewStepEvaluator(testClient, nil) vars, err := evaluator.Vars( - context.Background(), + t.Context(), tt.promoCtx, tt.step, ) @@ -955,7 +954,7 @@ func TestStepEvaluator_ShouldSkip(t *testing.T) { nil, ) got, err := evaluator.ShouldSkip( - context.Background(), + t.Context(), tt.promoCtx, tt.step, ) @@ -1421,7 +1420,7 @@ func TestStepEvaluator_Config(t *testing.T) { t.Run(tt.name, func(t *testing.T) { evaluator := NewStepEvaluator(testClient, nil) stepCfg, err := evaluator.Config( - context.Background(), + t.Context(), tt.promoCtx, tt.step, ) @@ -1554,7 +1553,7 @@ func TestStepEvaluator_BuildStepContext(t *testing.T) { t.Run(tt.name, func(t *testing.T) { evaluator := NewStepEvaluator(testClient, nil) stepCtx, err := evaluator.BuildStepContext( - context.Background(), + t.Context(), tt.promoCtx, tt.step, ) diff --git a/pkg/promotion/local_engine_test.go b/pkg/promotion/local_engine_test.go index ed6035b074..bed6a51f21 100644 --- a/pkg/promotion/local_engine_test.go +++ b/pkg/promotion/local_engine_test.go @@ -89,7 +89,7 @@ func TestSimpleEngine_Promote(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() testRegistry := MustNewStepRunnerRegistry( diff --git a/pkg/promotion/local_executor_test.go b/pkg/promotion/local_executor_test.go index 37da8c482a..c26e6c3166 100644 --- a/pkg/promotion/local_executor_test.go +++ b/pkg/promotion/local_executor_test.go @@ -190,7 +190,7 @@ func TestLocalStepExecutor_ExecuteStep(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { executor := NewLocalStepExecutor(tt.registry, nil, nil, nil) - result, err := executor.ExecuteStep(context.Background(), tt.request) + result, err := executor.ExecuteStep(t.Context(), tt.request) tt.assertions(t, result, err) }) } diff --git a/pkg/promotion/local_orchestrator_test.go b/pkg/promotion/local_orchestrator_test.go index 70cebd1f4c..ee27c83675 100644 --- a/pkg/promotion/local_orchestrator_test.go +++ b/pkg/promotion/local_orchestrator_test.go @@ -612,7 +612,7 @@ func TestLocalOrchestrator_ExecuteSteps(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) t.Cleanup(cancel) registry := MustNewStepRunnerRegistry( diff --git a/pkg/promotion/mock_engine_test.go b/pkg/promotion/mock_engine_test.go index ae16c93d01..7bbb1aa3e4 100644 --- a/pkg/promotion/mock_engine_test.go +++ b/pkg/promotion/mock_engine_test.go @@ -13,13 +13,13 @@ import ( func TestMockEngine_Promote(t *testing.T) { t.Run("without function injection", func(t *testing.T) { engine := &MockEngine{} - res, err := engine.Promote(context.Background(), Context{}, nil) + res, err := engine.Promote(t.Context(), Context{}, nil) assert.NoError(t, err) assert.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status) }) t.Run("with function injection", func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() promoCtx := Context{ Stage: "foo", } diff --git a/pkg/promotion/runner/builtin/argocd_common.go b/pkg/promotion/runner/builtin/argocd_common.go new file mode 100644 index 0000000000..a143c0cf7c --- /dev/null +++ b/pkg/promotion/runner/builtin/argocd_common.go @@ -0,0 +1,54 @@ +package builtin + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +// buildArgoCDAppLabelSelector converts an ArgoCDAppSelector into a Kubernetes +// labels.Selector. +func buildArgoCDAppLabelSelector( + selector *builtin.ArgoCDAppSelector, +) (labels.Selector, error) { + if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 { + return nil, fmt.Errorf("selector must have at least one match criterion") + } + + labelSelector := labels.NewSelector() + + for key, value := range selector.MatchLabels { + req, err := labels.NewRequirement(key, selection.Equals, []string{value}) + if err != nil { + return nil, fmt.Errorf("invalid matchLabel %s=%s: %w", key, value, err) + } + labelSelector = labelSelector.Add(*req) + } + + for _, expr := range selector.MatchExpressions { + var op selection.Operator + switch expr.Operator { + case builtin.In: + op = selection.In + case builtin.NotIn: + op = selection.NotIn + case builtin.Exists: + op = selection.Exists + case builtin.DoesNotExist: + op = selection.DoesNotExist + default: + return nil, fmt.Errorf("invalid operator: %s", expr.Operator) + } + + req, err := labels.NewRequirement(expr.Key, op, expr.Values) + if err != nil { + return nil, fmt.Errorf("invalid matchExpression: %w", err) + } + labelSelector = labelSelector.Add(*req) + } + + return labelSelector, nil +} diff --git a/pkg/promotion/runner/builtin/argocd_common_test.go b/pkg/promotion/runner/builtin/argocd_common_test.go new file mode 100644 index 0000000000..c3122bae94 --- /dev/null +++ b/pkg/promotion/runner/builtin/argocd_common_test.go @@ -0,0 +1,60 @@ +package builtin + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +func Test_buildArgoCDAppLabelSelector(t *testing.T) { + testCases := []struct { + name string + selector *builtin.ArgoCDAppSelector + expectErr bool + }{ + { + name: "empty selector", + selector: &builtin.ArgoCDAppSelector{}, + expectErr: true, + }, + { + name: "valid matchLabels", + selector: &builtin.ArgoCDAppSelector{ + MatchLabels: map[string]string{"app": "test"}, + }, + expectErr: false, + }, + { + name: "valid matchExpressions", + selector: &builtin.ArgoCDAppSelector{ + MatchExpressions: []builtin.MatchExpression{ + {Key: "app", Operator: builtin.In, Values: []string{"a", "b"}}, + }, + }, + expectErr: false, + }, + { + name: "invalid operator", + selector: &builtin.ArgoCDAppSelector{ + MatchExpressions: []builtin.MatchExpression{ + {Key: "app", Operator: "Invalid"}, + }, + }, + expectErr: true, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + sel, err := buildArgoCDAppLabelSelector(tc.selector) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.NotNil(t, sel) + } + }) + } +} diff --git a/pkg/promotion/runner/builtin/argocd_updater.go b/pkg/promotion/runner/builtin/argocd_updater.go index 201ae26c50..77f2a11d3f 100644 --- a/pkg/promotion/runner/builtin/argocd_updater.go +++ b/pkg/promotion/runner/builtin/argocd_updater.go @@ -12,8 +12,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/selection" - "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" kargoapi "github.com/akuity/kargo/api/v1alpha1" @@ -116,7 +114,7 @@ func newArgocdUpdater(caps promotion.StepRunnerCapabilities) promotion.StepRunne r := &argocdUpdater{argocdClient: caps.ArgoCDClient} r.schemaLoader = getConfigSchemaLoader(stepKindArgoCDUpdate) r.getAuthorizedApplicationsFn = r.getAuthorizedApplications - r.buildLabelSelectorFn = r.buildLabelSelector + r.buildLabelSelectorFn = buildArgoCDAppLabelSelector r.buildDesiredSourcesFn = r.buildDesiredSources r.mustPerformUpdateFn = r.mustPerformUpdate r.syncApplicationFn = r.syncApplication @@ -235,17 +233,6 @@ func (a *argocdUpdater) run( "status", aggregatedStatus, ) - // TODO(krancour): This enables more aggressive polling while waiting to - // observe the Application has successfully synced. This is a workaround for - // an as-yet-unexplained, but rare phenomenon where Application status change - // events do not seem to be promptly triggering re-reconciliation of the - // Promotion resources. - var retryAfter *time.Duration - if aggregatedStatus == kargoapi.PromotionStepStatusRunning { - retryAfter = ptr.To(30 * time.Second) - logger.Info("step to be retried", "interval", retryAfter) - } - return promotion.StepResult{ Status: aggregatedStatus, HealthCheck: &health.Criteria{ @@ -254,7 +241,6 @@ func (a *argocdUpdater) run( "apps": appHealthChecks, }, }, - RetryAfter: retryAfter, }, nil } @@ -933,49 +919,6 @@ func (a *argocdUpdater) authorizeArgoCDAppUpdate( return nil } -// buildLabelSelector converts an ArgoCDAppSelector into a Kubernetes labels.Selector. -func (a *argocdUpdater) buildLabelSelector( - selector *builtin.ArgoCDAppSelector, -) (labels.Selector, error) { - if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 { - return nil, fmt.Errorf("selector must have at least one match criterion") - } - - labelSelector := labels.NewSelector() - - for key, value := range selector.MatchLabels { - req, err := labels.NewRequirement(key, selection.Equals, []string{value}) - if err != nil { - return nil, fmt.Errorf("invalid matchLabel %s=%s: %w", key, value, err) - } - labelSelector = labelSelector.Add(*req) - } - - for _, expr := range selector.MatchExpressions { - var op selection.Operator - switch expr.Operator { - case builtin.In: - op = selection.In - case builtin.NotIn: - op = selection.NotIn - case builtin.Exists: - op = selection.Exists - case builtin.DoesNotExist: - op = selection.DoesNotExist - default: - return nil, fmt.Errorf("invalid operator: %s", expr.Operator) - } - - req, err := labels.NewRequirement(expr.Key, op, expr.Values) - if err != nil { - return nil, fmt.Errorf("invalid matchExpression: %w", err) - } - labelSelector = labelSelector.Add(*req) - } - - return labelSelector, nil -} - // applyArgoCDSourceUpdate updates a single Argo CD ApplicationSource. func (a *argocdUpdater) applyArgoCDSourceUpdate( update *builtin.ArgoCDAppSourceUpdate, diff --git a/pkg/promotion/runner/builtin/argocd_updater_test.go b/pkg/promotion/runner/builtin/argocd_updater_test.go index 3abef4c2ce..4d4fe6151f 100644 --- a/pkg/promotion/runner/builtin/argocd_updater_test.go +++ b/pkg/promotion/runner/builtin/argocd_updater_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" @@ -616,7 +615,7 @@ func Test_argoCDUpdater_run(t *testing.T) { }, assertions: func(t *testing.T, res promotion.StepResult, err error) { assert.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status) - assert.NotNil(t, res.RetryAfter) + assert.Nil(t, res.RetryAfter) require.NoError(t, err) }, }, @@ -652,7 +651,7 @@ func Test_argoCDUpdater_run(t *testing.T) { }, assertions: func(t *testing.T, res promotion.StepResult, err error) { assert.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status) - assert.NotNil(t, res.RetryAfter) + assert.Nil(t, res.RetryAfter) require.NoError(t, err) }, }, @@ -688,7 +687,7 @@ func Test_argoCDUpdater_run(t *testing.T) { }, assertions: func(t *testing.T, res promotion.StepResult, err error) { assert.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status) - assert.NotNil(t, res.RetryAfter) + assert.Nil(t, res.RetryAfter) require.NoError(t, err) }, }, @@ -1080,7 +1079,7 @@ func Test_argoCDUpdater_run(t *testing.T) { }, assertions: func(t *testing.T, res promotion.StepResult, err error) { assert.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status) - assert.NotNil(t, res.RetryAfter) + assert.Nil(t, res.RetryAfter) require.NoError(t, err) // Verify health checks include all 3 apps require.NotNil(t, res.HealthCheck) @@ -1271,7 +1270,7 @@ func Test_argoCDUpdater_run(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { res, err := testCase.runner.run( - context.Background(), + t.Context(), &promotion.StepContext{}, testCase.stepCfg, ) @@ -1796,7 +1795,7 @@ func Test_argoCDUpdater_syncApplication(t *testing.T) { }, } err := testCase.runner.syncApplication( - context.Background(), + t.Context(), stepCtx, testCase.app, testCase.desiredSources, @@ -1892,7 +1891,7 @@ func Test_argoCDUpdater_logAppEvent(t *testing.T) { eventMessage: "fake-message", assertions: func(t *testing.T, c client.Client, app *argocd.Application) { events := &corev1.EventList{} - require.NoError(t, c.List(context.Background(), events)) + require.NoError(t, c.List(t.Context(), events)) assert.Len(t, events.Items, 1) event := events.Items[0] @@ -1929,7 +1928,7 @@ func Test_argoCDUpdater_logAppEvent(t *testing.T) { eventMessage: "fake-message", assertions: func(t *testing.T, c client.Client, _ *argocd.Application) { events := &corev1.EventList{} - require.NoError(t, c.List(context.Background(), events)) + require.NoError(t, c.List(t.Context(), events)) assert.Len(t, events.Items, 1) event := events.Items[0] @@ -1945,7 +1944,7 @@ func Test_argoCDUpdater_logAppEvent(t *testing.T) { argocdClient: c, } runner.logAppEvent( - context.Background(), + t.Context(), testCase.app, testCase.user, testCase.eventReason, @@ -1958,7 +1957,7 @@ func Test_argoCDUpdater_logAppEvent(t *testing.T) { func Test_argoCDUpdater_authorizeArgoCDAppUpdate(t *testing.T) { const ( - permErr = "does not permit mutation" + permErr = "does not permit mutation by" parseErr = "unable to parse" deprecatedGlobErr = "deprecated glob expression" ) @@ -2404,143 +2403,6 @@ func Test_argoCDUpdater_recursiveMerge(t *testing.T) { } } -func Test_argoCDUpdater_buildLabelSelector(t *testing.T) { - testCases := []struct { - name string - selector *builtin.ArgoCDAppSelector - assertions func(*testing.T, labels.Selector, error) - }{ - { - name: "selector with matchLabels only", - selector: &builtin.ArgoCDAppSelector{ - MatchLabels: map[string]string{ - "env": "prod", - "team": "platform", - }, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.NoError(t, err) - require.NotNil(t, sel) - assert.True(t, sel.Matches(labels.Set{"env": "prod", "team": "platform"})) - assert.False(t, sel.Matches(labels.Set{"env": "dev", "team": "platform"})) - }, - }, - { - name: "selector with matchExpressions only", - selector: &builtin.ArgoCDAppSelector{ - MatchExpressions: []builtin.MatchExpression{ - { - Key: "env", - Operator: builtin.In, - Values: []string{"prod", "staging"}, - }, - }, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.NoError(t, err) - require.NotNil(t, sel) - assert.True(t, sel.Matches(labels.Set{"env": "prod"})) - assert.True(t, sel.Matches(labels.Set{"env": "staging"})) - assert.False(t, sel.Matches(labels.Set{"env": "dev"})) - }, - }, - { - name: "selector with both matchLabels and matchExpressions", - selector: &builtin.ArgoCDAppSelector{ - MatchLabels: map[string]string{ - "team": "platform", - }, - MatchExpressions: []builtin.MatchExpression{ - { - Key: "env", - Operator: builtin.In, - Values: []string{"prod", "staging"}, - }, - }, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.NoError(t, err) - require.NotNil(t, sel) - assert.True(t, sel.Matches(labels.Set{"env": "prod", "team": "platform"})) - assert.False(t, sel.Matches(labels.Set{"env": "prod", "team": "other"})) - assert.False(t, sel.Matches(labels.Set{"env": "dev", "team": "platform"})) - }, - }, - { - name: "selector with NotIn operator", - selector: &builtin.ArgoCDAppSelector{ - MatchExpressions: []builtin.MatchExpression{ - { - Key: "env", - Operator: builtin.NotIn, - Values: []string{"dev", "test"}, - }, - }, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.NoError(t, err) - require.NotNil(t, sel) - assert.True(t, sel.Matches(labels.Set{"env": "prod"})) - assert.False(t, sel.Matches(labels.Set{"env": "dev"})) - }, - }, - { - name: "selector with Exists operator", - selector: &builtin.ArgoCDAppSelector{ - MatchExpressions: []builtin.MatchExpression{ - { - Key: "environment", - Operator: builtin.Exists, - }, - }, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.NoError(t, err) - require.NotNil(t, sel) - assert.True(t, sel.Matches(labels.Set{"environment": "prod"})) - assert.False(t, sel.Matches(labels.Set{"env": "prod"})) - }, - }, - { - name: "selector with DoesNotExist operator", - selector: &builtin.ArgoCDAppSelector{ - MatchExpressions: []builtin.MatchExpression{ - { - Key: "deprecated", - Operator: builtin.DoesNotExist, - }, - }, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.NoError(t, err) - require.NotNil(t, sel) - assert.True(t, sel.Matches(labels.Set{"env": "prod"})) - assert.False(t, sel.Matches(labels.Set{"deprecated": "true"})) - }, - }, - { - name: "empty selector returns error", - selector: &builtin.ArgoCDAppSelector{ - MatchLabels: map[string]string{}, - MatchExpressions: []builtin.MatchExpression{}, - }, - assertions: func(t *testing.T, sel labels.Selector, err error) { - require.ErrorContains(t, err, "selector must have at least one match criterion") - require.Nil(t, sel) - }, - }, - } - - runner := &argocdUpdater{} - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - sel, err := runner.buildLabelSelector(testCase.selector) - testCase.assertions(t, sel, err) - }) - } -} - func Test_argoCDUpdater_getAuthorizedApplications(t *testing.T) { scheme := runtime.NewScheme() require.NoError(t, argocd.AddToScheme(scheme)) @@ -2809,10 +2671,10 @@ func Test_argoCDUpdater_getAuthorizedApplications(t *testing.T) { runner := &argocdUpdater{ argocdClient: c.Build(), } - runner.buildLabelSelectorFn = runner.buildLabelSelector + runner.buildLabelSelectorFn = buildArgoCDAppLabelSelector apps, err := runner.getAuthorizedApplications( - context.Background(), + t.Context(), &promotion.StepContext{ Project: "fake-project", Stage: "fake-stage", @@ -3060,7 +2922,7 @@ func Test_argoCDUpdater_processApplication(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { phase, err := testCase.runner.processApplication( - context.Background(), + t.Context(), &promotion.StepContext{}, testCase.update, testCase.app, diff --git a/pkg/promotion/runner/builtin/argocd_waiter.go b/pkg/promotion/runner/builtin/argocd_waiter.go new file mode 100644 index 0000000000..d39335eec6 --- /dev/null +++ b/pkg/promotion/runner/builtin/argocd_waiter.go @@ -0,0 +1,437 @@ +package builtin + +import ( + "context" + "errors" + "fmt" + "maps" + "slices" + "time" + + "github.com/xeipuuv/gojsonschema" + "sigs.k8s.io/controller-runtime/pkg/client" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + libargocd "github.com/akuity/kargo/pkg/argocd" + argocd "github.com/akuity/kargo/pkg/controller/argocd/api/v1alpha1" + "github.com/akuity/kargo/pkg/logging" + "github.com/akuity/kargo/pkg/promotion" + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +const ( + stepKindArgoCDWait = "argocd-wait" + + // healthStatusKey is the key used to store per-app health statuses in + // step output. Used for degradation detection across re-invocations. + healthStatusKey = "healthStatus" +) + +// defaultWaitFor is the default set of conditions to wait for, matching the +// behavior of `argocd app wait` when no flags are specified. +var defaultWaitFor = []builtin.WaitFor{builtin.Health, builtin.Sync, builtin.Operation} + +// healthErrorConditions are the ApplicationConditionType conditions that +// indicate an Argo CD Application has a configuration error. +var waitHealthErrorConditions = []argocd.ApplicationConditionType{ + argocd.ApplicationConditionComparisonError, + argocd.ApplicationConditionInvalidSpecError, +} + +func init() { + promotion.DefaultStepRunnerRegistry.MustRegister( + promotion.StepRunnerRegistration{ + Name: stepKindArgoCDWait, + Metadata: promotion.StepRunnerMetadata{ + DefaultTimeout: 5 * time.Minute, + RequiredCapabilities: []promotion.StepRunnerCapability{ + promotion.StepCapabilityAccessArgoCD, + }, + }, + Value: newArgocdWaiter, + }, + ) +} + +// argocdWaiter is an implementation of the promotion.StepRunner interface that +// waits for one or more Argo CD Applications to reach desired statuses. +type argocdWaiter struct { + schemaLoader gojsonschema.JSONLoader + argocdClient client.Client + + // These behaviors are overridable for testing purposes: + + getApplicationsFn func( + ctx context.Context, + argocdClient client.Client, + name string, + namespace string, + selector *builtin.ArgoCDAppSelector, + ) ([]*argocd.Application, error) + + checkAppReadinessFn func( + ctx context.Context, + app *argocd.Application, + waitFor []builtin.WaitFor, + prevHealthStatus string, + ) (ready bool, healthStatus string, err error) +} + +// newArgocdWaiter returns an implementation of the promotion.StepRunner +// interface that waits for Argo CD Applications to reach desired statuses. +func newArgocdWaiter(caps promotion.StepRunnerCapabilities) promotion.StepRunner { + w := &argocdWaiter{argocdClient: caps.ArgoCDClient} + w.schemaLoader = getConfigSchemaLoader(stepKindArgoCDWait) + w.getApplicationsFn = getArgoCDApplications + w.checkAppReadinessFn = w.checkAppReadiness + return w +} + +// Run implements the promotion.StepRunner interface. +func (w *argocdWaiter) Run( + ctx context.Context, + stepCtx *promotion.StepContext, +) (promotion.StepResult, error) { + cfg, err := w.convert(stepCtx.Config) + if err != nil { + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusFailed, + }, &promotion.TerminalError{Err: err} + } + return w.run(ctx, stepCtx, cfg) +} + +// convert validates argocdWaiter configuration against a JSON schema and +// converts it into a builtin.ArgoCDWaitConfig struct. +func (w *argocdWaiter) convert(cfg promotion.Config) (builtin.ArgoCDWaitConfig, error) { + return validateAndConvert[builtin.ArgoCDWaitConfig](w.schemaLoader, cfg, stepKindArgoCDWait) +} + +func (w *argocdWaiter) run( + ctx context.Context, + stepCtx *promotion.StepContext, + stepCfg builtin.ArgoCDWaitConfig, +) (promotion.StepResult, error) { + if w.argocdClient == nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, + errors.New( // nolint:staticcheck + "Argo CD integration is disabled on this controller; cannot " + + "wait for Argo CD Application resources", + ) + } + + logger := logging.LoggerFromContext(ctx) + logger.Info("executing argocd-wait promotion step") + + // Load previous health statuses from shared state (for degradation + // detection across re-invocations). + prevHealthStatuses := w.loadPreviousHealthStatuses(stepCtx) + // Seed with previous statuses so unchecked apps retain their last-known + // health if we bail early (e.g. on a TerminalError for another app). + newHealthStatuses := make(map[string]string, len(prevHealthStatuses)) + maps.Copy(newHealthStatuses, prevHealthStatuses) + + allReady := true + for i := range stepCfg.Apps { + appSpec := &stepCfg.Apps[i] + + // Apply defaults. + waitFor := appSpec.WaitFor + if len(waitFor) == 0 { + waitFor = defaultWaitFor + } + + // Resolve matching applications. + apps, err := w.getApplicationsFn( + ctx, + w.argocdClient, + appSpec.Name, + appSpec.Namespace, + appSpec.Selector, + ) + if err != nil { + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusErrored, + }, err + } + + for _, app := range apps { + appKey := fmt.Sprintf("%s/%s", app.Namespace, app.Name) + appLogger := logger.WithValues( + "app", app.Name, "namespace", app.Namespace, + ) + + ready, healthStatus, err := + w.checkAppReadinessFn(ctx, app, waitFor, prevHealthStatuses[appKey]) + if healthStatus != "" { + newHealthStatuses[appKey] = healthStatus + } + if err != nil { + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusErrored, + Output: map[string]any{ + healthStatusKey: newHealthStatuses, + }, + }, err + } + if !ready { + appLogger.Info("application is not ready") + allReady = false + } else { + appLogger.Info("application is ready") + } + } + } + + if allReady { + logger.Info("all applications are ready", "status", "Succeeded") + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusSucceeded, + Output: map[string]any{ + healthStatusKey: newHealthStatuses, + }, + }, nil + } + + logger.Info("waiting for applications to become ready") + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusRunning, + Output: map[string]any{ + healthStatusKey: newHealthStatuses, + }, + }, nil +} + +// checkAppReadiness checks whether a single Argo CD Application meets the +// desired conditions specified by waitFor. It returns: +// - ready: whether all conditions are met +// - healthStatus: the current health status string (for tracking) +// - err: a TerminalError if a non-recoverable condition is detected +func (w *argocdWaiter) checkAppReadiness( + ctx context.Context, + app *argocd.Application, + waitFor []builtin.WaitFor, + prevHealthStatus string, +) (ready bool, healthStatus string, err error) { + logger := logging.LoggerFromContext(ctx).WithValues( + "app", app.Name, "namespace", app.Namespace, + ) + healthStatus = string(app.Status.Health.Status) + + // Check for error conditions on the Application. + if errConditions := filterArgoCDAppConditions( + app, waitHealthErrorConditions..., + ); len(errConditions) > 0 { + issues := make([]error, len(errConditions)) + for i, condition := range errConditions { + issues[i] = fmt.Errorf( // nolint:staticcheck + "Argo CD Application %q in namespace %q has %q condition: %s", + app.Name, app.Namespace, condition.Type, condition.Message, + ) + } + return false, healthStatus, &promotion.TerminalError{ + Err: errors.Join(issues...), + } + } + + // Operation check. + if slices.Contains(waitFor, "operation") { + if operationInProgress(app) { + logger.Info("operation is in progress") + return false, healthStatus, nil + } + } + + healthBeingChecked := slices.Contains(waitFor, "health") || + slices.Contains(waitFor, "suspended") || + slices.Contains(waitFor, "degraded") + + // Argo CD executes operations and assesses health in separate reconciliation + // loops. Immediately after an operation completes, the health status may + // reflect state from prior to the operation. If app.Status.ReconciledAt is + // at or after the operation's FinishedAt, health was assessed after the + // operation completed and can be trusted. Otherwise, request a hard refresh + // so Argo CD will reconcile and update ReconciledAt; return not-ready until + // that occurs. + if healthBeingChecked { + if app.Status.OperationState != nil && + app.Status.OperationState.FinishedAt != nil && + (app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Before(app.Status.OperationState.FinishedAt)) { + libargocd.RequestAppRefresh(ctx, w.argocdClient, app) + logger.Info("application not yet reconciled after last operation, " + + "health status not trusted") + return false, healthStatus, nil + } + } + + // Health check: health, suspended, degraded are OR'd. + if healthBeingChecked { + healthCheckPassed := false + if slices.Contains(waitFor, "health") { + healthCheckPassed = healthCheckPassed || + app.Status.Health.Status == argocd.HealthStatusHealthy + } + if slices.Contains(waitFor, "suspended") { + healthCheckPassed = healthCheckPassed || + app.Status.Health.Status == argocd.HealthStatusSuspended + } + if slices.Contains(waitFor, "degraded") { + healthCheckPassed = healthCheckPassed || + app.Status.Health.Status == argocd.HealthStatusDegraded + } + + // Degradation detection: if waiting for health and the app transitions + // TO Degraded from a non-Degraded/non-Unknown state, fail immediately. + if slices.Contains(waitFor, "health") && + app.Status.Health.Status == argocd.HealthStatusDegraded && + prevHealthStatus != "" && + prevHealthStatus != string(argocd.HealthStatusDegraded) && + prevHealthStatus != string(argocd.HealthStatusUnknown) { + return false, healthStatus, &promotion.TerminalError{ + Err: fmt.Errorf( // nolint:staticcheck + "Argo CD Application %q in namespace %q health has "+ + "regressed from %s to %s", + app.Name, app.Namespace, + prevHealthStatus, app.Status.Health.Status, + ), + } + } + + if !healthCheckPassed { + logger.Info( + "health check not passed", + "currentHealth", app.Status.Health.Status, + ) + return false, healthStatus, nil + } + } + + // Sync check. + if slices.Contains(waitFor, "sync") { + if app.Status.Sync.Status != argocd.SyncStatusCodeSynced { + logger.Info( + "sync check not passed", + "currentSync", app.Status.Sync.Status, + ) + return false, healthStatus, nil + } + } + + return true, healthStatus, nil +} + +// operationInProgress returns true if the Application has an operation that is +// still running. +func operationInProgress(app *argocd.Application) bool { + // Active operation request. + if app.Operation != nil { + return true + } + if app.Status.OperationState == nil { + return false + } + // Operation not yet finished. + return app.Status.OperationState.FinishedAt == nil +} + +// loadPreviousHealthStatuses loads the previous health statuses from the step's +// shared state output. Returns an empty map if not available. +func (w *argocdWaiter) loadPreviousHealthStatuses( + stepCtx *promotion.StepContext, +) map[string]string { + result := make(map[string]string) + prevOutput, ok := stepCtx.SharedState[stepCtx.Alias] + if !ok { + return result + } + outputMap, ok := prevOutput.(map[string]any) + if !ok { + return result + } + statuses, ok := outputMap[healthStatusKey] + if !ok { + return result + } + statusMap, ok := statuses.(map[string]any) + if !ok { + return result + } + for k, v := range statusMap { + if s, ok := v.(string); ok { + result[k] = s + } + } + return result +} + +// getArgoCDApplications resolves Argo CD Applications by name or label +// selector. +func getArgoCDApplications( + ctx context.Context, + argocdClient client.Client, + name string, + namespace string, + selector *builtin.ArgoCDAppSelector, +) ([]*argocd.Application, error) { + if namespace == "" { + namespace = libargocd.Namespace() + } + + if selector != nil { + labelSelector, err := buildArgoCDAppLabelSelector(selector) + if err != nil { + return nil, fmt.Errorf("error building label selector: %w", err) + } + + appList := &argocd.ApplicationList{} + if err = argocdClient.List(ctx, appList, + client.InNamespace(namespace), + client.MatchingLabelsSelector{Selector: labelSelector}, + ); err != nil { + return nil, fmt.Errorf( + "error listing Argo CD Applications matching selector: %w", err, + ) + } + if len(appList.Items) == 0 { + return nil, fmt.Errorf( + "no Argo CD Applications found matching selector in namespace %q", + namespace, + ) + } + apps := make([]*argocd.Application, len(appList.Items)) + for i := range appList.Items { + apps[i] = &appList.Items[i] + } + return apps, nil + } + + app, err := argocd.GetApplication(ctx, argocdClient, namespace, name) + if err != nil { + return nil, fmt.Errorf( + "error finding Argo CD Application %q in namespace %q: %w", + name, namespace, err, + ) + } + if app == nil { + return nil, fmt.Errorf( + "unable to find Argo CD Application %q in namespace %q", + name, namespace, + ) + } + return []*argocd.Application{app}, nil +} + +// filterArgoCDAppConditions returns a slice of ApplicationCondition that match +// the provided types. +func filterArgoCDAppConditions( + app *argocd.Application, + t ...argocd.ApplicationConditionType, +) []argocd.ApplicationCondition { + errs := make([]argocd.ApplicationCondition, 0, len(app.Status.Conditions)) + for _, condition := range app.Status.Conditions { + if slices.Contains(t, condition.Type) { + errs = append(errs, condition) + } + } + return errs +} diff --git a/pkg/promotion/runner/builtin/argocd_waiter_test.go b/pkg/promotion/runner/builtin/argocd_waiter_test.go new file mode 100644 index 0000000000..c67f99585a --- /dev/null +++ b/pkg/promotion/runner/builtin/argocd_waiter_test.go @@ -0,0 +1,579 @@ +package builtin + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + argocd "github.com/akuity/kargo/pkg/controller/argocd/api/v1alpha1" + "github.com/akuity/kargo/pkg/promotion" + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +// argocdScheme is a runtime scheme with Argo CD types registered, used for +// fake clients that need to store Argo CD Application objects. +var argocdScheme = func() *runtime.Scheme { + s := runtime.NewScheme() + if err := argocd.AddToScheme(s); err != nil { + panic(err) + } + return s +}() + +func Test_argocdWaiter_convert(t *testing.T) { + tests := []validationTestCase{ + { + name: "apps not specified", + config: promotion.Config{}, + expectedProblems: []string{ + "(root): apps is required", + }, + }, + { + name: "apps is empty", + config: promotion.Config{ + "apps": []promotion.Config{}, + }, + expectedProblems: []string{ + "apps: Array must have at least 1 items", + }, + }, + { + name: "app entry has neither name nor selector", + config: promotion.Config{ + "apps": []promotion.Config{ + {}, + }, + }, + expectedProblems: []string{ + "apps.0: Must validate one and only one schema", + }, + }, + { + name: "app entry has both name and selector", + config: promotion.Config{ + "apps": []promotion.Config{ + { + "name": "my-app", + "selector": promotion.Config{ + "matchLabels": map[string]string{"env": "prod"}, + }, + }, + }, + }, + expectedProblems: []string{ + "apps.0: Must validate one and only one schema", + }, + }, + { + name: "waitFor has invalid value", + config: promotion.Config{ + "apps": []promotion.Config{ + { + "name": "my-app", + "waitFor": []string{"invalid"}, + }, + }, + }, + expectedProblems: []string{ + "apps.0.waitFor.0: apps.0.waitFor.0 must be one of the following", + }, + }, + { + name: "valid config with name", + config: promotion.Config{ + "apps": []promotion.Config{ + {"name": "my-app"}, + }, + }, + expectedProblems: nil, + }, + { + name: "valid config with selector", + config: promotion.Config{ + "apps": []promotion.Config{ + { + "selector": promotion.Config{ + "matchLabels": map[string]string{"env": "prod"}, + }, + }, + }, + }, + expectedProblems: nil, + }, + { + name: "valid config with waitFor", + config: promotion.Config{ + "apps": []promotion.Config{ + { + "name": "my-app", + "waitFor": []string{"health", "sync"}, + }, + }, + }, + expectedProblems: nil, + }, + } + runner := &argocdWaiter{} + runner.schemaLoader = getConfigSchemaLoader(stepKindArgoCDWait) + runValidationTests(t, runner.convert, tests) +} + +func Test_argocdWaiter_run(t *testing.T) { + testCases := []struct { + name string + runner *argocdWaiter + stepCtx *promotion.StepContext + stepCfg builtin.ArgoCDWaitConfig + assertions func(*testing.T, promotion.StepResult, error) + }{ + { + name: "argocd client is nil", + runner: &argocdWaiter{ + argocdClient: nil, + }, + stepCtx: &promotion.StepContext{}, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "my-app"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + assert.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status) + require.ErrorContains(t, err, "Argo CD integration is disabled") + }, + }, + { + name: "error getting applications", + runner: &argocdWaiter{ + argocdClient: fake.NewFakeClient(), + getApplicationsFn: func( + context.Context, client.Client, + string, string, *builtin.ArgoCDAppSelector, + ) ([]*argocd.Application, error) { + return nil, errors.New("something went wrong") + }, + }, + stepCtx: &promotion.StepContext{}, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "my-app"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + assert.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status) + require.ErrorContains(t, err, "something went wrong") + }, + }, + { + name: "checkAppReadiness terminal error stops loop", + runner: &argocdWaiter{ + argocdClient: fake.NewFakeClient(), + getApplicationsFn: appsFn(&argocd.Application{}), + checkAppReadinessFn: func( + context.Context, *argocd.Application, + []builtin.WaitFor, string, + ) (bool, string, error) { + return false, "", &promotion.TerminalError{ + Err: errors.New("bad condition"), + } + }, + }, + stepCtx: &promotion.StepContext{}, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "my-app"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + assert.Equal(t, kargoapi.PromotionStepStatusErrored, res.Status) + require.True(t, promotion.IsTerminal(err)) + require.ErrorContains(t, err, "bad condition") + }, + }, + { + name: "health status tracked in output", + runner: &argocdWaiter{ + argocdClient: fake.NewFakeClient(), + getApplicationsFn: appsFn(&argocd.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: "argocd"}, + }), + checkAppReadinessFn: func( + context.Context, *argocd.Application, + []builtin.WaitFor, string, + ) (bool, string, error) { + return false, "Progressing", nil + }, + }, + stepCtx: &promotion.StepContext{}, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "my-app"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status) + statuses, ok := res.Output[healthStatusKey].(map[string]string) + require.True(t, ok) + assert.Equal(t, "Progressing", statuses["argocd/my-app"]) + }, + }, + { + name: "multiple apps, one not ready returns Running", + runner: &argocdWaiter{ + argocdClient: fake.NewFakeClient(), + getApplicationsFn: func( + _ context.Context, _ client.Client, + name, _ string, _ *builtin.ArgoCDAppSelector, + ) ([]*argocd.Application, error) { + return []*argocd.Application{{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "argocd"}}}, nil + }, + checkAppReadinessFn: func( + _ context.Context, app *argocd.Application, + _ []builtin.WaitFor, _ string, + ) (bool, string, error) { + return app.Name == "app-a", "", nil + }, + }, + stepCtx: &promotion.StepContext{}, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "app-a"}, {Name: "app-b"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, kargoapi.PromotionStepStatusRunning, res.Status) + assert.Nil(t, res.RetryAfter) + }, + }, + { + name: "all apps ready returns Succeeded", + runner: &argocdWaiter{ + argocdClient: fake.NewFakeClient(), + getApplicationsFn: appsFn(&argocd.Application{}), + checkAppReadinessFn: func( + context.Context, *argocd.Application, + []builtin.WaitFor, string, + ) (bool, string, error) { + return true, "Healthy", nil + }, + }, + stepCtx: &promotion.StepContext{}, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "my-app"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status) + }, + }, + { + name: "previous health statuses passed to checkAppReadiness", + runner: &argocdWaiter{ + argocdClient: fake.NewFakeClient(), + getApplicationsFn: appsFn(&argocd.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: "argocd"}, + }), + checkAppReadinessFn: func( + _ context.Context, _ *argocd.Application, + _ []builtin.WaitFor, prevStatus string, + ) (bool, string, error) { + assert.Equal(t, "Progressing", prevStatus) + return true, "Healthy", nil + }, + }, + stepCtx: &promotion.StepContext{ + Alias: "wait-step", + SharedState: promotion.State{ + "wait-step": map[string]any{ + healthStatusKey: map[string]any{ + "argocd/my-app": "Progressing", + }, + }, + }, + }, + stepCfg: builtin.ArgoCDWaitConfig{ + Apps: []builtin.ArgoCDAppWait{{Name: "my-app"}}, + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status) + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := tc.runner.run(context.Background(), tc.stepCtx, tc.stepCfg) + tc.assertions(t, res, err) + }) + } +} + +func Test_argocdWaiter_checkAppReadiness(t *testing.T) { + t.Parallel() + + now := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) + + testCases := []struct { + name string + app *argocd.Application + storedApp *argocd.Application // pre-loaded into fake client for refresh patch + waitFor []builtin.WaitFor + prevHealthStatus string + assertions func(*testing.T, bool, string, error) + }{ + { + name: "error condition is terminal", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Conditions: []argocd.ApplicationCondition{{ + Type: argocd.ApplicationConditionInvalidSpecError, + Message: "bad spec", + }}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.True(t, promotion.IsTerminal(err)) + require.ErrorContains(t, err, "bad spec") + }, + }, + { + name: "operation in progress returns not ready", + app: &argocd.Application{ + Operation: &argocd.Operation{}, + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.NoError(t, err) + }, + }, + { + name: "reconciledAt nil after operation requests refresh and returns not ready", + app: &argocd.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: "argocd"}, + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &metav1.Time{Time: now}, + }, + // ReconciledAt is nil + }, + }, + storedApp: &argocd.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: "argocd"}, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.NoError(t, err) + }, + }, + { + name: "reconciledAt before finishedAt requests refresh and returns not ready", + app: &argocd.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: "argocd"}, + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &metav1.Time{Time: now.Add(10 * time.Second)}, + }, + ReconciledAt: &metav1.Time{Time: now.Add(5 * time.Second)}, + }, + }, + storedApp: &argocd.Application{ + ObjectMeta: metav1.ObjectMeta{Name: "my-app", Namespace: "argocd"}, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.NoError(t, err) + }, + }, + { + name: "reconciledAt equal to finishedAt trusts health", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &metav1.Time{Time: now}, + }, + ReconciledAt: &metav1.Time{Time: now}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.True(t, ready) + require.NoError(t, err) + }, + }, + { + name: "healthy and synced returns ready", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, healthStatus string, err error) { + assert.True(t, ready) + assert.Equal(t, string(argocd.HealthStatusHealthy), healthStatus) + require.NoError(t, err) + }, + }, + { + name: "progressing returns not ready", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusProgressing}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.NoError(t, err) + }, + }, + { + name: "out of sync returns not ready", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusHealthy}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeOutOfSync}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.NoError(t, err) + }, + }, + { + name: "waitFor sync only — degraded health ignored", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusDegraded}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: []builtin.WaitFor{builtin.Sync}, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.True(t, ready) + require.NoError(t, err) + }, + }, + { + name: "waitFor health and suspended — suspended satisfies health check", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusSuspended}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: []builtin.WaitFor{builtin.Health, builtin.Suspended}, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.True(t, ready) + require.NoError(t, err) + }, + }, + { + name: "health regression to Degraded from prior non-Degraded is terminal", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusDegraded}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: defaultWaitFor, + prevHealthStatus: string(argocd.HealthStatusProgressing), + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.True(t, promotion.IsTerminal(err)) + require.ErrorContains(t, err, "regressed") + }, + }, + { + name: "degraded with no prior health status is not terminal", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusDegraded}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeSynced}, + }, + }, + waitFor: defaultWaitFor, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.False(t, ready) + require.NoError(t, err) + }, + }, + { + name: "waitFor operation only — operation completed, health/sync ignored", + app: &argocd.Application{ + Status: argocd.ApplicationStatus{ + Health: argocd.HealthStatus{Status: argocd.HealthStatusDegraded}, + Sync: argocd.SyncStatus{Status: argocd.SyncStatusCodeOutOfSync}, + OperationState: &argocd.OperationState{ + Phase: argocd.OperationSucceeded, + FinishedAt: &metav1.Time{Time: now.Add(-time.Minute)}, + }, + }, + }, + waitFor: []builtin.WaitFor{builtin.Operation}, + assertions: func(t *testing.T, ready bool, _ string, err error) { + assert.True(t, ready) + require.NoError(t, err) + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + var argocdClient client.Client + if tc.storedApp != nil { + argocdClient = fake.NewClientBuilder(). + WithScheme(argocdScheme). + WithObjects(tc.storedApp). + Build() + } else { + argocdClient = fake.NewFakeClient() + } + + w := &argocdWaiter{argocdClient: argocdClient} + ready, healthStatus, err := w.checkAppReadiness( + context.Background(), tc.app, tc.waitFor, tc.prevHealthStatus, + ) + tc.assertions(t, ready, healthStatus, err) + }) + } +} + +// appsFn is a helper that returns a getApplicationsFn that always returns the +// given applications. +func appsFn(apps ...*argocd.Application) func( + context.Context, client.Client, + string, string, *builtin.ArgoCDAppSelector, +) ([]*argocd.Application, error) { + return func( + context.Context, client.Client, + string, string, *builtin.ArgoCDAppSelector, + ) ([]*argocd.Application, error) { + return apps, nil + } +} diff --git a/pkg/promotion/runner/builtin/file_copier_test.go b/pkg/promotion/runner/builtin/file_copier_test.go index 850ab8ee71..63a188f7aa 100644 --- a/pkg/promotion/runner/builtin/file_copier_test.go +++ b/pkg/promotion/runner/builtin/file_copier_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path/filepath" "strings" @@ -359,7 +358,7 @@ func Test_fileCopier_run(t *testing.T) { t.Run(tt.name, func(t *testing.T) { workDir := tt.setupFiles(t) result, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{WorkDir: workDir}, tt.cfg, ) diff --git a/pkg/promotion/runner/builtin/file_deleter_test.go b/pkg/promotion/runner/builtin/file_deleter_test.go index 0312c7fa1c..1bda98f924 100644 --- a/pkg/promotion/runner/builtin/file_deleter_test.go +++ b/pkg/promotion/runner/builtin/file_deleter_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path/filepath" "testing" @@ -224,7 +223,7 @@ func Test_fileDeleter_run(t *testing.T) { t.Run(tt.name, func(t *testing.T) { workDir := tt.setupFiles(t) result, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{WorkDir: workDir}, tt.cfg, ) diff --git a/pkg/promotion/runner/builtin/git_cloner_test.go b/pkg/promotion/runner/builtin/git_cloner_test.go index 56f6c9d772..b296e7d86a 100644 --- a/pkg/promotion/runner/builtin/git_cloner_test.go +++ b/pkg/promotion/runner/builtin/git_cloner_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "fmt" "net/http/httptest" "os" @@ -349,7 +348,7 @@ func Test_gitCloner_run(t *testing.T) { } res, err := runner.run( - context.Background(), + t.Context(), stepCtx, builtin.GitCloneConfig{ RepoURL: fmt.Sprintf("%s/test.git", server.URL), diff --git a/pkg/promotion/runner/builtin/git_commiter_test.go b/pkg/promotion/runner/builtin/git_commiter_test.go index de35e670d2..9ade50500b 100644 --- a/pkg/promotion/runner/builtin/git_commiter_test.go +++ b/pkg/promotion/runner/builtin/git_commiter_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "fmt" "net/http/httptest" "os" @@ -222,7 +221,7 @@ func Test_gitCommitter_run(t *testing.T) { } res, err := runner.run( - context.Background(), + t.Context(), stepCtx, builtin.GitCommitConfig{ Path: "master", @@ -243,7 +242,7 @@ func Test_gitCommitter_run(t *testing.T) { // Run the step again to confirm a Skipped status is returned when no new // commit is actually made. res, err = runner.run( - context.Background(), + t.Context(), stepCtx, builtin.GitCommitConfig{ Path: "master", diff --git a/pkg/promotion/runner/builtin/git_pr_merger.go b/pkg/promotion/runner/builtin/git_pr_merger.go index 01b1ed17d1..37287ffac9 100644 --- a/pkg/promotion/runner/builtin/git_pr_merger.go +++ b/pkg/promotion/runner/builtin/git_pr_merger.go @@ -120,9 +120,12 @@ func (g *gitPRMerger) run( var mergedPR *gitprovider.PullRequest var merged bool const maxMergeAttempts = 3 + for i := range maxMergeAttempts { if mergedPR, merged, err = gitProv.MergePullRequest( - ctx, cfg.PRNumber, + ctx, + cfg.PRNumber, + &gitprovider.MergePullRequestOpts{MergeMethod: cfg.MergeMethod}, ); err != nil { // Only actual errors (auth, network, invalid PR, closed but not merged, // etc.) reach here diff --git a/pkg/promotion/runner/builtin/git_pr_merger_test.go b/pkg/promotion/runner/builtin/git_pr_merger_test.go index 119019572b..8c24139f4e 100644 --- a/pkg/promotion/runner/builtin/git_pr_merger_test.go +++ b/pkg/promotion/runner/builtin/git_pr_merger_test.go @@ -85,6 +85,15 @@ func Test_gitPRMerger_convert(t *testing.T) { "wait": true, }, }, + { + name: "valid with merge method", + config: promotion.Config{ + "provider": "github", + "prNumber": 42, + "repoURL": "https://github.com/example/repo.git", + "mergeMethod": "squash", + }, + }, } r := newGitPRMerger(promotion.StepRunnerCapabilities{ @@ -109,6 +118,7 @@ func Test_gitPRMerger_run(t *testing.T) { MergePullRequestFn: func( context.Context, int64, + *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { return nil, false, errors.New("authentication failed") }, @@ -129,6 +139,7 @@ func Test_gitPRMerger_run(t *testing.T) { MergePullRequestFn: func( context.Context, int64, + *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { return nil, false, nil }, @@ -149,6 +160,7 @@ func Test_gitPRMerger_run(t *testing.T) { MergePullRequestFn: func( context.Context, int64, + *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { return nil, false, nil }, @@ -168,9 +180,10 @@ func Test_gitPRMerger_run(t *testing.T) { provider: &gitprovider.Fake{ MergePullRequestFn: func( _ context.Context, - prNumber int64, + id int64, + _ *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { - require.Equal(t, int64(123), prNumber) + require.Equal(t, int64(123), id) return &gitprovider.PullRequest{ MergeCommitSHA: "commit456", }, true, nil @@ -191,6 +204,7 @@ func Test_gitPRMerger_run(t *testing.T) { MergePullRequestFn: func( context.Context, int64, + *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { return &gitprovider.PullRequest{ MergeCommitSHA: "", @@ -212,6 +226,7 @@ func Test_gitPRMerger_run(t *testing.T) { MergePullRequestFn: func( context.Context, int64, + *gitprovider.MergePullRequestOpts, ) (*gitprovider.PullRequest, bool, error) { return &gitprovider.PullRequest{ MergeCommitSHA: "abc123", @@ -227,6 +242,30 @@ func Test_gitPRMerger_run(t *testing.T) { require.Equal(t, "abc123", res.Output[stateKeyCommit]) }, }, + { + name: "successful merge with explicit method", + provider: &gitprovider.Fake{ + MergePullRequestFn: func( + _ context.Context, + _ int64, + opts *gitprovider.MergePullRequestOpts, + ) (*gitprovider.PullRequest, bool, error) { + require.Equal(t, "squash", opts.MergeMethod) + return &gitprovider.PullRequest{ + MergeCommitSHA: "squash123", + }, true, nil + }, + }, + config: builtin.GitMergePRConfig{ + PRNumber: 42, + MergeMethod: "squash", + }, + assertions: func(t *testing.T, res promotion.StepResult, err error) { + require.NoError(t, err) + require.Equal(t, kargoapi.PromotionStepStatusSucceeded, res.Status) + require.Equal(t, "squash123", res.Output[stateKeyCommit]) + }, + }, } r := newGitPRMerger(promotion.StepRunnerCapabilities{ @@ -258,7 +297,7 @@ func Test_gitPRMerger_run(t *testing.T) { cfg.RepoURL = "https://github.com/example/repo.git" res, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{}, cfg, ) diff --git a/pkg/promotion/runner/builtin/git_pr_waiter_test.go b/pkg/promotion/runner/builtin/git_pr_waiter_test.go index 808294f3a5..ae3740c9d4 100644 --- a/pkg/promotion/runner/builtin/git_pr_waiter_test.go +++ b/pkg/promotion/runner/builtin/git_pr_waiter_test.go @@ -225,7 +225,7 @@ func Test_gitPRWaiter_run(t *testing.T) { ) res, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{}, builtin.GitWaitForPRConfig{ Provider: ptr.To(builtin.Provider(testGitProviderName)), diff --git a/pkg/promotion/runner/builtin/git_tagger_test.go b/pkg/promotion/runner/builtin/git_tagger_test.go index 392f4ee0c7..e3f04f107e 100644 --- a/pkg/promotion/runner/builtin/git_tagger_test.go +++ b/pkg/promotion/runner/builtin/git_tagger_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "fmt" "net/http/httptest" "os" @@ -163,7 +162,7 @@ func Test_gitTagger_run(t *testing.T) { // Test creating a tag res, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{WorkDir: workDir}, builtin.GitTagConfig{ Path: "master", diff --git a/pkg/promotion/runner/builtin/git_tree_clearer_test.go b/pkg/promotion/runner/builtin/git_tree_clearer_test.go index 4af30f03a5..ff1336b49c 100644 --- a/pkg/promotion/runner/builtin/git_tree_clearer_test.go +++ b/pkg/promotion/runner/builtin/git_tree_clearer_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "fmt" "net/http/httptest" "os" @@ -94,7 +93,7 @@ func Test_gitTreeOverwriter_run(t *testing.T) { require.True(t, ok) res, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{ Project: "fake-project", Stage: "fake-stage", diff --git a/pkg/promotion/runner/builtin/helm_chart_updater_test.go b/pkg/promotion/runner/builtin/helm_chart_updater_test.go index 9951ac2d46..1571a37664 100644 --- a/pkg/promotion/runner/builtin/helm_chart_updater_test.go +++ b/pkg/promotion/runner/builtin/helm_chart_updater_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "net/http" "net/http/httptest" "os" @@ -328,7 +327,7 @@ func Test_helmChartUpdater_run(t *testing.T) { require.NoError(t, os.WriteFile(filepath.Join(chartPath, "Chart.yaml"), b, 0o600)) } - result, err := runner.run(context.Background(), stepCtx, tt.cfg) + result, err := runner.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, stepCtx.WorkDir, result, err) // Assert that the Helm cache directory was not used diff --git a/pkg/promotion/runner/builtin/helm_template_runner_test.go b/pkg/promotion/runner/builtin/helm_template_runner_test.go index bb8c603135..7e97dae96e 100644 --- a/pkg/promotion/runner/builtin/helm_template_runner_test.go +++ b/pkg/promotion/runner/builtin/helm_template_runner_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path/filepath" "testing" @@ -750,7 +749,7 @@ metadata: WorkDir: workDir, Project: "test-project", } - result, err := runner.run(context.Background(), stepCtx, tt.cfg) + result, err := runner.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, workDir, result, err) }) } diff --git a/pkg/promotion/runner/builtin/http_downloader_test.go b/pkg/promotion/runner/builtin/http_downloader_test.go index de53bf4e63..b3bc0c99a6 100644 --- a/pkg/promotion/runner/builtin/http_downloader_test.go +++ b/pkg/promotion/runner/builtin/http_downloader_test.go @@ -373,7 +373,7 @@ func Test_httpDownloader_run(t *testing.T) { // Run the downloader d := &httpDownloader{} - res, err := d.run(context.Background(), stepCtx, tt.cfg) + res, err := d.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, res, err, workDir) }) } @@ -524,7 +524,7 @@ func Test_httpDownloader_downloadToFile(t *testing.T) { // Download the file d := &httpDownloader{} - err := d.downloadToFile(context.Background(), resp, outPath) + err := d.downloadToFile(t.Context(), resp, outPath) tt.assertions(t, err, outPath) }) } @@ -553,7 +553,7 @@ func Test_httpDownloader_downloadToFile_contextCancellation(t *testing.T) { outPath := filepath.Join(tempDir, "interrupted-file.txt") // Create context that will be canceled - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) // Cancel context after a short delay go func() { @@ -591,7 +591,7 @@ func Test_httpDownloader_downloadToFile_sizeExceeded(t *testing.T) { outPath := filepath.Join(tempDir, "large-file.txt") d := &httpDownloader{} - err := d.downloadToFile(context.Background(), resp, outPath) + err := d.downloadToFile(t.Context(), resp, outPath) require.ErrorContains(t, err, "download exceeds limit") diff --git a/pkg/promotion/runner/builtin/http_requester_test.go b/pkg/promotion/runner/builtin/http_requester_test.go index d951ee619f..c79d839488 100644 --- a/pkg/promotion/runner/builtin/http_requester_test.go +++ b/pkg/promotion/runner/builtin/http_requester_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "io" "net/http" "net/http/httptest" @@ -567,7 +566,7 @@ func Test_httpRequester_run(t *testing.T) { srv := httptest.NewServer(testCase.handler) t.Cleanup(srv.Close) testCase.cfg.URL = srv.URL - res, err := h.run(context.Background(), nil, testCase.cfg) + res, err := h.run(t.Context(), nil, testCase.cfg) testCase.assertions(t, res, err) }) } @@ -1060,7 +1059,7 @@ func Test_httpRequester_buildExprEnv(t *testing.T) { h := &httpRequester{} for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - env, err := h.buildExprEnv(context.Background(), testCase.resp, testCase.responseContentType) + env, err := h.buildExprEnv(t.Context(), testCase.resp, testCase.responseContentType) testCase.assertions(t, env, err) }) } diff --git a/pkg/promotion/runner/builtin/json_parser_test.go b/pkg/promotion/runner/builtin/json_parser_test.go index 563884f36c..b8cfd62f63 100644 --- a/pkg/promotion/runner/builtin/json_parser_test.go +++ b/pkg/promotion/runner/builtin/json_parser_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path" "path/filepath" @@ -308,7 +307,7 @@ func Test_jsonParser_run(t *testing.T) { require.NoError(t, os.WriteFile(path.Join(stepCtx.WorkDir, p), []byte(c), 0o600)) } - result, err := runner.run(context.Background(), stepCtx, tt.cfg) + result, err := runner.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, stepCtx.WorkDir, result, err) }) } diff --git a/pkg/promotion/runner/builtin/json_updater_test.go b/pkg/promotion/runner/builtin/json_updater_test.go index 1492f3cbf1..4f7a001afe 100644 --- a/pkg/promotion/runner/builtin/json_updater_test.go +++ b/pkg/promotion/runner/builtin/json_updater_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "encoding/json" "os" "path" @@ -467,7 +466,7 @@ func Test_jsonUpdater_run(t *testing.T) { require.NoError(t, os.WriteFile(path.Join(stepCtx.WorkDir, p), []byte(c), 0o600)) } - result, err := runner.run(context.Background(), stepCtx, tt.cfg) + result, err := runner.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, stepCtx.WorkDir, result, err) }) } diff --git a/pkg/promotion/runner/builtin/kustomize_image_setter_test.go b/pkg/promotion/runner/builtin/kustomize_image_setter_test.go index 40f1d83aeb..db7c0c74ff 100644 --- a/pkg/promotion/runner/builtin/kustomize_image_setter_test.go +++ b/pkg/promotion/runner/builtin/kustomize_image_setter_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path/filepath" "strings" @@ -264,7 +263,7 @@ kind: Kustomization if tt.setupFiles != nil { tt.setupFiles(t, tt.stepCtx.WorkDir) } - result, err := runner.run(context.Background(), tt.stepCtx, tt.cfg) + result, err := runner.run(t.Context(), tt.stepCtx, tt.cfg) tt.assertions(t, tt.stepCtx.WorkDir, result, err) }) } @@ -420,7 +419,7 @@ func Test_kustomizeImageSetter_buildTargetImagesAutomatically(t *testing.T) { }, } - result, err := runner.buildTargetImagesAutomatically(context.Background(), stepCtx) + result, err := runner.buildTargetImagesAutomatically(t.Context(), stepCtx) tt.assertions(t, result, err) }) } diff --git a/pkg/promotion/runner/builtin/metadata_setter_test.go b/pkg/promotion/runner/builtin/metadata_setter_test.go index a879da6f3f..2259636d6b 100644 --- a/pkg/promotion/runner/builtin/metadata_setter_test.go +++ b/pkg/promotion/runner/builtin/metadata_setter_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "encoding/json" "testing" @@ -263,7 +262,7 @@ func Test_metadataSetter_run(t *testing.T) { stage := &kargoapi.Stage{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: testObjName, Namespace: testProject, @@ -378,7 +377,7 @@ func Test_metadataSetter_run(t *testing.T) { freight := &kargoapi.Freight{} err = c.Get( - context.Background(), + t.Context(), types.NamespacedName{ Name: testObjName, Namespace: testProject, @@ -423,7 +422,7 @@ func Test_metadataSetter_run(t *testing.T) { t.Run(tt.name, func(t *testing.T) { setter := &metadataSetter{kargoClient: tt.client} stepCtx := &promotion.StepContext{Project: testProject} - result, err := setter.run(context.Background(), stepCtx, tt.cfg) + result, err := setter.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, result, tt.client, err) }) } diff --git a/pkg/promotion/runner/builtin/oci_common.go b/pkg/promotion/runner/builtin/oci_common.go new file mode 100644 index 0000000000..b16eb3aa41 --- /dev/null +++ b/pkg/promotion/runner/builtin/oci_common.go @@ -0,0 +1,105 @@ +package builtin + +import ( + "context" + "crypto/tls" + "fmt" + "net/http" + "strings" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/hashicorp/go-cleanhttp" + + "github.com/akuity/kargo/pkg/credentials" +) + +// parseOCIReference parses an OCI image or chart reference and determines the +// credential type. If the reference starts with "oci://", it is treated as a +// Helm OCI repository and the credential type is set to TypeHelm. +func parseOCIReference(imageRef string) (name.Reference, credentials.Type, error) { + credType := credentials.TypeImage + + // To support Helm OCI repositories, we check if the image reference + // starts with "oci://". If it does, we treat it as a Helm repository + // and set the credential type accordingly. + if trimmed, ok := strings.CutPrefix(imageRef, "oci://"); ok { + imageRef = trimmed + credType = credentials.TypeHelm + } + + ref, err := name.ParseReference(imageRef) + if err != nil { + return nil, "", fmt.Errorf("invalid image reference %q: %w", imageRef, err) + } + + return ref, credType, nil +} + +// buildOCIRemoteOptions constructs the remote options for interacting with an +// OCI registry, including context, HTTP transport, and authentication. +func buildOCIRemoteOptions( + ctx context.Context, + credsDB credentials.Database, + project string, + ref name.Reference, + credType credentials.Type, + insecureSkipTLSVerify bool, +) ([]remote.Option, error) { + remoteOpts := []remote.Option{ + remote.WithContext(ctx), + remote.WithTransport(ociHTTPTransport(insecureSkipTLSVerify)), + } + + if authOpt, err := ociAuthOption(ctx, credsDB, project, ref, credType); err != nil { + return nil, err + } else if authOpt != nil { + remoteOpts = append(remoteOpts, authOpt) + } + + return remoteOpts, nil +} + +// ociHTTPTransport creates a new HTTP transport with TLS settings based on the +// insecureSkipTLSVerify flag. +func ociHTTPTransport(insecureSkipTLSVerify bool) *http.Transport { + httpTransport := cleanhttp.DefaultTransport() + if insecureSkipTLSVerify { + httpTransport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, // nolint: gosec + } + } + return httpTransport +} + +// ociAuthOption retrieves and configures authentication for an OCI registry. +func ociAuthOption( + ctx context.Context, + credsDB credentials.Database, + project string, + ref name.Reference, + credType credentials.Type, +) (remote.Option, error) { + repoURL := ref.Context().String() + + // NB: Some credential database implementations expect the URL to be + // prefixed with "oci://". + if credType == credentials.TypeHelm { + repoURL = "oci://" + repoURL + } + + creds, err := credsDB.Get(ctx, project, credType, repoURL) + if err != nil { + return nil, fmt.Errorf("error obtaining credentials for image repo %q: %w", repoURL, err) + } + + if creds != nil && (creds.Username != "" || creds.Password != "") { + return remote.WithAuth(&authn.Basic{ + Username: creds.Username, + Password: creds.Password, + }), nil + } + + return nil, nil +} diff --git a/pkg/promotion/runner/builtin/oci_common_test.go b/pkg/promotion/runner/builtin/oci_common_test.go new file mode 100644 index 0000000000..bb3b48d28e --- /dev/null +++ b/pkg/promotion/runner/builtin/oci_common_test.go @@ -0,0 +1,316 @@ +package builtin + +import ( + "context" + "errors" + "net/http" + "testing" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/akuity/kargo/pkg/credentials" +) + +func Test_parseOCIReference(t *testing.T) { + tests := []struct { + name string + imageRef string + assertions func(*testing.T, name.Reference, credentials.Type, error) + }{ + { + name: "standard registry reference", + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { + require.NoError(t, err) + require.NotNil(t, ref) + assert.Equal(t, credentials.TypeImage, credType) + assert.Equal(t, "registry.example.com/image:tag", ref.String()) + }, + }, + { + name: "OCI Helm reference", + imageRef: "oci://registry.example.com/chart:1.0.0", + assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { + require.NoError(t, err) + require.NotNil(t, ref) + assert.Equal(t, credentials.TypeHelm, credType) + assert.Equal(t, "registry.example.com/chart:1.0.0", ref.String()) + }, + }, + { + name: "invalid reference", + imageRef: "invalid::reference", + assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { + assert.ErrorContains(t, err, "invalid image reference") + assert.Nil(t, ref) + assert.Empty(t, credType) + }, + }, + { + name: "OCI reference with port", + imageRef: "oci://localhost:5000/chart:latest", + assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { + require.NoError(t, err) + require.NotNil(t, ref) + assert.Equal(t, credentials.TypeHelm, credType) + assert.Equal(t, "localhost:5000/chart:latest", ref.String()) + }, + }, + { + name: "standard registry reference with port", + imageRef: "an.internal.registry.com:5050/myrepo/myimage:latest", + assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { + require.NoError(t, err) + require.NotNil(t, ref) + assert.Equal(t, credentials.TypeImage, credType) + assert.Equal(t, "an.internal.registry.com:5050/myrepo/myimage:latest", ref.String()) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ref, credType, err := parseOCIReference(tt.imageRef) + tt.assertions(t, ref, credType, err) + }) + } +} + +func Test_buildOCIRemoteOptions(t *testing.T) { + tests := []struct { + name string + credsDB credentials.Database + imageRef string + assertions func(*testing.T, []remote.Option, error) + }{ + { + name: "basic options without auth", + credsDB: &credentials.FakeDB{}, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opts []remote.Option, err error) { + require.NoError(t, err) + assert.Len(t, opts, 2) + }, + }, + { + name: "options with authentication", + credsDB: &credentials.FakeDB{ + GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { + return &credentials.Credentials{ + Username: "user", + Password: "pass", + }, nil + }, + }, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opts []remote.Option, err error) { + require.NoError(t, err) + assert.Len(t, opts, 3) + }, + }, + { + name: "OCI Helm authentication", + credsDB: &credentials.FakeDB{ + GetFn: func( + _ context.Context, + _ string, + credType credentials.Type, + repoURL string, + ) (*credentials.Credentials, error) { + assert.Equal(t, credentials.TypeHelm, credType) + assert.Equal(t, "oci://registry.example.com/chart", repoURL) + return &credentials.Credentials{ + Username: "helm-user", + Password: "helm-pass", + }, nil + }, + }, + imageRef: "oci://registry.example.com/chart:1.0.0", + assertions: func(t *testing.T, opts []remote.Option, err error) { + require.NoError(t, err) + assert.Len(t, opts, 3) + }, + }, + { + name: "credentials error", + credsDB: &credentials.FakeDB{ + GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { + return nil, errors.New("credentials database error") + }, + }, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opts []remote.Option, err error) { + assert.ErrorContains(t, err, "error obtaining credentials") + assert.Nil(t, opts) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ref, credType, err := parseOCIReference(tt.imageRef) + require.NoError(t, err) + + opts, err := buildOCIRemoteOptions( + context.Background(), tt.credsDB, "fake-project", + ref, credType, false, + ) + tt.assertions(t, opts, err) + }) + } +} + +func Test_ociHTTPTransport(t *testing.T) { + tests := []struct { + name string + insecureSkipTLSVerify bool + assertions func(*testing.T, *http.Transport) + }{ + { + name: "default TLS verification", + insecureSkipTLSVerify: false, + assertions: func(t *testing.T, transport *http.Transport) { + require.NotNil(t, transport) + if transport.TLSClientConfig != nil { + assert.False(t, transport.TLSClientConfig.InsecureSkipVerify) + } + }, + }, + { + name: "skip TLS verification", + insecureSkipTLSVerify: true, + assertions: func(t *testing.T, transport *http.Transport) { + require.NotNil(t, transport) + require.NotNil(t, transport.TLSClientConfig) + assert.True(t, transport.TLSClientConfig.InsecureSkipVerify) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + transport := ociHTTPTransport(tt.insecureSkipTLSVerify) + tt.assertions(t, transport) + }) + } +} + +func Test_ociAuthOption(t *testing.T) { + tests := []struct { + name string + credsDB credentials.Database + imageRef string + assertions func(*testing.T, remote.Option, error) + }{ + { + name: "no credentials for image", + credsDB: &credentials.FakeDB{}, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opt remote.Option, err error) { + require.NoError(t, err) + assert.Nil(t, opt) + }, + }, + { + name: "no credentials for Helm", + credsDB: &credentials.FakeDB{}, + imageRef: "registry.example.com/chart:1.0.0", + assertions: func(t *testing.T, opt remote.Option, err error) { + require.NoError(t, err) + assert.Nil(t, opt) + }, + }, + { + name: "valid image credentials", + credsDB: &credentials.FakeDB{ + GetFn: func( + _ context.Context, + _ string, + credType credentials.Type, + repoURL string, + ) (*credentials.Credentials, error) { + assert.Equal(t, credentials.TypeImage, credType) + assert.Equal(t, "registry.example.com/image", repoURL) + return &credentials.Credentials{ + Username: "user", + Password: "pass", + }, nil + }, + }, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opt remote.Option, err error) { + require.NoError(t, err) + require.NotNil(t, opt) + }, + }, + { + name: "valid Helm credentials with OCI prefix", + credsDB: &credentials.FakeDB{ + GetFn: func( + _ context.Context, + _ string, + credType credentials.Type, + repoURL string, + ) (*credentials.Credentials, error) { + assert.Equal(t, credentials.TypeHelm, credType) + assert.Equal(t, "oci://registry.example.com/chart", repoURL) + return &credentials.Credentials{ + Username: "helm-user", + Password: "helm-pass", + }, nil + }, + }, + imageRef: "oci://registry.example.com/chart:1.0.0", + assertions: func(t *testing.T, opt remote.Option, err error) { + require.NoError(t, err) + require.NotNil(t, opt) + }, + }, + { + name: "empty username and password", + credsDB: &credentials.FakeDB{ + GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { + return &credentials.Credentials{ + Username: "", + Password: "", + }, nil + }, + }, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opt remote.Option, err error) { + require.NoError(t, err) + assert.Nil(t, opt) + }, + }, + { + name: "credentials database error", + credsDB: &credentials.FakeDB{ + GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { + return nil, errors.New("credentials database error") + }, + }, + imageRef: "registry.example.com/image:tag", + assertions: func(t *testing.T, opt remote.Option, err error) { + assert.ErrorContains(t, err, "error obtaining credentials") + assert.ErrorContains(t, err, "credentials database error") + assert.Nil(t, opt) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ref, credType, err := parseOCIReference(tt.imageRef) + require.NoError(t, err) + + opt, err := ociAuthOption( + context.Background(), tt.credsDB, "fake-project", + ref, credType, + ) + tt.assertions(t, opt, err) + }) + } +} diff --git a/pkg/promotion/runner/builtin/oci_downloader.go b/pkg/promotion/runner/builtin/oci_downloader.go index 97b41dccee..a8d7bff9bd 100644 --- a/pkg/promotion/runner/builtin/oci_downloader.go +++ b/pkg/promotion/runner/builtin/oci_downloader.go @@ -2,20 +2,14 @@ package builtin import ( "context" - "crypto/tls" "errors" "fmt" - "net/http" "os" "path/filepath" - "strings" securejoin "github.com/cyphar/filepath-securejoin" - "github.com/google/go-containerregistry/pkg/authn" - "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/hashicorp/go-cleanhttp" "github.com/xeipuuv/gojsonschema" kargoapi "github.com/akuity/kargo/api/v1alpha1" @@ -146,12 +140,14 @@ func (d *ociDownloader) resolveImage( stepCtx *promotion.StepContext, cfg builtin.OCIDownloadConfig, ) (v1.Image, error) { - ref, credType, err := d.parseImageReference(cfg.ImageRef) + ref, credType, err := parseOCIReference(cfg.ImageRef) if err != nil { return nil, fmt.Errorf("failed to parse image reference %q: %w", cfg.ImageRef, err) } - remoteOpts, err := d.buildRemoteOptions(ctx, stepCtx, cfg, ref, credType) + remoteOpts, err := buildOCIRemoteOptions( + ctx, d.credsDB, stepCtx.Project, ref, credType, cfg.InsecureSkipTLSVerify, + ) if err != nil { return nil, err } @@ -164,93 +160,6 @@ func (d *ociDownloader) resolveImage( return img, nil } -// parseImageReference parses the image reference and determines credential type. -func (d *ociDownloader) parseImageReference(imageRef string) (name.Reference, credentials.Type, error) { - credType := credentials.TypeImage - - // To support Helm OCI repositories, we check if the image reference - // starts with "oci://". If it does, we treat it as a Helm repository - // and set the credential type accordingly. - if strings.HasPrefix(imageRef, "oci://") { - // Remove the "oci://" prefix if present, as the parser expects a - // standard image reference format. - imageRef = strings.TrimPrefix(imageRef, "oci://") - credType = credentials.TypeHelm - } - - ref, err := name.ParseReference(imageRef) - if err != nil { - return nil, "", fmt.Errorf("invalid image reference %q: %w", imageRef, err) - } - - return ref, credType, nil -} - -// buildRemoteOptions constructs the remote options for the registry. -func (d *ociDownloader) buildRemoteOptions( - ctx context.Context, - stepCtx *promotion.StepContext, - cfg builtin.OCIDownloadConfig, - ref name.Reference, - credType credentials.Type, -) ([]remote.Option, error) { - remoteOpts := []remote.Option{ - remote.WithContext(ctx), - remote.WithTransport(d.buildHTTPTransport(cfg)), - } - - // Configure authentication - if authOpt, err := d.getAuthOption(ctx, stepCtx, ref, credType); err != nil { - return nil, err - } else if authOpt != nil { - remoteOpts = append(remoteOpts, authOpt) - } - - return remoteOpts, nil -} - -// buildHTTPTransport creates a new HTTP transport with TLS settings based on -// the configuration. -func (d *ociDownloader) buildHTTPTransport(cfg builtin.OCIDownloadConfig) *http.Transport { - httpTransport := cleanhttp.DefaultTransport() - if cfg.InsecureSkipTLSVerify { - httpTransport.TLSClientConfig = &tls.Config{ - InsecureSkipVerify: true, // nolint: gosec - } - } - return httpTransport -} - -// getAuthOption retrieves and configures authentication for the registry. -func (d *ociDownloader) getAuthOption( - ctx context.Context, - stepCtx *promotion.StepContext, - ref name.Reference, - credType credentials.Type, -) (remote.Option, error) { - repoURL := ref.Context().String() - - // NB: Some credential database implementations expect the URL to be - // prefixed with "oci://". - if credType == credentials.TypeHelm { - repoURL = "oci://" + repoURL - } - - creds, err := d.credsDB.Get(ctx, stepCtx.Project, credType, repoURL) - if err != nil { - return nil, fmt.Errorf("error obtaining credentials for image repo %q: %w", repoURL, err) - } - - if creds != nil && (creds.Username != "" || creds.Password != "") { - return remote.WithAuth(&authn.Basic{ - Username: creds.Username, - Password: creds.Password, - }), nil - } - - return nil, nil -} - // extractLayerToFile extracts the target layer from the image to the specified // file. func (d *ociDownloader) extractLayerToFile(img v1.Image, mediaType, absOutPath string) error { diff --git a/pkg/promotion/runner/builtin/oci_downloader_test.go b/pkg/promotion/runner/builtin/oci_downloader_test.go index 60ddd19f9d..11e37a1f46 100644 --- a/pkg/promotion/runner/builtin/oci_downloader_test.go +++ b/pkg/promotion/runner/builtin/oci_downloader_test.go @@ -4,17 +4,14 @@ import ( "context" "errors" "io" - "net/http" "os" "path" "path/filepath" "strings" "testing" - "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/fake" - "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/static" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/stretchr/testify/assert" @@ -87,73 +84,6 @@ func Test_ociDownloader_validate(t *testing.T) { runValidationTests(t, runner.convert, tests) } -func Test_ociDownloader_parseImageReference(t *testing.T) { - tests := []struct { - name string - imageRef string - assertions func(*testing.T, name.Reference, credentials.Type, error) - }{ - { - name: "standard registry reference", - imageRef: "registry.example.com/image:tag", - assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { - require.NoError(t, err) - require.NotNil(t, ref) - assert.Equal(t, credentials.TypeImage, credType) - assert.Equal(t, "registry.example.com/image:tag", ref.String()) - }, - }, - { - name: "OCI Helm reference", - imageRef: "oci://registry.example.com/chart:1.0.0", - assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { - require.NoError(t, err) - require.NotNil(t, ref) - assert.Equal(t, credentials.TypeHelm, credType) - assert.Equal(t, "registry.example.com/chart:1.0.0", ref.String()) - }, - }, - { - name: "invalid reference", - imageRef: "invalid::reference", - assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { - assert.ErrorContains(t, err, "invalid image reference") - assert.Nil(t, ref) - assert.Empty(t, credType) - }, - }, - { - name: "OCI reference with port", - imageRef: "oci://localhost:5000/chart:latest", - assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { - require.NoError(t, err) - require.NotNil(t, ref) - assert.Equal(t, credentials.TypeHelm, credType) - assert.Equal(t, "localhost:5000/chart:latest", ref.String()) - }, - }, - { - name: "standard registry reference with port", - imageRef: "an.internal.registry.com:5050/myrepo/myimage:latest", - assertions: func(t *testing.T, ref name.Reference, credType credentials.Type, err error) { - require.NoError(t, err) - require.NotNil(t, ref) - assert.Equal(t, credentials.TypeImage, credType) - assert.Equal(t, "an.internal.registry.com:5050/myrepo/myimage:latest", ref.String()) - }, - }, - } - - runner := &ociDownloader{} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ref, credType, err := runner.parseImageReference(tt.imageRef) - tt.assertions(t, ref, credType, err) - }) - } -} - func Test_ociDownloader_resolveImage(t *testing.T) { tests := []struct { name string @@ -220,7 +150,7 @@ func Test_ociDownloader_resolveImage(t *testing.T) { Project: "fake-project", } - img, err := runner.resolveImage(context.Background(), stepCtx, tt.cfg) + img, err := runner.resolveImage(t.Context(), stepCtx, tt.cfg) tt.assertions(t, img, err) }) } @@ -313,310 +243,6 @@ func Test_ociDownloader_prepareOutputPath(t *testing.T) { } } -func Test_ociDownloader_buildRemoteOptions(t *testing.T) { - tests := []struct { - name string - credsDB credentials.Database - cfg builtin.OCIDownloadConfig - assertions func(*testing.T, []remote.Option, error) - }{ - { - name: "basic options without auth", - credsDB: &credentials.FakeDB{}, - cfg: builtin.OCIDownloadConfig{ - ImageRef: "registry.example.com/image:tag", - }, - assertions: func(t *testing.T, opts []remote.Option, err error) { - require.NoError(t, err) - assert.Len(t, opts, 2) - }, - }, - { - name: "options with authentication", - credsDB: &credentials.FakeDB{ - GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { - return &credentials.Credentials{ - Username: "user", - Password: "pass", - }, nil - }, - }, - cfg: builtin.OCIDownloadConfig{ - ImageRef: "registry.example.com/image:tag", - }, - assertions: func(t *testing.T, opts []remote.Option, err error) { - require.NoError(t, err) - assert.Len(t, opts, 3) - }, - }, - { - name: "OCI Helm authentication", - credsDB: &credentials.FakeDB{ - GetFn: func( - _ context.Context, - _ string, - credType credentials.Type, - repoURL string, - ) (*credentials.Credentials, error) { - // Verify the credential type and URL format for OCI Helm - assert.Equal(t, credentials.TypeHelm, credType) - assert.Equal(t, "oci://registry.example.com/chart", repoURL) - return &credentials.Credentials{ - Username: "helm-user", - Password: "helm-pass", - }, nil - }, - }, - cfg: builtin.OCIDownloadConfig{ - ImageRef: "oci://registry.example.com/chart:1.0.0", - }, - assertions: func(t *testing.T, opts []remote.Option, err error) { - require.NoError(t, err) - assert.Len(t, opts, 3) - }, - }, - { - name: "credentials error", - credsDB: &credentials.FakeDB{ - GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { - return nil, errors.New("credentials database error") - }, - }, - cfg: builtin.OCIDownloadConfig{ - ImageRef: "registry.example.com/image:tag", - InsecureSkipTLSVerify: false, - }, - assertions: func(t *testing.T, opts []remote.Option, err error) { - assert.ErrorContains(t, err, "error obtaining credentials") - assert.Nil(t, opts) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - runner := &ociDownloader{credsDB: tt.credsDB} - - ref, credType, err := runner.parseImageReference(tt.cfg.ImageRef) - require.NoError(t, err) - - stepCtx := &promotion.StepContext{ - Project: "fake-project", - } - - opts, err := runner.buildRemoteOptions(context.Background(), stepCtx, tt.cfg, ref, credType) - tt.assertions(t, opts, err) - }) - } -} - -func Test_ociDownloader_buildHTTPTransport(t *testing.T) { - tests := []struct { - name string - cfg builtin.OCIDownloadConfig - assertions func(*testing.T, *http.Transport) - }{ - { - name: "default TLS verification", - cfg: builtin.OCIDownloadConfig{ - InsecureSkipTLSVerify: false, - }, - assertions: func(t *testing.T, transport *http.Transport) { - require.NotNil(t, transport) - if transport.TLSClientConfig != nil { - assert.False(t, transport.TLSClientConfig.InsecureSkipVerify) - } - }, - }, - { - name: "skip TLS verification", - cfg: builtin.OCIDownloadConfig{ - InsecureSkipTLSVerify: true, - }, - assertions: func(t *testing.T, transport *http.Transport) { - require.NotNil(t, transport) - require.NotNil(t, transport.TLSClientConfig) - assert.True(t, transport.TLSClientConfig.InsecureSkipVerify) - }, - }, - } - - runner := &ociDownloader{} - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - transport := runner.buildHTTPTransport(tt.cfg) - tt.assertions(t, transport) - }) - } -} - -func Test_ociDownloader_getAuthOption(t *testing.T) { - tests := []struct { - name string - credsDB credentials.Database - imageRef string - assertions func(*testing.T, remote.Option, error) - }{ - { - name: "no credentials for image", - credsDB: &credentials.FakeDB{}, - imageRef: "registry.example.com/image:tag", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - assert.Nil(t, opt) - }, - }, - { - name: "no credentials for Helm", - credsDB: &credentials.FakeDB{}, - imageRef: "registry.example.com/chart:1.0.0", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - assert.Nil(t, opt) - }, - }, - { - name: "valid image credentials", - credsDB: &credentials.FakeDB{ - GetFn: func( - _ context.Context, - _ string, - credType credentials.Type, - repoURL string, - ) (*credentials.Credentials, error) { - assert.Equal(t, credentials.TypeImage, credType) - assert.Equal(t, "registry.example.com/image", repoURL) - return &credentials.Credentials{ - Username: "user", - Password: "pass", - }, nil - }, - }, - imageRef: "registry.example.com/image:tag", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - require.NotNil(t, opt) - }, - }, - { - name: "valid Helm credentials with OCI prefix", - credsDB: &credentials.FakeDB{ - GetFn: func( - _ context.Context, - _ string, - credType credentials.Type, - repoURL string, - ) (*credentials.Credentials, error) { - assert.Equal(t, credentials.TypeHelm, credType) - assert.Equal(t, "oci://registry.example.com/chart", repoURL) - return &credentials.Credentials{ - Username: "helm-user", - Password: "helm-pass", - }, nil - }, - }, - imageRef: "oci://registry.example.com/chart:1.0.0", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - require.NotNil(t, opt) - }, - }, - { - name: "valid image credentials with port", - credsDB: &credentials.FakeDB{ - GetFn: func( - _ context.Context, - _ string, - credType credentials.Type, - repoURL string, - ) (*credentials.Credentials, error) { - assert.Equal(t, credentials.TypeImage, credType) - assert.Equal(t, "an.internal.registry.com:5050/myrepo/myimage", repoURL) - return &credentials.Credentials{ - Username: "user", - Password: "pass", - }, nil - }, - }, - imageRef: "an.internal.registry.com:5050/myrepo/myimage:latest", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - require.NotNil(t, opt) - }, - }, - { - name: "valid Helm credentials with OCI prefix and port", - credsDB: &credentials.FakeDB{ - GetFn: func( - _ context.Context, - _ string, - credType credentials.Type, - repoURL string, - ) (*credentials.Credentials, error) { - assert.Equal(t, credentials.TypeHelm, credType) - assert.Equal(t, "oci://registry.example.com:5050/chart", repoURL) - return &credentials.Credentials{ - Username: "helm-user", - Password: "helm-pass", - }, nil - }, - }, - imageRef: "oci://registry.example.com:5050/chart:1.0.0", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - require.NotNil(t, opt) - }, - }, - { - name: "empty username and password", - credsDB: &credentials.FakeDB{ - GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { - return &credentials.Credentials{ - Username: "", - Password: "", - }, nil - }, - }, - imageRef: "registry.example.com/image:tag", - assertions: func(t *testing.T, opt remote.Option, err error) { - require.NoError(t, err) - assert.Nil(t, opt) - }, - }, - { - name: "credentials database error", - credsDB: &credentials.FakeDB{ - GetFn: func(context.Context, string, credentials.Type, string) (*credentials.Credentials, error) { - return nil, errors.New("credentials database error") - }, - }, - imageRef: "registry.example.com/image:tag", - assertions: func(t *testing.T, opt remote.Option, err error) { - assert.ErrorContains(t, err, "error obtaining credentials") - assert.ErrorContains(t, err, "credentials database error") - assert.Nil(t, opt) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - runner := &ociDownloader{credsDB: tt.credsDB} - - ref, credType, err := runner.parseImageReference(tt.imageRef) - require.NoError(t, err) - - stepCtx := &promotion.StepContext{ - Project: "fake-project", - } - - opt, err := runner.getAuthOption(context.Background(), stepCtx, ref, credType) - tt.assertions(t, opt, err) - }) - } -} - func Test_ociDownloader_extractLayerToFile(t *testing.T) { tests := []struct { name string diff --git a/pkg/promotion/runner/builtin/oci_pusher.go b/pkg/promotion/runner/builtin/oci_pusher.go new file mode 100644 index 0000000000..49a1dd34d0 --- /dev/null +++ b/pkg/promotion/runner/builtin/oci_pusher.go @@ -0,0 +1,316 @@ +package builtin + +import ( + "context" + "fmt" + "strings" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/kelseyhightower/envconfig" + "github.com/xeipuuv/gojsonschema" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/pkg/credentials" + libfmt "github.com/akuity/kargo/pkg/fmt" + "github.com/akuity/kargo/pkg/image/mutate" + "github.com/akuity/kargo/pkg/promotion" + builtin "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +const stepKindOCIPush = "oci-push" + +// ociPusherConfig holds environment-based configuration for the oci-push step +// runner. A value of -1 for MaxArtifactSize disables the size limit entirely. +type ociPusherConfig struct { + MaxArtifactSize int64 `envconfig:"MAX_OCI_PUSH_ARTIFACT_SIZE" default:"1073741824"` // 1 GiB +} + +func init() { + cfg := ociPusherConfig{} + envconfig.MustProcess("", &cfg) + promotion.DefaultStepRunnerRegistry.MustRegister( + promotion.StepRunnerRegistration{ + Name: stepKindOCIPush, + Metadata: promotion.StepRunnerMetadata{ + RequiredCapabilities: []promotion.StepRunnerCapability{ + promotion.StepCapabilityAccessCredentials, + }, + }, + Value: func( + caps promotion.StepRunnerCapabilities, + ) promotion.StepRunner { + return newOCIPusher(caps, cfg) + }, + }, + ) +} + +// ociPusher is an implementation of the promotion.StepRunner interface that +// copies/retags OCI artifacts (container images and Helm charts) between +// registries. +type ociPusher struct { + schemaLoader gojsonschema.JSONLoader + credsDB credentials.Database + maxArtifactSize int64 // maximum compressed artifact size in bytes +} + +// newOCIPusher returns an implementation of the promotion.StepRunner interface +// that pushes OCI artifacts to a registry. It uses the provided credentials +// database to authenticate with source and destination registries. +func newOCIPusher( + caps promotion.StepRunnerCapabilities, + cfg ociPusherConfig, +) promotion.StepRunner { + return &ociPusher{ + credsDB: caps.CredsDB, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: cfg.MaxArtifactSize, + } +} + +// Run implements the promotion.StepRunner interface. +func (p *ociPusher) Run( + ctx context.Context, + stepCtx *promotion.StepContext, +) (promotion.StepResult, error) { + cfg, err := p.convert(stepCtx.Config) + if err != nil { + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusFailed, + }, &promotion.TerminalError{Err: err} + } + return p.run(ctx, stepCtx, cfg) +} + +// convert validates the ociPusher configuration against a JSON schema and +// converts it into a builtin.OCIPushConfig struct. +func (p *ociPusher) convert(cfg promotion.Config) (builtin.OCIPushConfig, error) { + return validateAndConvert[builtin.OCIPushConfig](p.schemaLoader, cfg, stepKindOCIPush) +} + +// run executes the ociPusher step with the provided configuration. +func (p *ociPusher) run( + ctx context.Context, + stepCtx *promotion.StepContext, + cfg builtin.OCIPushConfig, +) (promotion.StepResult, error) { + srcRef, srcCredType, err := parseOCIReference(cfg.SrcRef) + if err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusFailed}, + &promotion.TerminalError{ + Err: fmt.Errorf("failed to parse source reference %q: %w", cfg.SrcRef, err), + } + } + + dstRef, dstCredType, err := parseOCIReference(cfg.DestRef) + if err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusFailed}, + &promotion.TerminalError{ + Err: fmt.Errorf("failed to parse destination reference %q: %w", cfg.DestRef, err), + } + } + + srcOpts, err := buildOCIRemoteOptions( + ctx, p.credsDB, stepCtx.Project, srcRef, srcCredType, cfg.InsecureSkipTLSVerify, + ) + if err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err + } + + dstOpts, err := buildOCIRemoteOptions( + ctx, p.credsDB, stepCtx.Project, dstRef, dstCredType, cfg.InsecureSkipTLSVerify, + ) + if err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err + } + + desc, err := remote.Get(srcRef, srcOpts...) + if err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, + fmt.Errorf("failed to get source artifact %q: %w", cfg.SrcRef, err) + } + + digest, err := p.push(desc, srcRef, dstRef, cfg.Annotations, dstOpts) + if err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, err + } + + // Extract tag from destination reference if available. + var tag string + if t, ok := dstRef.(name.Tag); ok { + tag = t.TagStr() + } + + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusSucceeded, + Output: map[string]any{ + "image": dstRef.String(), + "digest": digest.String(), + "tag": tag, + }, + }, nil +} + +// annotationScopes holds annotations separated by their target scope. +// Keys prefixed with "index:" target the image index manifest, keys prefixed +// with "manifest:" or unprefixed target image manifests. +type annotationScopes struct { + index map[string]string // applied to the image index manifest + manifest map[string]string // applied to each image manifest +} + +// parseAnnotationScopes splits annotation keys by their scope prefix. +// Keys prefixed with "index:" are routed to the index manifest, keys prefixed +// with "manifest:" or unprefixed are routed to image manifests. +func (p *ociPusher) parseAnnotationScopes(annotations map[string]string) annotationScopes { + scopes := annotationScopes{ + index: make(map[string]string), + manifest: make(map[string]string), + } + for k, v := range annotations { + switch { + case strings.HasPrefix(k, "index:"): + scopes.index[strings.TrimPrefix(k, "index:")] = v + case strings.HasPrefix(k, "manifest:"): + scopes.manifest[strings.TrimPrefix(k, "manifest:")] = v + default: + scopes.manifest[k] = v + } + } + return scopes +} + +// imageSize returns the total compressed size of an image (config + layers) +// using only manifest metadata — no blob downloads are performed. +func (p *ociPusher) imageSize(img v1.Image) (int64, error) { + m, err := img.Manifest() + if err != nil { + return 0, err + } + var total int64 + total += m.Config.Size + for _, l := range m.Layers { + total += l.Size + } + return total, nil +} + +// indexSize returns the total compressed size across all child images of an +// image index. Each child manifest is fetched to read its layer sizes, but no +// blobs are downloaded. +func (p *ociPusher) indexSize(idx v1.ImageIndex) (int64, error) { + im, err := idx.IndexManifest() + if err != nil { + return 0, err + } + var total int64 + for _, desc := range im.Manifests { + img, err := idx.Image(desc.Digest) + if err != nil { + return 0, fmt.Errorf("failed to resolve child image %s: %w", desc.Digest, err) + } + sz, err := p.imageSize(img) + if err != nil { + return 0, fmt.Errorf("failed to compute size of child image %s: %w", desc.Digest, err) + } + total += sz + } + return total, nil +} + +// artifactSize returns the total compressed size of an OCI artifact (config + +// layers) from its descriptor metadata. For image indexes, this includes the +// sum across all child images. No blobs are downloaded. +func (p *ociPusher) artifactSize(desc *remote.Descriptor) (int64, error) { + switch { + case desc.MediaType.IsImage(): + img, err := desc.Image() + if err != nil { + return 0, fmt.Errorf("failed to resolve source image: %w", err) + } + return p.imageSize(img) + case desc.MediaType.IsIndex(): + idx, err := desc.ImageIndex() + if err != nil { + return 0, fmt.Errorf("failed to resolve source image index: %w", err) + } + return p.indexSize(idx) + default: + return 0, &promotion.TerminalError{ + Err: fmt.Errorf("unsupported media type %q", desc.MediaType), + } + } +} + +// push pushes the described artifact to the destination reference, optionally +// applying scoped annotations to the manifest. +func (p *ociPusher) push( + desc *remote.Descriptor, + srcRef, dstRef name.Reference, + annotations map[string]string, + dstOpts []remote.Option, +) (v1.Hash, error) { + // Enforce the size limit only when copying across repositories (registry + + // path). Within the same repository the blobs are already present, so no + // large transfer occurs. A negative maxArtifactSize disables the check. + if p.maxArtifactSize >= 0 && srcRef.Context().String() != dstRef.Context().String() { + if p.maxArtifactSize == 0 { + return v1.Hash{}, &promotion.TerminalError{ + Err: fmt.Errorf("cross-repository push is disabled"), + } + } + sz, err := p.artifactSize(desc) + if err != nil { + return v1.Hash{}, err + } + if sz > p.maxArtifactSize { + return v1.Hash{}, &promotion.TerminalError{ + Err: fmt.Errorf( + "compressed artifact size %s exceeds maximum allowed size of %s", + libfmt.FormatByteCount(sz), libfmt.FormatByteCount(p.maxArtifactSize), + ), + } + } + } + + scopes := p.parseAnnotationScopes(annotations) + + switch { + case desc.MediaType.IsImage(): + img, err := desc.Image() + if err != nil { + return v1.Hash{}, fmt.Errorf("failed to resolve source image: %w", err) + } + annotated, err := mutate.Annotations(img, nil, scopes.manifest) + if err != nil { + return v1.Hash{}, fmt.Errorf("failed to annotate image: %w", err) + } + img = annotated.(v1.Image) //nolint:forcetypeassert + if err = remote.Write(dstRef, img, dstOpts...); err != nil { + return v1.Hash{}, fmt.Errorf("failed to push image to %q: %w", dstRef.String(), err) + } + return img.Digest() + + case desc.MediaType.IsIndex(): + idx, err := desc.ImageIndex() + if err != nil { + return v1.Hash{}, fmt.Errorf("failed to resolve source image index: %w", err) + } + annotated, err := mutate.Annotations(idx, scopes.index, scopes.manifest) + if err != nil { + return v1.Hash{}, fmt.Errorf("failed to annotate index: %w", err) + } + idx = annotated.(v1.ImageIndex) //nolint:forcetypeassert + if err = remote.WriteIndex(dstRef, idx, dstOpts...); err != nil { + return v1.Hash{}, fmt.Errorf("failed to push image index to %q: %w", dstRef.String(), err) + } + return idx.Digest() + + default: + return v1.Hash{}, &promotion.TerminalError{ + Err: fmt.Errorf("unsupported media type %q", desc.MediaType), + } + } +} diff --git a/pkg/promotion/runner/builtin/oci_pusher_test.go b/pkg/promotion/runner/builtin/oci_pusher_test.go new file mode 100644 index 0000000000..0eafd1754d --- /dev/null +++ b/pkg/promotion/runner/builtin/oci_pusher_test.go @@ -0,0 +1,832 @@ +package builtin + +import ( + "context" + "fmt" + "net/http/httptest" + "testing" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/registry" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/random" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/kelseyhightower/envconfig" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/pkg/credentials" + "github.com/akuity/kargo/pkg/promotion" + builtin "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +func Test_ociPusher_validate(t *testing.T) { + tests := []validationTestCase{ + { + name: "srcRef is not specified", + config: promotion.Config{}, + expectedProblems: []string{ + "(root): srcRef is required", + }, + }, + { + name: "destRef is not specified", + config: promotion.Config{}, + expectedProblems: []string{ + "(root): destRef is required", + }, + }, + { + name: "valid minimal config", + config: promotion.Config{ + "srcRef": "registry.example.com/image:tag", + "destRef": "registry.example.com/image:newtag", + }, + }, + { + name: "valid config with OCI protocol", + config: promotion.Config{ + "srcRef": "oci://registry.example.com/chart:1.0.0", + "destRef": "oci://registry.example.com/chart:2.0.0", + }, + }, + { + name: "valid config with non-standard port", + config: promotion.Config{ + "srcRef": "an.internal.registry.com:5050/myrepo/myimage:latest", + "destRef": "an.internal.registry.com:5050/myrepo/myimage:newtag", + }, + }, + { + name: "valid config with OCI protocol and non-standard port", + config: promotion.Config{ + "srcRef": "oci://registry.example.com:5050/chart:1.0.0", + "destRef": "oci://registry.example.com:5050/chart:2.0.0", + }, + }, + { + name: "valid config with all optional fields", + config: promotion.Config{ + "srcRef": "registry.example.com/image:tag", + "destRef": "registry.example.com/image:newtag", + "insecureSkipTLSVerify": true, + "annotations": map[string]any{ + "org.opencontainers.image.source": "https://github.com/example/repo", + }, + }, + }, + } + + r := newOCIPusher(promotion.StepRunnerCapabilities{}, ociPusherConfig{ + MaxArtifactSize: int64(1 << 30), + }) + runner, ok := r.(*ociPusher) + require.True(t, ok) + + runValidationTests(t, runner.convert, tests) +} + +func Test_ociPusher_run(t *testing.T) { + // Start an in-memory registry for testing. + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + + // Strip the "http://" prefix to get a valid registry host. + regHost := srv.Listener.Addr().String() + + // Push a test image to the registry for use as a source. + srcImageRef := fmt.Sprintf("%s/test/image:v1.0.0", regHost) + srcRef, err := name.ParseReference(srcImageRef) + require.NoError(t, err) + + testImg, err := random.Image(256, 1) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, testImg)) + + srcDigest, err := testImg.Digest() + require.NoError(t, err) + + // Push a test image index to the registry. + srcIndexRef := fmt.Sprintf("%s/test/multiarch:v1.0.0", regHost) + idxRef, err := name.ParseReference(srcIndexRef) + require.NoError(t, err) + + testIdx, err := random.Index(256, 1, 2) // 2 platform images + require.NoError(t, err) + require.NoError(t, remote.WriteIndex(idxRef, testIdx)) + + srcIdxDigest, err := testIdx.Digest() + require.NoError(t, err) + + tests := []struct { + name string + cfg builtin.OCIPushConfig + assertions func(*testing.T, promotion.StepResult, error) + }{ + { + name: "push single image to new tag", + cfg: builtin.OCIPushConfig{ + SrcRef: srcImageRef, + DestRef: fmt.Sprintf("%s/test/image:v2.0.0", regHost), + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + assert.Equal(t, + fmt.Sprintf("%s/test/image:v2.0.0", regHost), + result.Output["image"], + ) + assert.Equal(t, srcDigest.String(), result.Output["digest"]) + assert.Equal(t, "v2.0.0", result.Output["tag"]) + + // Verify the image is retrievable at the destination. + dstRef, parseErr := name.ParseReference( + fmt.Sprintf("%s/test/image:v2.0.0", regHost), + ) + require.NoError(t, parseErr) + desc, getErr := remote.Get(dstRef) + require.NoError(t, getErr) + assert.Equal(t, srcDigest, desc.Digest) + }, + }, + { + name: "push image by digest", + cfg: builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/image@%s", regHost, srcDigest.String()), + DestRef: fmt.Sprintf("%s/test/image:pinned", regHost), + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + assert.Equal(t, srcDigest.String(), result.Output["digest"]) + assert.Equal(t, "pinned", result.Output["tag"]) + }, + }, + { + name: "push image index", + cfg: builtin.OCIPushConfig{ + SrcRef: srcIndexRef, + DestRef: fmt.Sprintf("%s/test/multiarch:v2.0.0", regHost), + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + assert.Equal(t, srcIdxDigest.String(), result.Output["digest"]) + assert.Equal(t, "v2.0.0", result.Output["tag"]) + + // Verify the index is retrievable at the destination. + dstRef, parseErr := name.ParseReference( + fmt.Sprintf("%s/test/multiarch:v2.0.0", regHost), + ) + require.NoError(t, parseErr) + desc, getErr := remote.Get(dstRef) + require.NoError(t, getErr) + assert.True(t, desc.MediaType.IsIndex()) + }, + }, + { + name: "push with annotations", + cfg: builtin.OCIPushConfig{ + SrcRef: srcImageRef, + DestRef: fmt.Sprintf("%s/test/image:annotated", regHost), + Annotations: map[string]string{ + "org.opencontainers.image.source": "https://github.com/example", + }, + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + // Verify annotations on the pushed manifest. + dstRef, parseErr := name.ParseReference( + fmt.Sprintf("%s/test/image:annotated", regHost), + ) + require.NoError(t, parseErr) + img, getErr := remote.Image(dstRef) + require.NoError(t, getErr) + manifest, mErr := img.Manifest() + require.NoError(t, mErr) + assert.Equal(t, + "https://github.com/example", + manifest.Annotations["org.opencontainers.image.source"], + ) + }, + }, + { + name: "push index with unprefixed annotations goes to child manifests", + cfg: builtin.OCIPushConfig{ + SrcRef: srcIndexRef, + DestRef: fmt.Sprintf("%s/test/multiarch:annotated", regHost), + Annotations: map[string]string{ + "io.kargo.test": "true", + }, + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + dstRef, parseErr := name.ParseReference( + fmt.Sprintf("%s/test/multiarch:annotated", regHost), + ) + require.NoError(t, parseErr) + idx, getErr := remote.Index(dstRef) + require.NoError(t, getErr) + + // Unprefixed annotations should NOT be on the index. + idxManifest, mErr := idx.IndexManifest() + require.NoError(t, mErr) + assert.Empty(t, idxManifest.Annotations["io.kargo.test"]) + + // Unprefixed annotations should be on each child manifest. + for _, desc := range idxManifest.Manifests { + img, imgErr := idx.Image(desc.Digest) + require.NoError(t, imgErr) + m, manifestErr := img.Manifest() + require.NoError(t, manifestErr) + assert.Equal(t, "true", m.Annotations["io.kargo.test"]) + } + }, + }, + { + name: "push index with scoped annotations", + cfg: builtin.OCIPushConfig{ + SrcRef: srcIndexRef, + DestRef: fmt.Sprintf("%s/test/multiarch:scoped", regHost), + Annotations: map[string]string{ + "index:io.kargo.index-only": "idx", + "manifest:io.kargo.manifest-only": "mfst", + "io.kargo.default": "both", + }, + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + dstRef, parseErr := name.ParseReference( + fmt.Sprintf("%s/test/multiarch:scoped", regHost), + ) + require.NoError(t, parseErr) + idx, getErr := remote.Index(dstRef) + require.NoError(t, getErr) + + // Index annotations: only "index:" prefixed. + idxManifest, mErr := idx.IndexManifest() + require.NoError(t, mErr) + assert.Equal(t, "idx", idxManifest.Annotations["io.kargo.index-only"]) + assert.Empty(t, idxManifest.Annotations["io.kargo.manifest-only"]) + assert.Empty(t, idxManifest.Annotations["io.kargo.default"]) + + // Child manifest annotations: "manifest:" prefixed + unprefixed. + for _, desc := range idxManifest.Manifests { + img, imgErr := idx.Image(desc.Digest) + require.NoError(t, imgErr) + m, manifestErr := img.Manifest() + require.NoError(t, manifestErr) + assert.Equal(t, "mfst", m.Annotations["io.kargo.manifest-only"]) + assert.Equal(t, "both", m.Annotations["io.kargo.default"]) + assert.Empty(t, m.Annotations["io.kargo.index-only"]) + } + }, + }, + { + name: "cross-repo push", + cfg: builtin.OCIPushConfig{ + SrcRef: srcImageRef, + DestRef: fmt.Sprintf("%s/other/repo:latest", regHost), + }, + assertions: func(t *testing.T, result promotion.StepResult, err error) { + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + // Verify the image is at the new repo. + dstRef, parseErr := name.ParseReference( + fmt.Sprintf("%s/other/repo:latest", regHost), + ) + require.NoError(t, parseErr) + desc, getErr := remote.Get(dstRef) + require.NoError(t, getErr) + assert.Equal(t, srcDigest, desc.Digest) + }, + }, + { + name: "source not found", + cfg: builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/nonexistent/image:v1.0.0", regHost), + DestRef: fmt.Sprintf("%s/test/image:copy", regHost), + }, + assertions: func(t *testing.T, _ promotion.StepResult, err error) { + assert.ErrorContains(t, err, "failed to get source artifact") + }, + }, + { + name: "invalid source reference", + cfg: builtin.OCIPushConfig{ + SrcRef: "invalid::ref", + DestRef: fmt.Sprintf("%s/test/image:copy", regHost), + }, + assertions: func(t *testing.T, _ promotion.StepResult, err error) { + assert.Error(t, err) + assert.ErrorContains(t, err, "failed to parse source reference") + var termErr *promotion.TerminalError + assert.ErrorAs(t, err, &termErr) + }, + }, + { + name: "invalid destination reference", + cfg: builtin.OCIPushConfig{ + SrcRef: srcImageRef, + DestRef: "invalid::ref", + }, + assertions: func(t *testing.T, _ promotion.StepResult, err error) { + assert.Error(t, err) + assert.ErrorContains(t, err, "failed to parse destination reference") + var termErr *promotion.TerminalError + assert.ErrorAs(t, err, &termErr) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: int64(1 << 30), + } + + stepCtx := &promotion.StepContext{ + Project: "fake-project", + } + + result, err := runner.run(context.Background(), stepCtx, tt.cfg) + tt.assertions(t, result, err) + }) + } +} + +func Test_ociPusher_push_unsupportedMediaType(t *testing.T) { + // Create a descriptor with an unsupported media type. + desc := &remote.Descriptor{ + Descriptor: v1.Descriptor{ + MediaType: types.MediaType("application/vnd.unsupported"), + }, + } + + runner := &ociPusher{maxArtifactSize: int64(1 << 30)} + srcRef, err := name.ParseReference("localhost:5000/src:tag") + require.NoError(t, err) + dstRef, err := name.ParseReference("localhost:5000/test:tag") + require.NoError(t, err) + + _, err = runner.push(desc, srcRef, dstRef, nil, nil) + assert.ErrorContains(t, err, "unsupported media type") + var termErr *promotion.TerminalError + assert.ErrorAs(t, err, &termErr) +} + +func Test_ociPusher_run_credentialError(t *testing.T) { + tests := []struct { + name string + cfg builtin.OCIPushConfig + credsDB credentials.Database + errMsg string + }{ + { + name: "source credential error", + cfg: builtin.OCIPushConfig{ + SrcRef: "registry.example.com/image:tag", + DestRef: "registry.example.com/image:newtag", + }, + credsDB: &credentials.FakeDB{ + GetFn: func( + _ context.Context, _ string, _ credentials.Type, repoURL string, + ) (*credentials.Credentials, error) { + if repoURL == "registry.example.com/image" { + return nil, fmt.Errorf("source cred error") + } + return nil, nil + }, + }, + errMsg: "error obtaining credentials", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + runner := &ociPusher{ + credsDB: tt.credsDB, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: int64(1 << 30), + } + + stepCtx := &promotion.StepContext{ + Project: "fake-project", + } + + _, err := runner.run(context.Background(), stepCtx, tt.cfg) + assert.ErrorContains(t, err, tt.errMsg) + }) + } +} + +// Test that annotations don't mutate the source image when none are provided. +func Test_ociPusher_run_noAnnotationsMutation(t *testing.T) { + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + regHost := srv.Listener.Addr().String() + + // Create an OCI image with existing annotations. + srcImg, err := random.Image(256, 1) + require.NoError(t, err) + annotated, ok := mutate.Annotations(srcImg, map[string]string{ + "existing": "annotation", + }).(v1.Image) + require.True(t, ok) + srcImg = annotated + + srcRef, err := name.ParseReference(fmt.Sprintf("%s/test/annotated:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, srcImg)) + + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: int64(1 << 30), + } + + // Push without specifying annotations. + result, err := runner.run(context.Background(), &promotion.StepContext{ + Project: "fake-project", + }, builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/annotated:v1", regHost), + DestRef: fmt.Sprintf("%s/test/annotated:v2", regHost), + }) + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + // Verify the existing annotation is preserved and no extra ones added. + dstRef, err := name.ParseReference(fmt.Sprintf("%s/test/annotated:v2", regHost)) + require.NoError(t, err) + dstImg, err := remote.Image(dstRef) + require.NoError(t, err) + manifest, err := dstImg.Manifest() + require.NoError(t, err) + assert.Equal(t, "annotation", manifest.Annotations["existing"]) +} + +func Test_parseAnnotationScopes(t *testing.T) { + tests := []struct { + name string + annotations map[string]string + wantIndex map[string]string + wantManifest map[string]string + }{ + { + name: "nil annotations", + annotations: nil, + wantIndex: map[string]string{}, + wantManifest: map[string]string{}, + }, + { + name: "unprefixed go to manifest", + annotations: map[string]string{ + "foo": "bar", + }, + wantIndex: map[string]string{}, + wantManifest: map[string]string{"foo": "bar"}, + }, + { + name: "index prefix", + annotations: map[string]string{ + "index:foo": "bar", + }, + wantIndex: map[string]string{"foo": "bar"}, + wantManifest: map[string]string{}, + }, + { + name: "manifest prefix", + annotations: map[string]string{ + "manifest:foo": "bar", + }, + wantIndex: map[string]string{}, + wantManifest: map[string]string{"foo": "bar"}, + }, + { + name: "mixed scopes", + annotations: map[string]string{ + "index:a": "1", + "manifest:b": "2", + "c": "3", + }, + wantIndex: map[string]string{"a": "1"}, + wantManifest: map[string]string{"b": "2", "c": "3"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &ociPusher{} + scopes := p.parseAnnotationScopes(tt.annotations) + assert.Equal(t, tt.wantIndex, scopes.index) + assert.Equal(t, tt.wantManifest, scopes.manifest) + }) + } +} + +func Test_ociPusher_run_scopedAnnotationsOnImage(t *testing.T) { + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + regHost := srv.Listener.Addr().String() + + srcImg, err := random.Image(256, 1) + require.NoError(t, err) + srcRef, err := name.ParseReference(fmt.Sprintf("%s/test/scoped:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, srcImg)) + + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: int64(1 << 30), + } + + // Push with mixed scoped annotations. "index:" should be ignored for images. + result, err := runner.run(context.Background(), &promotion.StepContext{ + Project: "fake-project", + }, builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/scoped:v1", regHost), + DestRef: fmt.Sprintf("%s/test/scoped:v2", regHost), + Annotations: map[string]string{ + "index:ignored.key": "ignored", + "manifest:explicit": "yes", + "unprefixed": "also-yes", + }, + }) + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + dstRef, err := name.ParseReference(fmt.Sprintf("%s/test/scoped:v2", regHost)) + require.NoError(t, err) + dstImg, err := remote.Image(dstRef) + require.NoError(t, err) + manifest, err := dstImg.Manifest() + require.NoError(t, err) + + // manifest: and unprefixed should appear on the image manifest. + assert.Equal(t, "yes", manifest.Annotations["explicit"]) + assert.Equal(t, "also-yes", manifest.Annotations["unprefixed"]) + // index: should NOT appear. + assert.Empty(t, manifest.Annotations["ignored.key"]) +} + +// Test OCI image with an OCI manifest (not Docker) to ensure annotations work. +func Test_ociPusher_run_ociManifestAnnotations(t *testing.T) { + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + regHost := srv.Listener.Addr().String() + + // Create an OCI-format image (empty.Image is OCI by default). + srcImg := empty.Image + srcRef, err := name.ParseReference(fmt.Sprintf("%s/test/oci:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, srcImg)) + + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: int64(1 << 30), + } + + result, err := runner.run(context.Background(), &promotion.StepContext{ + Project: "fake-project", + }, builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/oci:v1", regHost), + DestRef: fmt.Sprintf("%s/test/oci:v2", regHost), + Annotations: map[string]string{ + "test.key": "test.value", + }, + }) + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + + dstRef, err := name.ParseReference(fmt.Sprintf("%s/test/oci:v2", regHost)) + require.NoError(t, err) + dstImg, err := remote.Image(dstRef) + require.NoError(t, err) + manifest, err := dstImg.Manifest() + require.NoError(t, err) + assert.Equal(t, "test.value", manifest.Annotations["test.key"]) +} + +func Test_imageSize(t *testing.T) { + img, err := random.Image(256, 3) + require.NoError(t, err) + + p := &ociPusher{} + sz, err := p.imageSize(img) + require.NoError(t, err) + assert.Greater(t, sz, int64(0)) + + // Verify it matches the sum of config + layers from the manifest. + m, err := img.Manifest() + require.NoError(t, err) + var expected int64 + expected += m.Config.Size + for _, l := range m.Layers { + expected += l.Size + } + assert.Equal(t, expected, sz) +} + +func Test_indexSize(t *testing.T) { + idx, err := random.Index(256, 2, 3) // 3 platform images, 2 layers each + require.NoError(t, err) + + p := &ociPusher{} + sz, err := p.indexSize(idx) + require.NoError(t, err) + assert.Greater(t, sz, int64(0)) + + // Verify it equals the sum of imageSize for each child. + im, err := idx.IndexManifest() + require.NoError(t, err) + var expected int64 + for _, desc := range im.Manifests { + child, imgErr := idx.Image(desc.Digest) + require.NoError(t, imgErr) + childSz, szErr := p.imageSize(child) + require.NoError(t, szErr) + expected += childSz + } + assert.Equal(t, expected, sz) +} + +func Test_ociPusher_push_sizeLimitExceeded(t *testing.T) { + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + regHost := srv.Listener.Addr().String() + + // Push a test image (will exceed our tiny limit). + srcImg, err := random.Image(256, 1) + require.NoError(t, err) + srcRef, err := name.ParseReference(fmt.Sprintf("%s/test/big:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, srcImg)) + + // Push a test index. + srcIdx, err := random.Index(256, 1, 2) + require.NoError(t, err) + idxRef, err := name.ParseReference(fmt.Sprintf("%s/test/bigidx:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.WriteIndex(idxRef, srcIdx)) + + tests := []struct { + name string + srcRef string + }{ + { + name: "image exceeds size limit", + srcRef: fmt.Sprintf("%s/test/big:v1", regHost), + }, + { + name: "index exceeds size limit", + srcRef: fmt.Sprintf("%s/test/bigidx:v1", regHost), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: 100, // tiny limit to trigger the error + } + + result, err := runner.run(context.Background(), &promotion.StepContext{ + Project: "fake-project", + }, builtin.OCIPushConfig{ + SrcRef: tt.srcRef, + DestRef: fmt.Sprintf("%s/test/dst:v1", regHost), + }) + assert.Equal(t, string(kargoapi.PromotionStepStatusErrored), string(result.Status)) + assert.ErrorContains(t, err, "exceeds maximum allowed size of") + var termErr *promotion.TerminalError + assert.ErrorAs(t, err, &termErr) + }) + } +} + +func Test_ociPusher_push_sizeLimitZero(t *testing.T) { + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + regHost := srv.Listener.Addr().String() + + srcImg, err := random.Image(256, 1) + require.NoError(t, err) + srcRef, err := name.ParseReference(fmt.Sprintf("%s/test/img:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, srcImg)) + + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: 0, // blocks all cross-repo pushes + } + stepCtx := &promotion.StepContext{Project: "fake-project"} + + t.Run("cross-repo push is blocked", func(t *testing.T) { + result, err := runner.run(context.Background(), stepCtx, builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/img:v1", regHost), + DestRef: fmt.Sprintf("%s/other/repo:v1", regHost), + }) + assert.Equal(t, string(kargoapi.PromotionStepStatusErrored), string(result.Status)) + assert.ErrorContains(t, err, "cross-repository push is disabled") + }) + + t.Run("same-repo retag succeeds", func(t *testing.T) { + result, err := runner.run(context.Background(), stepCtx, builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/img:v1", regHost), + DestRef: fmt.Sprintf("%s/test/img:v2", regHost), + }) + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) + }) +} + +func Test_ociPusher_push_sizeLimitDisabled(t *testing.T) { + regHandler := registry.New() + srv := httptest.NewServer(regHandler) + t.Cleanup(srv.Close) + regHost := srv.Listener.Addr().String() + + srcImg, err := random.Image(256, 1) + require.NoError(t, err) + srcRef, err := name.ParseReference(fmt.Sprintf("%s/test/img:v1", regHost)) + require.NoError(t, err) + require.NoError(t, remote.Write(srcRef, srcImg)) + + runner := &ociPusher{ + credsDB: &credentials.FakeDB{}, + schemaLoader: getConfigSchemaLoader(stepKindOCIPush), + maxArtifactSize: -1, // unlimited + } + + result, err := runner.run(context.Background(), &promotion.StepContext{ + Project: "fake-project", + }, builtin.OCIPushConfig{ + SrcRef: fmt.Sprintf("%s/test/img:v1", regHost), + DestRef: fmt.Sprintf("%s/other/repo:v1", regHost), + }) + require.NoError(t, err) + assert.Equal(t, string(kargoapi.PromotionStepStatusSucceeded), string(result.Status)) +} + +func Test_ociPusherConfig(t *testing.T) { + tests := []struct { + name string + envValue string // empty means unset + expected int64 + }{ + { + name: "unset returns default 1 GiB", + envValue: "", + expected: 1 << 30, + }, + { + name: "zero blocks cross-repo pushes", + envValue: "0", + expected: 0, + }, + { + name: "negative one disables limit", + envValue: "-1", + expected: -1, + }, + { + name: "custom value", + envValue: "536870912", + expected: 536870912, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.envValue != "" { + t.Setenv("MAX_OCI_PUSH_ARTIFACT_SIZE", tt.envValue) + } + cfg := ociPusherConfig{} + envconfig.MustProcess("", &cfg) + assert.Equal(t, tt.expected, cfg.MaxArtifactSize) + }) + } +} diff --git a/pkg/promotion/runner/builtin/schemas/argocd-common.json b/pkg/promotion/runner/builtin/schemas/argocd-common.json new file mode 100644 index 0000000000..3674d3db85 --- /dev/null +++ b/pkg/promotion/runner/builtin/schemas/argocd-common.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ArgoCDCommonDefs", + + "definitions": { + "argoCDAppSelector": { + "type": "object", + "description": "Selector to match Argo CD Application resources by labels. Must contain at least one selection criterion.", + "additionalProperties": false, + "properties": { + "matchLabels": { + "type": "object", + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is 'key', the operator is 'In', and the values array contains only 'value'. The requirements are ANDed.", + "additionalProperties": { + "type": "string" + } + }, + "matchExpressions": { + "type": "array", + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["key", "operator"], + "properties": { + "key": { + "type": "string", + "description": "key is the label key that the selector applies to.", + "minLength": 1 + }, + "operator": { + "type": "string", + "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", + "enum": ["In", "NotIn", "Exists", "DoesNotExist"] + }, + "values": { + "type": "array", + "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", + "items": { + "type": "string" + } + } + } + } + } + }, + "anyOf": [ + { + "required": ["matchLabels"], + "properties": { + "matchLabels": { + "minProperties": 1 + } + } + }, + { + "required": ["matchExpressions"], + "properties": { + "matchExpressions": { + "minItems": 1 + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/pkg/promotion/runner/builtin/schemas/argocd-update-config.json b/pkg/promotion/runner/builtin/schemas/argocd-update-config.json index 37c5d9bd02..6e94a7b6b7 100644 --- a/pkg/promotion/runner/builtin/schemas/argocd-update-config.json +++ b/pkg/promotion/runner/builtin/schemas/argocd-update-config.json @@ -19,7 +19,7 @@ "minLength": 1 }, "selector": { - "$ref": "#/definitions/argoCDAppSelector", + "$ref": "argocd-common.json#/definitions/argoCDAppSelector", "description": "Specifies a label selector to match Argo CD Application resources to be updated. Mutually exclusive with 'name'." }, "sources": { @@ -54,67 +54,6 @@ ] }, - "argoCDAppSelector": { - "type": "object", - "description": "Selector to match Argo CD Application resources by labels. Must contain at least one selection criterion.", - "additionalProperties": false, - "properties": { - "matchLabels": { - "type": "object", - "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is 'key', the operator is 'In', and the values array contains only 'value'. The requirements are ANDed.", - "additionalProperties": { - "type": "string" - } - }, - "matchExpressions": { - "type": "array", - "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", - "items": { - "type": "object", - "additionalProperties": false, - "required": ["key", "operator"], - "properties": { - "key": { - "type": "string", - "description": "key is the label key that the selector applies to.", - "minLength": 1 - }, - "operator": { - "type": "string", - "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", - "enum": ["In", "NotIn", "Exists", "DoesNotExist"] - }, - "values": { - "type": "array", - "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", - "items": { - "type": "string" - } - } - } - } - } - }, - "anyOf": [ - { - "required": ["matchLabels"], - "properties": { - "matchLabels": { - "minProperties": 1 - } - } - }, - { - "required": ["matchExpressions"], - "properties": { - "matchExpressions": { - "minItems": 1 - } - } - } - ] - }, - "argoCDAppSourceUpdate": { "type": "object", "additionalProperties": false, diff --git a/pkg/promotion/runner/builtin/schemas/argocd-wait-config.json b/pkg/promotion/runner/builtin/schemas/argocd-wait-config.json new file mode 100644 index 0000000000..9503107020 --- /dev/null +++ b/pkg/promotion/runner/builtin/schemas/argocd-wait-config.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ArgoCDWaitConfig", + + "definitions": { + + "argoCDAppWait": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Specifies the exact name of an Argo CD Application resource to wait for. Mutually exclusive with 'selector'.", + "minLength": 1 + }, + "namespace": { + "type": "string", + "description": "Specifies the namespace of the Argo CD Application. If left unspecified, the namespace will be the controller's configured default.", + "minLength": 1 + }, + "selector": { + "$ref": "argocd-common.json#/definitions/argoCDAppSelector", + "description": "Specifies a label selector to match Argo CD Application resources to wait for. Mutually exclusive with 'name'." + }, + "waitFor": { + "type": "array", + "description": "Specifies the conditions to wait for. Valid values are 'health', 'sync', 'operation', 'suspended', and 'degraded'. Health-related conditions (health, suspended, degraded) are OR'd. All other conditions are AND'd. Defaults to ['health', 'sync', 'operation'] when omitted.", + "items": { + "type": "string", + "enum": ["health", "sync", "operation", "suspended", "degraded"] + }, + "minItems": 1, + "uniqueItems": true + } + }, + "oneOf": [ + { + "required": ["name"], + "properties": { + "name": { + "minLength": 1 + }, + "selector": { + "enum": [null] + } + } + }, + { + "required": ["selector"], + "properties": { + "name": { + "enum": ["", null] + } + } + } + ] + } + }, + + "type": "object", + "additionalProperties": false, + "required": ["apps"], + "properties": { + "apps": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/argoCDAppWait" + } + } + } +} diff --git a/pkg/promotion/runner/builtin/schemas/git-clone-config.json b/pkg/promotion/runner/builtin/schemas/git-clone-config.json index d0c26a9800..f92a0e672c 100644 --- a/pkg/promotion/runner/builtin/schemas/git-clone-config.json +++ b/pkg/promotion/runner/builtin/schemas/git-clone-config.json @@ -15,7 +15,7 @@ }, "repoURL": { "type": "string", - "description": "The URL of a remote Git repository to clone. Required.", + "description": "The URL of a remote Git repository to clone. Required. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1 }, "author": { diff --git a/pkg/promotion/runner/builtin/schemas/git-merge-pr-config.json b/pkg/promotion/runner/builtin/schemas/git-merge-pr-config.json index 50bd0d57b2..6447b6b375 100644 --- a/pkg/promotion/runner/builtin/schemas/git-merge-pr-config.json +++ b/pkg/promotion/runner/builtin/schemas/git-merge-pr-config.json @@ -7,7 +7,7 @@ "properties": { "repoURL": { "type": "string", - "description": "The URL of the remote Git repository containing the pull request.", + "description": "The URL of the remote Git repository containing the pull request. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1, "format": "uri" }, @@ -28,6 +28,11 @@ "wait": { "type": "boolean", "description": "If true, the step will return RUNNING instead of FAILED when the PR is not yet mergeable. The merge will be retried on the next reconciliation until it succeeds or times out. Default is false." + }, + "mergeMethod": { + "type": "string", + "description": "The merge method to use when merging the pull request. Options are provider-specific.", + "minLength": 1 } } } diff --git a/pkg/promotion/runner/builtin/schemas/git-open-pr-config.json b/pkg/promotion/runner/builtin/schemas/git-open-pr-config.json index 9329c39839..30ec97cfc8 100644 --- a/pkg/promotion/runner/builtin/schemas/git-open-pr-config.json +++ b/pkg/promotion/runner/builtin/schemas/git-open-pr-config.json @@ -20,7 +20,7 @@ }, "repoURL": { "type": "string", - "description": "The URL of a remote Git repository to clone.", + "description": "The URL of a remote Git repository to clone. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1, "format": "uri" }, diff --git a/pkg/promotion/runner/builtin/schemas/git-wait-for-pr-config.json b/pkg/promotion/runner/builtin/schemas/git-wait-for-pr-config.json index e309fb9b32..515a41379f 100644 --- a/pkg/promotion/runner/builtin/schemas/git-wait-for-pr-config.json +++ b/pkg/promotion/runner/builtin/schemas/git-wait-for-pr-config.json @@ -21,7 +21,7 @@ }, "repoURL": { "type": "string", - "description": "The URL of a remote Git repository to clone.", + "description": "The URL of a remote Git repository to clone. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1, "format": "uri" } diff --git a/pkg/promotion/runner/builtin/schemas/oci-push-config.json b/pkg/promotion/runner/builtin/schemas/oci-push-config.json new file mode 100644 index 0000000000..15aef4938f --- /dev/null +++ b/pkg/promotion/runner/builtin/schemas/oci-push-config.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "OCIPushConfig", + "type": "object", + "additionalProperties": false, + "required": ["srcRef", "destRef"], + "properties": { + "srcRef": { + "type": "string", + "description": "SrcRef is the source OCI artifact reference with tag or digest (e.g. 'registry/repo:tag' or 'registry/repo@sha256:...'). Use 'oci://' prefix for Helm charts.", + "minLength": 1, + "pattern": "^(oci://)?[a-zA-Z0-9._-]+(:\\d+)?(/[a-zA-Z0-9._-]+)*[@:][a-zA-Z0-9._:-]+$" + }, + "destRef": { + "type": "string", + "description": "DestRef is the destination reference including tag (e.g. 'registry/repo:tag' or 'oci://registry/repo:tag'). For retag-in-place, use the same repo as srcRef with the new tag.", + "minLength": 1, + "pattern": "^(oci://)?[a-zA-Z0-9._-]+(:\\d+)?(/[a-zA-Z0-9._-]+)*[:][a-zA-Z0-9._-]+$" + }, + "annotations": { + "type": "object", + "description": "Annotations to set on the destination artifact. Keys may be prefixed with 'index:' or 'manifest:' to scope them to the index or image manifest respectively. Unprefixed keys default to the image manifest. For single images, 'index:'-prefixed keys are ignored.", + "additionalProperties": { + "type": "string" + } + }, + "insecureSkipTLSVerify": { + "type": "boolean", + "description": "Whether to skip TLS verification when communicating with registries. Defaults to false." + } + } +} diff --git a/pkg/promotion/runner/builtin/schemas/toml-parse-config.json b/pkg/promotion/runner/builtin/schemas/toml-parse-config.json new file mode 100644 index 0000000000..f06dcd61f3 --- /dev/null +++ b/pkg/promotion/runner/builtin/schemas/toml-parse-config.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TOMLParseConfig", + + "definitions": { + "tomlParse": { + "type": "object", + "additionalProperties": false, + "required": ["name", "fromExpression"], + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The name of the output variable to store the result." + }, + "fromExpression": { + "type": "string", + "minLength": 1, + "description": "The expression used to extract data from the TOML file." + } + } + } + }, + + "type": "object", + "additionalProperties": false, + "required": ["path", "outputs"], + "properties": { + "path": { + "type": "string", + "description": "The path to the TOML file to be parsed.", + "minLength": 1 + }, + "outputs": { + "type": "array", + "description": "An array of outputs to extract from the TOML file.", + "minItems": 1, + "items": { + "$ref": "#/definitions/tomlParse" + } + } + } +} diff --git a/pkg/promotion/runner/builtin/schemas/toml-update-config.json b/pkg/promotion/runner/builtin/schemas/toml-update-config.json new file mode 100644 index 0000000000..7caf2bf056 --- /dev/null +++ b/pkg/promotion/runner/builtin/schemas/toml-update-config.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TOMLUpdateConfig", + + "definitions": { + "tomlUpdate": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string", + "description": "The key whose value needs to be updated. For nested values, use a TOML dot notation path.", + "minLength": 1 + }, + "value": { + "description": "The new value for the specified key." + } + }, + "required": ["key", "value"] + } + }, + + "type": "object", + "required": ["path", "updates"], + "additionalProperties": false, + "properties": { + "path": { + "type": "string", + "description": "The path to a TOML file.", + "minLength": 1 + }, + "updates": { + "type": "array", + "description": "A list of updates to apply to the TOML file.", + "minItems": 1, + "items": { + "$ref": "#/definitions/tomlUpdate" + } + } + } +} diff --git a/pkg/promotion/runner/builtin/tar_extractor_test.go b/pkg/promotion/runner/builtin/tar_extractor_test.go index 8a754b6f45..9e8bc7f7c7 100644 --- a/pkg/promotion/runner/builtin/tar_extractor_test.go +++ b/pkg/promotion/runner/builtin/tar_extractor_test.go @@ -3,7 +3,6 @@ package builtin import ( "archive/tar" "compress/gzip" - "context" "fmt" "os" "path/filepath" @@ -420,7 +419,7 @@ func Test_tarExtractor_run(t *testing.T) { t.Run(tt.name, func(t *testing.T) { workDir := tt.setupFiles(t) result, err := runner.run( - context.Background(), + t.Context(), &promotion.StepContext{WorkDir: workDir}, tt.cfg, ) @@ -1011,7 +1010,7 @@ func Test_tarExtractor_extractToDir(t *testing.T) { extractDir := filepath.Join(workDir, "temp_extract") result, err := runner.extractToDir( - context.Background(), + t.Context(), tt.cfg, tarPath, extractDir, diff --git a/pkg/promotion/runner/builtin/toml_parser.go b/pkg/promotion/runner/builtin/toml_parser.go new file mode 100644 index 0000000000..7f61f1d422 --- /dev/null +++ b/pkg/promotion/runner/builtin/toml_parser.go @@ -0,0 +1,139 @@ +package builtin + +import ( + "context" + "fmt" + "os" + + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/expr-lang/expr" + tomlv2 "github.com/pelletier/go-toml/v2" + "github.com/xeipuuv/gojsonschema" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/pkg/promotion" + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +const stepKindTOMLParse = "toml-parse" + +func init() { + promotion.DefaultStepRunnerRegistry.MustRegister( + promotion.StepRunnerRegistration{ + Name: stepKindTOMLParse, + Value: newTOMLParser, + }, + ) +} + +// tomlParser is an implementation of the promotion.StepRunner interface that +// parses a TOML file and extracts specified outputs. +type tomlParser struct { + schemaLoader gojsonschema.JSONLoader +} + +// newTOMLParser returns a new instance of tomlParser. +func newTOMLParser(promotion.StepRunnerCapabilities) promotion.StepRunner { + return &tomlParser{schemaLoader: getConfigSchemaLoader(stepKindTOMLParse)} +} + +// Run implements the promotion.StepRunner interface. +func (tp *tomlParser) Run( + ctx context.Context, + stepCtx *promotion.StepContext, +) (promotion.StepResult, error) { + cfg, err := tp.convert(stepCtx.Config) + if err != nil { + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusFailed, + }, &promotion.TerminalError{Err: err} + } + return tp.run(ctx, stepCtx, cfg) +} + +// convert validates tomlParser configuration against a JSON schema and +// converts it into a builtin.TOMLParseConfig struct. +func (tp *tomlParser) convert(cfg promotion.Config) (builtin.TOMLParseConfig, error) { + return validateAndConvert[builtin.TOMLParseConfig](tp.schemaLoader, cfg, stepKindTOMLParse) +} + +func (tp *tomlParser) run( + _ context.Context, + stepCtx *promotion.StepContext, + cfg builtin.TOMLParseConfig, +) (promotion.StepResult, error) { + failure := promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored} + + if cfg.Path == "" { + return failure, fmt.Errorf("TOML file path cannot be empty") + } + + if len(cfg.Outputs) == 0 { + return failure, fmt.Errorf("invalid %s config: outputs is required", stepKindTOMLParse) + } + + data, err := tp.readAndParseTOML(stepCtx.WorkDir, cfg.Path) + if err != nil { + return failure, err + } + + extractedValues, err := tp.extractValues(data, cfg.Outputs) + if err != nil { + return failure, fmt.Errorf("failed to extract outputs: %w", err) + } + + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusSucceeded, + Output: extractedValues, + }, nil +} + +// readAndParseTOML reads and unmarshals a TOML document and returns the result. +func (tp *tomlParser) readAndParseTOML(workDir string, path string) (any, error) { + absFilePath, err := securejoin.SecureJoin(workDir, path) + if err != nil { + return nil, fmt.Errorf("error joining path %q: %w", path, err) + } + tomlData, err := os.ReadFile(absFilePath) + if err != nil { + return nil, fmt.Errorf("error reading TOML file %q: %w", absFilePath, err) + } + if len(tomlData) == 0 { + return nil, fmt.Errorf("could not parse empty TOML file: %q", absFilePath) + } + var data any + if err := tomlv2.Unmarshal(tomlData, &data); err != nil { + return nil, fmt.Errorf("could not parse TOML file: %w", err) + } + return data, nil +} + +// extractValues returns select data extracted from the provided data by +// evaluating it against expressions contained within the provided +// []builtin.TOMLParse. +func (tp *tomlParser) extractValues( + data any, + outputs []builtin.TomlParse, +) (map[string]any, error) { + results := make(map[string]any, len(outputs)) + for _, output := range outputs { + program, err := expr.Compile(output.FromExpression) + if err != nil { + return nil, fmt.Errorf( + "error compiling expression %q: %w", + output.FromExpression, + err, + ) + } + value, err := expr.Run(program, data) + if err != nil { + return nil, fmt.Errorf( + "error evaluating expression %q: %w", + output.FromExpression, + err, + ) + } + results[output.Name] = value + } + return results, nil +} diff --git a/pkg/promotion/runner/builtin/toml_parser_test.go b/pkg/promotion/runner/builtin/toml_parser_test.go new file mode 100644 index 0000000000..741282879f --- /dev/null +++ b/pkg/promotion/runner/builtin/toml_parser_test.go @@ -0,0 +1,267 @@ +package builtin + +import ( + "os" + "path" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/pkg/promotion" + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +func Test_tomlParser_convert(t *testing.T) { + tests := []validationTestCase{ + { + name: "path not specified", + config: promotion.Config{ + "outputs": []map[string]any{{"name": "output1", "fromExpression": "app.version"}}, + }, + expectedProblems: []string{"(root): path is required"}, + }, + { + name: "path is empty string", + config: promotion.Config{ + "path": "", + "outputs": []map[string]any{{"name": "output1", "fromExpression": "app.version"}}, + }, + expectedProblems: []string{"path: String length must be greater than or equal to 1"}, + }, + { + name: "outputs field is missing", + config: promotion.Config{ + "path": "valid.toml", + }, + expectedProblems: []string{"(root): outputs is required"}, + }, + { + name: "outputs field is an empty array", + config: promotion.Config{ + "path": "valid.toml", + "outputs": []map[string]any{}, + }, + expectedProblems: []string{"outputs: Array must have at least 1 items"}, + }, + { + name: "name is not specified", + config: promotion.Config{ + "path": "valid.toml", + "outputs": []map[string]any{{"fromExpression": "app.version"}}, + }, + expectedProblems: []string{"outputs.0: name is required"}, + }, + { + name: "name is empty", + config: promotion.Config{ + "path": "valid.toml", + "outputs": []map[string]any{{"name": "", "fromExpression": "app.version"}}, + }, + expectedProblems: []string{"name: String length must be greater than or equal to 1"}, + }, + { + name: "fromExpression is not specified", + config: promotion.Config{ + "path": "valid.toml", + "outputs": []map[string]any{{"name": "output1"}}, + }, + expectedProblems: []string{"outputs.0: fromExpression is required"}, + }, + { + name: "fromExpression is empty", + config: promotion.Config{ + "path": "valid.toml", + "outputs": []map[string]any{{"name": "output1", "fromExpression": ""}}, + }, + expectedProblems: []string{"fromExpression: String length must be greater than or equal to 1"}, + }, + { + name: "valid configuration", + config: promotion.Config{ + "path": "valid.toml", + "outputs": []map[string]any{{"name": "output1", "fromExpression": "app.version"}}, + }, + }, + } + + r := newTOMLParser(promotion.StepRunnerCapabilities{}) + runner, ok := r.(*tomlParser) + require.True(t, ok) + + runValidationTests(t, runner.convert, tests) +} + +func Test_tomlParser_run(t *testing.T) { + tests := []struct { + name string + stepCtx *promotion.StepContext + cfg builtin.TOMLParseConfig + files map[string]string + assertions func(*testing.T, string, promotion.StepResult, error) + }{ + { + name: "successful run with outputs", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLParseConfig{ + Path: "config.toml", + Outputs: []builtin.TomlParse{ + {Name: "appVersion", FromExpression: "app.version"}, + {Name: "featureStatus", FromExpression: "features.newFeature"}, + }, + }, + files: map[string]string{ + "config.toml": "[app]\nversion = \"1.0.0\"\n\n[features]\nnewFeature = false\n", + }, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, promotion.StepResult{ + Status: kargoapi.PromotionStepStatusSucceeded, + Output: map[string]any{ + "appVersion": "1.0.0", + "featureStatus": false, + }, + }, result) + }, + }, + { + name: "failed to extract outputs", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLParseConfig{ + Path: "config.toml", + Outputs: []builtin.TomlParse{{Name: "invalidField", FromExpression: "nonexistent.path"}}, + }, + files: map[string]string{"config.toml": "[app]\nversion = \"1.0.0\"\n"}, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.Error(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result) + assert.Contains(t, err.Error(), "failed to extract outputs") + }, + }, + { + name: "no outputs provided", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLParseConfig{Path: "config.toml", Outputs: []builtin.TomlParse{}}, + files: map[string]string{"config.toml": "[app]\nversion = \"1.0.0\"\n"}, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.Error(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result) + assert.Contains(t, err.Error(), "outputs is required") + }, + }, + { + name: "handle empty TOML file", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLParseConfig{ + Path: "config.toml", + Outputs: []builtin.TomlParse{{Name: "key", FromExpression: "app.key"}}, + }, + files: map[string]string{"config.toml": ""}, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.Error(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result) + assert.Contains(t, err.Error(), "could not parse empty TOML file") + }, + }, + { + name: "path is empty", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLParseConfig{ + Path: "", + Outputs: []builtin.TomlParse{{Name: "key", FromExpression: "app.key"}}, + }, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.Error(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result) + assert.Contains(t, err.Error(), "TOML file path cannot be empty") + }, + }, + { + name: "path is a directory instead of a file", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLParseConfig{ + Path: "config", + Outputs: []builtin.TomlParse{{Name: "key", FromExpression: "app.key"}}, + }, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.Error(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result) + assert.Contains(t, err.Error(), "no such file or directory") + }, + }, + } + + runner := &tomlParser{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stepCtx := tt.stepCtx + stepCtx.WorkDir = t.TempDir() + for p, c := range tt.files { + require.NoError(t, os.MkdirAll(path.Join(stepCtx.WorkDir, path.Dir(p)), 0o700)) + require.NoError(t, os.WriteFile(path.Join(stepCtx.WorkDir, p), []byte(c), 0o600)) + } + + result, err := runner.run(t.Context(), stepCtx, tt.cfg) + tt.assertions(t, stepCtx.WorkDir, result, err) + }) + } +} + +func Test_tomlParser_readAndParseTOML(t *testing.T) { + tp := &tomlParser{} + + tests := []struct { + name string + content string + expected any + expectedErrMsg string + }{ + { + name: "valid TOML with nested structure", + content: "title = \"example\"\nnum = 42\nflag = true\nitems = [1, 2]\n[app]\nversion = \"1.2.3\"\n", + expected: map[string]any{ + "title": "example", + "num": int64(42), + "flag": true, + "items": []any{int64(1), int64(2)}, + "app": map[string]any{ + "version": "1.2.3", + }, + }, + }, + { + name: "invalid TOML syntax", + content: "title = \n", + expectedErrMsg: "could not parse TOML file", + }, + { + name: "empty TOML file", + content: "", + expectedErrMsg: "could not parse empty TOML file", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tempDir := t.TempDir() + filePath := filepath.Join(tempDir, "test.toml") + + err := os.WriteFile(filePath, []byte(tt.content), 0o600) + require.NoError(t, err) + + result, err := tp.readAndParseTOML(tempDir, "test.toml") + + if tt.expectedErrMsg != "" { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.expectedErrMsg) + return + } + + assert.NoError(t, err) + assert.EqualValues(t, tt.expected, result) + }) + } +} diff --git a/pkg/promotion/runner/builtin/toml_updater.go b/pkg/promotion/runner/builtin/toml_updater.go new file mode 100644 index 0000000000..1d6a1f0347 --- /dev/null +++ b/pkg/promotion/runner/builtin/toml_updater.go @@ -0,0 +1,117 @@ +package builtin + +import ( + "context" + "fmt" + "strings" + + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/xeipuuv/gojsonschema" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/pkg/promotion" + inttoml "github.com/akuity/kargo/pkg/toml" + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +const stepKindTOMLUpdate = "toml-update" + +func init() { + promotion.DefaultStepRunnerRegistry.MustRegister( + promotion.StepRunnerRegistration{ + Name: stepKindTOMLUpdate, + Value: newTOMLUpdater, + }, + ) +} + +// tomlUpdater is an implementation of the promotion.StepRunner interface that +// updates the values of specified keys in a TOML file. +type tomlUpdater struct { + schemaLoader gojsonschema.JSONLoader +} + +// newTOMLUpdater returns an implementation of the promotion.StepRunner interface +// that updates the values of specified keys in a TOML file. +func newTOMLUpdater(promotion.StepRunnerCapabilities) promotion.StepRunner { + return &tomlUpdater{schemaLoader: getConfigSchemaLoader(stepKindTOMLUpdate)} +} + +// Run implements the promotion.StepRunner interface. +func (t *tomlUpdater) Run( + ctx context.Context, + stepCtx *promotion.StepContext, +) (promotion.StepResult, error) { + cfg, err := t.convert(stepCtx.Config) + if err != nil { + return promotion.StepResult{ + Status: kargoapi.PromotionStepStatusFailed, + }, &promotion.TerminalError{Err: err} + } + return t.run(ctx, stepCtx, cfg) +} + +// convert validates tomlUpdater configuration against a JSON schema and +// converts it into a builtin.TOMLUpdateConfig struct. +func (t *tomlUpdater) convert(cfg promotion.Config) (builtin.TOMLUpdateConfig, error) { + return validateAndConvert[builtin.TOMLUpdateConfig](t.schemaLoader, cfg, stepKindTOMLUpdate) +} + +func (t *tomlUpdater) run( + _ context.Context, + stepCtx *promotion.StepContext, + cfg builtin.TOMLUpdateConfig, +) (promotion.StepResult, error) { + updates := make([]inttoml.Update, len(cfg.Updates)) + for i, update := range cfg.Updates { + updates[i] = inttoml.Update{ + Key: update.Key, + Value: update.Value, + } + } + + result := promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded} + if len(updates) > 0 { + if err := t.updateFile(stepCtx.WorkDir, cfg.Path, updates); err != nil { + return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, + fmt.Errorf("TOML file update failed: %w", err) + } + + if commitMsg := t.generateCommitMessage(cfg.Path, cfg.Updates); commitMsg != "" { + result.Output = map[string]any{ + "commitMessage": commitMsg, + } + } + } + return result, nil +} + +func (t *tomlUpdater) updateFile(workDir string, path string, updates []inttoml.Update) error { + absFilePath, err := securejoin.SecureJoin(workDir, path) + if err != nil { + return fmt.Errorf("error joining path %q: %w", path, err) + } + if err := inttoml.SetValuesInFile(absFilePath, updates); err != nil { + return fmt.Errorf("error updating TOML file %q: %w", path, err) + } + return nil +} + +func (t *tomlUpdater) generateCommitMessage(path string, updates []builtin.TomlUpdate) string { + if len(updates) == 0 { + return "" + } + + var commitMsg strings.Builder + _, _ = fmt.Fprintf(&commitMsg, "Updated %s\n", path) + for _, update := range updates { + _, _ = fmt.Fprintf( + &commitMsg, + "\n- %s: %s", + update.Key, + inttoml.FormatValueString(update.Value), + ) + } + + return commitMsg.String() +} diff --git a/pkg/promotion/runner/builtin/toml_updater_test.go b/pkg/promotion/runner/builtin/toml_updater_test.go new file mode 100644 index 0000000000..99111bf435 --- /dev/null +++ b/pkg/promotion/runner/builtin/toml_updater_test.go @@ -0,0 +1,274 @@ +package builtin + +import ( + "os" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/pkg/promotion" + inttoml "github.com/akuity/kargo/pkg/toml" + "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" +) + +func Test_tomlUpdater_convert(t *testing.T) { + tests := []validationTestCase{ + { + name: "path is not specified", + config: promotion.Config{}, + expectedProblems: []string{"(root): path is required"}, + }, + { + name: "path is empty", + config: promotion.Config{ + "path": "", + }, + expectedProblems: []string{"path: String length must be greater than or equal to 1"}, + }, + { + name: "updates is null", + config: promotion.Config{}, + expectedProblems: []string{"(root): updates is required"}, + }, + { + name: "updates is empty", + config: promotion.Config{ + "updates": []promotion.Config{}, + }, + expectedProblems: []string{"updates: Array must have at least 1 items"}, + }, + { + name: "key not specified", + config: promotion.Config{ + "updates": []promotion.Config{{}}, + }, + expectedProblems: []string{"updates.0: key is required"}, + }, + { + name: "key is empty", + config: promotion.Config{ + "updates": []promotion.Config{{"key": ""}}, + }, + expectedProblems: []string{"updates.0.key: String length must be greater than or equal to 1"}, + }, + { + name: "value not specified", + config: promotion.Config{ + "updates": []promotion.Config{{}}, + }, + expectedProblems: []string{"updates.0: value is required"}, + }, + { + name: "valid config", + config: promotion.Config{ + "path": "fake-path", + "updates": []promotion.Config{ + {"key": "package.version", "value": "1.2.3"}, + {"key": "features.enabled", "value": true}, + }, + }, + }, + } + + r := newTOMLUpdater(promotion.StepRunnerCapabilities{}) + runner, ok := r.(*tomlUpdater) + require.True(t, ok) + + runValidationTests(t, runner.convert, tests) +} + +func Test_tomlUpdater_run(t *testing.T) { + tests := []struct { + name string + stepCtx *promotion.StepContext + cfg builtin.TOMLUpdateConfig + files map[string]string + assertions func(*testing.T, string, promotion.StepResult, error) + }{ + { + name: "successful run with updates", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLUpdateConfig{ + Path: "config.toml", + Updates: []builtin.TomlUpdate{ + {Key: "package.version", Value: "1.0.1"}, + {Key: "features.newFeature", Value: true}, + {Key: "threshold", Value: 100}, + }, + }, + files: map[string]string{ + "config.toml": "threshold = 1\n\n[package]\nversion = \"1.0.0\"\n\n[features]\nnewFeature = false\n", + }, + assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, promotion.StepResult{ + Status: kargoapi.PromotionStepStatusSucceeded, + Output: map[string]any{ + "commitMessage": "Updated config.toml\n\n" + + "- package.version: '1.0.1'\n" + + "- features.newFeature: true\n" + + "- threshold: 100", + }, + }, result) + content, err := os.ReadFile(path.Join(workDir, "config.toml")) + require.NoError(t, err) + assert.Contains(t, string(content), "version = '1.0.1'") + assert.Contains(t, string(content), "newFeature = true") + assert.Contains(t, string(content), "threshold = 100") + }, + }, + { + name: "failed to update file", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLUpdateConfig{ + Path: "non-existent/config.toml", + Updates: []builtin.TomlUpdate{{Key: "package.version", Value: "1.0.1"}}, + }, + assertions: func(t *testing.T, _ string, result promotion.StepResult, err error) { + assert.Error(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, result) + assert.Contains(t, err.Error(), "TOML file update failed") + }, + }, + { + name: "no updates provided", + stepCtx: &promotion.StepContext{Project: "test-project"}, + cfg: builtin.TOMLUpdateConfig{Path: "config.toml", Updates: []builtin.TomlUpdate{}}, + files: map[string]string{"config.toml": "[package]\nversion = \"1.0.0\"\n"}, + assertions: func(t *testing.T, workDir string, result promotion.StepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, promotion.StepResult{Status: kargoapi.PromotionStepStatusSucceeded}, result) + content, err := os.ReadFile(path.Join(workDir, "config.toml")) + require.NoError(t, err) + assert.Equal(t, "[package]\nversion = \"1.0.0\"\n", string(content)) + }, + }, + } + + runner := &tomlUpdater{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + stepCtx := tt.stepCtx + stepCtx.WorkDir = t.TempDir() + for p, c := range tt.files { + require.NoError(t, os.MkdirAll(path.Join(stepCtx.WorkDir, path.Dir(p)), 0o700)) + require.NoError(t, os.WriteFile(path.Join(stepCtx.WorkDir, p), []byte(c), 0o600)) + } + + result, err := runner.run(t.Context(), stepCtx, tt.cfg) + tt.assertions(t, stepCtx.WorkDir, result, err) + }) + } +} + +func Test_tomlUpdater_updateFile(t *testing.T) { + tests := []struct { + name string + valuesContent string + updates []inttoml.Update + assertions func(*testing.T, string, error) + }{ + { + name: "successful update", + valuesContent: "title = \"value\"\n", + updates: []inttoml.Update{{Key: "title", Value: "newvalue"}}, + assertions: func(t *testing.T, valuesFilePath string, err error) { + require.NoError(t, err) + content, readErr := os.ReadFile(valuesFilePath) + require.NoError(t, readErr) + assert.Equal(t, "title = 'newvalue'\n", string(content)) + }, + }, + { + name: "file does not exist", + valuesContent: "", + updates: []inttoml.Update{{Key: "title", Value: "value"}}, + assertions: func(t *testing.T, valuesFilePath string, err error) { + require.ErrorContains(t, err, "no such file or directory") + require.NoFileExists(t, valuesFilePath) + }, + }, + { + name: "empty changes", + valuesContent: "title = \"value\"\n", + updates: []inttoml.Update{}, + assertions: func(t *testing.T, valuesFilePath string, err error) { + require.NoError(t, err) + content, readErr := os.ReadFile(valuesFilePath) + require.NoError(t, readErr) + assert.Equal(t, "title = \"value\"\n", string(content)) + }, + }, + } + + runner := &tomlUpdater{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + workDir := t.TempDir() + valuesFile := path.Join(workDir, "values.toml") + + if tt.valuesContent != "" { + err := os.WriteFile(valuesFile, []byte(tt.valuesContent), 0o600) + require.NoError(t, err) + } + + err := runner.updateFile(workDir, path.Base(valuesFile), tt.updates) + tt.assertions(t, valuesFile, err) + }) + } +} + +func Test_tomlUpdater_generateCommitMessage(t *testing.T) { + tests := []struct { + name string + path string + updates []builtin.TomlUpdate + assertions func(*testing.T, string) + }{ + { + name: "no changes", + path: "values.toml", + assertions: func(t *testing.T, result string) { + assert.Empty(t, result) + }, + }, + { + name: "single change", + path: "values.toml", + updates: []builtin.TomlUpdate{{Key: "package.version", Value: "1.2.3"}}, + assertions: func(t *testing.T, result string) { + assert.Equal(t, "Updated values.toml\n\n- package.version: '1.2.3'", result) + }, + }, + { + name: "multiple changes", + path: "Cargo.toml", + updates: []builtin.TomlUpdate{ + {Key: "package.version", Value: "1.2.3"}, + {Key: "features.enabled", Value: true}, + {Key: "threshold", Value: 42}, + }, + assertions: func(t *testing.T, result string) { + assert.Equal( + t, + "Updated Cargo.toml\n\n- package.version: '1.2.3'\n- features.enabled: true\n- threshold: 42", + result, + ) + }, + }, + } + + runner := &tomlUpdater{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := runner.generateCommitMessage(tt.path, tt.updates) + tt.assertions(t, result) + }) + } +} diff --git a/pkg/promotion/runner/builtin/yaml_parser_test.go b/pkg/promotion/runner/builtin/yaml_parser_test.go index 48031d7f29..f0d6be6031 100644 --- a/pkg/promotion/runner/builtin/yaml_parser_test.go +++ b/pkg/promotion/runner/builtin/yaml_parser_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path" "path/filepath" @@ -309,7 +308,7 @@ config: require.NoError(t, os.WriteFile(path.Join(stepCtx.WorkDir, p), []byte(c), 0o600)) } - result, err := runner.run(context.Background(), stepCtx, tt.cfg) + result, err := runner.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, stepCtx.WorkDir, result, err) }) } diff --git a/pkg/promotion/runner/builtin/yaml_updater_test.go b/pkg/promotion/runner/builtin/yaml_updater_test.go index f8d9ab5a68..76d2c3d40f 100644 --- a/pkg/promotion/runner/builtin/yaml_updater_test.go +++ b/pkg/promotion/runner/builtin/yaml_updater_test.go @@ -1,7 +1,6 @@ package builtin import ( - "context" "os" "path" "testing" @@ -186,7 +185,7 @@ image: require.NoError(t, os.WriteFile(path.Join(stepCtx.WorkDir, p), []byte(c), 0o600)) } - result, err := runner.run(context.Background(), stepCtx, tt.cfg) + result, err := runner.run(t.Context(), stepCtx, tt.cfg) tt.assertions(t, stepCtx.WorkDir, result, err) }) } diff --git a/pkg/rollouts/analysis_run_builder_test.go b/pkg/rollouts/analysis_run_builder_test.go index 51275197f7..ace686e20d 100644 --- a/pkg/rollouts/analysis_run_builder_test.go +++ b/pkg/rollouts/analysis_run_builder_test.go @@ -1,7 +1,6 @@ package rollouts import ( - "context" "strings" "testing" @@ -290,7 +289,7 @@ func TestAnalysisRunBuilder_Build(t *testing.T) { Build() builder := NewAnalysisRunBuilder(c, tt.cfg) - ar, err := builder.Build(context.Background(), tt.namespace, tt.verification, tt.options...) + ar, err := builder.Build(t.Context(), tt.namespace, tt.verification, tt.options...) tt.assertions(t, ar, err) }) } @@ -894,7 +893,7 @@ func TestAnalysisRunBuilder_buildOwnerReferences(t *testing.T) { Build() builder := &AnalysisRunBuilder{client: c} - refs, err := builder.buildOwnerReferences(context.Background(), tt.owners) + refs, err := builder.buildOwnerReferences(t.Context(), tt.owners) tt.assertions(t, refs, err) }) } @@ -1018,7 +1017,7 @@ func TestAnalysisRunBuilder_getAnalysisTemplates(t *testing.T) { builder := &AnalysisRunBuilder{client: c} analysisTemplates, clusterAnalysisTemplates, err := builder.getAnalysisTemplates( - context.Background(), + t.Context(), tt.namespace, tt.references, ) diff --git a/pkg/server/approve_freight_v1alpha1_test.go b/pkg/server/approve_freight_v1alpha1_test.go index bdff234b38..e753c84f66 100644 --- a/pkg/server/approve_freight_v1alpha1_test.go +++ b/pkg/server/approve_freight_v1alpha1_test.go @@ -384,7 +384,7 @@ func TestApproveFreight(t *testing.T) { recorder := fakeevent.NewEventRecorder(1) testCase.server.sender = k8sevent.NewEventSender(recorder) resp, err := testCase.server.ApproveFreight( - context.Background(), + t.Context(), connect.NewRequest(testCase.req), ) testCase.assertions(t, recorder, resp, err) diff --git a/pkg/server/auth_middleware_test.go b/pkg/server/auth_middleware_test.go index 5da409ef3c..41d2710dd8 100644 --- a/pkg/server/auth_middleware_test.go +++ b/pkg/server/auth_middleware_test.go @@ -50,7 +50,7 @@ c1e3 func TestNewAuthMiddleware(t *testing.T) { a := &authMiddleware{} - middleware := newAuthMiddleware(context.Background(), config.ServerConfig{}, nil) + middleware := newAuthMiddleware(t.Context(), config.ServerConfig{}, nil) require.NotNil(t, middleware) // Call the middleware to get the initialized authMiddleware // We can't directly inspect it, but we can verify it doesn't panic @@ -151,7 +151,7 @@ func TestGetKeySet(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { svr, cfg := testCase.setup() t.Cleanup(svr.Close) - keyset, err := getKeySet(context.Background(), cfg) + keyset, err := getKeySet(t.Context(), cfg) require.NoError(t, err) require.NotNil(t, keyset) }) @@ -412,7 +412,7 @@ func TestAuthenticate(t *testing.T) { ts.authMiddleware = &authMiddleware{} } ctx, err := ts.authMiddleware.authenticate( - context.Background(), + t.Context(), ts.path, ts.token, ) @@ -507,7 +507,7 @@ func TestVerifyIDPIssuedTokenFn(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { c, err := testCase.authMiddleware.verifyIDPIssuedToken( - context.Background(), + t.Context(), // With the way these tests are constructed, this doesn't have to // be valid. "some-token", diff --git a/pkg/server/create_api_token_v1alpha1.go b/pkg/server/create_api_token_v1alpha1.go index 7ec22b90ed..7923c28f22 100644 --- a/pkg/server/create_api_token_v1alpha1.go +++ b/pkg/server/create_api_token_v1alpha1.go @@ -8,6 +8,7 @@ import ( "connectrpc.com/connect" "github.com/gin-gonic/gin" + corev1 "k8s.io/api/core/v1" svcv1alpha1 "github.com/akuity/kargo/api/service/v1alpha1" libhttp "github.com/akuity/kargo/pkg/http" @@ -70,7 +71,7 @@ type createAPITokenRequest struct { // @Param project path string true "Project name" // @Param role path string true "Role name" // @Param body body createAPITokenRequest true "Token" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/roles/{role}/api-tokens [post] func (s *server) createProjectAPIToken(c *gin.Context) { ctx := c.Request.Context() @@ -89,6 +90,7 @@ func (s *server) createProjectAPIToken(c *gin.Context) { return } + var tokenSecret *corev1.Secret tokenSecret, err := s.rolesDB.CreateAPIToken( ctx, false, project, role, req.Name, ) @@ -113,7 +115,7 @@ func (s *server) createProjectAPIToken(c *gin.Context) { // @Produce json // @Param role path string true "Role name" // @Param body body createAPITokenRequest true "Token" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/system/roles/{role}/api-tokens [post] func (s *server) createSystemAPIToken(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/create_config_map_v1alpha1.go b/pkg/server/create_config_map_v1alpha1.go index 5101d3931f..7f4ebcc38c 100644 --- a/pkg/server/create_config_map_v1alpha1.go +++ b/pkg/server/create_config_map_v1alpha1.go @@ -113,7 +113,7 @@ type createConfigMapRequest struct { // @Produce json // @Param project path string true "Project name" // @Param body body createConfigMapRequest true "ConfigMap" -// @Success 201 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 201 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/projects/{project}/configmaps [post] func (s *server) createProjectConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -153,7 +153,7 @@ func (s *server) createProjectConfigMap(c *gin.Context) { // @Accept json // @Produce json // @Param body body createConfigMapRequest true "ConfigMap" -// @Success 201 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 201 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/system/configmaps [post] func (s *server) createSystemConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -192,7 +192,7 @@ func (s *server) createSystemConfigMap(c *gin.Context) { // @Accept json // @Produce json // @Param body body createConfigMapRequest true "ConfigMap" -// @Success 201 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 201 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/shared/configmaps [post] func (s *server) createSharedConfigMap(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/create_config_map_v1alpha1_test.go b/pkg/server/create_config_map_v1alpha1_test.go index b7109c6685..920f5f0f06 100644 --- a/pkg/server/create_config_map_v1alpha1_test.go +++ b/pkg/server/create_config_map_v1alpha1_test.go @@ -174,7 +174,7 @@ func TestCreateConfigMap(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() client, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/create_generic_credentials_v1alpha1.go b/pkg/server/create_generic_credentials_v1alpha1.go index 0c1a7a6611..eb2d2433f9 100644 --- a/pkg/server/create_generic_credentials_v1alpha1.go +++ b/pkg/server/create_generic_credentials_v1alpha1.go @@ -97,7 +97,7 @@ type createGenericCredentialsRequest struct { // @Produce json // @Param project path string true "Project name" // @Param body body createGenericCredentialsRequest true "Generic credentials" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/generic-credentials [post] func (s *server) createProjectGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -142,7 +142,7 @@ func (s *server) createProjectGenericCredentials(c *gin.Context) { // @Accept json // @Produce json // @Param body body createGenericCredentialsRequest true "Generic credentials" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/system/generic-credentials [post] func (s *server) createSystemGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -186,7 +186,7 @@ func (s *server) createSystemGenericCredentials(c *gin.Context) { // @Accept json // @Produce json // @Param body body createGenericCredentialsRequest true "Generic credentials" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/generic-credentials [post] func (s *server) createSharedGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/create_generic_credentials_v1alpha1_test.go b/pkg/server/create_generic_credentials_v1alpha1_test.go index d207a9bec7..60efbe7f48 100644 --- a/pkg/server/create_generic_credentials_v1alpha1_test.go +++ b/pkg/server/create_generic_credentials_v1alpha1_test.go @@ -26,7 +26,7 @@ import ( ) func TestCreateGenericCredentials(t *testing.T) { - ctx := context.Background() + ctx := t.Context() cl, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/create_repo_credentials_v1alpha1.go b/pkg/server/create_repo_credentials_v1alpha1.go index 2bffaaccf8..6097d06b84 100644 --- a/pkg/server/create_repo_credentials_v1alpha1.go +++ b/pkg/server/create_repo_credentials_v1alpha1.go @@ -122,7 +122,7 @@ type createRepoCredentialsRequest struct { // @Produce json // @Param project path string true "Project name" // @Param body body createRepoCredentialsRequest true "Credentials" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/repo-credentials [post] func (s *server) createProjectRepoCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -171,7 +171,7 @@ func (s *server) createProjectRepoCredentials(c *gin.Context) { // @Accept json // @Produce json // @Param body body createRepoCredentialsRequest true "Credentials" -// @Success 201 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 201 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/repo-credentials [post] func (s *server) createSharedRepoCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/create_repo_credentials_v1alpha1_test.go b/pkg/server/create_repo_credentials_v1alpha1_test.go index 9d66e0dbae..57d5c32480 100644 --- a/pkg/server/create_repo_credentials_v1alpha1_test.go +++ b/pkg/server/create_repo_credentials_v1alpha1_test.go @@ -27,7 +27,7 @@ import ( ) func TestCreateRepoCredentials(t *testing.T) { - ctx := context.Background() + ctx := t.Context() cl, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/create_role_v1alpha1.go b/pkg/server/create_role_v1alpha1.go index 05c8dbb363..254540d5fe 100644 --- a/pkg/server/create_role_v1alpha1.go +++ b/pkg/server/create_role_v1alpha1.go @@ -56,7 +56,7 @@ func (s *server) CreateRole( // @Produce json // @Param project path string true "Project name" // @Param body body object true "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" -// @Success 201 {object} object "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" +// @Success 201 {object} rbacapi.Role "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" // @Router /v1beta1/projects/{project}/roles [post] func (s *server) createProjectRole(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/delete_config_map_v1alpha1_test.go b/pkg/server/delete_config_map_v1alpha1_test.go index 6f0690a890..daae26f81d 100644 --- a/pkg/server/delete_config_map_v1alpha1_test.go +++ b/pkg/server/delete_config_map_v1alpha1_test.go @@ -119,7 +119,7 @@ func TestDeleteConfigMap(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() client, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/delete_generic_credentials_v1alpha1_test.go b/pkg/server/delete_generic_credentials_v1alpha1_test.go index 36871a9d80..4ea8e56304 100644 --- a/pkg/server/delete_generic_credentials_v1alpha1_test.go +++ b/pkg/server/delete_generic_credentials_v1alpha1_test.go @@ -25,7 +25,7 @@ import ( ) func TestDeleteGenericCredentials(t *testing.T) { - ctx := context.Background() + ctx := t.Context() cl, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/get_analysisrun_v1alpha1.go b/pkg/server/get_analysisrun_v1alpha1.go index 5df1f7f547..86581d1343 100644 --- a/pkg/server/get_analysisrun_v1alpha1.go +++ b/pkg/server/get_analysisrun_v1alpha1.go @@ -81,7 +81,7 @@ func (s *server) GetAnalysisRun( // @Param project path string true "Project name" // @Param analysis-run path string true "AnalysisRun name" // @Produce json -// @Success 200 {object} object "AnalysisRun custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun)" +// @Success 200 {object} rolloutsapi.AnalysisRun "AnalysisRun custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun)" // @Router /v1beta1/projects/{project}/analysis-runs/{analysis-run} [get] func (s *server) getAnalysisRun(c *gin.Context) { if !s.cfg.RolloutsIntegrationEnabled { diff --git a/pkg/server/get_analysistemplate_v1alpha1.go b/pkg/server/get_analysistemplate_v1alpha1.go index 52db197cc7..ae0782826c 100644 --- a/pkg/server/get_analysistemplate_v1alpha1.go +++ b/pkg/server/get_analysistemplate_v1alpha1.go @@ -88,7 +88,7 @@ func (s *server) GetAnalysisTemplate( // @Param project path string true "Project name" // @Param analysis-template path string true "AnalysisTemplate name" // @Produce json -// @Success 200 {object} object "AnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplate)" +// @Success 200 {object} rolloutsapi.AnalysisTemplate "AnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplate)" // @Router /v1beta1/projects/{project}/analysis-templates/{analysis-template} [get] func (s *server) getAnalysisTemplate(c *gin.Context) { if !s.cfg.RolloutsIntegrationEnabled { diff --git a/pkg/server/get_api_token_v1alpha1.go b/pkg/server/get_api_token_v1alpha1.go index 03bd2799ae..ae0df776d2 100644 --- a/pkg/server/get_api_token_v1alpha1.go +++ b/pkg/server/get_api_token_v1alpha1.go @@ -8,6 +8,7 @@ import ( "connectrpc.com/connect" "github.com/gin-gonic/gin" + corev1 "k8s.io/api/core/v1" sigyaml "sigs.k8s.io/yaml" svcv1alpha1 "github.com/akuity/kargo/api/service/v1alpha1" @@ -77,7 +78,7 @@ func (s *server) GetAPIToken( // @Param project path string true "Project name" // @Param apitoken path string true "API token name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/api-tokens/{apitoken} [get] func (s *server) getProjectAPIToken(c *gin.Context) { ctx := c.Request.Context() @@ -85,6 +86,7 @@ func (s *server) getProjectAPIToken(c *gin.Context) { project := c.Param("project") name := c.Param("apitoken") + var tokenSecret *corev1.Secret tokenSecret, err := s.rolesDB.GetAPIToken(ctx, false, project, name) if err != nil { _ = c.Error(err) @@ -102,7 +104,7 @@ func (s *server) getProjectAPIToken(c *gin.Context) { // @Security BearerAuth // @Param apitoken path string true "API token name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/system/api-tokens/{apitoken} [get] func (s *server) getSystemAPIToken(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_cluster_config_v1alpha1.go b/pkg/server/get_cluster_config_v1alpha1.go index 72af3a30a1..e0ec4c7007 100644 --- a/pkg/server/get_cluster_config_v1alpha1.go +++ b/pkg/server/get_cluster_config_v1alpha1.go @@ -64,7 +64,7 @@ func (s *server) GetClusterConfig( // @Tags System, Config, Cluster-Scoped Resource, Singleton // @Security BearerAuth // @Produce json -// @Success 200 {object} object "ClusterConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterConfig)" +// @Success 200 {object} kargoapi.ClusterConfig "ClusterConfig custom resource" // @Router /v1beta1/system/cluster-config [get] func (s *server) getClusterConfig(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_cluster_promotion_task_v1alpha1.go b/pkg/server/get_cluster_promotion_task_v1alpha1.go index 94b48d8765..8d86e7cc4f 100644 --- a/pkg/server/get_cluster_promotion_task_v1alpha1.go +++ b/pkg/server/get_cluster_promotion_task_v1alpha1.go @@ -66,7 +66,7 @@ func (s *server) GetClusterPromotionTask( // @Security BearerAuth // @Param cluster-promotion-task path string true "ClusterPromotionTask name" // @Produce json -// @Success 200 {object} object "ClusterPromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTask)" +// @Success 200 {object} kargoapi.ClusterPromotionTask "ClusterPromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTask)" // @Router /v1beta1/shared/cluster-promotion-tasks/{cluster-promotion-task} [get] func (s *server) getClusterPromotionTask(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_clusteranalysistemplate_v1alpha1.go b/pkg/server/get_clusteranalysistemplate_v1alpha1.go index f5c65050e8..de1df75cb1 100644 --- a/pkg/server/get_clusteranalysistemplate_v1alpha1.go +++ b/pkg/server/get_clusteranalysistemplate_v1alpha1.go @@ -75,7 +75,7 @@ func (s *server) GetClusterAnalysisTemplate( // @Security BearerAuth // @Param cluster-analysis-template path string true "ClusterAnalysisTemplate name" // @Produce json -// @Success 200 {object} object "ClusterAnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate)" +// @Success 200 {object} rolloutsapi.ClusterAnalysisTemplate "ClusterAnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate)" // @Router /v1beta1/shared/cluster-analysis-templates/{cluster-analysis-template} [get] func (s *server) getClusterAnalysisTemplate(c *gin.Context) { if !s.cfg.RolloutsIntegrationEnabled { diff --git a/pkg/server/get_config_map_v1alpha1.go b/pkg/server/get_config_map_v1alpha1.go index c253d5a6bd..f4ff2c35e7 100644 --- a/pkg/server/get_config_map_v1alpha1.go +++ b/pkg/server/get_config_map_v1alpha1.go @@ -85,7 +85,7 @@ func (s *server) GetConfigMap( // @Param project path string true "Project name" // @Param configmap path string true "ConfigMap name" // @Produce json -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/projects/{project}/configmaps/{configmap} [get] func (s *server) getProjectConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -111,7 +111,7 @@ func (s *server) getProjectConfigMap(c *gin.Context) { // @Security BearerAuth // @Param configmap path string true "ConfigMap name" // @Produce json -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/system/configmaps/{configmap} [get] func (s *server) getSystemConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -135,7 +135,7 @@ func (s *server) getSystemConfigMap(c *gin.Context) { // @Security BearerAuth // @Param configmap path string true "ConfigMap name" // @Produce json -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/shared/configmaps/{configmap} [get] func (s *server) getSharedConfigMap(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_freight_v1alpha1.go b/pkg/server/get_freight_v1alpha1.go index 4093f52781..3a58c31ac9 100644 --- a/pkg/server/get_freight_v1alpha1.go +++ b/pkg/server/get_freight_v1alpha1.go @@ -111,7 +111,7 @@ func (s *server) GetFreight( // @Produce json // @Param project path string true "Project name" // @Param freight-name-or-alias path string true "Freight name or alias" -// @Success 200 {object} object "Freight custom resource (github.com/akuity/kargo/api/v1alpha1.Freight)" +// @Success 200 {object} kargoapi.Freight "Freight custom resource (github.com/akuity/kargo/api/v1alpha1.Freight)" // @Router /v1beta1/projects/{project}/freight/{freight-name-or-alias} [get] func (s *server) getFreight(c *gin.Context) { project := c.Param("project") diff --git a/pkg/server/get_generic_credentials_v1alpha1.go b/pkg/server/get_generic_credentials_v1alpha1.go index d18ebb9a93..411b893b71 100644 --- a/pkg/server/get_generic_credentials_v1alpha1.go +++ b/pkg/server/get_generic_credentials_v1alpha1.go @@ -17,7 +17,7 @@ import ( // @Param project path string true "Project name" // @Param generic-credentials path string true "Credentials name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/generic-credentials/{generic-credentials} [get] func (s *server) getProjectGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -55,7 +55,7 @@ func (s *server) getProjectGenericCredentials(c *gin.Context) { // @Security BearerAuth // @Param generic-credentials path string true "Credentials name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/system/generic-credentials/{generic-credentials} [get] func (s *server) getSystemGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -92,7 +92,7 @@ func (s *server) getSystemGenericCredentials(c *gin.Context) { // @Security BearerAuth // @Param generic-credentials path string true "Credentials name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/generic-credentials/{generic-credentials} [get] func (s *server) getSharedGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/get_project_config_v1alpha1.go b/pkg/server/get_project_config_v1alpha1.go index 99b71e2f02..1194c04df9 100644 --- a/pkg/server/get_project_config_v1alpha1.go +++ b/pkg/server/get_project_config_v1alpha1.go @@ -74,7 +74,7 @@ func (s *server) GetProjectConfig( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "ProjectConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectConfig)" +// @Success 200 {object} kargoapi.ProjectConfig "ProjectConfig custom resource" // @Router /v1beta1/projects/{project}/config [get] func (s *server) getProjectConfig(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_project_v1alpha1.go b/pkg/server/get_project_v1alpha1.go index 3636c53432..832af010c5 100644 --- a/pkg/server/get_project_v1alpha1.go +++ b/pkg/server/get_project_v1alpha1.go @@ -64,7 +64,7 @@ func (s *server) GetProject( // @Security BearerAuth // @Produce json // @Param project path string true "Project name" -// @Success 200 {object} object "Project custom resource (github.com/akuity/kargo/api/v1alpha1.Project)" +// @Success 200 {object} kargoapi.Project "Project custom resource (github.com/akuity/kargo/api/v1alpha1.Project)" // @Router /v1beta1/projects/{project} [get] func (s *server) getProject(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_promotion_task_v1alpha1.go b/pkg/server/get_promotion_task_v1alpha1.go index 5a8614fdfb..c08cf086d9 100644 --- a/pkg/server/get_promotion_task_v1alpha1.go +++ b/pkg/server/get_promotion_task_v1alpha1.go @@ -78,7 +78,7 @@ func (s *server) GetPromotionTask( // @Produce json // @Param project path string true "Project name" // @Param promotion-task path string true "PromotionTask name" -// @Success 200 {object} object "PromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTask)" +// @Success 200 {object} kargoapi.PromotionTask "PromotionTask custom resource" // @Router /v1beta1/projects/{project}/promotion-tasks/{promotion-task} [get] func (s *server) getPromotionTask(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_promotion_v1alpha1.go b/pkg/server/get_promotion_v1alpha1.go index c7f63f70e5..42f2ef2050 100644 --- a/pkg/server/get_promotion_v1alpha1.go +++ b/pkg/server/get_promotion_v1alpha1.go @@ -78,7 +78,7 @@ func (s *server) GetPromotion( // @Param project path string true "Project name" // @Param promotion path string true "Promotion name" // @Produce json -// @Success 200 {object} object "Promotion custom resource (github.com/akuity/kargo/api/v1alpha1.Promotion)" +// @Success 200 {object} kargoapi.Promotion "Promotion custom resource (github.com/akuity/kargo/api/v1alpha1.Promotion)" // @Router /v1beta1/projects/{project}/promotions/{promotion} [get] func (s *server) getPromotion(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_repo_credentials_v1alpha1.go b/pkg/server/get_repo_credentials_v1alpha1.go index 45d920224b..83567c86c0 100644 --- a/pkg/server/get_repo_credentials_v1alpha1.go +++ b/pkg/server/get_repo_credentials_v1alpha1.go @@ -100,7 +100,7 @@ func (s *server) GetRepoCredentials( // @Param project path string true "Project name" // @Param repo-credentials path string true "Credentials name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/repo-credentials/{repo-credentials} [get] func (s *server) getProjectRepoCredentials(c *gin.Context) { ctx := c.Request.Context() @@ -134,7 +134,7 @@ func (s *server) getProjectRepoCredentials(c *gin.Context) { // @Security BearerAuth // @Param repo-credentials path string true "Credentials name" // @Produce json -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/repo-credentials/{repo-credentials} [get] func (s *server) getSharedRepoCredentials(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_repo_credentials_v1alpha1_test.go b/pkg/server/get_repo_credentials_v1alpha1_test.go index 51b352cd44..83337db50d 100644 --- a/pkg/server/get_repo_credentials_v1alpha1_test.go +++ b/pkg/server/get_repo_credentials_v1alpha1_test.go @@ -282,7 +282,7 @@ func TestGetRepoCredentials(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() client, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/get_stage_v1alpha1.go b/pkg/server/get_stage_v1alpha1.go index 7c9ae1af97..c8384e0fb9 100644 --- a/pkg/server/get_stage_v1alpha1.go +++ b/pkg/server/get_stage_v1alpha1.go @@ -78,7 +78,7 @@ func (s *server) GetStage( // @Produce json // @Param project path string true "Project name" // @Param stage path string true "Stage name" -// @Success 200 {object} object "Stage custom resource (github.com/akuity/kargo/api/v1alpha1.Stage)" +// @Success 200 {object} kargoapi.Stage "Stage custom resource (github.com/akuity/kargo/api/v1alpha1.Stage)" // @Router /v1beta1/projects/{project}/stages/{stage} [get] func (s *server) getStage(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/get_warehouse_v1alpha1.go b/pkg/server/get_warehouse_v1alpha1.go index 1e3c73c448..e3e8fb3330 100644 --- a/pkg/server/get_warehouse_v1alpha1.go +++ b/pkg/server/get_warehouse_v1alpha1.go @@ -103,7 +103,7 @@ func prepareOutboundWarehouse(w *kargoapi.Warehouse) error { // @Param project path string true "Project name" // @Param warehouse path string true "Warehouse name" // @Produce json -// @Success 200 {object} object "Warehouse custom resource (github.com/akuity/kargo/api/v1alpha1.Warehouse)" +// @Success 200 {object} kargoapi.Warehouse "Warehouse custom resource (github.com/akuity/kargo/api/v1alpha1.Warehouse)" // @Router /v1beta1/projects/{project}/warehouses/{warehouse} [get] func (s *server) getWarehouse(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/grant_v1alpha1.go b/pkg/server/grant_v1alpha1.go index b6f6964e51..df45a4f969 100644 --- a/pkg/server/grant_v1alpha1.go +++ b/pkg/server/grant_v1alpha1.go @@ -81,7 +81,7 @@ type userClaims struct { // @Produce json // @Param project path string true "Project name" // @Param body body grantRequest true "Grant request" -// @Success 200 {object} object "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" +// @Success 200 {object} rbacapi.Role "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" // @Router /v1beta1/projects/{project}/roles/grants [post] func (s *server) grant(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/kubernetes/client.go b/pkg/server/kubernetes/client.go index 14a3fea483..ff0e298e9d 100644 --- a/pkg/server/kubernetes/client.go +++ b/pkg/server/kubernetes/client.go @@ -226,6 +226,14 @@ func newDefaultInternalClient( ); err != nil { return nil, fmt.Errorf("error indexing Freight by Warehouse: %w", err) } + if err = cluster.GetFieldIndexer().IndexField( + ctx, + &kargoapi.Freight{}, + indexer.FreightByCurrentStagesField, + indexer.FreightByCurrentStages, + ); err != nil { + return nil, fmt.Errorf("error indexing Freight by Stages in which it is currently in use: %w", err) + } if err = cluster.GetFieldIndexer().IndexField( ctx, &kargoapi.Freight{}, diff --git a/pkg/server/kubernetes/client_test.go b/pkg/server/kubernetes/client_test.go index 3f9d5d5c0e..9b225a876d 100644 --- a/pkg/server/kubernetes/client_test.go +++ b/pkg/server/kubernetes/client_test.go @@ -29,7 +29,7 @@ func TestSetOptionsDefaults(t *testing.T) { func TestNewClient(t *testing.T) { testInternalClient := fake.NewClientBuilder().Build() c, err := NewClient( - context.Background(), + t.Context(), &rest.Config{}, ClientOptions{ // Override this because the default behavior will fail without real REST @@ -54,7 +54,7 @@ func TestNewClient(t *testing.T) { func TestAllClientOperations(t *testing.T) { getOp := func(client *client) error { return client.Get( - context.Background(), + t.Context(), types.NamespacedName{ Namespace: "test-namespace", Name: "test-name", @@ -65,7 +65,7 @@ func TestAllClientOperations(t *testing.T) { listOp := func(client *client) error { return client.List( - context.Background(), + t.Context(), &corev1.PodList{}, libClient.InNamespace("test-namespace"), ) @@ -73,7 +73,7 @@ func TestAllClientOperations(t *testing.T) { createOp := func(client *client) error { return client.Create( - context.Background(), + t.Context(), &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test-namespace", @@ -85,7 +85,7 @@ func TestAllClientOperations(t *testing.T) { deleteOp := func(client *client) error { return client.Delete( - context.Background(), + t.Context(), &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test-namespace", @@ -97,7 +97,7 @@ func TestAllClientOperations(t *testing.T) { updateOp := func(client *client) error { return client.Update( - context.Background(), + t.Context(), &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test-namespace", @@ -109,7 +109,7 @@ func TestAllClientOperations(t *testing.T) { patchOp := func(client *client) error { return client.Patch( - context.Background(), + t.Context(), &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test-namespace", @@ -122,7 +122,7 @@ func TestAllClientOperations(t *testing.T) { deleteAllOp := func(client *client) error { return client.DeleteAllOf( - context.Background(), + t.Context(), &corev1.Pod{}, libClient.InNamespace("test-namespace"), ) @@ -130,7 +130,7 @@ func TestAllClientOperations(t *testing.T) { updateStatusOp := func(client *client) error { return client.Status().Update( - context.Background(), + t.Context(), &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test-namespace", @@ -142,7 +142,7 @@ func TestAllClientOperations(t *testing.T) { patchStatusOp := func(client *client) error { return client.Status().Patch( - context.Background(), + t.Context(), &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Namespace: "test-namespace", @@ -155,7 +155,7 @@ func TestAllClientOperations(t *testing.T) { watchOp := func(client *client) error { _, err := client.Watch( - context.Background(), + t.Context(), &corev1.PodList{}, libClient.InNamespace("test-namespace"), ) @@ -351,7 +351,7 @@ func TestAllClientOperations(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { c, err := NewClient( - context.Background(), + t.Context(), nil, ClientOptions{ NewInternalClient: func( @@ -431,7 +431,7 @@ func TestGetAuthorizedClient(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { if testCase.userInfo != nil { - ctx := user.ContextWithInfo(context.Background(), *testCase.userInfo) + ctx := user.ContextWithInfo(t.Context(), *testCase.userInfo) client, err := getAuthorizedClient(nil)( ctx, testInternalClient, diff --git a/pkg/server/list_analysistemplates_v1alpha1.go b/pkg/server/list_analysistemplates_v1alpha1.go index c6a637995f..bacdf0ad64 100644 --- a/pkg/server/list_analysistemplates_v1alpha1.go +++ b/pkg/server/list_analysistemplates_v1alpha1.go @@ -67,7 +67,7 @@ func (s *server) ListAnalysisTemplates( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "AnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList)" +// @Success 200 {object} rolloutsapi.AnalysisTemplateList "AnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList)" // @Router /v1beta1/projects/{project}/analysis-templates [get] func (s *server) listAnalysisTemplates(c *gin.Context) { if !s.cfg.RolloutsIntegrationEnabled { diff --git a/pkg/server/list_api_tokens_v1alpha1.go b/pkg/server/list_api_tokens_v1alpha1.go index 136b7b6156..e50827deea 100644 --- a/pkg/server/list_api_tokens_v1alpha1.go +++ b/pkg/server/list_api_tokens_v1alpha1.go @@ -62,7 +62,7 @@ func (s *server) ListAPITokens( // @Param project path string true "Project name" // @Param role query string false "Role name filter" // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/projects/{project}/api-tokens [get] func (s *server) listProjectAPITokens(c *gin.Context) { ctx := c.Request.Context() @@ -87,7 +87,7 @@ func (s *server) listProjectAPITokens(c *gin.Context) { // @Security BearerAuth // @Param role query string false "Role name filter" // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/system/api-tokens [get] func (s *server) listSystemAPITokens(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_cluster_promotion_tasks_v1alpha1.go b/pkg/server/list_cluster_promotion_tasks_v1alpha1.go index 1c9313e09d..d737d1626e 100644 --- a/pkg/server/list_cluster_promotion_tasks_v1alpha1.go +++ b/pkg/server/list_cluster_promotion_tasks_v1alpha1.go @@ -46,7 +46,7 @@ func (s *server) ListClusterPromotionTasks( // @Tags Core, Shared, Cluster-Scoped Resource // @Security BearerAuth // @Produce json -// @Success 200 {object} object "ClusterPromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTaskList)" +// @Success 200 {object} kargoapi.ClusterPromotionTaskList "ClusterPromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTaskList)" // @Router /v1beta1/shared/cluster-promotion-tasks [get] func (s *server) listClusterPromotionTasks(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_clusteranalysistemplates_v1alpha1.go b/pkg/server/list_clusteranalysistemplates_v1alpha1.go index 9ec9d8f089..8a43a8fcef 100644 --- a/pkg/server/list_clusteranalysistemplates_v1alpha1.go +++ b/pkg/server/list_clusteranalysistemplates_v1alpha1.go @@ -54,7 +54,7 @@ func (s *server) ListClusterAnalysisTemplates( // @Tags Verifications, Shared, Cluster-Scoped Resource // @Security BearerAuth // @Produce json -// @Success 200 {object} object "ClusterAnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList)" +// @Success 200 {object} rollouts.ClusterAnalysisTemplateList "ClusterAnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList)" // @Router /v1beta1/shared/cluster-analysis-templates [get] func (s *server) listClusterAnalysisTemplates(c *gin.Context) { if !s.cfg.RolloutsIntegrationEnabled { diff --git a/pkg/server/list_config_maps_v1alpha1.go b/pkg/server/list_config_maps_v1alpha1.go index adcf8d86bd..e78652fb5e 100644 --- a/pkg/server/list_config_maps_v1alpha1.go +++ b/pkg/server/list_config_maps_v1alpha1.go @@ -67,7 +67,7 @@ func (s *server) ListConfigMaps( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)" +// @Success 200 {object} corev1.ConfigMapList "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)" // @Router /v1beta1/projects/{project}/configmaps [get] func (s *server) listProjectConfigMaps(c *gin.Context) { ctx := c.Request.Context() @@ -97,7 +97,7 @@ func (s *server) listProjectConfigMaps(c *gin.Context) { // @Tags Core, Generic Config, System-Level // @Security BearerAuth // @Produce json -// @Success 200 {object} object "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)" +// @Success 200 {object} corev1.ConfigMapList "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)" // @Router /v1beta1/system/configmaps [get] func (s *server) listSystemConfigMaps(c *gin.Context) { ctx := c.Request.Context() @@ -125,7 +125,7 @@ func (s *server) listSystemConfigMaps(c *gin.Context) { // @Tags Core, Generic Config, Shared // @Security BearerAuth // @Produce json -// @Success 200 {object} object "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)" +// @Success 200 {object} corev1.ConfigMapList "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)" // @Router /v1beta1/shared/configmaps [get] func (s *server) listSharedConfigMaps(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_generic_credentials_v1alpha1.go b/pkg/server/list_generic_credentials_v1alpha1.go index 9d5217de76..64e197cae8 100644 --- a/pkg/server/list_generic_credentials_v1alpha1.go +++ b/pkg/server/list_generic_credentials_v1alpha1.go @@ -85,7 +85,7 @@ func (s *server) ListGenericCredentials( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/projects/{project}/generic-credentials [get] func (s *server) listProjectGenericCredentials(c *gin.Context) { ctx := c.Request.Context() @@ -124,7 +124,7 @@ func (s *server) listProjectGenericCredentials(c *gin.Context) { // @Tags Credentials, Generic Credentials, System-Level // @Security BearerAuth // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/system/generic-credentials [get] func (s *server) listSystemGenericCredentials(c *gin.Context) { ctx := c.Request.Context() @@ -161,7 +161,7 @@ func (s *server) listSystemGenericCredentials(c *gin.Context) { // @Tags Credentials, Generic Credentials, Shared // @Security BearerAuth // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/shared/generic-credentials [get] func (s *server) listSharedGenericCredentials(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_generic_credentials_v1alpha1_test.go b/pkg/server/list_generic_credentials_v1alpha1_test.go index 837924a378..540d9188df 100644 --- a/pkg/server/list_generic_credentials_v1alpha1_test.go +++ b/pkg/server/list_generic_credentials_v1alpha1_test.go @@ -24,7 +24,7 @@ import ( ) func TestListGenericCredentials(t *testing.T) { - ctx := context.Background() + ctx := t.Context() testData := map[string][]byte{ "PROJECT_SECRET": []byte("Soylent Green is people!"), diff --git a/pkg/server/list_project_events_v1alpha1.go b/pkg/server/list_project_events_v1alpha1.go index 736e7a36cc..2d25d3e155 100644 --- a/pkg/server/list_project_events_v1alpha1.go +++ b/pkg/server/list_project_events_v1alpha1.go @@ -69,7 +69,7 @@ func (s *server) ListProjectEvents( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "EventList resource (k8s.io/api/core/v1.EventList)" +// @Success 200 {object} corev1.EventList "EventList resource (k8s.io/api/core/v1.EventList)" // @Router /v1beta1/projects/{project}/events [get] func (s *server) listProjectEvents(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_projects_v1alpha1.go b/pkg/server/list_projects_v1alpha1.go index 8b76a825b4..7e8d70baf3 100644 --- a/pkg/server/list_projects_v1alpha1.go +++ b/pkg/server/list_projects_v1alpha1.go @@ -93,7 +93,7 @@ func (s *server) ListProjects( // @Tags Core, Cluster-Scoped Resource // @Security BearerAuth // @Produce json -// @Success 200 {object} object "ProjectList custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectList)" +// @Success 200 {object} kargoapi.ProjectList "ProjectList custom resource" // @Router /v1beta1/projects [get] func (s *server) listProjects(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_promotion_tasks_v1alpha1.go b/pkg/server/list_promotion_tasks_v1alpha1.go index 2c76560c0b..06dfcaeb59 100644 --- a/pkg/server/list_promotion_tasks_v1alpha1.go +++ b/pkg/server/list_promotion_tasks_v1alpha1.go @@ -62,7 +62,7 @@ func (s *server) ListPromotionTasks( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "PromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTaskList)" +// @Success 200 {object} kargoapi.PromotionTaskList "PromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTaskList)" // @Router /v1beta1/projects/{project}/promotion-tasks [get] func (s *server) listPromotionTasks(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_promotions_v1alpha1.go b/pkg/server/list_promotions_v1alpha1.go index 7d215ae5d6..a28a96bddd 100644 --- a/pkg/server/list_promotions_v1alpha1.go +++ b/pkg/server/list_promotions_v1alpha1.go @@ -66,7 +66,7 @@ func (s *server) ListPromotions( // @Param project path string true "Project name" // @Param stage query string false "Stage filter" // @Produce json -// @Success 200 {object} object "PromotionList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionList)" +// @Success 200 {object} kargoapi.PromotionList "PromotionList custom resource" // @Router /v1beta1/projects/{project}/promotions [get] func (s *server) listPromotions(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_repo_credentials_v1alpha1.go b/pkg/server/list_repo_credentials_v1alpha1.go index c1b8b3105d..233d479043 100644 --- a/pkg/server/list_repo_credentials_v1alpha1.go +++ b/pkg/server/list_repo_credentials_v1alpha1.go @@ -96,7 +96,7 @@ func (s *server) ListRepoCredentials( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/projects/{project}/repo-credentials [get] func (s *server) listProjectRepoCredentials(c *gin.Context) { ctx := c.Request.Context() @@ -149,7 +149,7 @@ func (s *server) listProjectRepoCredentials(c *gin.Context) { // @Tags Credentials, Repo Credentials, Shared // @Security BearerAuth // @Produce json -// @Success 200 {object} object "SecretList resource (k8s.io/api/core/v1.SecretList)" +// @Success 200 {object} corev1.SecretList "SecretList resource (k8s.io/api/core/v1.SecretList)" // @Router /v1beta1/shared/repo-credentials [get] func (s *server) listSharedRepoCredentials(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_roles_v1alpha1.go b/pkg/server/list_roles_v1alpha1.go index d4bd95dac8..0e7f426b7a 100644 --- a/pkg/server/list_roles_v1alpha1.go +++ b/pkg/server/list_roles_v1alpha1.go @@ -112,7 +112,7 @@ func (s *server) ListRoles( // @Param project path string true "Project name" // @Query as-resources boolean false "Return the roles as their underlying Kubernetes resources" // @Produce json -// @Success 200 {object} object "RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList)" +// @Success 200 {object} object "RoleList custom resource (rbacapi.RoleList) or underlying resources" // @Router /v1beta1/projects/{project}/roles [get] func (s *server) listProjectRoles(c *gin.Context) { ctx := c.Request.Context() @@ -186,7 +186,7 @@ func (s *server) listProjectRoles(c *gin.Context) { // @Security BearerAuth // @Query as-resources boolean false "Return the roles as their underlying Kubernetes resources" // @Produce json -// @Success 200 {object} object "RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList)" +// @Success 200 {object} object "RoleList custom resource (rbacapi.RoleList) or underlying resources" // @Router /v1beta1/system/roles [get] func (s *server) listSystemRoles(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_stages_v1alpha1.go b/pkg/server/list_stages_v1alpha1.go index 2fe8bc07ea..ca4d832924 100644 --- a/pkg/server/list_stages_v1alpha1.go +++ b/pkg/server/list_stages_v1alpha1.go @@ -56,7 +56,7 @@ func (s *server) ListStages( // @Security BearerAuth // @Produce json // @Param project path string true "Project name" -// @Success 200 {object} object "StageList custom resource (github.com/akuity/kargo/api/v1alpha1.StageList)" +// @Success 200 {object} kargoapi.StageList "StageList custom resource (github.com/akuity/kargo/api/v1alpha1.StageList)" // @Router /v1beta1/projects/{project}/stages [get] func (s *server) listStages(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/list_warehouses_v1alpha1.go b/pkg/server/list_warehouses_v1alpha1.go index 5cc8a51f2d..bcc0a7a697 100644 --- a/pkg/server/list_warehouses_v1alpha1.go +++ b/pkg/server/list_warehouses_v1alpha1.go @@ -62,7 +62,7 @@ func (s *server) ListWarehouses( // @Security BearerAuth // @Param project path string true "Project name" // @Produce json -// @Success 200 {object} object "WarehouseList custom resource (github.com/akuity/kargo/api/v1alpha1.WarehouseList)" +// @Success 200 {object} kargoapi.WarehouseList "WarehouseList custom resource" // @Router /v1beta1/projects/{project}/warehouses [get] func (s *server) listWarehouses(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/option/auth_test.go b/pkg/server/option/auth_test.go index edc2630094..8e233e910e 100644 --- a/pkg/server/option/auth_test.go +++ b/pkg/server/option/auth_test.go @@ -48,7 +48,7 @@ c1e3 -----END CERTIFICATE-----`) func TestNewAuthInterceptor(t *testing.T) { - a := newAuthInterceptor(context.Background(), config.ServerConfig{}, nil) + a := newAuthInterceptor(t.Context(), config.ServerConfig{}, nil) require.NotNil(t, a) require.NotNil(t, a.parseUnverifiedJWTFn) require.NotNil(t, a.verifyKargoIssuedTokenFn) @@ -147,7 +147,7 @@ func TestGetKeySet(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { svr, cfg := testCase.setup() t.Cleanup(svr.Close) - keyset, err := getKeySet(context.Background(), cfg) + keyset, err := getKeySet(t.Context(), cfg) require.NoError(t, err) require.NotNil(t, keyset) }) @@ -408,7 +408,7 @@ func TestAuthenticate(t *testing.T) { header.Set("Authorization", ts.token) } ctx, err := ts.authInterceptor.authenticate( - context.Background(), + t.Context(), ts.procedure, header, ) @@ -503,7 +503,7 @@ func TestVerifyIDPIssuedTokenFn(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { c, err := testCase.authInterceptor.verifyIDPIssuedToken( - context.Background(), + t.Context(), // With the way these tests are constructed, this doesn't have to // be valid. "some-token", diff --git a/pkg/server/option/error_test.go b/pkg/server/option/error_test.go index a487721e28..5535d2bb6d 100644 --- a/pkg/server/option/error_test.go +++ b/pkg/server/option/error_test.go @@ -105,7 +105,7 @@ func TestErrorInterceptor(t *testing.T) { cli := svcv1alpha1connect.NewKargoServiceClient(srv.Client(), srv.URL, connect.WithGRPC()) _, err := cli.GetVersionInfo( - context.Background(), + t.Context(), connect.NewRequest(&svcv1alpha1.GetVersionInfoRequest{}), ) if tc.errExpected { diff --git a/pkg/server/option/log_test.go b/pkg/server/option/log_test.go index ca0055799c..d7fdca7f4c 100644 --- a/pkg/server/option/log_test.go +++ b/pkg/server/option/log_test.go @@ -1,7 +1,6 @@ package option import ( - "context" "net/http" "net/http/httptest" "testing" @@ -55,7 +54,7 @@ func TestUnaryServerLogging(t *testing.T) { srv.URL+"/grpc.health.v1.Health/Check", connect.WithGRPC(), ) - _, err := client.CallUnary(context.Background(), + _, err := client.CallUnary(t.Context(), connect.NewRequest[grpc_health_v1.HealthCheckRequest]( &grpc_health_v1.HealthCheckRequest{})) require.NoError(t, err) diff --git a/pkg/server/patch_config_map_v1alpha1.go b/pkg/server/patch_config_map_v1alpha1.go index 0525078cdf..f321c28396 100644 --- a/pkg/server/patch_config_map_v1alpha1.go +++ b/pkg/server/patch_config_map_v1alpha1.go @@ -35,7 +35,7 @@ type patchConfigMapRequest struct { // @Param project path string true "Project name" // @Param configmap path string true "ConfigMap name" // @Param body body patchConfigMapRequest true "ConfigMap patch" -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/projects/{project}/configmaps/{configmap} [patch] func (s *server) patchProjectConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -84,7 +84,7 @@ func (s *server) patchProjectConfigMap(c *gin.Context) { // @Produce json // @Param configmap path string true "ConfigMap name" // @Param body body patchConfigMapRequest true "ConfigMap patch" -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/system/configmaps/{configmap} [patch] func (s *server) patchSystemConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -134,7 +134,7 @@ func (s *server) patchSystemConfigMap(c *gin.Context) { // @Produce json // @Param configmap path string true "ConfigMap name" // @Param body body patchConfigMapRequest true "ConfigMap patch" -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/shared/configmaps/{configmap} [patch] func (s *server) patchSharedConfigMap(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/patch_generic_credentials_v1alpha1.go b/pkg/server/patch_generic_credentials_v1alpha1.go index 2ab46e84f9..4724e1257e 100644 --- a/pkg/server/patch_generic_credentials_v1alpha1.go +++ b/pkg/server/patch_generic_credentials_v1alpha1.go @@ -29,7 +29,7 @@ type patchGenericCredentialsRequest struct { // @Param project path string true "Project name" // @Param generic-credentials path string true "Generic credentials name" // @Param body body patchGenericCredentialsRequest true "GenericCredentials patch" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/generic-credentials/{generic-credentials} [patch] func (s *server) patchProjectGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -87,7 +87,7 @@ func (s *server) patchProjectGenericCredentials(c *gin.Context) { // @Produce json // @Param generic-credentials path string true "Generic credentials name" // @Param body body patchGenericCredentialsRequest true "GenericCredentials patch" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/system/generic-credentials/{generic-credentials} [patch] func (s *server) patchSystemGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -146,7 +146,7 @@ func (s *server) patchSystemGenericCredentials(c *gin.Context) { // @Produce json // @Param generic-credentials path string true "Generic credentials name" // @Param body body patchGenericCredentialsRequest true "GenericCredentials patch" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/generic-credentials/{generic-credentials} [patch] func (s *server) patchSharedGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/patch_repo_credentials_v1alpha1.go b/pkg/server/patch_repo_credentials_v1alpha1.go index 8ce516222f..c68d4cbe1a 100644 --- a/pkg/server/patch_repo_credentials_v1alpha1.go +++ b/pkg/server/patch_repo_credentials_v1alpha1.go @@ -35,7 +35,7 @@ type patchRepoCredentialsRequest struct { // @Param project path string true "Project name" // @Param repo-credentials path string true "Repo credentials name" // @Param body body patchRepoCredentialsRequest true "Credentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/repo-credentials/{repo-credentials} [patch] func (s *server) patchProjectRepoCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -86,7 +86,7 @@ func (s *server) patchProjectRepoCredentials(c *gin.Context) { // @Produce json // @Param repo-credentials path string true "Repo credentials name" // @Param body body patchRepoCredentialsRequest true "Credentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/repo-credentials/{repo-credentials} [patch] func (s *server) patchSharedRepoCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/promote_downstream_v1alpha1_test.go b/pkg/server/promote_downstream_v1alpha1_test.go index 084e754a81..fdc6fd4cc4 100644 --- a/pkg/server/promote_downstream_v1alpha1_test.go +++ b/pkg/server/promote_downstream_v1alpha1_test.go @@ -664,7 +664,7 @@ func TestPromoteDownstream(t *testing.T) { recorder := fakeevent.NewEventRecorder(1) testCase.server.sender = k8sevent.NewEventSender(recorder) resp, err := testCase.server.PromoteDownstream( - context.Background(), + t.Context(), connect.NewRequest(testCase.req), ) testCase.assertions(t, recorder, resp, err) diff --git a/pkg/server/promote_to_stage_v1alpha1.go b/pkg/server/promote_to_stage_v1alpha1.go index 525796197e..f48734c523 100644 --- a/pkg/server/promote_to_stage_v1alpha1.go +++ b/pkg/server/promote_to_stage_v1alpha1.go @@ -173,7 +173,7 @@ type promoteToStageRequest struct { // @Param project path string true "Project name" // @Param stage path string true "Stage name" // @Param body body promoteToStageRequest true "Promote request" -// @Success 201 {object} object "Promotion resource (github.com/akuity/kargo/api/v1alpha1.Promotion)" +// @Success 201 {object} kargoapi.Promotion "Promotion resource (github.com/akuity/kargo/api/v1alpha1.Promotion)" // @Router /v1beta1/projects/{project}/stages/{stage}/promotions [post] func (s *server) promoteToStage(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/promote_to_stage_v1alpha1_test.go b/pkg/server/promote_to_stage_v1alpha1_test.go index 25eb8ef7be..3c6ab6771d 100644 --- a/pkg/server/promote_to_stage_v1alpha1_test.go +++ b/pkg/server/promote_to_stage_v1alpha1_test.go @@ -529,7 +529,7 @@ func TestPromoteToStage(t *testing.T) { recorder := fakeevent.NewEventRecorder(1) testCase.server.sender = k8sevent.NewEventSender(recorder) res, err := testCase.server.PromoteToStage( - context.Background(), + t.Context(), connect.NewRequest(testCase.req), ) testCase.assertions(t, recorder, res, err) diff --git a/pkg/server/query_freights_v1alpha1_test.go b/pkg/server/query_freights_v1alpha1_test.go index 1c45e30e6f..af3d9a5fe6 100644 --- a/pkg/server/query_freights_v1alpha1_test.go +++ b/pkg/server/query_freights_v1alpha1_test.go @@ -354,7 +354,7 @@ func TestQueryFreight(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { res, err := testCase.server.QueryFreight( - context.Background(), + t.Context(), connect.NewRequest(testCase.req), ) testCase.assertions(t, res, err) @@ -418,7 +418,7 @@ func TestGetFreightFromWarehouse(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { freight, err := testCase.server.getFreightFromWarehouses( - context.Background(), + t.Context(), "fake-project", []string{"fake-warehouse"}, ) @@ -484,7 +484,7 @@ func TestGetVerifiedFreight(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { freight, err := testCase.server.getVerifiedFreight( - context.Background(), + t.Context(), "fake-project", []string{ "fake-stage", diff --git a/pkg/server/rbac/roles_test.go b/pkg/server/rbac/roles_test.go index 28b45174ac..2c32cfb081 100644 --- a/pkg/server/rbac/roles_test.go +++ b/pkg/server/rbac/roles_test.go @@ -2257,7 +2257,7 @@ func Test_rolesDatabase_waitForTokenData(t *testing.T) { internalClient: testCase.client, } secret, err := s.waitForTokenData( - context.Background(), + t.Context(), testProject, testTokenName, 2, // Only two attempts so that backoffs are minimal during tests diff --git a/pkg/server/refresh_v1alpha1_test.go b/pkg/server/refresh_v1alpha1_test.go index 7e2d5b7dd2..5543dfc940 100644 --- a/pkg/server/refresh_v1alpha1_test.go +++ b/pkg/server/refresh_v1alpha1_test.go @@ -301,7 +301,7 @@ func TestRefreshResource(t *testing.T) { } for name, ts := range testSets { t.Run(name, func(t *testing.T) { - ctx := context.Background() + ctx := t.Context() client, err := kubernetes.NewClient( ctx, &rest.Config{}, diff --git a/pkg/server/rest_test.go b/pkg/server/rest_test.go index 00cd0ab5ec..ce3a53d87b 100644 --- a/pkg/server/rest_test.go +++ b/pkg/server/rest_test.go @@ -205,7 +205,7 @@ func testRESTWatchEndpoint( internalClient := testCase.clientBuilder.WithScheme(testScheme).Build() var err error s.client, err = kubernetes.NewClient( - context.Background(), + t.Context(), &rest.Config{}, kubernetes.ClientOptions{ SkipAuthorization: true, @@ -236,7 +236,7 @@ func testRESTWatchEndpoint( } // Create a context with timeout to prevent hanging on watch endpoints - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + ctx, cancel := context.WithTimeout(t.Context(), 100*time.Millisecond) defer cancel() req = req.WithContext(ctx) @@ -249,7 +249,7 @@ func testRESTWatchEndpoint( }() } - router := s.setupRESTRouter(context.Background()) + router := s.setupRESTRouter(t.Context()) router.ServeHTTP(w, req) testCase.assertions(t, w, internalClient) diff --git a/pkg/server/revoke_v1alpha1.go b/pkg/server/revoke_v1alpha1.go index 515e2eeea0..2acc4c4270 100644 --- a/pkg/server/revoke_v1alpha1.go +++ b/pkg/server/revoke_v1alpha1.go @@ -76,7 +76,7 @@ type revokeRequest struct { // @Produce json // @Param project path string true "Project name" // @Param body body revokeRequest true "Revoke request" -// @Success 200 {object} object "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" +// @Success 200 {object} rbacapi.Role "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" // @Router /v1beta1/projects/{project}/roles/revocations [post] func (s *server) revoke(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index eaeb14483d..aa7fc2569a 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -20,7 +20,7 @@ import ( func TestNewServer(t *testing.T) { testServerConfig := config.ServerConfig{} testClient, err := kubernetes.NewClient( - context.Background(), + t.Context(), &rest.Config{}, kubernetes.ClientOptions{ NewInternalClient: func( diff --git a/pkg/server/update_config_map_v1alpha1.go b/pkg/server/update_config_map_v1alpha1.go index 72dd98033b..28ae1f9023 100644 --- a/pkg/server/update_config_map_v1alpha1.go +++ b/pkg/server/update_config_map_v1alpha1.go @@ -80,7 +80,7 @@ type updateConfigMapRequest struct { // @Param project path string true "Project name" // @Param configmap path string true "ConfigMap name" // @Param body body updateConfigMapRequest true "ConfigMap" -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/projects/{project}/configmaps/{configmap} [put] func (s *server) updateProjectConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -131,7 +131,7 @@ func (s *server) updateProjectConfigMap(c *gin.Context) { // @Produce json // @Param configmap path string true "ConfigMap name" // @Param body body updateConfigMapRequest true "ConfigMap" -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/system/configmaps/{configmap} [put] func (s *server) updateSystemConfigMap(c *gin.Context) { ctx := c.Request.Context() @@ -183,7 +183,7 @@ func (s *server) updateSystemConfigMap(c *gin.Context) { // @Produce json // @Param configmap path string true "ConfigMap name" // @Param body body updateConfigMapRequest true "ConfigMap" -// @Success 200 {object} object "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" +// @Success 200 {object} corev1.ConfigMap "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)" // @Router /v1beta1/shared/configmaps/{configmap} [put] func (s *server) updateSharedConfigMap(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/update_config_map_v1alpha1_test.go b/pkg/server/update_config_map_v1alpha1_test.go index 0c62c8dca6..e1b848629a 100644 --- a/pkg/server/update_config_map_v1alpha1_test.go +++ b/pkg/server/update_config_map_v1alpha1_test.go @@ -226,7 +226,7 @@ func TestUpdateConfigMap(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - ctx := context.Background() + ctx := t.Context() client, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/update_freight_alias_v1alpha1_test.go b/pkg/server/update_freight_alias_v1alpha1_test.go index 205c03a982..671d7f41b7 100644 --- a/pkg/server/update_freight_alias_v1alpha1_test.go +++ b/pkg/server/update_freight_alias_v1alpha1_test.go @@ -298,7 +298,7 @@ func TestUpdateFreightAlias(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { _, err := testCase.server.UpdateFreightAlias( - context.Background(), + t.Context(), connect.NewRequest(testCase.req), ) testCase.assertions(t, err) diff --git a/pkg/server/update_generic_credentials_v1alpha1.go b/pkg/server/update_generic_credentials_v1alpha1.go index 7aece0aaf2..7a5fc9b191 100644 --- a/pkg/server/update_generic_credentials_v1alpha1.go +++ b/pkg/server/update_generic_credentials_v1alpha1.go @@ -114,7 +114,7 @@ type updateGenericCredentialsRequest struct { // @Param project path string true "Project name" // @Param generic-credentials path string true "Generic credentials name" // @Param body body updateGenericCredentialsRequest true "GenericCredentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/generic-credentials/{generic-credentials} [put] func (s *server) updateProjectGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -174,7 +174,7 @@ func (s *server) updateProjectGenericCredentials(c *gin.Context) { // @Produce json // @Param generic-credentials path string true "Generic credentials name" // @Param body body updateGenericCredentialsRequest true "GenericCredentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/system/generic-credentials/{generic-credentials} [put] func (s *server) updateSystemGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -235,7 +235,7 @@ func (s *server) updateSystemGenericCredentials(c *gin.Context) { // @Produce json // @Param generic-credentials path string true "Generic credentials name" // @Param body body updateGenericCredentialsRequest true "GenericCredentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/generic-credentials/{generic-credentials} [put] func (s *server) updateSharedGenericCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/update_generic_credentials_v1alpha1_test.go b/pkg/server/update_generic_credentials_v1alpha1_test.go index fbf7a373d1..a6366d6de4 100644 --- a/pkg/server/update_generic_credentials_v1alpha1_test.go +++ b/pkg/server/update_generic_credentials_v1alpha1_test.go @@ -26,7 +26,7 @@ import ( ) func TestUpdateGenericCredentials(t *testing.T) { - ctx := context.Background() + ctx := t.Context() cl, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/update_repo_credentials_v1alpha1.go b/pkg/server/update_repo_credentials_v1alpha1.go index 580e895f5f..0ff1c8ff00 100644 --- a/pkg/server/update_repo_credentials_v1alpha1.go +++ b/pkg/server/update_repo_credentials_v1alpha1.go @@ -108,7 +108,7 @@ type updateRepoCredentialsRequest struct { // @Param project path string true "Project name" // @Param repo-credentials path string true "Repo credentials name" // @Param body body updateRepoCredentialsRequest true "Credentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/projects/{project}/repo-credentials/{repo-credentials} [put] func (s *server) updateProjectRepoCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { @@ -164,7 +164,7 @@ func (s *server) updateProjectRepoCredentials(c *gin.Context) { // @Produce json // @Param repo-credentials path string true "Repo credentials name" // @Param body body updateRepoCredentialsRequest true "Credentials" -// @Success 200 {object} object "Secret resource (k8s.io/api/core/v1.Secret)" +// @Success 200 {object} corev1.Secret "Secret resource (k8s.io/api/core/v1.Secret)" // @Router /v1beta1/shared/repo-credentials/{repo-credentials} [put] func (s *server) updateSharedRepoCredentials(c *gin.Context) { if !s.requireSecretManagement(c) { diff --git a/pkg/server/update_repo_credentials_v1alpha1_test.go b/pkg/server/update_repo_credentials_v1alpha1_test.go index c7ce31f72b..1050c10538 100644 --- a/pkg/server/update_repo_credentials_v1alpha1_test.go +++ b/pkg/server/update_repo_credentials_v1alpha1_test.go @@ -27,7 +27,7 @@ import ( ) func TestUpdateRepoCredentials(t *testing.T) { - ctx := context.Background() + ctx := t.Context() cl, err := kubernetes.NewClient( ctx, diff --git a/pkg/server/update_role_v1alpha1.go b/pkg/server/update_role_v1alpha1.go index aacacf1b2c..d051979f1a 100644 --- a/pkg/server/update_role_v1alpha1.go +++ b/pkg/server/update_role_v1alpha1.go @@ -57,7 +57,7 @@ func (s *server) UpdateRole( // @Param project path string true "Project name" // @Param role path string true "Role name" // @Param body body object true "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" -// @Success 200 {object} object "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" +// @Success 200 {object} rbacapi.Role "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)" // @Router /v1beta1/projects/{project}/roles/{role} [put] func (s *server) updateRole(c *gin.Context) { ctx := c.Request.Context() diff --git a/pkg/server/user/user_test.go b/pkg/server/user/user_test.go index 7fc58d7b0c..b7d8e96edf 100644 --- a/pkg/server/user/user_test.go +++ b/pkg/server/user/user_test.go @@ -11,17 +11,17 @@ func TestContextWithUserInfo(t *testing.T) { testUserInfo := Info{ Claims: map[string]any{"sub": "hansolo"}, } - ctx := ContextWithInfo(context.Background(), testUserInfo) + ctx := ContextWithInfo(t.Context(), testUserInfo) require.Equal(t, testUserInfo, ctx.Value(userInfoKey{})) } func TestUserInfoFromContext(t *testing.T) { - _, ok := InfoFromContext(context.Background()) + _, ok := InfoFromContext(t.Context()) require.False(t, ok) testUserInfo := Info{ Claims: map[string]any{"sub": "hansolo"}, } - ctx := context.WithValue(context.Background(), userInfoKey{}, testUserInfo) + ctx := context.WithValue(t.Context(), userInfoKey{}, testUserInfo) u, ok := InfoFromContext(ctx) require.True(t, ok) require.Equal(t, testUserInfo, u) diff --git a/pkg/server/validators_test.go b/pkg/server/validators_test.go index 387d25f629..3fca3e6588 100644 --- a/pkg/server/validators_test.go +++ b/pkg/server/validators_test.go @@ -187,7 +187,7 @@ func TestValidateProjectExists(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { testCase.assertions( t, - testCase.server.validateProjectExists(context.Background(), "fake-project"), + testCase.server.validateProjectExists(t.Context(), "fake-project"), ) }) } diff --git a/pkg/sjson/split_key.go b/pkg/sjson/split_key.go new file mode 100644 index 0000000000..490f7ecbd5 --- /dev/null +++ b/pkg/sjson/split_key.go @@ -0,0 +1,67 @@ +package sjson + +import ( + "fmt" + "strings" +) + +// SplitKey splits a key string into parts separated by dots. It observes the +// same basic syntax rules as tidwall/sjson. Dots are separators unless escaped. +// Colons, unless escaped, are hints that a numeric-looking key part should be +// treated as a key in an object, rather than an index in a sequence. +func SplitKey(key string) ([]string, error) { + key = strings.TrimSpace(key) + if key == "" { + return nil, fmt.Errorf("empty key") + } + parts := make([]string, 0, strings.Count(key, ".")+1) + currentPart := strings.Builder{} + escaped := false + for i := 0; i < len(key); i++ { + char := key[i] + if !escaped { + switch char { + case '\\': + escaped = true // Enter escape mode. + case '.': + // We've reached the end of the current part. + if currentPart.Len() == 0 { + return nil, fmt.Errorf("empty key part in key %q", key) + } + parts = append(parts, currentPart.String()) + currentPart.Reset() + case ':': + if currentPart.Len() > 0 { + // An unescaped colon is only valid as the first character of a key + // part. + return nil, fmt.Errorf("unexpected colon in key %q", key) + } + // We don't actually need to KEEP the colon, since the code that uses + // the key parts returned from this function requires no hint that a + // numeric-looking key part should be treated as a key in an object, + // rather than an index in a sequence. + default: + // Any other character is added to the current part as is. + if err := currentPart.WriteByte(char); err != nil { + return nil, err + } + } + continue + } + // If we get to here, we're currently in escape mode. + switch char { + case '.', ':': + if err := currentPart.WriteByte(char); err != nil { + return nil, err + } + escaped = false // Exit escape mode. + default: + return nil, fmt.Errorf("invalid escape sequence in key %q", key) + } + } + // Don't forget about whatever is left over in currentPart. + if currentPart.Len() == 0 { + return nil, fmt.Errorf("empty key part in key %q", key) + } + return append(parts, currentPart.String()), nil +} diff --git a/pkg/sjson/split_key_test.go b/pkg/sjson/split_key_test.go new file mode 100644 index 0000000000..1424a9dd13 --- /dev/null +++ b/pkg/sjson/split_key_test.go @@ -0,0 +1,78 @@ +package sjson + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSplitKey(t *testing.T) { + testCases := []struct { + name string + key string + expected []string + errContains string + }{ + { + name: "empty key", + errContains: "empty key", + }, + { + name: "starts with dot", + key: ".foo", + errContains: "empty key part in key", + }, + { + name: "ends with dot", + key: "foo.", + errContains: "empty key part in key", + }, + { + name: "double dots", + key: "foo..bar", + errContains: "empty key part in key", + }, + { + name: "invalid escape sequence", + key: `foo\nbar`, + errContains: "invalid escape sequence", + }, + { + name: "invalid use of colon", + key: `foo:bar`, + errContains: "unexpected colon in key", + }, + { + name: "basic split", + key: "foo.bar.bat.baz", + expected: []string{"foo", "bar", "bat", "baz"}, + }, + { + name: "split key with escaped dots", + key: `foo\.bar.bat\.baz`, + expected: []string{"foo.bar", "bat.baz"}, + }, + { + name: "split key with escaped colon", + key: `foo.bar\:bat.baz`, + expected: []string{"foo", "bar:bat", "baz"}, + }, + { + name: "split key with unescaped colon", + key: `foo.bar.:2.baz`, + expected: []string{"foo", "bar", "2", "baz"}, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + parts, err := SplitKey(testCase.key) + if testCase.errContains != "" { + require.ErrorContains(t, err, testCase.errContains) + } else { + require.NoError(t, err) + assert.Equal(t, testCase.expected, parts) + } + }) + } +} diff --git a/pkg/subscription/git.go b/pkg/subscription/git.go index c140724fd4..727faa3413 100644 --- a/pkg/subscription/git.go +++ b/pkg/subscription/git.go @@ -46,6 +46,9 @@ func newGitSubscriber( var ( // nolint: lll + // TODO(v1.13.0): Remove SSH/SCP-style URL support from this regex. The + // first alternation allows ssh as a scheme; the second alternation handles + // SCP-style URLs entirely. gitURLRegex = regexp.MustCompile(`(?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*))`) branchRegex = regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9._\/-]*[a-zA-Z0-9_-])?$`) diff --git a/pkg/subscription/schemas/chart.json b/pkg/subscription/schemas/chart.json index 718729e4c6..b66858a726 100644 --- a/pkg/subscription/schemas/chart.json +++ b/pkg/subscription/schemas/chart.json @@ -25,6 +25,10 @@ "maximum": 100, "default": 20, "description": "DiscoveryLimit is an optional limit on the number of chart versions that can be discovered for this subscription. The limit is applied after filtering charts based on the semverConstraint field. The upper limit for this field is 100." + }, + "insecureSkipTLSVerify": { + "type": "boolean", + "description": "InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored when connecting to the repository. This should be enabled only with great caution." } }, "additionalProperties": false diff --git a/pkg/subscription/schemas/git.json b/pkg/subscription/schemas/git.json index 058c2e5d3a..e591c7f420 100644 --- a/pkg/subscription/schemas/git.json +++ b/pkg/subscription/schemas/git.json @@ -9,7 +9,7 @@ "type": "string", "minLength": 1, "pattern": "(?:^(ssh|https?)://(?:([\\w-]+)(:(.+))?@)?([\\w-]+(?:\\.[\\w-]+)*)(?::(\\d{1,5}))?(/.*)$)|(?:^([\\w-]+)@([\\w+]+(?:\\.[\\w-]+)*):(/?.*))$", - "description": "URL is the repository's URL. This is a required field." + "description": "URL is the repository's URL. This is a required field. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead." }, "commitSelectionStrategy": { "type": "string", @@ -86,6 +86,11 @@ "maximum": 100, "default": 20, "description": "DiscoveryLimit is an optional limit on the number of commits that can be discovered for this subscription. The upper limit is 100." + }, + "since": { + "type": "string", + "format": "date-time", + "description": "An optional date (RFC 3339) that limits commit discovery to commits at or after this date. When specified, discovery stops upon reaching a commit older than this date. When left unspecified, there is no cutoff." } }, "additionalProperties": false diff --git a/pkg/toml/toml.go b/pkg/toml/toml.go new file mode 100644 index 0000000000..932a80b714 --- /dev/null +++ b/pkg/toml/toml.go @@ -0,0 +1,292 @@ +package toml + +import ( + "bytes" + "fmt" + "os" + "sort" + "strconv" + "strings" + "time" + + tomlv2 "github.com/pelletier/go-toml/v2" + // Note: This is the only go-toml API that exposes byte offsets, which we need + // for in-place edits. It is explicitly not a stable API, so go-toml version + // bumps may require changes here. Test coverage in toml_test.go exercises + // every node type and should catch most unanticipated breaking changes. + "github.com/pelletier/go-toml/v2/unstable" + + "github.com/akuity/kargo/pkg/sjson" +) + +// Update represents a discrete update to be made to a TOML document. +type Update struct { + // Key is the dot-separated path to the field to update. + Key string + // Value is the new value to set for the field. + Value any +} + +type nodeRef struct { + kind unstable.Kind + raw unstable.Range +} + +type nodeIndex struct { + nodes map[string]nodeRef + scalars map[string]nodeRef +} + +type change struct { + offset int + length int + replacement []byte +} + +// SetValuesInFile overwrites the specified file with the changes specified by +// the list of Updates. Keys are of the form ..... +// Integers may be used as keys where a specific array element needs to be +// selected. An error is returned for any attempted update to a key that does +// not exist or does not address a scalar node. Untouched bytes are preserved. +func SetValuesInFile(file string, updates []Update) error { + inBytes, err := os.ReadFile(file) + if err != nil { + return fmt.Errorf("error reading file %q: %w", file, err) + } + outBytes, err := SetValuesInBytes(inBytes, updates) + if err != nil { + return fmt.Errorf("error mutating bytes: %w", err) + } + if err = os.WriteFile(file, outBytes, 0o600); err != nil { + return fmt.Errorf("error writing mutated bytes to file %q: %w", file, err) + } + return nil +} + +// SetValuesInBytes returns a copy of the provided bytes with the changes +// specified by Updates applied. Keys are of the form ..... +// Integers may be used as keys where a specific array element needs to be +// selected. An error is returned for any attempted update to a key that does +// not exist or does not address a scalar node. Untouched bytes are preserved. +func SetValuesInBytes(inBytes []byte, updates []Update) ([]byte, error) { + index, err := indexNodes(inBytes) + if err != nil { + return nil, err + } + + changesByPath := map[string]change{} + for _, update := range updates { + keyPath, err := sjson.SplitKey(update.Key) + if err != nil { + return nil, fmt.Errorf("error splitting key %s: %w", update.Key, err) + } + encodedPath := encodePath(keyPath) + + node, ok := index.scalars[encodedPath] + if !ok { + if ref, found := index.nodes[encodedPath]; found { + return nil, fmt.Errorf( + "error finding key %s: key path addresses %s instead of a scalar node", + update.Key, + ref.kind, + ) + } + return nil, fmt.Errorf("error finding key %s: key path not found", update.Key) + } + + replacement, err := FormatValue(update.Value) + if err != nil { + return nil, fmt.Errorf("error formatting value for key %s: %w", update.Key, err) + } + + changesByPath[encodedPath] = change{ + offset: int(node.raw.Offset), + length: int(node.raw.Length), + replacement: replacement, + } + } + + outBytes := bytes.Clone(inBytes) + changes := make([]change, 0, len(changesByPath)) + for _, ch := range changesByPath { + changes = append(changes, ch) + } + sort.Slice(changes, func(i, j int) bool { + return changes[i].offset > changes[j].offset + }) + + for _, ch := range changes { + end := ch.offset + ch.length + if ch.offset < 0 || end > len(outBytes) { + return nil, fmt.Errorf("invalid replacement range [%d:%d]", ch.offset, end) + } + + updatedBytes := make([]byte, 0, len(outBytes)-ch.length+len(ch.replacement)) + updatedBytes = append(updatedBytes, outBytes[:ch.offset]...) + updatedBytes = append(updatedBytes, ch.replacement...) + updatedBytes = append(updatedBytes, outBytes[end:]...) + outBytes = updatedBytes + } + + return outBytes, nil +} + +// FormatValue returns a TOML-encoded scalar value. +func FormatValue(value any) ([]byte, error) { + if !isValidScalar(value) { + return nil, fmt.Errorf("value is not a TOML scalar type") + } + + encodedValue, err := tomlv2.Marshal(map[string]any{"value": value}) + if err != nil { + return nil, fmt.Errorf("error marshaling TOML value: %w", err) + } + + const prefix = "value = " + encodedValue = bytes.TrimSuffix(encodedValue, []byte("\n")) + if !bytes.HasPrefix(encodedValue, []byte(prefix)) { + return nil, fmt.Errorf("unexpected encoded TOML value %q", encodedValue) + } + + return bytes.Clone(encodedValue[len(prefix):]), nil +} + +// FormatValueString returns a TOML-encoded scalar value as a string. +func FormatValueString(value any) string { + formatted, err := FormatValue(value) + if err != nil { + return fmt.Sprintf("%v", value) + } + return string(formatted) +} + +func indexNodes(inBytes []byte) (*nodeIndex, error) { + idx := &nodeIndex{ + nodes: map[string]nodeRef{}, + scalars: map[string]nodeRef{}, + } + + parser := unstable.Parser{KeepComments: true} + parser.Reset(inBytes) + + currentPath := []string{} + arrayTableCounts := map[string]int{} + + for parser.NextExpression() { + expr := parser.Expression() + switch expr.Kind { + case unstable.Comment: + continue + case unstable.Table: + currentPath = iteratorParts(expr.Key()) + idx.register(currentPath, expr) + case unstable.ArrayTable: + basePath := iteratorParts(expr.Key()) + idx.register(basePath, expr) + countKey := encodePath(basePath) + currentIndex := arrayTableCounts[countKey] + arrayTableCounts[countKey] = currentIndex + 1 + currentPath = append(copyPath(basePath), strconv.Itoa(currentIndex)) + idx.register(currentPath, expr) + case unstable.KeyValue: + fullPath := append(copyPath(currentPath), iteratorParts(expr.Key())...) + idx.indexValue(&parser, expr.Value(), fullPath) + default: + return nil, fmt.Errorf( + "error parsing input: unsupported expression kind %s", + expr.Kind, + ) + } + } + + if err := parser.Error(); err != nil { + return nil, fmt.Errorf("error parsing input: %w", err) + } + + return idx, nil +} + +func (n *nodeIndex) indexValue( + parser *unstable.Parser, + node *unstable.Node, + path []string, +) { + if node == nil || !node.Valid() { + return + } + + n.register(path, node) + + switch node.Kind { + case unstable.Array: + it := node.Children() + index := 0 + for it.Next() { + n.indexValue(parser, it.Node(), append(copyPath(path), strconv.Itoa(index))) + index++ + } + case unstable.InlineTable: + it := node.Children() + for it.Next() { + child := it.Node() + if child.Kind != unstable.KeyValue { + continue + } + childPath := append(copyPath(path), iteratorParts(child.Key())...) + n.indexValue(parser, child.Value(), childPath) + } + case unstable.String, + unstable.Bool, + unstable.Float, + unstable.Integer, + unstable.LocalDate, + unstable.LocalTime, + unstable.LocalDateTime, + unstable.DateTime: + raw := node.Raw + if raw.Length == 0 && len(node.Data) > 0 { + raw = parser.Range(node.Data) + } + n.scalars[encodePath(path)] = nodeRef{kind: node.Kind, raw: raw} + } +} + +func (n *nodeIndex) register(path []string, node *unstable.Node) { + n.nodes[encodePath(path)] = nodeRef{kind: node.Kind, raw: node.Raw} +} + +func encodePath(path []string) string { + var builder strings.Builder + for _, part := range path { + _, _ = fmt.Fprintf(&builder, "%d:%s|", len(part), part) + } + return builder.String() +} + +func copyPath(path []string) []string { + return append([]string(nil), path...) +} + +func iteratorParts(iterator unstable.Iterator) []string { + parts := []string{} + for iterator.Next() { + parts = append(parts, string(iterator.Node().Data)) + } + return parts +} + +func isValidScalar(value any) bool { + switch value.(type) { + case int, int8, int16, int32, int64, + uint, uint8, uint16, uint32, uint64, + float32, float64, + string, bool, + time.Time, + tomlv2.LocalDate, + tomlv2.LocalTime, + tomlv2.LocalDateTime: + return true + default: + return false + } +} diff --git a/pkg/toml/toml_test.go b/pkg/toml/toml_test.go new file mode 100644 index 0000000000..db5e147c68 --- /dev/null +++ b/pkg/toml/toml_test.go @@ -0,0 +1,259 @@ +package toml + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSetValuesInBytes(t *testing.T) { + tests := []struct { + name string + inBytes []byte + updates []Update + assertions func(*testing.T, []byte, error) + }{ + // Error cases + { + name: "invalid TOML", + inBytes: []byte("key = \n"), + assertions: func(t *testing.T, bytes []byte, err error) { + require.ErrorContains(t, err, "error parsing input") + require.Nil(t, bytes) + }, + }, + { + name: "missing key", + inBytes: []byte("title = \"old\"\n"), + updates: []Update{{Key: "missing", Value: "new"}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.ErrorContains(t, err, "key path not found") + require.Nil(t, bytes) + }, + }, + { + name: "non scalar target", + inBytes: []byte("[service]\nname = \"api\"\n"), + updates: []Update{{Key: "service", Value: "other"}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.ErrorContains(t, err, "addresses Table instead of a scalar node") + require.Nil(t, bytes) + }, + }, + { + name: "unsupported value type", + inBytes: []byte("title = \"old\"\n"), + updates: []Update{{Key: "title", Value: []string{"a", "b"}}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.ErrorContains(t, err, "value is not a TOML scalar type") + require.Nil(t, bytes) + }, + }, + // Single top-level updates + { + name: "updates scalar value", + inBytes: []byte("title = \"old\"\nactive = true\n"), + updates: []Update{{Key: "title", Value: "new"}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("title = 'new'\nactive = true\n"), bytes) + }, + }, + { + name: "updates escaped dot key", + inBytes: []byte("\"example.com/version\" = \"1.0.0\"\n"), + updates: []Update{{Key: `example\.com/version`, Value: "2.0.0"}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("\"example.com/version\" = '2.0.0'\n"), bytes) + }, + }, + // Single updates under tables + { + name: "updates scalar under table header", + inBytes: []byte("[package]\nversion = \"1.0.0\"\n"), + updates: []Update{{Key: "package.version", Value: "2.0.0"}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("[package]\nversion = '2.0.0'\n"), bytes) + }, + }, + { + name: "updates scalar under nested table header", + inBytes: []byte("[a.b]\nc = 1\n"), + updates: []Update{{Key: "a.b.c", Value: 99}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("[a.b]\nc = 99\n"), bytes) + }, + }, + { + name: "updates scalar under table header that follows other expressions", + inBytes: []byte("threshold = 1\n\n[features]\nenabled = false\n"), + updates: []Update{{Key: "features.enabled", Value: true}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("threshold = 1\n\n[features]\nenabled = true\n"), bytes) + }, + }, + // Single updates in inline/array constructs + { + name: "updates array item", + inBytes: []byte("values = [1, 2, 3]\n"), + updates: []Update{{Key: "values.1", Value: 42}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("values = [1, 42, 3]\n"), bytes) + }, + }, + { + name: "updates inline table item", + inBytes: []byte("service = { name = \"api\", port = 8080 }\n"), + updates: []Update{{Key: "service.port", Value: 9090}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("service = { name = \"api\", port = 9090 }\n"), bytes) + }, + }, + { + name: "updates array table item", + inBytes: []byte("[[services]]\nname = \"api\"\nport = 8080\n\n[[services]]\nname = \"web\"\nport = 8081\n"), + updates: []Update{{Key: "services.1.port", Value: 9090}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal( + t, + []byte("[[services]]\nname = \"api\"\nport = 8080\n\n[[services]]\nname = \"web\"\nport = 9090\n"), + bytes, + ) + }, + }, + // Formatting preservation + { + name: "preserves inline comments around updated value", + inBytes: []byte("title = \"old\" # keep me\nactive = true\n"), + updates: []Update{{Key: "title", Value: "new"}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("title = 'new' # keep me\nactive = true\n"), bytes) + }, + }, + { + name: "preserves standalone comment lines", + inBytes: []byte("# header comment\nv = 1\n# footer comment\n"), + updates: []Update{{Key: "v", Value: 2}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("# header comment\nv = 2\n# footer comment\n"), bytes) + }, + }, + { + name: "preserves blank lines between sections", + inBytes: []byte("[a]\nx = 1\n\n\n[b]\ny = 2\n"), + updates: []Update{{Key: "b.y", Value: 99}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("[a]\nx = 1\n\n\n[b]\ny = 99\n"), bytes) + }, + }, + { + name: "value grows in length", + inBytes: []byte("v = 1\nother = true\n"), + updates: []Update{{Key: "v", Value: 99999}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("v = 99999\nother = true\n"), bytes) + }, + }, + { + name: "value shrinks in length", + inBytes: []byte("v = 99999\nother = true\n"), + updates: []Update{{Key: "v", Value: 1}}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("v = 1\nother = true\n"), bytes) + }, + }, + // Multiple updates + { + name: "multiple updates to different top-level keys", + inBytes: []byte("a = 1\nb = 2\nc = 3\n"), + updates: []Update{ + {Key: "a", Value: 10}, + {Key: "c", Value: 30}, + }, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("a = 10\nb = 2\nc = 30\n"), bytes) + }, + }, + { + name: "multiple updates across top-level and table-scoped keys", + inBytes: []byte("threshold = 1\n\n[package]\nversion = \"1.0.0\"\n\n[features]\nenabled = false\n"), + updates: []Update{ + {Key: "threshold", Value: 100}, + {Key: "package.version", Value: "2.0.0"}, + {Key: "features.enabled", Value: true}, + }, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal( + t, + []byte("threshold = 100\n\n[package]\nversion = '2.0.0'\n\n[features]\nenabled = true\n"), + bytes, + ) + }, + }, + { + name: "multiple updates within same table", + inBytes: []byte("[server]\nhost = \"localhost\"\nport = 8080\n"), + updates: []Update{ + {Key: "server.host", Value: "0.0.0.0"}, + {Key: "server.port", Value: 9090}, + }, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal( + t, + []byte("[server]\nhost = '0.0.0.0'\nport = 9090\n"), + bytes, + ) + }, + }, + { + name: "duplicate key in updates uses last value", + inBytes: []byte("v = 1\n"), + updates: []Update{ + {Key: "v", Value: 2}, + {Key: "v", Value: 3}, + }, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("v = 3\n"), bytes) + }, + }, + // Edge cases + { + name: "no updates returns input unchanged", + inBytes: []byte("title = \"hello\"\n"), + updates: []Update{}, + assertions: func(t *testing.T, bytes []byte, err error) { + require.NoError(t, err) + require.Equal(t, []byte("title = \"hello\"\n"), bytes) + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + outBytes, err := SetValuesInBytes(test.inBytes, test.updates) + test.assertions(t, outBytes, err) + }) + } +} + +func TestFormatValueString(t *testing.T) { + require.Equal(t, `'value'`, FormatValueString("value")) + require.Equal(t, "42", FormatValueString(42)) + require.Equal(t, "true", FormatValueString(true)) +} diff --git a/pkg/urls/git.go b/pkg/urls/git.go index 74f70574f9..7056794c54 100644 --- a/pkg/urls/git.go +++ b/pkg/urls/git.go @@ -7,6 +7,8 @@ import ( "strings" ) +// TODO(v1.13.0): Remove scpSyntaxRegex when SSH/SCP-style URL support is +// removed. var scpSyntaxRegex = regexp.MustCompile(`^((?:[\w-]+@)?[\w-]+(?:\.[\w-]+)*)(?::(.*))?$`) // NormalizeGit normalizes Git URLs of the following forms: @@ -38,6 +40,7 @@ func NormalizeGit(repo string) string { return repoURL.String() } + // TODO(v1.13.0): Remove this block when SSH URL support is removed. // URLS of the form ssh://[user@]host.xz[:port][/path/to/repo[.git][/]] if strings.HasPrefix(repo, "ssh://") { // repo = strings.TrimPrefix(repo, "ssh://") @@ -53,6 +56,7 @@ func NormalizeGit(repo string) string { repoURL.Path = strings.TrimSuffix(repoURL.Path, ".git") return repoURL.String() } + // TODO(v1.13.0): Remove this block when SCP-style URL support is removed. // URLS of the form [user@]host.xz[:path/to/repo[.git][/]] matches := scpSyntaxRegex.FindStringSubmatch(repo) if len(matches) != 2 && len(matches) != 3 { diff --git a/pkg/webhook/external/server_test.go b/pkg/webhook/external/server_test.go index 0ad5a933d1..70a5c1bdbd 100644 --- a/pkg/webhook/external/server_test.go +++ b/pkg/webhook/external/server_test.go @@ -30,7 +30,7 @@ func TestServer_Healthz(t *testing.T) { require.NoError(t, err) defer l.Close() - ctx, cancel := context.WithCancel(context.Background()) + ctx, cancel := context.WithCancel(t.Context()) defer cancel() go func() { diff --git a/pkg/webhook/kubernetes/clusterconfig/webhook_test.go b/pkg/webhook/kubernetes/clusterconfig/webhook_test.go index 9fb3a4240f..9a874fa8c2 100644 --- a/pkg/webhook/kubernetes/clusterconfig/webhook_test.go +++ b/pkg/webhook/kubernetes/clusterconfig/webhook_test.go @@ -1,7 +1,6 @@ package clusterconfig import ( - "context" "errors" "testing" @@ -106,7 +105,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { w := &webhook{} - warnings, err := w.ValidateCreate(context.Background(), testCase.cfg) + warnings, err := w.ValidateCreate(t.Context(), testCase.cfg) testCase.assertions(t, warnings, err) }) } @@ -181,7 +180,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { w := &webhook{} - warnings, err := w.ValidateUpdate(context.Background(), nil, testCase.cfg) + warnings, err := w.ValidateUpdate(t.Context(), nil, testCase.cfg) testCase.assertions(t, warnings, err) }) } diff --git a/pkg/webhook/kubernetes/config.go b/pkg/webhook/kubernetes/config.go index c424a88e7a..f21ee63197 100644 --- a/pkg/webhook/kubernetes/config.go +++ b/pkg/webhook/kubernetes/config.go @@ -7,10 +7,17 @@ import ( ) type Config struct { + // KargoNamespace is the namespace in which Kargo is installed. + KargoNamespace string `envconfig:"KARGO_NAMESPACE" required:"true"` // RawControlplaneUserRegex is a regular expression to match the username in // admission request to distinguish if the request is coming from controlplane. RawControlplaneUserRegex string `envconfig:"CONTROLPLANE_USER_REGEX"` ControlplaneUserRegex *regexp.Regexp `ignored:"true"` + // ManagementControllerUsername is the exact username (typically a service + // account name) of the management controller. This is used where only the + // management controller (not the API server or other controlplane + // components) should be permitted to act. + ManagementControllerUsername string `envconfig:"MANAGEMENT_CONTROLLER_USERNAME"` } func ConfigFromEnv() Config { diff --git a/pkg/webhook/kubernetes/config_test.go b/pkg/webhook/kubernetes/config_test.go index 2d56e9a76f..e46edfe23a 100644 --- a/pkg/webhook/kubernetes/config_test.go +++ b/pkg/webhook/kubernetes/config_test.go @@ -13,6 +13,7 @@ func TestConfigFromEnv(t *testing.T) { }{ "empty controlplane user regex should not panic": { envs: map[string]string{ + "KARGO_NAMESPACE": "kargo", "CONTROLPLANE_USER_REGEX": "", }, assertFn: func(t *testing.T, f func() Config) { @@ -25,6 +26,7 @@ func TestConfigFromEnv(t *testing.T) { }, "invalid controlplane user regex should panic": { envs: map[string]string{ + "KARGO_NAMESPACE": "kargo", "CONTROLPLANE_USER_REGEX": "[", }, assertFn: func(t *testing.T, f func() Config) { @@ -33,6 +35,7 @@ func TestConfigFromEnv(t *testing.T) { }, "default controlplane user regex in helm chart": { envs: map[string]string{ + "KARGO_NAMESPACE": "kargo", "CONTROLPLANE_USER_REGEX": "^system:serviceaccount:kargo:(kargo-api|kargo-controller)$", }, assertFn: func(t *testing.T, f func() Config) { @@ -47,6 +50,7 @@ func TestConfigFromEnv(t *testing.T) { }, "sample controlplane user regex in helm chart": { envs: map[string]string{ + "KARGO_NAMESPACE": "kargo", "CONTROLPLANE_USER_REGEX": "^system:serviceaccount:kargo:[a-z0-9]([-a-z0-9]*[a-z0-9])?$", }, assertFn: func(t *testing.T, f func() Config) { @@ -59,6 +63,23 @@ func TestConfigFromEnv(t *testing.T) { require.True(t, cfg.ControlplaneUserRegex.MatchString("system:serviceaccount:kargo:kargo-controller")) }, }, + "management controller username is populated": { + envs: map[string]string{ + "KARGO_NAMESPACE": "kargo", + "MANAGEMENT_CONTROLLER_USERNAME": "system:serviceaccount:kargo:kargo-management-controller", + }, + assertFn: func(t *testing.T, f func() Config) { + var cfg Config + require.NotPanics(t, func() { + cfg = f() + }) + require.Equal( + t, + "system:serviceaccount:kargo:kargo-management-controller", + cfg.ManagementControllerUsername, + ) + }, + }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { diff --git a/pkg/webhook/kubernetes/freight/webhook_test.go b/pkg/webhook/kubernetes/freight/webhook_test.go index c5f64c9df0..f78084b2a5 100644 --- a/pkg/webhook/kubernetes/freight/webhook_test.go +++ b/pkg/webhook/kubernetes/freight/webhook_test.go @@ -138,7 +138,7 @@ func Test_webhook_Default(t *testing.T) { }, } for _, testCase := range testCases { - ctx := context.Background() + ctx := t.Context() if testCase.op != "" { ctx = admission.NewContextWithRequest( ctx, @@ -481,7 +481,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { for _, testCase := range testCases { tc := testCase // Avoid implicit memory aliasing t.Run(testCase.name, func(t *testing.T) { - _, err := tc.webhook.ValidateCreate(context.Background(), &tc.freight) + _, err := tc.webhook.ValidateCreate(t.Context(), &tc.freight) tc.assertions(t, err) }) } @@ -797,7 +797,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { if testCase.userInfo != nil { req.UserInfo = *testCase.userInfo } - ctx := admission.NewContextWithRequest(context.Background(), req) + ctx := admission.NewContextWithRequest(t.Context(), req) _, err := testCase.webhook.ValidateUpdate( ctx, @@ -870,7 +870,7 @@ func Test_webhook_ValidateDelete(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { t.Parallel() - _, err := tc.webhook.ValidateDelete(context.Background(), tc.input) + _, err := tc.webhook.ValidateDelete(t.Context(), tc.input) if tc.shouldErr { require.Error(t, err) require.True(t, apierrors.IsForbidden(err)) diff --git a/pkg/webhook/kubernetes/project/webhook.go b/pkg/webhook/kubernetes/project/webhook.go index 80cf256cf8..01d6fda20f 100644 --- a/pkg/webhook/kubernetes/project/webhook.go +++ b/pkg/webhook/kubernetes/project/webhook.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" - "github.com/kelseyhightower/envconfig" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -20,6 +19,7 @@ import ( kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/pkg/logging" + libWebhook "github.com/akuity/kargo/pkg/webhook/kubernetes" ) var projectGroupResource = schema.GroupResource{ @@ -27,22 +27,12 @@ var projectGroupResource = schema.GroupResource{ Resource: "projects", } -type WebhookConfig struct { - KargoNamespace string `envconfig:"KARGO_NAMESPACE" required:"true"` -} - -func WebhookConfigFromEnv() WebhookConfig { - cfg := WebhookConfig{} - envconfig.MustProcess("", &cfg) - return cfg -} - type webhook struct { - cfg WebhookConfig + cfg libWebhook.Config client client.Client } -func SetupWebhookWithManager(mgr ctrl.Manager, cfg WebhookConfig) error { +func SetupWebhookWithManager(mgr ctrl.Manager, cfg libWebhook.Config) error { w := &webhook{ cfg: cfg, client: mgr.GetClient(), diff --git a/pkg/webhook/kubernetes/project/webhook_test.go b/pkg/webhook/kubernetes/project/webhook_test.go index 26af7587c7..cd220d52f0 100644 --- a/pkg/webhook/kubernetes/project/webhook_test.go +++ b/pkg/webhook/kubernetes/project/webhook_test.go @@ -1,7 +1,6 @@ package project import ( - "context" "errors" "testing" @@ -18,15 +17,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" kargoapi "github.com/akuity/kargo/api/v1alpha1" + libWebhook "github.com/akuity/kargo/pkg/webhook/kubernetes" ) -func TestWebhookConfigFromEnv(t *testing.T) { - const kargoNamespace = "test-kargo-namespace" - t.Setenv("KARGO_NAMESPACE", kargoNamespace) - cfg := WebhookConfigFromEnv() - assert.Equal(t, kargoNamespace, cfg.KargoNamespace) -} - func Test_webhook_ValidateCreate(t *testing.T) { scheme := runtime.NewScheme() require.NoError(t, corev1.AddToScheme(scheme)) @@ -123,12 +116,10 @@ func Test_webhook_ValidateCreate(t *testing.T) { w := &webhook{ client: c, - cfg: WebhookConfig{ - KargoNamespace: "kargo-system", - }, + cfg: libWebhook.Config{KargoNamespace: "kargo-system"}, } - ctx := admission.NewContextWithRequest(context.Background(), admission.Request{ + ctx := admission.NewContextWithRequest(t.Context(), admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ DryRun: &tt.isDryRun, }, @@ -149,7 +140,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { }, } - warnings, err := w.ValidateUpdate(context.Background(), project, project) + warnings, err := w.ValidateUpdate(t.Context(), project, project) assert.Empty(t, warnings) assert.NoError(t, err) } @@ -163,7 +154,7 @@ func Test_webhook_ValidateDelete(t *testing.T) { }, } - warnings, err := w.ValidateDelete(context.Background(), project) + warnings, err := w.ValidateDelete(t.Context(), project) assert.Empty(t, warnings) assert.NoError(t, err) } @@ -247,7 +238,7 @@ func Test_webhook_ensureNamespace(t *testing.T) { client: c, } - err := w.ensureNamespace(context.Background(), tt.project) + err := w.ensureNamespace(t.Context(), tt.project) tt.assertions(t, err) }) } @@ -305,7 +296,7 @@ func Test_webhook_ensureProjectAdminPermissions(t *testing.T) { // Check role binding creation rb := &rbacv1.RoleBinding{} - err = c.Get(context.Background(), client.ObjectKey{ + err = c.Get(t.Context(), client.ObjectKey{ Name: roleBindingName, Namespace: testProjectName, }, rb) @@ -339,12 +330,10 @@ func Test_webhook_ensureProjectAdminPermissions(t *testing.T) { w := &webhook{ client: c, - cfg: WebhookConfig{ - KargoNamespace: kargoNamespace, - }, + cfg: libWebhook.Config{KargoNamespace: kargoNamespace}, } - err := w.ensureProjectAdminPermissions(context.Background(), tt.project) + err := w.ensureProjectAdminPermissions(t.Context(), tt.project) tt.assertions(t, err, c) }) } diff --git a/pkg/webhook/kubernetes/projectconfig/webhook_test.go b/pkg/webhook/kubernetes/projectconfig/webhook_test.go index 0d3820c247..5dff7f4218 100644 --- a/pkg/webhook/kubernetes/projectconfig/webhook_test.go +++ b/pkg/webhook/kubernetes/projectconfig/webhook_test.go @@ -1,7 +1,6 @@ package projectconfig import ( - "context" "errors" "fmt" "sort" @@ -651,7 +650,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { client: c, } - ctx := admission.NewContextWithRequest(context.Background(), admission.Request{ + ctx := admission.NewContextWithRequest(t.Context(), admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ DryRun: &tt.isDryRun, }, @@ -858,7 +857,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { w := &webhook{} - warnings, err := w.ValidateUpdate(context.Background(), nil, tt.projectCfg) + warnings, err := w.ValidateUpdate(t.Context(), nil, tt.projectCfg) tt.assertions(t, warnings, err) }) } diff --git a/pkg/webhook/kubernetes/promotion/webhook_test.go b/pkg/webhook/kubernetes/promotion/webhook_test.go index 80d6372a0d..8e1ddbb682 100644 --- a/pkg/webhook/kubernetes/promotion/webhook_test.go +++ b/pkg/webhook/kubernetes/promotion/webhook_test.go @@ -623,7 +623,7 @@ func Test_webhook_Default(t *testing.T) { } ctx := admission.NewContextWithRequest( - context.Background(), + t.Context(), testCase.req, ) testCase.assertions( @@ -926,7 +926,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { if testCase.userInfo != nil { req.UserInfo = *testCase.userInfo } - ctx := admission.NewContextWithRequest(context.Background(), req) + ctx := admission.NewContextWithRequest(t.Context(), req) _, err := testCase.webhook.ValidateCreate( ctx, @@ -1030,7 +1030,7 @@ func Tes_webhook_tValidateUpdate(t *testing.T) { authorizeFn: testCase.authorizeFn, } oldPromo, newPromo := testCase.setup() - _, err := w.ValidateUpdate(context.Background(), oldPromo, newPromo) + _, err := w.ValidateUpdate(t.Context(), oldPromo, newPromo) testCase.assertions(t, err) }) } @@ -1068,7 +1068,7 @@ func Test_webhook_ValidateDelete(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { _, err := testCase.webhook.ValidateDelete( - context.Background(), + t.Context(), &kargoapi.Promotion{}, ) testCase.assertions(t, err) @@ -1168,7 +1168,7 @@ func Test_webhook_Authorize(t *testing.T) { testCase.assertions( t, w.authorize( - context.Background(), + t.Context(), &kargoapi.Promotion{ ObjectMeta: metav1.ObjectMeta{ Name: "fake-promotion", diff --git a/pkg/webhook/kubernetes/promotiontask/webhook_test.go b/pkg/webhook/kubernetes/promotiontask/webhook_test.go index e92dc30e52..39b1f892cf 100644 --- a/pkg/webhook/kubernetes/promotiontask/webhook_test.go +++ b/pkg/webhook/kubernetes/promotiontask/webhook_test.go @@ -1,7 +1,6 @@ package promotiontask import ( - "context" "testing" "github.com/stretchr/testify/assert" @@ -88,7 +87,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { client: c, } - got, err := w.ValidateCreate(context.Background(), tt.task) + got, err := w.ValidateCreate(t.Context(), tt.task) tt.assertions(t, got, err) }) } diff --git a/pkg/webhook/kubernetes/replicatedresource/webhook.go b/pkg/webhook/kubernetes/replicatedresource/webhook.go new file mode 100644 index 0000000000..41cd13c43f --- /dev/null +++ b/pkg/webhook/kubernetes/replicatedresource/webhook.go @@ -0,0 +1,45 @@ +package replicatedresource + +import ( + "context" + + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + libWebhook "github.com/akuity/kargo/pkg/webhook/kubernetes" +) + +type webhook struct { + cfg libWebhook.Config +} + +// SetupWebhookWithManager registers the replicated resource validating +// webhook with the given manager. +func SetupWebhookWithManager( + cfg libWebhook.Config, + mgr ctrl.Manager, +) error { + w := newWebhook(cfg) + mgr.GetWebhookServer().Register( + "/validate-v1-replicated-resource", + &admission.Webhook{Handler: w}, + ) + return nil +} + +func newWebhook(cfg libWebhook.Config) *webhook { + return &webhook{cfg: cfg} +} + +func (w *webhook) Handle( + _ context.Context, + req admission.Request, +) admission.Response { + if req.UserInfo.Username == w.cfg.ManagementControllerUsername { + return admission.Allowed("request from Kargo management controller") + } + return admission.Denied( + "replicated resources are managed by Kargo" + + " and cannot be created, modified, or deleted by end users", + ) +} diff --git a/pkg/webhook/kubernetes/replicatedresource/webhook_test.go b/pkg/webhook/kubernetes/replicatedresource/webhook_test.go new file mode 100644 index 0000000000..db2d05acfe --- /dev/null +++ b/pkg/webhook/kubernetes/replicatedresource/webhook_test.go @@ -0,0 +1,143 @@ +package replicatedresource + +import ( + "testing" + + "github.com/stretchr/testify/require" + admissionv1 "k8s.io/api/admission/v1" + authnv1 "k8s.io/api/authentication/v1" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" + + libWebhook "github.com/akuity/kargo/pkg/webhook/kubernetes" +) + +const testManagementControllerUsername = "system:serviceaccount:kargo:kargo-management-controller" + +func TestNewWebhook(t *testing.T) { + w := newWebhook(libWebhook.Config{ + ManagementControllerUsername: testManagementControllerUsername, + }) + require.Equal( + t, + testManagementControllerUsername, + w.cfg.ManagementControllerUsername, + ) +} + +func TestHandle(t *testing.T) { + cfg := libWebhook.Config{ + ManagementControllerUsername: testManagementControllerUsername, + } + testCases := []struct { + name string + req admission.Request + assert func(*testing.T, admission.Response) + }{ + { + name: "management controller CREATE is allowed", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Create, + UserInfo: authnv1.UserInfo{ + Username: testManagementControllerUsername, + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.True(t, resp.Allowed) + }, + }, + { + name: "management controller UPDATE is allowed", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Update, + UserInfo: authnv1.UserInfo{ + Username: testManagementControllerUsername, + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.True(t, resp.Allowed) + }, + }, + { + name: "management controller DELETE is allowed", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Delete, + UserInfo: authnv1.UserInfo{ + Username: testManagementControllerUsername, + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.True(t, resp.Allowed) + }, + }, + { + name: "other controlplane component is denied", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Update, + UserInfo: authnv1.UserInfo{ + Username: "system:serviceaccount:kargo:kargo-api", + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.False(t, resp.Allowed) + }, + }, + { + name: "non-controlplane user CREATE is denied", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Create, + UserInfo: authnv1.UserInfo{ + Username: "some-user", + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.False(t, resp.Allowed) + }, + }, + { + name: "non-controlplane user UPDATE is denied", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Update, + UserInfo: authnv1.UserInfo{ + Username: "some-user", + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.False(t, resp.Allowed) + }, + }, + { + name: "non-controlplane user DELETE is denied", + req: admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Operation: admissionv1.Delete, + UserInfo: authnv1.UserInfo{ + Username: "some-user", + }, + }, + }, + assert: func(t *testing.T, resp admission.Response) { + require.False(t, resp.Allowed) + }, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + w := newWebhook(cfg) + resp := w.Handle(t.Context(), testCase.req) + testCase.assert(t, resp) + }) + } +} diff --git a/pkg/webhook/kubernetes/stage/webhook_test.go b/pkg/webhook/kubernetes/stage/webhook_test.go index 4ab8093d5f..603d43ba95 100644 --- a/pkg/webhook/kubernetes/stage/webhook_test.go +++ b/pkg/webhook/kubernetes/stage/webhook_test.go @@ -822,7 +822,7 @@ func Test_webhook_Default(t *testing.T) { } ctx := admission.NewContextWithRequest( - context.Background(), + t.Context(), tc.req, ) tc.assertions( @@ -909,7 +909,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { _, err := testCase.webhook.ValidateCreate( - context.Background(), + t.Context(), &kargoapi.Stage{}, ) testCase.assertions(t, err) @@ -955,7 +955,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { _, err := testCase.webhook.ValidateUpdate( - context.Background(), + t.Context(), nil, &kargoapi.Stage{}, ) @@ -966,7 +966,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { func Test_webhook_ValidateDelete(t *testing.T) { w := &webhook{} - _, err := w.ValidateDelete(context.Background(), nil) + _, err := w.ValidateDelete(t.Context(), nil) require.NoError(t, err) } diff --git a/pkg/webhook/kubernetes/warehouse/webhook_test.go b/pkg/webhook/kubernetes/warehouse/webhook_test.go index c60e7d7b6a..ca0030a656 100644 --- a/pkg/webhook/kubernetes/warehouse/webhook_test.go +++ b/pkg/webhook/kubernetes/warehouse/webhook_test.go @@ -87,7 +87,7 @@ func Test_webhook_Default(t *testing.T) { t.Run("shard stays default when not specified at all", func(t *testing.T) { warehouse := &kargoapi.Warehouse{} - err := w.Default(context.Background(), warehouse) + err := w.Default(t.Context(), warehouse) require.NoError(t, err) require.Empty(t, warehouse.Labels) require.Empty(t, warehouse.Spec.Shard) @@ -99,7 +99,7 @@ func Test_webhook_Default(t *testing.T) { Shard: testShardName, }, } - err := w.Default(context.Background(), warehouse) + err := w.Default(t.Context(), warehouse) require.NoError(t, err) require.Equal(t, testShardName, warehouse.Spec.Shard) require.Equal(t, testShardName, warehouse.Labels[kargoapi.LabelKeyShard]) @@ -113,7 +113,7 @@ func Test_webhook_Default(t *testing.T) { }, }, } - err := w.Default(context.Background(), warehouse) + err := w.Default(t.Context(), warehouse) require.NoError(t, err) require.Empty(t, warehouse.Spec.Shard) _, ok := warehouse.Labels[kargoapi.LabelKeyShard] @@ -133,7 +133,7 @@ func Test_webhook_Default(t *testing.T) { }, }, } - err := w.Default(context.Background(), warehouse) + err := w.Default(t.Context(), warehouse) require.NoError(t, err) const testDiscoveryLimit int64 = 42 require.Equal(t, testDiscoveryLimit, warehouse.Spec.InternalSubscriptions[0].Git.DiscoveryLimit) @@ -150,7 +150,7 @@ func Test_webhook_Default(t *testing.T) { }, }, } - err := w.Default(context.Background(), warehouse) + err := w.Default(t.Context(), warehouse) require.NoError(t, err) require.Equal( t, @@ -251,7 +251,7 @@ func Test_webhook_ValidateCreate(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { testCase.webhook.subscriberRegistry = subscription.DefaultSubscriberRegistry _, err := testCase.webhook.ValidateCreate( - context.Background(), + t.Context(), testCase.warehouse, ) testCase.assertions(t, err) @@ -333,7 +333,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { t.Run(testCase.name, func(t *testing.T) { testCase.webhook.subscriberRegistry = subscription.DefaultSubscriberRegistry _, err := testCase.webhook.ValidateUpdate( - context.Background(), + t.Context(), nil, testCase.warehouse, ) @@ -344,7 +344,7 @@ func Test_webhook_ValidateUpdate(t *testing.T) { func Test_webhook_ValidateDelete(t *testing.T) { w := &webhook{} - _, err := w.ValidateDelete(context.Background(), nil) + _, err := w.ValidateDelete(t.Context(), nil) require.NoError(t, err, nil) } diff --git a/pkg/x/promotion/runner/builtin/zz_config_types.go b/pkg/x/promotion/runner/builtin/zz_config_types.go index 3e4b86fe8e..b8edcc7672 100644 --- a/pkg/x/promotion/runner/builtin/zz_config_types.go +++ b/pkg/x/promotion/runner/builtin/zz_config_types.go @@ -2,6 +2,8 @@ package builtin +type ArgoCDCommonDefs interface{} + type CommonDefs interface{} type ComposeOutput map[string]interface{} @@ -27,6 +29,9 @@ type ArgoCDAppUpdate struct { // Specifies a label selector to match Argo CD Application resources to be updated. Mutually // exclusive with 'name'. // +// Specifies a label selector to match Argo CD Application resources to wait for. Mutually +// exclusive with 'name'. +// // Selector to match Argo CD Application resources by labels. Must contain at least one // selection criterion. type ArgoCDAppSelector struct { @@ -111,6 +116,27 @@ type ArgoCDKustomizeImageUpdate struct { Tag string `json:"tag,omitempty"` } +type ArgoCDWaitConfig struct { + Apps []ArgoCDAppWait `json:"apps"` +} + +type ArgoCDAppWait struct { + // Specifies the exact name of an Argo CD Application resource to wait for. Mutually + // exclusive with 'selector'. + Name string `json:"name,omitempty"` + // Specifies the namespace of the Argo CD Application. If left unspecified, the namespace + // will be the controller's configured default. + Namespace string `json:"namespace,omitempty"` + // Specifies a label selector to match Argo CD Application resources to wait for. Mutually + // exclusive with 'name'. + Selector *ArgoCDAppSelector `json:"selector,omitempty"` + // Specifies the conditions to wait for. Valid values are 'health', 'sync', 'operation', + // 'suspended', and 'degraded'. Health-related conditions (health, suspended, degraded) are + // OR'd. All other conditions are AND'd. Defaults to ['health', 'sync', 'operation'] when + // omitted. + WaitFor []WaitFor `json:"waitFor,omitempty"` +} + type CopyConfig struct { // Ignore is a (multiline) string of glob patterns to ignore when copying files. It accepts // the same syntax as .gitignore files. @@ -152,7 +178,9 @@ type GitCloneConfig struct { // Indicates whether to recursively clone submodules. Default is false. Note that any // provided credentials must also be valid for the submodules. RecurseSubmodules bool `json:"recurseSubmodules,omitempty"` - // The URL of a remote Git repository to clone. Required. + // The URL of a remote Git repository to clone. Required. Deprecated: Support for SSH URLs + // (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in + // v1.13.0. Use HTTPS URLs instead. RepoURL string `json:"repoURL"` } @@ -219,13 +247,17 @@ type GitCommitConfigAuthor struct { type GitMergePRConfig struct { // Skip TLS verification when interacting with the Git provider. Default is false. InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty"` + // The merge method to use when merging the pull request. Options are provider-specific. + MergeMethod string `json:"mergeMethod,omitempty"` // The number of the pull request to merge. PRNumber int64 `json:"prNumber"` // The name of the Git provider to use. Currently 'azure', 'bitbucket', 'gitea', 'github', // and 'gitlab' are supported. Kargo will try to infer the provider if it is not explicitly // specified. Provider *Provider `json:"provider,omitempty"` - // The URL of the remote Git repository containing the pull request. + // The URL of the remote Git repository containing the pull request. Deprecated: Support for + // SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be + // removed in v1.13.0. Use HTTPS URLs instead. RepoURL string `json:"repoURL"` // If true, the step will return RUNNING instead of FAILED when the PR is not yet mergeable. // The merge will be retried on the next reconciliation until it succeeds or times out. @@ -247,7 +279,9 @@ type GitOpenPRConfig struct { // and 'gitlab' are supported. Kargo will try to infer the provider if it is not explicitly // specified. Provider *Provider `json:"provider,omitempty"` - // The URL of a remote Git repository to clone. + // The URL of a remote Git repository to clone. Deprecated: Support for SSH URLs (ssh:// and + // SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use + // HTTPS URLs instead. RepoURL string `json:"repoURL"` // The branch containing the changes to be merged. This branch must already exist and be up // to date on the remote. @@ -348,7 +382,9 @@ type GitWaitForPRConfig struct { // and 'gitlab' are supported. Kargo will try to infer the provider if it is not explicitly // specified. Provider *Provider `json:"provider,omitempty"` - // The URL of a remote Git repository to clone. + // The URL of a remote Git repository to clone. Deprecated: Support for SSH URLs (ssh:// and + // SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use + // HTTPS URLs instead. RepoURL string `json:"repoURL"` } @@ -605,6 +641,22 @@ type OCIDownloadConfig struct { OutPath string `json:"outPath"` } +type OCIPushConfig struct { + // Annotations to set on the destination artifact. Keys may be prefixed with 'index:' or + // 'manifest:' to scope them to the index or image manifest respectively. Unprefixed keys + // default to the image manifest. For single images, 'index:'-prefixed keys are ignored. + Annotations map[string]string `json:"annotations,omitempty"` + // DestRef is the destination reference including tag (e.g. 'registry/repo:tag' or + // 'oci://registry/repo:tag'). For retag-in-place, use the same repo as srcRef with the new + // tag. + DestRef string `json:"destRef"` + // Whether to skip TLS verification when communicating with registries. Defaults to false. + InsecureSkipTLSVerify bool `json:"insecureSkipTLSVerify,omitempty"` + // SrcRef is the source OCI artifact reference with tag or digest (e.g. 'registry/repo:tag' + // or 'registry/repo@sha256:...'). Use 'oci://' prefix for Helm charts. + SrcRef string `json:"srcRef"` +} + type SetFreightAliasConfig struct { // The new alias to assign to the Freight. Aliases must be unique within the project. Alias string `json:"alias"` @@ -626,6 +678,34 @@ type Update struct { Values map[string]interface{} `json:"values"` } +type TOMLParseConfig struct { + // An array of outputs to extract from the TOML file. + Outputs []TomlParse `json:"outputs"` + // The path to the TOML file to be parsed. + Path string `json:"path"` +} + +type TomlParse struct { + // The expression used to extract data from the TOML file. + FromExpression string `json:"fromExpression"` + // The name of the output variable to store the result. + Name string `json:"name"` +} + +type TOMLUpdateConfig struct { + // The path to a TOML file. + Path string `json:"path"` + // A list of updates to apply to the TOML file. + Updates []TomlUpdate `json:"updates"` +} + +type TomlUpdate struct { + // The key whose value needs to be updated. For nested values, use a TOML dot notation path. + Key string `json:"key"` + // The new value for the specified key. + Value interface{} `json:"value"` +} + type UntarConfig struct { // Ignore is a (multiline) string of glob patterns to ignore when extracting files. It // accepts the same syntax as .gitignore files. @@ -688,6 +768,16 @@ const ( NotIn Operator = "NotIn" ) +type WaitFor string + +const ( + Degraded WaitFor = "degraded" + Health WaitFor = "health" + Operation WaitFor = "operation" + Suspended WaitFor = "suspended" + Sync WaitFor = "sync" +) + // The name of the Git provider to use. Currently 'azure', 'bitbucket', 'gitea', 'github', // and 'gitlab' are supported. Kargo will try to infer the provider if it is not explicitly // specified. diff --git a/pkg/yaml/decode.go b/pkg/yaml/decode.go index c0945b6a7d..9669a36a8a 100644 --- a/pkg/yaml/decode.go +++ b/pkg/yaml/decode.go @@ -4,6 +4,8 @@ import ( "fmt" "go.yaml.in/yaml/v3" + + "github.com/akuity/kargo/pkg/sjson" ) // FieldNotFoundErr is an error type that is returned when a field is not found @@ -21,7 +23,7 @@ func (e FieldNotFoundErr) Error() string { // and decodes it into the provided value. The path is specified using a // dot-separated string, similar to the UpdateField function. func DecodeField(node *yaml.Node, path string, out any) error { - parts, err := splitKey(path) + parts, err := sjson.SplitKey(path) if err != nil { return err } diff --git a/pkg/yaml/update.go b/pkg/yaml/update.go index 5834fc09c8..34a90ebe44 100644 --- a/pkg/yaml/update.go +++ b/pkg/yaml/update.go @@ -3,9 +3,10 @@ package yaml import ( "fmt" "strconv" - "strings" "go.yaml.in/yaml/v3" + + "github.com/akuity/kargo/pkg/sjson" ) // UpdateField updates the value of a field in a YAML document. The field is @@ -16,7 +17,7 @@ import ( // the yaml package. This includes basic types (string, int, bool, etc.), maps, // slices, and structs. func UpdateField(node *yaml.Node, key string, value any) error { - parts, err := splitKey(key) + parts, err := sjson.SplitKey(key) if err != nil { return err } @@ -159,67 +160,6 @@ func preserveComments(oldNode, newNode *yaml.Node) { } } -// splitKey splits a key string into parts separated by dots. It observes the -// same basic syntax rules as tidwall/sjson. Dots are separators unless escaped. -// Colons, unless escaped, are hints that a numeric-looking key part should be -// treated as a key in an object, rather than an index in a sequence. -func splitKey(key string) ([]string, error) { - key = strings.TrimSpace(key) - if key == "" { - return nil, fmt.Errorf("empty key") - } - parts := make([]string, 0, strings.Count(key, ".")+1) - currentPart := strings.Builder{} - escaped := false - for i := 0; i < len(key); i++ { - char := key[i] - if !escaped { - switch char { - case '\\': - escaped = true // Enter escape mode. - case '.': - // We've reached the end of the current part. - if currentPart.Len() == 0 { - return nil, fmt.Errorf("empty key part in key %q", key) - } - parts = append(parts, currentPart.String()) - currentPart.Reset() - case ':': - if currentPart.Len() > 0 { - // An unescaped colon is only valid as the first character of a key - // part. - return nil, fmt.Errorf("unexpected colon in key %q", key) - } - // We don't actually need to KEEP the colon, since the code that uses - // the key parts returned from this function requires no hint that a - // numeric-looking key part should be treated as a key in an object, - // rather than an index in a sequence. - default: - // Any other character is added to the current part as is. - if err := currentPart.WriteByte(char); err != nil { - return nil, err - } - } - continue - } - // If we get to here, we're currently in escape mode. - switch char { - case '.', ':': - if err := currentPart.WriteByte(char); err != nil { - return nil, err - } - escaped = false // Exit escape mode. - default: - return nil, fmt.Errorf("invalid escape sequence in key %q", key) - } - } - // Don't forget about whatever is left over in currentPart. - if currentPart.Len() == 0 { - return nil, fmt.Errorf("empty key part in key %q", key) - } - return append(parts, currentPart.String()), nil -} - // parseIndex attempts to parse the provided string as an int. If it is unable // to do so, it falls back on parsing according to legacy syntax rules, i.e. // extracting n from a string in the format "[n]". diff --git a/pkg/yaml/update_test.go b/pkg/yaml/update_test.go index f152290ed1..efce4a3f86 100644 --- a/pkg/yaml/update_test.go +++ b/pkg/yaml/update_test.go @@ -527,73 +527,3 @@ root: }) } } - -func TestSplitKey(t *testing.T) { - testCases := []struct { - name string - key string - expected []string - errContains string - }{ - { - name: "empty key", - errContains: "empty key", - }, - { - name: "starts with dot", - key: ".foo", - errContains: "empty key part in key", - }, - { - name: "ends with dot", - key: "foo.", - errContains: "empty key part in key", - }, - { - name: "double dots", - key: "foo..bar", - errContains: "empty key part in key", - }, - { - name: "invalid escape sequence", - key: `foo\nbar`, - errContains: "invalid escape sequence", - }, - { - name: "invalid use of colon", - key: `foo:bar`, - errContains: "unexpected colon in key", - }, - { - name: "basic split", - key: "foo.bar.bat.baz", - expected: []string{"foo", "bar", "bat", "baz"}, - }, - { - name: "split key with escaped dots", - key: `foo\.bar.bat\.baz`, - expected: []string{"foo.bar", "bat.baz"}, - }, - { - name: "split key with escaped colon", - key: `foo.bar\:bat.baz`, - expected: []string{"foo", "bar:bat", "baz"}, - }, - { - name: "split key with unescaped colon", - key: `foo.bar.:2.baz`, - expected: []string{"foo", "bar", "2", "baz"}, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - parts, err := splitKey(testCase.key) - if testCase.errContains != "" { - require.ErrorContains(t, err, testCase.errContains) - } else { - require.NoError(t, err) - assert.Equal(t, testCase.expected, parts) - } - }) - } -} diff --git a/pkg/yaml/yaml.go b/pkg/yaml/yaml.go index bcdfcafecf..d6a643521b 100644 --- a/pkg/yaml/yaml.go +++ b/pkg/yaml/yaml.go @@ -9,6 +9,8 @@ import ( "strings" "go.yaml.in/yaml/v3" + + "github.com/akuity/kargo/pkg/sjson" ) // The maximum size of the input buffer for processing YAML files. Given that the max size of a @@ -79,7 +81,10 @@ func SetValuesInBytes(inBytes []byte, updates []Update) ([]byte, error) { } changesByLine := map[int]change{} for _, update := range updates { - keyPath := splitKeyPath(update.Key) + keyPath, err := sjson.SplitKey(update.Key) + if err != nil { + return nil, fmt.Errorf("error splitting key %s: %w", update.Key, err) + } line, col, err := findScalarNode(doc, keyPath) if err != nil { return nil, fmt.Errorf("error finding key %s: %w", update.Key, err) @@ -162,40 +167,3 @@ func findScalarNode(node *yaml.Node, keyPath []string) (int, int, error) { } return 0, 0, fmt.Errorf("key path not found") } - -// splitKeyPath splits a key string into path elements for traversal. -// -// Escape sequences: -// - \. → literal dot (not a separator) -// - \\ → literal backslash -// - \x → x (any other escaped char becomes itself) -// -// Examples: -// - `image.tag` → [`image`, `tag`] -// - `example\.com/version` → [`example.com/version`] -// - `path\\to.file` → [`path\to", `file`] -func splitKeyPath(key string) []string { - var parts []string - var current strings.Builder - escaped := false - for _, r := range key { - switch { - case escaped: - current.WriteRune(r) - escaped = false - case r == '\\': - escaped = true - case r == '.': - parts = append(parts, current.String()) - current.Reset() - default: - current.WriteRune(r) - } - } - // Trailing backslash is preserved literally - if escaped { - current.WriteRune('\\') - } - parts = append(parts, current.String()) - return parts -} diff --git a/pkg/yaml/yaml_test.go b/pkg/yaml/yaml_test.go index 458d86337e..d39d66a4e3 100644 --- a/pkg/yaml/yaml_test.go +++ b/pkg/yaml/yaml_test.go @@ -106,50 +106,6 @@ characters: ) }, }, - { - name: "escaped dots in keys", - inBytes: []byte(` -example.com/version: v1.0.0 -image: - tag: v1.0.0 -configs: - example.com/feature: false -containers: - - name: my-app - image: my-app:v1.0 -`), - updates: []Update{ - { - Key: `example\.com/version`, - Value: `v2.0.0`, - }, - { - Key: `image.tag`, - Value: `v2.0.0`, - }, - { - Key: `configs.example\.com/feature`, - Value: true, - }, - { - Key: `containers.0.image`, - Value: `my-app:v2.0.0`, - }, - }, - assertions: func(t *testing.T, bytes []byte, err error) { - require.NoError(t, err) - require.Equal(t, []byte(` -example.com/version: v2.0.0 -image: - tag: v2.0.0 -configs: - example.com/feature: true -containers: - - name: my-app - image: my-app:v2.0.0 -`), bytes) - }, - }, { name: "really long lines still work", // nolint:lll @@ -180,50 +136,6 @@ characters: ) }, }, - { - name: "escaped dot in nested key", - inBytes: []byte(` -configs: - example.com/feature: - enabled: false -`), - updates: []Update{ - { - Key: `configs.example\.com/feature.enabled`, - Value: true, - }, - }, - assertions: func(t *testing.T, bytes []byte, err error) { - require.NoError(t, err) - require.Equal(t, []byte(` -configs: - example.com/feature: - enabled: true -`), bytes) - }, - }, - { - name: "escaped dot in key with sequence index", - inBytes: []byte(` -services: - - example.com/label: old-value - name: my-service -`), - updates: []Update{ - { - Key: `services.0.example\.com/label`, - Value: "new-value", - }, - }, - assertions: func(t *testing.T, bytes []byte, err error) { - require.NoError(t, err) - require.Equal(t, []byte(` -services: - - example.com/label: new-value - name: my-service -`), bytes) - }, - }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { @@ -287,49 +199,3 @@ characters: }) } } - -func TestSplitKeyPath(t *testing.T) { - testCases := []struct { - input string - expected []string - }{ - { - input: `image.tag`, - expected: []string{`image`, `tag`}, - }, - { - input: `example\.com/version`, - expected: []string{`example.com/version`}, - }, - { - input: `configs.example\.com/feature`, - expected: []string{`configs`, `example.com/feature`}, - }, - { - input: `containers.0.image`, - expected: []string{`containers`, `0`, `image`}, - }, - { - input: `foo\\bar`, - expected: []string{`foo\bar`}, - }, - { - input: `foo\\.bar`, - expected: []string{`foo\`, `bar`}, - }, - { - input: `foo\`, - expected: []string{`foo\`}, - }, - { - input: `foo\.\.bar`, - expected: []string{`foo..bar`}, - }, - } - for _, tc := range testCases { - t.Run(tc.input, func(t *testing.T) { - got := splitKeyPath(tc.input) - require.Equal(t, tc.expected, got) - }) - } -} diff --git a/swagger.json b/swagger.json index e2b5566ffd..4c7cc356b5 100644 --- a/swagger.json +++ b/swagger.json @@ -1,5163 +1,12188 @@ { - "swagger": "2.0", - "info": { - "description": "REST API for Kargo", - "title": "Kargo API", - "contact": {}, - "version": "v1alpha1" - }, - "basePath": "/", - "paths": { - "/v1beta1/login": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Authenticate as the admin user if enabled.", - "produces": [ - "application/json" - ], - "tags": [ - "System" - ], - "summary": "Admin login", - "operationId": "AdminLogin", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/AdminLoginResponse" - } - } - } - } - }, - "/v1beta1/projects": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List all Projects resources. Returns a ProjectList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Cluster-Scoped Resource" - ], - "summary": "List projects", - "operationId": "ListProjects", - "responses": { - "200": { - "description": "ProjectList custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a Project resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Cluster-Scoped Resource" - ], - "summary": "Retrieve a Project resource", - "operationId": "GetProject", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Project custom resource (github.com/akuity/kargo/api/v1alpha1.Project)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a Project resource and its associated namespace.", - "tags": [ - "Core", - "Cluster-Scoped Resource" - ], - "summary": "Delete a Project", - "operationId": "DeleteProject", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/analysis-runs/{analysis-run}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve an AnalysisRun resource from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "Retrieve an AnalysisRun", - "operationId": "GetAnalysisRun", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "AnalysisRun name", - "name": "analysis-run", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "AnalysisRun custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/analysis-runs/{analysis-run}/logs": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Stream logs from an AnalysisRun job as Server-Sent Events (SSE).", - "produces": [ - "text/event-stream" - ], - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "Stream AnalysisRun logs", - "operationId": "GetAnalysisRunLogs", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "AnalysisRun name", - "name": "analysis-run", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Metric name", - "name": "metricName", - "in": "query" - }, - { - "type": "string", - "description": "Container name", - "name": "containerName", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Log stream (SSE)", - "schema": { - "type": "string" - } - } - } - } - }, - "/v1beta1/projects/{project}/analysis-templates": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List AnalysisTemplate resources from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "List AnalysisTemplates", - "operationId": "ListAnalysisTemplates", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "AnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/analysis-templates/{analysis-template}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve an AnalysisTemplate resource from a project's\nnamespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "Retrieve an AnalysisTemplate", - "operationId": "GetAnalysisTemplate", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "AnalysisTemplate name", - "name": "analysis-template", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "AnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplate)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete an AnalysisTemplate resource from a project's namespace.", - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "Delete an AnalysisTemplate", - "operationId": "DeleteAnalysisTemplate", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "AnalysisTemplate name", - "name": "analysis-template", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/api-tokens": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List project-level API tokens. Returns a Kubernetes SecretList\nresource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Credentials", - "Project-Level" - ], - "summary": "List project-level API tokens", - "operationId": "ListProjectAPITokens", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Role name filter", - "name": "role", - "in": "query" - } - ], - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/api-tokens/{apitoken}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a project-level API token by name. Returns a heavily\nredacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Credentials", - "Project-Level" - ], - "summary": "Retrieve a project-level API token", - "operationId": "GetProjectAPIToken", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "API token name", - "name": "apitoken", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a project-level API token from a project's namespace.", - "tags": [ - "Rbac", - "Credentials", - "Project-Level" - ], - "summary": "Delete a project-level API token", - "operationId": "DeleteProjectAPIToken", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "API token name", - "name": "apitoken", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/config": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve the single ProjectConfig resource from a project's\nnamespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level", - "Config", - "Singleton" - ], - "summary": "Retrieve ProjectConfig", - "operationId": "GetProjectConfig", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ProjectConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectConfig)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete the single ProjectConfig resource from a project's\nnamespace.", - "tags": [ - "Core", - "Project-Level", - "Config", - "Singleton" - ], - "summary": "Delete a ProjectConfig resource", - "operationId": "DeleteProjectConfig", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/config/refresh": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Refresh the single ProjectConfig resource in a project's\nnamespace. Refreshing enqueues the resource for reconciliation\nby its corresponding controller.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Config", - "Project-Level", - "Singleton" - ], - "summary": "Refresh ProjectConfig", - "operationId": "RefreshProjectConfig", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/configmaps": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List ConfigMap resources from a project's namespace. Returns a\nKubernetes ConfigMapList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Project-Level" - ], - "summary": "List project-level ConfigMaps", - "operationId": "ListProjectConfigMaps", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a ConfigMap in a project's namespace. Returns the created\nKubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Project-Level" - ], - "summary": "Create a project-level ConfigMap", - "operationId": "CreateProjectConfigMap", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "description": "ConfigMap", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateConfigMapRequest" - } - } - ], - "responses": { - "201": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/configmaps/{configmap}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a ConfigMap by name from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Project-Level" - ], - "summary": "Retrieve a project-level ConfigMap", - "operationId": "GetProjectConfigMap", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace a ConfigMap in a project's namespace. All existing data\nis replaced. Returns the updated Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Project-Level" - ], - "summary": "Replace a project-level ConfigMap", - "operationId": "UpdateProjectConfigMap", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - }, - { - "description": "ConfigMap", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateConfigMapRequest" - } - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a ConfigMap from a project's namespace.", - "tags": [ - "Core", - "Generic Config", - "Project-Level" - ], - "summary": "Delete a project-level ConfigMap", - "operationId": "DeleteProjectConfigMap", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch a ConfigMap in a project's namespace. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns the updated Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Project-Level" - ], - "summary": "Patch a project-level ConfigMap", - "operationId": "PatchProjectConfigMap", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - }, - { - "description": "ConfigMap patch", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchConfigMapRequest" - } - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/events": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List Kubernetes Events from a project's namespace. Returns a\nKubernetes EventList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Events", - "Project-Level" - ], - "summary": "List project-level Kubernetes Events", - "operationId": "ListProjectEvents", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "EventList resource (k8s.io/api/core/v1.EventList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/freight": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Query and filter Freight resources from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Query Freight", - "operationId": "QueryFreightsRest", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name to get available freight for", - "name": "stage", - "in": "query" - }, - { - "type": "array", - "items": { - "type": "string" - }, - "collectionFormat": "csv", - "description": "Warehouse names to get freight from", - "name": "origins", - "in": "query" - }, - { - "type": "string", - "description": "Group filter", - "name": "group", - "in": "query" - }, - { - "type": "string", - "description": "Group by (image_repo, git_repo, chart_repo)", - "name": "groupBy", - "in": "query" - }, - { - "type": "string", - "description": "Order by (first_seen, tag)", - "name": "orderBy", - "in": "query" - }, - { - "type": "boolean", - "description": "Reverse order", - "name": "reverse", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Map of freight groups", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/freight/{freight-name-or-alias}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a Freight resource from a project's namespace by name\nor alias.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Retrieve a Freight resource", - "operationId": "GetFreight", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Freight name or alias", - "name": "freight-name-or-alias", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Freight custom resource (github.com/akuity/kargo/api/v1alpha1.Freight)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a Freight resource from a project's namespace by name or\nalias.", - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Delete a Freight resource", - "operationId": "DeleteFreight", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Freight name or alias", - "name": "freight-name-or-alias", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/freight/{freight-name-or-alias}/alias": { - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch a Freight resource's human-friendly alias.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Patch a Freight resource's alias", - "operationId": "PatchFreightAlias", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Freight name or alias", - "name": "freight-name-or-alias", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "New alias", - "name": "newAlias", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/freight/{freight-name-or-alias}/approve": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Approve Freight for promotion to a Stage.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Approve Freight for promotion to a Stage", - "operationId": "ApproveFreight", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Freight name or alias", - "name": "freight-name-or-alias", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/generic-credentials": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List project-level generic credentials. Returns a Kubernetes\nSecretList resource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Project-Level" - ], - "summary": "List project-level generic credentials", - "operationId": "ListProjectGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create project-level generic credentials. Returns a heavily\nredacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Project-Level" - ], - "summary": "Create project-level generic credentials", - "operationId": "CreateProjectGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "description": "Generic credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateGenericCredentialsRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/generic-credentials/{generic-credentials}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve project-level generic credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Project-Level" - ], - "summary": "Retrieve project-level generic credentials", - "operationId": "GetProjectGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace project-level generic credentials. All existing data is\nreplaced. Returns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Project-Level" - ], - "summary": "Replace project-level generic credentials", - "operationId": "UpdateProjectGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - }, - { - "description": "GenericCredentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateGenericCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete generic credentials from a project's namespace.", - "tags": [ - "Credentials", - "Generic Credentials", - "Project-Level" - ], - "summary": "Delete project-level generic credentials", - "operationId": "DeleteProjectGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch project-level generic credentials. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Project-Level" - ], - "summary": "Patch project-level generic credentials", - "operationId": "PatchProjectGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - }, - { - "description": "GenericCredentials patch", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchGenericCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/images": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List container images referenced by Freight resources in a\nproject's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "List container images", - "operationId": "ListImages", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/TagMap" - } - } - } - } - } - }, - "/v1beta1/projects/{project}/promotion-tasks": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List PromotionTask resources from a project's namespace. Returns\na PromotionTaskList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "List PromotionTasks", - "operationId": "ListPromotionTasks", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "PromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTaskList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/promotion-tasks/{promotion-task}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a PromotionTask resource from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Retrieve a PromotionTask", - "operationId": "GetPromotionTask", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "PromotionTask name", - "name": "promotion-task", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "PromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTask)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/promotions": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List Promotion resources from a project's namespace. Returns a\nPromotionList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "List Promotions", - "operationId": "ListPromotions", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage filter", - "name": "stage", - "in": "query" - } - ], - "responses": { - "200": { - "description": "PromotionList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/promotions/{promotion}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a Promotion resource from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Retrieve a Promotion", - "operationId": "GetPromotion", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Promotion name", - "name": "promotion", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Promotion custom resource (github.com/akuity/kargo/api/v1alpha1.Promotion)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/promotions/{promotion}/abort": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Abort a running Promotion.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Abort a Promotion", - "operationId": "AbortPromotion", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Promotion name", - "name": "promotion", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/promotions/{promotion}/refresh": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Refresh a Promotion resource in a project's namespace.\nRefreshing enqueues the resource for reconciliation by its\ncorresponding controller.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Refresh a Promotion", - "operationId": "RefreshPromotion", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Promotion name", - "name": "promotion", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/repo-credentials": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List project-level repository credentials. Returns a SecretList\nresource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Project-Level" - ], - "summary": "List project-level repository credentials", - "operationId": "ListProjectRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create project-level repository credentials. Returns a heavily\nredacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Project-Level" - ], - "summary": "Create project-level repository credentials", - "operationId": "CreateProjectRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "description": "Credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateRepoCredentialsRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/repo-credentials/{repo-credentials}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve project-level repository credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Project-Level" - ], - "summary": "Retrieve project-level repository credentials", - "operationId": "GetProjectRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace project-level repository credentials. All fields are replaced.\nReturns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Project-Level" - ], - "summary": "Replace project-level repository credentials", - "operationId": "UpdateProjectRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Repo credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - }, - { - "description": "Credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateRepoCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete repository credentials from a project's namespace.", - "tags": [ - "Credentials", - "Repo Credentials", - "Project-Level" - ], - "summary": "Delete project-level repository credentials", - "operationId": "DeleteProjectRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch project-level repository credentials. Only provided fields\nare updated. Returns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Project-Level" - ], - "summary": "Patch project-level repository credentials", - "operationId": "PatchProjectRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Repo credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - }, - { - "description": "Credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchRepoCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/roles": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List project-level Kargo Role virtual resources. Returns a\nRoleList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "List project-level Kargo Role virtual resources", - "operationId": "ListProjectRoles", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a project-level Kargo Role virtual resource by creating\nthe underlying Kubernetes ServiceAccount, Role, and RoleBinding\nresources.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "Create a project-level Kargo Role virtual resource", - "operationId": "CreateProjectRole", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", - "name": "body", - "in": "body", - "required": true, - "schema": { - "type": "object" - } - } - ], - "responses": { - "201": { - "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/roles/grants": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Grant a project-level Kargo Role to users or grant permissions\nto a project-level Kargo Role.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "Grant permissions", - "operationId": "Grant", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "description": "Grant request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/GrantRequest" - } - } - ], - "responses": { - "200": { - "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/roles/revocations": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Revoke a project-level Kargo Role from users or revoke\npermissions from a project-level Kargo Role.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "Revoke permissions", - "operationId": "Revoke", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "description": "Revoke request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/RevokeRequest" - } - } - ], - "responses": { - "200": { - "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/roles/{role}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a project-level Kargo Role virtual resource by name.\nReturns a Kargo Role virtual resource or its underlying\nKubernetes resources.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "Retrieve a project-level Kargo Role virtual resource", - "operationId": "GetProjectRole", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Role resource (k8s.io/api/rbac/v1.Role) or its underlying Kubernetes resources", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Update a project-level Kargo Role virtual resource by updating\nthe underlying Kubernetes ServiceAccount, Role, and RoleBinding\nresources.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "Update a project-level Kargo Role virtual resource", - "operationId": "UpdateRole", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Role name", - "name": "role", - "in": "path", - "required": true - }, - { - "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", - "name": "body", - "in": "body", - "required": true, - "schema": { - "type": "object" - } - } - ], - "responses": { - "200": { - "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a project-level Kargo Role virtual resource by deleting\nthe underlying Kubernetes ServiceAccount, Role, and RoleBinding\nresources from the project's namespace.", - "tags": [ - "Rbac", - "Project-Level" - ], - "summary": "Delete a project-level Kargo Role virtual resource", - "operationId": "DeleteProjectRole", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/roles/{role}/api-tokens": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a project-level API token associated with a Kargo Role\nvirtual resource. Returns a Kubernetes Secret resource\nrepresenting the token. Store it securely. The token is not\nretrievable via the Kargo API after creation except in a\nredacted form.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Credentials", - "Project-Level" - ], - "summary": "Create a project-level API token", - "operationId": "CreateProjectAPIToken", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Role name", - "name": "role", - "in": "path", - "required": true - }, - { - "description": "Token", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateAPITokenRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/stages": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List Stage resources from a project's namespace. Returns a\nStageList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "List Stages", - "operationId": "ListStages", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "StageList custom resource (github.com/akuity/kargo/api/v1alpha1.StageList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/stages/{stage}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a Stage resource from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Retrieve a Stage", - "operationId": "GetStage", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Stage custom resource (github.com/akuity/kargo/api/v1alpha1.Stage)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a Stage resource from a project's namespace.", - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Delete a Stage", - "operationId": "DeleteStage", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/stages/{stage}/promotions": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a Promotion resource to transition a specified Stage into\nthe state represented by the specified Freight.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Promote to Stage", - "operationId": "PromoteToStage", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - }, - { - "description": "Promote request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PromoteToStageRequest" - } - } - ], - "responses": { - "201": { - "description": "Promotion resource (github.com/akuity/kargo/api/v1alpha1.Promotion)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/stages/{stage}/promotions/downstream": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Creates a Promotion resource for each of a Stage's immediately\ndownstream Stages.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Promote downstream", - "operationId": "PromoteDownstream", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - }, - { - "description": "Promote request", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PromoteDownstreamRequest" - } - } - ], - "responses": { - "201": { - "description": "Promotions created", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/stages/{stage}/refresh": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Refresh a Stage resource in a project's namespace. Refreshing\nenqueues the resource for reconciliation by its corresponding\ncontroller.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Refresh a Stage", - "operationId": "RefreshStage", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/stages/{stage}/verification": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Trigger re-verification of the Freight currently in use by a\nStage.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "Reverify Freight", - "operationId": "Reverify", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/stages/{stage}/verification/abort": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Abort a running Verification process.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Project-Level" - ], - "summary": "Abort a running Verification process", - "operationId": "AbortVerification", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Stage name", - "name": "stage", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/projects/{project}/warehouses": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List Warehouse resources from a project's namespace. Returns a\nWarehouseList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "List Warehouses", - "operationId": "ListWarehouses", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "WarehouseList custom resource (github.com/akuity/kargo/api/v1alpha1.WarehouseList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/projects/{project}/warehouses/{warehouse}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a Warehouse resource from a project's namespace.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Retrieve a Warehouse", - "operationId": "GetWarehouse", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Warehouse name", - "name": "warehouse", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Warehouse custom resource (github.com/akuity/kargo/api/v1alpha1.Warehouse)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a Warehouse resource from a project's namespace.", - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Delete a Warehouse", - "operationId": "DeleteWarehouse", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Warehouse name", - "name": "warehouse", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/projects/{project}/warehouses/{warehouse}/refresh": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Refresh a Warehouse resource in a project's namespace.\nRefreshing enqueues the resource for reconciliation by its\ncorresponding controller.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Project-Level" - ], - "summary": "Refresh a Warehouse", - "operationId": "RefreshWarehouse", - "parameters": [ - { - "type": "string", - "description": "Project name", - "name": "project", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Warehouse name", - "name": "warehouse", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/resources": { - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Update (or optionally, upsert) one or more Kargo resources from", - "consumes": [ - "text/plain" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Resources" - ], - "summary": "Update resources", - "operationId": "UpdateResource", - "parameters": [ - { - "type": "boolean", - "description": "If true, create a resource if it does not exist", - "name": "upsert", - "in": "query" - }, - { - "description": "YAML or JSON manifest(s)", - "name": "manifest", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Update results", - "schema": { - "$ref": "#/definitions/CreateOrUpdateResourceResponse" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create one or more Kargo resources from YAML or JSON manifests.", - "consumes": [ - "text/plain" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Resources" - ], - "summary": "Create resources", - "operationId": "CreateResource", - "parameters": [ - { - "description": "YAML or JSON manifest(s)", - "name": "manifest", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Created successfully", - "schema": { - "$ref": "#/definitions/CreateResourceResponse" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete one or more Kargo resources using namespaces and names\nobtained from YAML or JSON manifests.", - "consumes": [ - "text/plain" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Resources" - ], - "summary": "Delete resources", - "operationId": "DeleteResource", - "parameters": [ - { - "description": "YAML or JSON manifest(s)", - "name": "manifest", - "in": "body", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/DeleteResourceResponse" - } - } - } - } - }, - "/v1beta1/shared/cluster-analysis-templates": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List ClusterAnalysisTemplate resources. Returns a\nClusterAnalysisTemplateList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Shared", - "Cluster-Scoped Resource" - ], - "summary": "List ClusterAnalysisTemplates", - "operationId": "ListClusterAnalysisTemplates", - "responses": { - "200": { - "description": "ClusterAnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/cluster-analysis-templates/{cluster-analysis-template}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a ClusterAnalysisTemplate by name.", - "produces": [ - "application/json" - ], - "tags": [ - "Verifications", - "Shared", - "Cluster-Scoped Resource" - ], - "summary": "Retrieve a ClusterAnalysisTemplate", - "operationId": "GetClusterAnalysisTemplate", - "parameters": [ - { - "type": "string", - "description": "ClusterAnalysisTemplate name", - "name": "cluster-analysis-template", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ClusterAnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a ClusterAnalysisTemplate resource.", - "tags": [ - "Verifications", - "Shared", - "Cluster-Scoped Resource" - ], - "summary": "Delete a ClusterAnalysisTemplate", - "operationId": "DeleteClusterAnalysisTemplate", - "parameters": [ - { - "type": "string", - "description": "ClusterAnalysisTemplate name", - "name": "cluster-analysis-template", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/shared/cluster-promotion-tasks": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List ClusterPromotionTask resources. Returns a\nClusterPromotionTaskList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Shared", - "Cluster-Scoped Resource" - ], - "summary": "List ClusterPromotionTasks", - "operationId": "ListClusterPromotionTasks", - "responses": { - "200": { - "description": "ClusterPromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTaskList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/cluster-promotion-tasks/{cluster-promotion-task}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a ClusterPromotionTask by name.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Shared", - "Cluster-Scoped Resource" - ], - "summary": "Retrieve a ClusterPromotionTask", - "operationId": "GetClusterPromotionTask", - "parameters": [ - { - "type": "string", - "description": "ClusterPromotionTask name", - "name": "cluster-promotion-task", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ClusterPromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTask)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/configmaps": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List shared ConfigMap resources referenceable by all projects.\nReturns a Kubernetes ConfigMapList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Shared" - ], - "summary": "List shared ConfigMaps", - "operationId": "ListSharedConfigMaps", - "responses": { - "200": { - "description": "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a shared ConfigMap referenceable by all projects. Returns\nthe created Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Shared" - ], - "summary": "Create a shared ConfigMap", - "operationId": "CreateSharedConfigMap", - "parameters": [ - { - "description": "ConfigMap", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateConfigMapRequest" - } - } - ], - "responses": { - "201": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/configmaps/{configmap}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a shared ConfigMap by name.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Shared" - ], - "summary": "Retrieve a shared ConfigMap", - "operationId": "GetSharedConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace a shared ConfigMap. All existing data is replaced.\nReturns the updated Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Shared" - ], - "summary": "Replace a shared ConfigMap", - "operationId": "UpdateSharedConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - }, - { - "description": "ConfigMap", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateConfigMapRequest" - } - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a shared ConfigMap.", - "tags": [ - "Core", - "Generic Config", - "Shared" - ], - "summary": "Delete a shared ConfigMap", - "operationId": "DeleteSharedConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch a shared ConfigMap. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns the updated Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "Shared" - ], - "summary": "Patch a shared ConfigMap", - "operationId": "PatchSharedConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - }, - { - "description": "ConfigMap patch", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchConfigMapRequest" - } - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/generic-credentials": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List shared generic credentials. Returns a Kubernetes SecretList\nresource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Shared" - ], - "summary": "List shared generic credentials", - "operationId": "ListSharedGenericCredentials", - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create shared generic credentials referenceable by all\nprojects. Returns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Shared" - ], - "summary": "Create shared generic credentials", - "operationId": "CreateSharedGenericCredentials", - "parameters": [ - { - "description": "Generic credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateGenericCredentialsRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/generic-credentials/{generic-credentials}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve shared generic credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Shared" - ], - "summary": "Retrieve shared generic credentials", - "operationId": "GetSharedGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace shared generic credentials. All existing data is replaced.\nReturns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Shared" - ], - "summary": "Replace shared generic credentials", - "operationId": "UpdateSharedGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - }, - { - "description": "GenericCredentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateGenericCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete shared generic credentials.", - "tags": [ - "Credentials", - "Generic Credentials", - "Shared" - ], - "summary": "Delete shared generic credentials", - "operationId": "DeleteSharedGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch shared generic credentials. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "Shared" - ], - "summary": "Patch shared generic credentials", - "operationId": "PatchSharedGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - }, - { - "description": "GenericCredentials patch", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchGenericCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/repo-credentials": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List shared repository credentials. Returns a SecretList\nresource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Shared" - ], - "summary": "List shared repository credentials", - "operationId": "ListSharedRepoCredentials", - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create shared repository credentials. Returns a heavily\nredacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Shared" - ], - "summary": "Create shared repository credentials", - "operationId": "CreateSharedRepoCredentials", - "parameters": [ - { - "description": "Credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateRepoCredentialsRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/shared/repo-credentials/{repo-credentials}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve shared repository credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Shared" - ], - "summary": "Retrieve shared repository credentials", - "operationId": "GetSharedRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace shared repository credentials. All fields are replaced.\nReturns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Shared" - ], - "summary": "Replace shared repository credentials", - "operationId": "UpdateSharedRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Repo credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - }, - { - "description": "Credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateRepoCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete shared repository credentials.", - "tags": [ - "Credentials", - "Repo Credentials", - "Shared" - ], - "summary": "Delete shared repository credentials", - "operationId": "DeleteSharedRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch shared repository credentials. Only provided fields\nare updated. Returns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Repo Credentials", - "Shared" - ], - "summary": "Patch shared repository credentials", - "operationId": "PatchSharedRepoCredentials", - "parameters": [ - { - "type": "string", - "description": "Repo credentials name", - "name": "repo-credentials", - "in": "path", - "required": true - }, - { - "description": "Credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchRepoCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/api-tokens": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List system-level API tokens. Returns a Kubernetes SecretList\nresource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Credentials", - "System-Level" - ], - "summary": "List system-level API tokens", - "operationId": "ListSystemAPITokens", - "parameters": [ - { - "type": "string", - "description": "Role name filter", - "name": "role", - "in": "query" - } - ], - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/api-tokens/{apitoken}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a system-level API token by name. Returns a heavily\nredacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Credentials", - "System-Level" - ], - "summary": "Retrieve a system-level API token", - "operationId": "GetSystemAPIToken", - "parameters": [ - { - "type": "string", - "description": "API token name", - "name": "apitoken", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a system-level API token.", - "tags": [ - "Rbac", - "Credentials", - "System-Level" - ], - "summary": "Delete a system-level API token", - "operationId": "DeleteSystemAPIToken", - "parameters": [ - { - "type": "string", - "description": "API token name", - "name": "apitoken", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/system/cluster-config": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve the single ClusterConfig resource.", - "produces": [ - "application/json" - ], - "tags": [ - "System", - "Config", - "Cluster-Scoped Resource", - "Singleton" - ], - "summary": "Retrieve the ClusterConfig", - "operationId": "GetClusterConfig", - "responses": { - "200": { - "description": "ClusterConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterConfig)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Deletes the single ClusterConfig resource.", - "tags": [ - "System", - "Config", - "Cluster-Scoped Resource", - "Singleton" - ], - "summary": "Delete the ClusterConfig", - "operationId": "DeleteClusterConfig", - "responses": { - "204": { - "description": "Deleted successfully" - } - } - } - }, - "/v1beta1/system/cluster-config/refresh": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Refresh the single ClusterConfig resource. Refreshing enqueues\nthe resource for reconciliation by its corresponding controller.", - "produces": [ - "application/json" - ], - "tags": [ - "System", - "Config", - "Cluster-Scoped Resource", - "Singleton" - ], - "summary": "Refresh the ClusterConfig", - "operationId": "RefreshClusterConfig", - "responses": { - "200": { - "description": "Success" - } - } - } - }, - "/v1beta1/system/configmaps": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List system-level ConfigMap resources. Returns a Kubernetes\nConfigMapList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "System-Level" - ], - "summary": "List system-level ConfigMaps", - "operationId": "ListSystemConfigMaps", - "responses": { - "200": { - "description": "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a system-level ConfigMap. Returns the created Kubernetes\nConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "System-Level" - ], - "summary": "Create a system-level ConfigMap", - "operationId": "CreateSystemConfigMap", - "parameters": [ - { - "description": "ConfigMap", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateConfigMapRequest" - } - } - ], - "responses": { - "201": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/configmaps/{configmap}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a system-level ConfigMap by name.", - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "System-Level" - ], - "summary": "Retrieve a system-level ConfigMap", - "operationId": "GetSystemConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace a system-level ConfigMap. All existing data is replaced.\nReturns the updated Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "System-Level" - ], - "summary": "Replace a system-level ConfigMap", - "operationId": "UpdateSystemConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - }, - { - "description": "ConfigMap", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateConfigMapRequest" - } - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete a system-level ConfigMap.", - "tags": [ - "Core", - "Generic Config", - "System-Level" - ], - "summary": "Delete a system-level ConfigMap", - "operationId": "DeleteSystemConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } - }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch a system-level ConfigMap. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns the updated Kubernetes ConfigMap resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Core", - "Generic Config", - "System-Level" - ], - "summary": "Patch a system-level ConfigMap", - "operationId": "PatchSystemConfigMap", - "parameters": [ - { - "type": "string", - "description": "ConfigMap name", - "name": "configmap", - "in": "path", - "required": true - }, - { - "description": "ConfigMap patch", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchConfigMapRequest" - } - } - ], - "responses": { - "200": { - "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/generic-credentials": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List system-level generic credentials. Returns a Kubernetes\nSecretList resource containing heavily redacted Secrets.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "System-Level" - ], - "summary": "List system-level generic credentials", - "operationId": "ListSystemGenericCredentials", - "responses": { - "200": { - "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", - "schema": { - "type": "object" - } - } - } - }, - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create system-level generic credentials. Returns a heavily\nredacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "System-Level" - ], - "summary": "Create system-level generic credentials", - "operationId": "CreateSystemGenericCredentials", - "parameters": [ - { - "description": "Generic credentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateGenericCredentialsRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/generic-credentials/{generic-credentials}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve system-level generic credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "System-Level" - ], - "summary": "Retrieve system-level generic credentials", - "operationId": "GetSystemGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "put": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Replace system-level generic credentials. All existing data is\nreplaced. Returns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "System-Level" - ], - "summary": "Replace system-level generic credentials", - "operationId": "UpdateSystemGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - }, - { - "description": "GenericCredentials", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/UpdateGenericCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - }, - "delete": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Delete system-level generic credentials.", - "tags": [ - "Credentials", - "Generic Credentials", - "System-Level" - ], - "summary": "Delete system-level generic credentials", - "operationId": "DeleteSystemGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - } - ], - "responses": { - "204": { - "description": "Deleted successfully" - } - } + "swagger": "2.0", + "info": { + "description": "REST API for Kargo", + "title": "Kargo API", + "contact": {}, + "version": "v1alpha1" + }, + "basePath": "/", + "paths": { + "/v1beta1/login": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Authenticate as the admin user if enabled.", + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "Admin login", + "operationId": "AdminLogin", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/AdminLoginResponse" + } + } + } + } + }, + "/v1beta1/projects": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List all Projects resources. Returns a ProjectList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Cluster-Scoped Resource" + ], + "summary": "List projects", + "operationId": "ListProjects", + "responses": { + "200": { + "description": "ProjectList custom resource", + "schema": { + "$ref": "#/definitions/ProjectList" + } + } + } + } + }, + "/v1beta1/projects/{project}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a Project resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Cluster-Scoped Resource" + ], + "summary": "Retrieve a Project resource", + "operationId": "GetProject", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Project custom resource (github.com/akuity/kargo/api/v1alpha1.Project)", + "schema": { + "$ref": "#/definitions/Project" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a Project resource and its associated namespace.", + "tags": [ + "Core", + "Cluster-Scoped Resource" + ], + "summary": "Delete a Project", + "operationId": "DeleteProject", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/analysis-runs/{analysis-run}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve an AnalysisRun resource from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "Retrieve an AnalysisRun", + "operationId": "GetAnalysisRun", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "AnalysisRun name", + "name": "analysis-run", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "AnalysisRun custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun)", + "schema": { + "$ref": "#/definitions/RolloutsAnalysisRun" + } + } + } + } + }, + "/v1beta1/projects/{project}/analysis-runs/{analysis-run}/logs": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Stream logs from an AnalysisRun job as Server-Sent Events (SSE).", + "produces": [ + "text/event-stream" + ], + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "Stream AnalysisRun logs", + "operationId": "GetAnalysisRunLogs", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "AnalysisRun name", + "name": "analysis-run", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Metric name", + "name": "metricName", + "in": "query" + }, + { + "type": "string", + "description": "Container name", + "name": "containerName", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Log stream (SSE)", + "schema": { + "type": "string" + } + } + } + } + }, + "/v1beta1/projects/{project}/analysis-templates": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List AnalysisTemplate resources from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "List AnalysisTemplates", + "operationId": "ListAnalysisTemplates", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "AnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList)", + "schema": { + "$ref": "#/definitions/RolloutsAnalysisTemplateList" + } + } + } + } + }, + "/v1beta1/projects/{project}/analysis-templates/{analysis-template}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve an AnalysisTemplate resource from a project's\nnamespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "Retrieve an AnalysisTemplate", + "operationId": "GetAnalysisTemplate", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "AnalysisTemplate name", + "name": "analysis-template", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "AnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplate)", + "schema": { + "$ref": "#/definitions/RolloutsAnalysisTemplate" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete an AnalysisTemplate resource from a project's namespace.", + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "Delete an AnalysisTemplate", + "operationId": "DeleteAnalysisTemplate", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "AnalysisTemplate name", + "name": "analysis-template", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/api-tokens": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List project-level API tokens. Returns a Kubernetes SecretList\nresource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Credentials", + "Project-Level" + ], + "summary": "List project-level API tokens", + "operationId": "ListProjectAPITokens", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Role name filter", + "name": "role", + "in": "query" + } + ], + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + } + }, + "/v1beta1/projects/{project}/api-tokens/{apitoken}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a project-level API token by name. Returns a heavily\nredacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Credentials", + "Project-Level" + ], + "summary": "Retrieve a project-level API token", + "operationId": "GetProjectAPIToken", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "API token name", + "name": "apitoken", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a project-level API token from a project's namespace.", + "tags": [ + "Rbac", + "Credentials", + "Project-Level" + ], + "summary": "Delete a project-level API token", + "operationId": "DeleteProjectAPIToken", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "API token name", + "name": "apitoken", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/config": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve the single ProjectConfig resource from a project's\nnamespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level", + "Config", + "Singleton" + ], + "summary": "Retrieve ProjectConfig", + "operationId": "GetProjectConfig", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ProjectConfig custom resource", + "schema": { + "$ref": "#/definitions/ProjectConfig" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete the single ProjectConfig resource from a project's\nnamespace.", + "tags": [ + "Core", + "Project-Level", + "Config", + "Singleton" + ], + "summary": "Delete a ProjectConfig resource", + "operationId": "DeleteProjectConfig", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/config/refresh": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Refresh the single ProjectConfig resource in a project's\nnamespace. Refreshing enqueues the resource for reconciliation\nby its corresponding controller.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Config", + "Project-Level", + "Singleton" + ], + "summary": "Refresh ProjectConfig", + "operationId": "RefreshProjectConfig", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/configmaps": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List ConfigMap resources from a project's namespace. Returns a\nKubernetes ConfigMapList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Project-Level" + ], + "summary": "List project-level ConfigMaps", + "operationId": "ListProjectConfigMaps", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)", + "schema": { + "$ref": "#/definitions/V1ConfigMapList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a ConfigMap in a project's namespace. Returns the created\nKubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Project-Level" + ], + "summary": "Create a project-level ConfigMap", + "operationId": "CreateProjectConfigMap", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "description": "ConfigMap", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateConfigMapRequest" + } + } + ], + "responses": { + "201": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + } + }, + "/v1beta1/projects/{project}/configmaps/{configmap}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a ConfigMap by name from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Project-Level" + ], + "summary": "Retrieve a project-level ConfigMap", + "operationId": "GetProjectConfigMap", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace a ConfigMap in a project's namespace. All existing data\nis replaced. Returns the updated Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Project-Level" + ], + "summary": "Replace a project-level ConfigMap", + "operationId": "UpdateProjectConfigMap", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + }, + { + "description": "ConfigMap", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateConfigMapRequest" + } + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a ConfigMap from a project's namespace.", + "tags": [ + "Core", + "Generic Config", + "Project-Level" + ], + "summary": "Delete a project-level ConfigMap", + "operationId": "DeleteProjectConfigMap", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch a ConfigMap in a project's namespace. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns the updated Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Project-Level" + ], + "summary": "Patch a project-level ConfigMap", + "operationId": "PatchProjectConfigMap", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + }, + { + "description": "ConfigMap patch", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchConfigMapRequest" + } + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + } + }, + "/v1beta1/projects/{project}/events": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List Kubernetes Events from a project's namespace. Returns a\nKubernetes EventList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Events", + "Project-Level" + ], + "summary": "List project-level Kubernetes Events", + "operationId": "ListProjectEvents", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "EventList resource (k8s.io/api/core/v1.EventList)", + "schema": { + "$ref": "#/definitions/V1EventList" + } + } + } + } + }, + "/v1beta1/projects/{project}/freight": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Query and filter Freight resources from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Query Freight", + "operationId": "QueryFreightsRest", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name to get available freight for", + "name": "stage", + "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" }, - "patch": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Patch system-level generic credentials. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns a heavily redacted Kubernetes Secret resource.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Credentials", - "Generic Credentials", - "System-Level" - ], - "summary": "Patch system-level generic credentials", - "operationId": "PatchSystemGenericCredentials", - "parameters": [ - { - "type": "string", - "description": "Generic credentials name", - "name": "generic-credentials", - "in": "path", - "required": true - }, - { - "description": "GenericCredentials patch", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/PatchGenericCredentialsRequest" - } - } - ], - "responses": { - "200": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/public-server-config": { - "get": { - "description": "Retrieve information a client may need to know about how the\nKargo API server is configured in order to proceed with\nauthentication.", - "produces": [ - "application/json" - ], - "tags": [ - "System", - "Config" - ], - "summary": "Retrieve public server configuration", - "operationId": "GetPublicConfig", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/PublicConfig" - } - } - } - } - }, - "/v1beta1/system/roles": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "List system-level Kargo Role virtual resources. Returns a\nRoleList resource.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "System-Level" - ], - "summary": "List system-level Kargo Role virtual resources", - "operationId": "ListSystemRoles", - "responses": { - "200": { - "description": "RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/roles/{role}": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve a system-level Kargo Role virtual resource by name.\nReturns a Kargo Role virtual resource or its underlying\nKubernetes resources.", - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "System-Level" - ], - "summary": "Retrieve a system-level Kargo Role virtual resource", - "operationId": "GetSystemRole", - "parameters": [ - { - "type": "string", - "description": "Role name", - "name": "role", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "Role resource (k8s.io/api/rbac/v1.Role) or its underlying Kubernetes resources", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/roles/{role}/api-tokens": { - "post": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Create a system-level API token associated with a system-level\nKargo Role virtual resource. Returns a Kubernetes Secret\nresource representing the token. Store it securely. The token\nis not retrievable via the Kargo API after creation except in\na redacted form.", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Rbac", - "Credentials", - "System-Level" - ], - "summary": "Create a system-level API token", - "operationId": "CreateSystemAPIToken", - "parameters": [ - { - "type": "string", - "description": "Role name", - "name": "role", - "in": "path", - "required": true - }, - { - "description": "Token", - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/CreateAPITokenRequest" - } - } - ], - "responses": { - "201": { - "description": "Secret resource (k8s.io/api/core/v1.Secret)", - "schema": { - "type": "object" - } - } - } - } - }, - "/v1beta1/system/server-config": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve information a client may need to know about how the\nKargo API server is configured.", - "produces": [ - "application/json" - ], - "tags": [ - "System", - "Config" - ], - "summary": "Retrieve server configuration", - "operationId": "GetConfig", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/GetConfigResponse" - } - } - } - } - }, - "/v1beta1/system/server-version": { - "get": { - "security": [ - { - "BearerAuth": [] - } - ], - "description": "Retrieve API Server version information.", - "produces": [ - "application/json" - ], - "tags": [ - "System" - ], - "summary": "Retrieve API Server version information", - "operationId": "GetVersionInfo", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/VersionInfo" - } - } - } - } - } - }, - "definitions": { - "AdminLoginResponse": { - "type": "object", - "properties": { - "idToken": { - "type": "string" - } - } - }, - "ArgoCDShard": { - "type": "object", - "properties": { - "namespace": { - "type": "string" - }, - "url": { - "type": "string" - } - } - }, - "Claim": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateAPITokenRequest": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - }, - "CreateConfigMapRequest": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - } - } - }, - "CreateGenericCredentialsRequest": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "type": "string" - }, - "name": { - "type": "string" - } - } - }, - "CreateOrUpdateResourceResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/CreateOrUpdateResourceResult" - } - } - } - }, - "CreateOrUpdateResourceResult": { - "type": "object", - "properties": { - "createdResourceManifest": { - "type": "object", - "additionalProperties": {} - }, - "error": { - "type": "string" - }, - "updatedResourceManifest": { - "type": "object", - "additionalProperties": {} - } - } - }, - "CreateRepoCredentialsRequest": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "name": { - "type": "string" - }, - "password": { - "description": "#nosec G117 -- Request data is unmarshaled into this struct, but the struct\nis never marshaled and transmitted to anywhere.", - "type": "string" - }, - "repoUrl": { - "type": "string" - }, - "repoUrlIsRegex": { - "type": "boolean" - }, - "type": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "CreateResourceResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/CreateResourceResult" - } - } - } - }, - "CreateResourceResult": { - "type": "object", - "properties": { - "createdResourceManifest": { - "type": "object", - "additionalProperties": {} - }, - "error": { - "type": "string" - } - } - }, - "DeleteResourceResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "$ref": "#/definitions/DeleteResourceResult" - } - } - } - }, - "DeleteResourceResult": { - "type": "object", - "properties": { - "deletedResourceManifest": { - "type": "object", - "additionalProperties": {} - }, - "error": { - "type": "string" - } - } - }, - "GetConfigResponse": { - "type": "object", - "properties": { - "argocdShards": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ArgoCDShard" - } - }, - "hasAnalysisRunLogsUrlTemplate": { - "type": "boolean" - }, - "kargoNamespace": { - "type": "string" - }, - "secretManagementEnabled": { - "type": "boolean" - }, - "sharedResourcesNamespace": { - "type": "string" - }, - "systemResourcesNamespace": { - "type": "string" - } - } - }, - "GrantRequest": { - "type": "object", - "properties": { - "resourceDetails": { - "$ref": "#/definitions/ResourceDetails" - }, - "role": { - "type": "string" - }, - "userClaims": { - "$ref": "#/definitions/UserClaims" - } - } - }, - "ImageStageMap": { - "type": "object", - "properties": { - "stages": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int32" - } - } - } - }, - "OIDCConfig": { - "type": "object", - "properties": { - "cliClientId": { - "type": "string" - }, - "clientId": { - "type": "string" - }, - "issuerUrl": { - "type": "string" - }, - "scopes": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PatchConfigMapRequest": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "type": "string" - }, - "removeKeys": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PatchGenericCredentialsRequest": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "type": "string" - }, - "removeKeys": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PatchRepoCredentialsRequest": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "password": { - "description": "#nosec G117 -- Request data is unmarshaled into this struct, but the struct\nis never marshaled and transmitted to anywhere.", - "type": "string" - }, - "repoUrl": { - "type": "string" - }, - "repoUrlIsRegex": { - "type": "boolean" - }, - "type": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "PromoteDownstreamRequest": { - "type": "object", - "properties": { - "freight": { - "type": "string" - }, - "freightAlias": { - "type": "string" - } - } - }, - "PromoteToStageRequest": { - "type": "object", - "properties": { - "freight": { - "type": "string" - }, - "freightAlias": { - "type": "string" - } - } - }, - "PublicConfig": { - "type": "object", - "properties": { - "adminAccountEnabled": { - "type": "boolean" - }, - "oidcConfig": { - "$ref": "#/definitions/OIDCConfig" - }, - "skipAuth": { - "type": "boolean" - } - } - }, - "ResourceDetails": { - "type": "object", - "properties": { - "resourceName": { - "type": "string" - }, - "resourceType": { - "type": "string" - }, - "verbs": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "RevokeRequest": { - "type": "object", - "properties": { - "resourceDetails": { - "$ref": "#/definitions/ResourceDetails" - }, - "role": { - "type": "string" - }, - "userClaims": { - "$ref": "#/definitions/UserClaims" - } - } - }, - "TagMap": { - "type": "object", - "properties": { - "tags": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ImageStageMap" - } - } - } - }, - "UpdateConfigMapRequest": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "type": "string" - } - } - }, - "UpdateGenericCredentialsRequest": { - "type": "object", - "properties": { - "data": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "type": "string" - } - } - }, - "UpdateRepoCredentialsRequest": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "password": { - "description": "#nosec G117 -- Request data is unmarshaled into this struct, but the struct\nis never marshaled and transmitted to anywhere.", - "type": "string" - }, - "repoUrl": { - "type": "string" - }, - "repoUrlIsRegex": { - "type": "boolean" - }, - "type": { - "type": "string" - }, - "username": { - "type": "string" - } - } - }, - "UserClaims": { - "type": "object", - "properties": { - "claims": { - "type": "array", - "items": { - "$ref": "#/definitions/Claim" - } - } - } - }, - "VersionInfo": { - "type": "object", - "properties": { - "buildDate": { - "description": "BuildDate is the date/time on which the application was built.", - "type": "string" - }, - "compiler": { - "description": "Compiler indicates what Go compiler was used for the build.", - "type": "string" - }, - "gitCommit": { - "description": "GitCommit is the ID (sha) of the last commit to the application's source\ncode that is included in this build.", - "type": "string" - }, - "gitTreeDirty": { - "description": "GitTreeDirty is true if the application's source code contained\nuncommitted changes at the time it was built; otherwise it is false.", - "type": "boolean" - }, - "goVersion": { - "description": "GoVersion is the version of Go that was used to build the application.", - "type": "string" - }, - "platform": { - "description": "Platform indicates the OS and CPU architecture for which the application\nwas built.", - "type": "string" - }, - "version": { - "description": "Version is a human-friendly version string.", - "type": "string" - } - } - } - }, - "securityDefinitions": { - "BearerAuth": { - "description": "Bearer token authentication. Obtain token via OIDC/PKCE flow with your identity provider.", - "type": "apiKey", - "name": "Authorization", - "in": "header" - } - }, - "tags": [ - { - "description": "Manage the primary Kargo resources that make up a promotion pipeline: Projects (tenancy boundaries), Warehouses (artifact sources), Freight (versioned artifact bundles), Stages (promotion targets), and Promotions (records of a Freight moving through a Stage).", - "name": "Core" - }, - { - "description": "Cluster-wide administrative operations for Kargo operators: retrieving server and API version info, authenticating as the built-in admin user, and reading or modifying cluster-level server configuration.", - "name": "System" - }, - { - "description": "Manage Kargo's role-based access control model. Kargo Roles are named collections of Kubernetes RBAC rules scoped to a project; API tokens are service-account-backed credentials that can be bound to a Role for non-human access.", - "name": "Rbac" - }, - { - "description": "Top-level grouping for all credential types that Kargo uses to authenticate with external systems. See the Repo Credentials and Generic Credentials sub-tags for the specific credential kinds.", - "name": "Credentials" - }, - { - "description": "Interact with Argo Rollouts AnalysisRun and AnalysisTemplate resources used to verify Stage health after a promotion. Includes triggering, aborting, and re-running analysis, as well as reading run logs.", - "name": "Verifications" - }, - { - "description": "Low-level operations for creating, updating, and deleting arbitrary Kargo Kubernetes resources by raw manifest. Useful for tooling that needs to manage resource types not covered by dedicated endpoints.", - "name": "Resources" - }, - { - "description": "Read Kubernetes Events emitted by Kargo controllers. Events record notable state transitions (e.g. a Promotion starting, completing, or failing) and are useful for auditing and debugging.", - "name": "Events" - }, - { - "description": "Manage structured configuration resources: ProjectConfig holds per-project promotion policy settings; ClusterConfig holds cluster-wide defaults and feature flags applied by the Kargo operator.", - "name": "Config" - }, - { - "description": "Manage free-form ConfigMap-backed configuration that Kargo promotion steps can read at runtime. Supports project-scoped, system-scoped, and shared ConfigMaps, allowing pipelines to consume environment-specific values without embedding them in Git.", - "name": "Generic Config" - }, - { - "description": "Credentials for authenticating with artifact repositories: Git repositories, Helm chart registries, and container image registries. Kargo uses these when polling for new artifacts and when running promotion steps that read from or write to a repository.", - "name": "Repo Credentials" - }, - { - "description": "Arbitrary key-value secrets that promotion steps can consume at runtime for any purpose not covered by repository credentials — for example, API tokens, signing keys, or connection strings for external services.", - "name": "Generic Credentials" - }, - { - "description": "The resource or operation is scoped to a single Kargo project (Kubernetes namespace). Access is governed by the requesting user's permissions within that project.", - "name": "Project-Level" - }, - { - "description": "The resource or operation lives in the Kargo system namespace and applies across all projects. Typically restricted to cluster administrators.", - "name": "System-Level" - }, - { - "description": "The resource is a Kubernetes cluster-scoped object (not namespaced), such as a Project or ClusterAnalysisTemplate. These exist at the cluster level and are accessible to users with appropriate cluster-wide permissions.", - "name": "Cluster-Scoped Resource" - }, - { - "description": "The resource is defined once and shared across multiple projects or scopes. For example, a shared ConfigMap or credential can be referenced by any project without being duplicated per namespace.", - "name": "Shared" - }, - { - "description": "At most, one instance of this resource kind exists per scope. For example, each project has, at most, one ProjectConfig and each cluster has, at most, one ClusterConfig.", - "name": "Singleton" - } - ] -} \ No newline at end of file + "collectionFormat": "csv", + "description": "Warehouse names to get freight from", + "name": "origins", + "in": "query" + }, + { + "type": "string", + "description": "Group filter", + "name": "group", + "in": "query" + }, + { + "type": "string", + "description": "Group by (image_repo, git_repo, chart_repo)", + "name": "groupBy", + "in": "query" + }, + { + "type": "string", + "description": "Order by (first_seen, tag)", + "name": "orderBy", + "in": "query" + }, + { + "type": "boolean", + "description": "Reverse order", + "name": "reverse", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Map of freight groups", + "schema": { + "type": "object" + } + } + } + } + }, + "/v1beta1/projects/{project}/freight/{freight-name-or-alias}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a Freight resource from a project's namespace by name\nor alias.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Retrieve a Freight resource", + "operationId": "GetFreight", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Freight name or alias", + "name": "freight-name-or-alias", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Freight custom resource (github.com/akuity/kargo/api/v1alpha1.Freight)", + "schema": { + "$ref": "#/definitions/Freight" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a Freight resource from a project's namespace by name or\nalias.", + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Delete a Freight resource", + "operationId": "DeleteFreight", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Freight name or alias", + "name": "freight-name-or-alias", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/freight/{freight-name-or-alias}/alias": { + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch a Freight resource's human-friendly alias.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Patch a Freight resource's alias", + "operationId": "PatchFreightAlias", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Freight name or alias", + "name": "freight-name-or-alias", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "New alias", + "name": "newAlias", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/freight/{freight-name-or-alias}/approve": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Approve Freight for promotion to a Stage.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Approve Freight for promotion to a Stage", + "operationId": "ApproveFreight", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Freight name or alias", + "name": "freight-name-or-alias", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/generic-credentials": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List project-level generic credentials. Returns a Kubernetes\nSecretList resource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Project-Level" + ], + "summary": "List project-level generic credentials", + "operationId": "ListProjectGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create project-level generic credentials. Returns a heavily\nredacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Project-Level" + ], + "summary": "Create project-level generic credentials", + "operationId": "CreateProjectGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "description": "Generic credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateGenericCredentialsRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/projects/{project}/generic-credentials/{generic-credentials}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve project-level generic credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Project-Level" + ], + "summary": "Retrieve project-level generic credentials", + "operationId": "GetProjectGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace project-level generic credentials. All existing data is\nreplaced. Returns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Project-Level" + ], + "summary": "Replace project-level generic credentials", + "operationId": "UpdateProjectGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + }, + { + "description": "GenericCredentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateGenericCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete generic credentials from a project's namespace.", + "tags": [ + "Credentials", + "Generic Credentials", + "Project-Level" + ], + "summary": "Delete project-level generic credentials", + "operationId": "DeleteProjectGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch project-level generic credentials. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Project-Level" + ], + "summary": "Patch project-level generic credentials", + "operationId": "PatchProjectGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + }, + { + "description": "GenericCredentials patch", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchGenericCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/projects/{project}/images": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List container images referenced by Freight resources in a\nproject's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "List container images", + "operationId": "ListImages", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/TagMap" + } + } + } + } + } + }, + "/v1beta1/projects/{project}/promotion-tasks": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List PromotionTask resources from a project's namespace. Returns\na PromotionTaskList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "List PromotionTasks", + "operationId": "ListPromotionTasks", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "PromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTaskList)", + "schema": { + "$ref": "#/definitions/PromotionTaskList" + } + } + } + } + }, + "/v1beta1/projects/{project}/promotion-tasks/{promotion-task}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a PromotionTask resource from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Retrieve a PromotionTask", + "operationId": "GetPromotionTask", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "PromotionTask name", + "name": "promotion-task", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "PromotionTask custom resource", + "schema": { + "$ref": "#/definitions/PromotionTask" + } + } + } + } + }, + "/v1beta1/projects/{project}/promotions": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List Promotion resources from a project's namespace. Returns a\nPromotionList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "List Promotions", + "operationId": "ListPromotions", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage filter", + "name": "stage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "PromotionList custom resource", + "schema": { + "$ref": "#/definitions/PromotionList" + } + } + } + } + }, + "/v1beta1/projects/{project}/promotions/{promotion}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a Promotion resource from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Retrieve a Promotion", + "operationId": "GetPromotion", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Promotion name", + "name": "promotion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Promotion custom resource (github.com/akuity/kargo/api/v1alpha1.Promotion)", + "schema": { + "$ref": "#/definitions/Promotion" + } + } + } + } + }, + "/v1beta1/projects/{project}/promotions/{promotion}/abort": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Abort a running Promotion.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Abort a Promotion", + "operationId": "AbortPromotion", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Promotion name", + "name": "promotion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/promotions/{promotion}/refresh": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Refresh a Promotion resource in a project's namespace.\nRefreshing enqueues the resource for reconciliation by its\ncorresponding controller.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Refresh a Promotion", + "operationId": "RefreshPromotion", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Promotion name", + "name": "promotion", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/repo-credentials": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List project-level repository credentials. Returns a SecretList\nresource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Project-Level" + ], + "summary": "List project-level repository credentials", + "operationId": "ListProjectRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create project-level repository credentials. Returns a heavily\nredacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Project-Level" + ], + "summary": "Create project-level repository credentials", + "operationId": "CreateProjectRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "description": "Credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateRepoCredentialsRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/projects/{project}/repo-credentials/{repo-credentials}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve project-level repository credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Project-Level" + ], + "summary": "Retrieve project-level repository credentials", + "operationId": "GetProjectRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace project-level repository credentials. All fields are replaced.\nReturns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Project-Level" + ], + "summary": "Replace project-level repository credentials", + "operationId": "UpdateProjectRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repo credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + }, + { + "description": "Credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateRepoCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete repository credentials from a project's namespace.", + "tags": [ + "Credentials", + "Repo Credentials", + "Project-Level" + ], + "summary": "Delete project-level repository credentials", + "operationId": "DeleteProjectRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch project-level repository credentials. Only provided fields\nare updated. Returns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Project-Level" + ], + "summary": "Patch project-level repository credentials", + "operationId": "PatchProjectRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repo credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + }, + { + "description": "Credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchRepoCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/projects/{project}/roles": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List project-level Kargo Role virtual resources. Returns a\nRoleList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "List project-level Kargo Role virtual resources", + "operationId": "ListProjectRoles", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "RoleList custom resource (rbacapi.RoleList) or underlying resources", + "schema": { + "type": "object" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a project-level Kargo Role virtual resource by creating\nthe underlying Kubernetes ServiceAccount, Role, and RoleBinding\nresources.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "Create a project-level Kargo Role virtual resource", + "operationId": "CreateProjectRole", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "201": { + "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", + "schema": { + "$ref": "#/definitions/RbacRole" + } + } + } + } + }, + "/v1beta1/projects/{project}/roles/grants": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Grant a project-level Kargo Role to users or grant permissions\nto a project-level Kargo Role.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "Grant permissions", + "operationId": "Grant", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "description": "Grant request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GrantRequest" + } + } + ], + "responses": { + "200": { + "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", + "schema": { + "$ref": "#/definitions/RbacRole" + } + } + } + } + }, + "/v1beta1/projects/{project}/roles/revocations": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Revoke a project-level Kargo Role from users or revoke\npermissions from a project-level Kargo Role.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "Revoke permissions", + "operationId": "Revoke", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "description": "Revoke request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RevokeRequest" + } + } + ], + "responses": { + "200": { + "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", + "schema": { + "$ref": "#/definitions/RbacRole" + } + } + } + } + }, + "/v1beta1/projects/{project}/roles/{role}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a project-level Kargo Role virtual resource by name.\nReturns a Kargo Role virtual resource or its underlying\nKubernetes resources.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "Retrieve a project-level Kargo Role virtual resource", + "operationId": "GetProjectRole", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Role name", + "name": "role", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Role resource (k8s.io/api/rbac/v1.Role) or its underlying Kubernetes resources", + "schema": { + "type": "object" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Update a project-level Kargo Role virtual resource by updating\nthe underlying Kubernetes ServiceAccount, Role, and RoleBinding\nresources.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "Update a project-level Kargo Role virtual resource", + "operationId": "UpdateRole", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Role name", + "name": "role", + "in": "path", + "required": true + }, + { + "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + } + ], + "responses": { + "200": { + "description": "Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role)", + "schema": { + "$ref": "#/definitions/RbacRole" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a project-level Kargo Role virtual resource by deleting\nthe underlying Kubernetes ServiceAccount, Role, and RoleBinding\nresources from the project's namespace.", + "tags": [ + "Rbac", + "Project-Level" + ], + "summary": "Delete a project-level Kargo Role virtual resource", + "operationId": "DeleteProjectRole", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Role name", + "name": "role", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/roles/{role}/api-tokens": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a project-level API token associated with a Kargo Role\nvirtual resource. Returns a Kubernetes Secret resource\nrepresenting the token. Store it securely. The token is not\nretrievable via the Kargo API after creation except in a\nredacted form.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Credentials", + "Project-Level" + ], + "summary": "Create a project-level API token", + "operationId": "CreateProjectAPIToken", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Role name", + "name": "role", + "in": "path", + "required": true + }, + { + "description": "Token", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateAPITokenRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/projects/{project}/stages": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List Stage resources from a project's namespace. Returns a\nStageList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "List Stages", + "operationId": "ListStages", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "StageList custom resource (github.com/akuity/kargo/api/v1alpha1.StageList)", + "schema": { + "$ref": "#/definitions/StageList" + } + } + } + } + }, + "/v1beta1/projects/{project}/stages/{stage}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a Stage resource from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Retrieve a Stage", + "operationId": "GetStage", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Stage custom resource (github.com/akuity/kargo/api/v1alpha1.Stage)", + "schema": { + "$ref": "#/definitions/Stage" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a Stage resource from a project's namespace.", + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Delete a Stage", + "operationId": "DeleteStage", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/stages/{stage}/promotions": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a Promotion resource to transition a specified Stage into\nthe state represented by the specified Freight.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Promote to Stage", + "operationId": "PromoteToStage", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + }, + { + "description": "Promote request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PromoteToStageRequest" + } + } + ], + "responses": { + "201": { + "description": "Promotion resource (github.com/akuity/kargo/api/v1alpha1.Promotion)", + "schema": { + "$ref": "#/definitions/Promotion" + } + } + } + } + }, + "/v1beta1/projects/{project}/stages/{stage}/promotions/downstream": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Creates a Promotion resource for each of a Stage's immediately\ndownstream Stages.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Promote downstream", + "operationId": "PromoteDownstream", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + }, + { + "description": "Promote request", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PromoteDownstreamRequest" + } + } + ], + "responses": { + "201": { + "description": "Promotions created", + "schema": { + "type": "object" + } + } + } + } + }, + "/v1beta1/projects/{project}/stages/{stage}/refresh": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Refresh a Stage resource in a project's namespace. Refreshing\nenqueues the resource for reconciliation by its corresponding\ncontroller.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Refresh a Stage", + "operationId": "RefreshStage", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/stages/{stage}/verification": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Trigger re-verification of the Freight currently in use by a\nStage.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "Reverify Freight", + "operationId": "Reverify", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/stages/{stage}/verification/abort": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Abort a running Verification process.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Project-Level" + ], + "summary": "Abort a running Verification process", + "operationId": "AbortVerification", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Stage name", + "name": "stage", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/projects/{project}/warehouses": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List Warehouse resources from a project's namespace. Returns a\nWarehouseList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "List Warehouses", + "operationId": "ListWarehouses", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "WarehouseList custom resource", + "schema": { + "$ref": "#/definitions/WarehouseList" + } + } + } + } + }, + "/v1beta1/projects/{project}/warehouses/{warehouse}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a Warehouse resource from a project's namespace.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Retrieve a Warehouse", + "operationId": "GetWarehouse", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Warehouse name", + "name": "warehouse", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Warehouse custom resource (github.com/akuity/kargo/api/v1alpha1.Warehouse)", + "schema": { + "$ref": "#/definitions/Warehouse" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a Warehouse resource from a project's namespace.", + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Delete a Warehouse", + "operationId": "DeleteWarehouse", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Warehouse name", + "name": "warehouse", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/projects/{project}/warehouses/{warehouse}/refresh": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Refresh a Warehouse resource in a project's namespace.\nRefreshing enqueues the resource for reconciliation by its\ncorresponding controller.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Project-Level" + ], + "summary": "Refresh a Warehouse", + "operationId": "RefreshWarehouse", + "parameters": [ + { + "type": "string", + "description": "Project name", + "name": "project", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Warehouse name", + "name": "warehouse", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/resources": { + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Update (or optionally, upsert) one or more Kargo resources from", + "consumes": [ + "text/plain" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Resources" + ], + "summary": "Update resources", + "operationId": "UpdateResource", + "parameters": [ + { + "type": "boolean", + "description": "If true, create a resource if it does not exist", + "name": "upsert", + "in": "query" + }, + { + "description": "YAML or JSON manifest(s)", + "name": "manifest", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Update results", + "schema": { + "$ref": "#/definitions/CreateOrUpdateResourceResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create one or more Kargo resources from YAML or JSON manifests.", + "consumes": [ + "text/plain" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Resources" + ], + "summary": "Create resources", + "operationId": "CreateResource", + "parameters": [ + { + "description": "YAML or JSON manifest(s)", + "name": "manifest", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Created successfully", + "schema": { + "$ref": "#/definitions/CreateResourceResponse" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete one or more Kargo resources using namespaces and names\nobtained from YAML or JSON manifests.", + "consumes": [ + "text/plain" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Resources" + ], + "summary": "Delete resources", + "operationId": "DeleteResource", + "parameters": [ + { + "description": "YAML or JSON manifest(s)", + "name": "manifest", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/DeleteResourceResponse" + } + } + } + } + }, + "/v1beta1/shared/cluster-analysis-templates": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List ClusterAnalysisTemplate resources. Returns a\nClusterAnalysisTemplateList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Shared", + "Cluster-Scoped Resource" + ], + "summary": "List ClusterAnalysisTemplates", + "operationId": "ListClusterAnalysisTemplates", + "responses": { + "200": { + "description": "ClusterAnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList)", + "schema": { + "$ref": "#/definitions/RolloutsClusterAnalysisTemplateList" + } + } + } + } + }, + "/v1beta1/shared/cluster-analysis-templates/{cluster-analysis-template}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a ClusterAnalysisTemplate by name.", + "produces": [ + "application/json" + ], + "tags": [ + "Verifications", + "Shared", + "Cluster-Scoped Resource" + ], + "summary": "Retrieve a ClusterAnalysisTemplate", + "operationId": "GetClusterAnalysisTemplate", + "parameters": [ + { + "type": "string", + "description": "ClusterAnalysisTemplate name", + "name": "cluster-analysis-template", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ClusterAnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate)", + "schema": { + "$ref": "#/definitions/RolloutsClusterAnalysisTemplate" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a ClusterAnalysisTemplate resource.", + "tags": [ + "Verifications", + "Shared", + "Cluster-Scoped Resource" + ], + "summary": "Delete a ClusterAnalysisTemplate", + "operationId": "DeleteClusterAnalysisTemplate", + "parameters": [ + { + "type": "string", + "description": "ClusterAnalysisTemplate name", + "name": "cluster-analysis-template", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/shared/cluster-promotion-tasks": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List ClusterPromotionTask resources. Returns a\nClusterPromotionTaskList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Shared", + "Cluster-Scoped Resource" + ], + "summary": "List ClusterPromotionTasks", + "operationId": "ListClusterPromotionTasks", + "responses": { + "200": { + "description": "ClusterPromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTaskList)", + "schema": { + "$ref": "#/definitions/ClusterPromotionTaskList" + } + } + } + } + }, + "/v1beta1/shared/cluster-promotion-tasks/{cluster-promotion-task}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a ClusterPromotionTask by name.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Shared", + "Cluster-Scoped Resource" + ], + "summary": "Retrieve a ClusterPromotionTask", + "operationId": "GetClusterPromotionTask", + "parameters": [ + { + "type": "string", + "description": "ClusterPromotionTask name", + "name": "cluster-promotion-task", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ClusterPromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTask)", + "schema": { + "$ref": "#/definitions/ClusterPromotionTask" + } + } + } + } + }, + "/v1beta1/shared/configmaps": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List shared ConfigMap resources referenceable by all projects.\nReturns a Kubernetes ConfigMapList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Shared" + ], + "summary": "List shared ConfigMaps", + "operationId": "ListSharedConfigMaps", + "responses": { + "200": { + "description": "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)", + "schema": { + "$ref": "#/definitions/V1ConfigMapList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a shared ConfigMap referenceable by all projects. Returns\nthe created Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Shared" + ], + "summary": "Create a shared ConfigMap", + "operationId": "CreateSharedConfigMap", + "parameters": [ + { + "description": "ConfigMap", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateConfigMapRequest" + } + } + ], + "responses": { + "201": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + } + }, + "/v1beta1/shared/configmaps/{configmap}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a shared ConfigMap by name.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Shared" + ], + "summary": "Retrieve a shared ConfigMap", + "operationId": "GetSharedConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace a shared ConfigMap. All existing data is replaced.\nReturns the updated Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Shared" + ], + "summary": "Replace a shared ConfigMap", + "operationId": "UpdateSharedConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + }, + { + "description": "ConfigMap", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateConfigMapRequest" + } + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a shared ConfigMap.", + "tags": [ + "Core", + "Generic Config", + "Shared" + ], + "summary": "Delete a shared ConfigMap", + "operationId": "DeleteSharedConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch a shared ConfigMap. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns the updated Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "Shared" + ], + "summary": "Patch a shared ConfigMap", + "operationId": "PatchSharedConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + }, + { + "description": "ConfigMap patch", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchConfigMapRequest" + } + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + } + }, + "/v1beta1/shared/generic-credentials": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List shared generic credentials. Returns a Kubernetes SecretList\nresource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Shared" + ], + "summary": "List shared generic credentials", + "operationId": "ListSharedGenericCredentials", + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create shared generic credentials referenceable by all\nprojects. Returns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Shared" + ], + "summary": "Create shared generic credentials", + "operationId": "CreateSharedGenericCredentials", + "parameters": [ + { + "description": "Generic credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateGenericCredentialsRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/shared/generic-credentials/{generic-credentials}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve shared generic credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Shared" + ], + "summary": "Retrieve shared generic credentials", + "operationId": "GetSharedGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace shared generic credentials. All existing data is replaced.\nReturns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Shared" + ], + "summary": "Replace shared generic credentials", + "operationId": "UpdateSharedGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + }, + { + "description": "GenericCredentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateGenericCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete shared generic credentials.", + "tags": [ + "Credentials", + "Generic Credentials", + "Shared" + ], + "summary": "Delete shared generic credentials", + "operationId": "DeleteSharedGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch shared generic credentials. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "Shared" + ], + "summary": "Patch shared generic credentials", + "operationId": "PatchSharedGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + }, + { + "description": "GenericCredentials patch", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchGenericCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/shared/repo-credentials": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List shared repository credentials. Returns a SecretList\nresource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Shared" + ], + "summary": "List shared repository credentials", + "operationId": "ListSharedRepoCredentials", + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create shared repository credentials. Returns a heavily\nredacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Shared" + ], + "summary": "Create shared repository credentials", + "operationId": "CreateSharedRepoCredentials", + "parameters": [ + { + "description": "Credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateRepoCredentialsRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/shared/repo-credentials/{repo-credentials}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve shared repository credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Shared" + ], + "summary": "Retrieve shared repository credentials", + "operationId": "GetSharedRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace shared repository credentials. All fields are replaced.\nReturns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Shared" + ], + "summary": "Replace shared repository credentials", + "operationId": "UpdateSharedRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Repo credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + }, + { + "description": "Credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateRepoCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete shared repository credentials.", + "tags": [ + "Credentials", + "Repo Credentials", + "Shared" + ], + "summary": "Delete shared repository credentials", + "operationId": "DeleteSharedRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch shared repository credentials. Only provided fields\nare updated. Returns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Repo Credentials", + "Shared" + ], + "summary": "Patch shared repository credentials", + "operationId": "PatchSharedRepoCredentials", + "parameters": [ + { + "type": "string", + "description": "Repo credentials name", + "name": "repo-credentials", + "in": "path", + "required": true + }, + { + "description": "Credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchRepoCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/system/api-tokens": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List system-level API tokens. Returns a Kubernetes SecretList\nresource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Credentials", + "System-Level" + ], + "summary": "List system-level API tokens", + "operationId": "ListSystemAPITokens", + "parameters": [ + { + "type": "string", + "description": "Role name filter", + "name": "role", + "in": "query" + } + ], + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + } + }, + "/v1beta1/system/api-tokens/{apitoken}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a system-level API token by name. Returns a heavily\nredacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Credentials", + "System-Level" + ], + "summary": "Retrieve a system-level API token", + "operationId": "GetSystemAPIToken", + "parameters": [ + { + "type": "string", + "description": "API token name", + "name": "apitoken", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a system-level API token.", + "tags": [ + "Rbac", + "Credentials", + "System-Level" + ], + "summary": "Delete a system-level API token", + "operationId": "DeleteSystemAPIToken", + "parameters": [ + { + "type": "string", + "description": "API token name", + "name": "apitoken", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/system/cluster-config": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve the single ClusterConfig resource.", + "produces": [ + "application/json" + ], + "tags": [ + "System", + "Config", + "Cluster-Scoped Resource", + "Singleton" + ], + "summary": "Retrieve the ClusterConfig", + "operationId": "GetClusterConfig", + "responses": { + "200": { + "description": "ClusterConfig custom resource", + "schema": { + "$ref": "#/definitions/ClusterConfig" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Deletes the single ClusterConfig resource.", + "tags": [ + "System", + "Config", + "Cluster-Scoped Resource", + "Singleton" + ], + "summary": "Delete the ClusterConfig", + "operationId": "DeleteClusterConfig", + "responses": { + "204": { + "description": "Deleted successfully" + } + } + } + }, + "/v1beta1/system/cluster-config/refresh": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Refresh the single ClusterConfig resource. Refreshing enqueues\nthe resource for reconciliation by its corresponding controller.", + "produces": [ + "application/json" + ], + "tags": [ + "System", + "Config", + "Cluster-Scoped Resource", + "Singleton" + ], + "summary": "Refresh the ClusterConfig", + "operationId": "RefreshClusterConfig", + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/v1beta1/system/configmaps": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List system-level ConfigMap resources. Returns a Kubernetes\nConfigMapList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "System-Level" + ], + "summary": "List system-level ConfigMaps", + "operationId": "ListSystemConfigMaps", + "responses": { + "200": { + "description": "ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList)", + "schema": { + "$ref": "#/definitions/V1ConfigMapList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a system-level ConfigMap. Returns the created Kubernetes\nConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "System-Level" + ], + "summary": "Create a system-level ConfigMap", + "operationId": "CreateSystemConfigMap", + "parameters": [ + { + "description": "ConfigMap", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateConfigMapRequest" + } + } + ], + "responses": { + "201": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + } + }, + "/v1beta1/system/configmaps/{configmap}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a system-level ConfigMap by name.", + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "System-Level" + ], + "summary": "Retrieve a system-level ConfigMap", + "operationId": "GetSystemConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace a system-level ConfigMap. All existing data is replaced.\nReturns the updated Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "System-Level" + ], + "summary": "Replace a system-level ConfigMap", + "operationId": "UpdateSystemConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + }, + { + "description": "ConfigMap", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateConfigMapRequest" + } + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a system-level ConfigMap.", + "tags": [ + "Core", + "Generic Config", + "System-Level" + ], + "summary": "Delete a system-level ConfigMap", + "operationId": "DeleteSystemConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch a system-level ConfigMap. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns the updated Kubernetes ConfigMap resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Core", + "Generic Config", + "System-Level" + ], + "summary": "Patch a system-level ConfigMap", + "operationId": "PatchSystemConfigMap", + "parameters": [ + { + "type": "string", + "description": "ConfigMap name", + "name": "configmap", + "in": "path", + "required": true + }, + { + "description": "ConfigMap patch", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchConfigMapRequest" + } + } + ], + "responses": { + "200": { + "description": "ConfigMap resource (k8s.io/api/core/v1.ConfigMap)", + "schema": { + "$ref": "#/definitions/V1ConfigMap" + } + } + } + } + }, + "/v1beta1/system/generic-credentials": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List system-level generic credentials. Returns a Kubernetes\nSecretList resource containing heavily redacted Secrets.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "System-Level" + ], + "summary": "List system-level generic credentials", + "operationId": "ListSystemGenericCredentials", + "responses": { + "200": { + "description": "SecretList resource (k8s.io/api/core/v1.SecretList)", + "schema": { + "$ref": "#/definitions/V1SecretList" + } + } + } + }, + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create system-level generic credentials. Returns a heavily\nredacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "System-Level" + ], + "summary": "Create system-level generic credentials", + "operationId": "CreateSystemGenericCredentials", + "parameters": [ + { + "description": "Generic credentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateGenericCredentialsRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/system/generic-credentials/{generic-credentials}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve system-level generic credentials by name. Returns a\nheavily redacted Kubernetes Secret resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "System-Level" + ], + "summary": "Retrieve system-level generic credentials", + "operationId": "GetSystemGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Replace system-level generic credentials. All existing data is\nreplaced. Returns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "System-Level" + ], + "summary": "Replace system-level generic credentials", + "operationId": "UpdateSystemGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + }, + { + "description": "GenericCredentials", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UpdateGenericCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete system-level generic credentials.", + "tags": [ + "Credentials", + "Generic Credentials", + "System-Level" + ], + "summary": "Delete system-level generic credentials", + "operationId": "DeleteSystemGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "Deleted successfully" + } + } + }, + "patch": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Patch system-level generic credentials. Merges provided data\nwith existing data. Use removeKeys to delete specific keys.\nReturns a heavily redacted Kubernetes Secret resource.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Credentials", + "Generic Credentials", + "System-Level" + ], + "summary": "Patch system-level generic credentials", + "operationId": "PatchSystemGenericCredentials", + "parameters": [ + { + "type": "string", + "description": "Generic credentials name", + "name": "generic-credentials", + "in": "path", + "required": true + }, + { + "description": "GenericCredentials patch", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PatchGenericCredentialsRequest" + } + } + ], + "responses": { + "200": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/system/public-server-config": { + "get": { + "description": "Retrieve information a client may need to know about how the\nKargo API server is configured in order to proceed with\nauthentication.", + "produces": [ + "application/json" + ], + "tags": [ + "System", + "Config" + ], + "summary": "Retrieve public server configuration", + "operationId": "GetPublicConfig", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/PublicConfig" + } + } + } + } + }, + "/v1beta1/system/roles": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "List system-level Kargo Role virtual resources. Returns a\nRoleList resource.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "System-Level" + ], + "summary": "List system-level Kargo Role virtual resources", + "operationId": "ListSystemRoles", + "responses": { + "200": { + "description": "RoleList custom resource (rbacapi.RoleList) or underlying resources", + "schema": { + "type": "object" + } + } + } + } + }, + "/v1beta1/system/roles/{role}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve a system-level Kargo Role virtual resource by name.\nReturns a Kargo Role virtual resource or its underlying\nKubernetes resources.", + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "System-Level" + ], + "summary": "Retrieve a system-level Kargo Role virtual resource", + "operationId": "GetSystemRole", + "parameters": [ + { + "type": "string", + "description": "Role name", + "name": "role", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Role resource (k8s.io/api/rbac/v1.Role) or its underlying Kubernetes resources", + "schema": { + "type": "object" + } + } + } + } + }, + "/v1beta1/system/roles/{role}/api-tokens": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Create a system-level API token associated with a system-level\nKargo Role virtual resource. Returns a Kubernetes Secret\nresource representing the token. Store it securely. The token\nis not retrievable via the Kargo API after creation except in\na redacted form.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Rbac", + "Credentials", + "System-Level" + ], + "summary": "Create a system-level API token", + "operationId": "CreateSystemAPIToken", + "parameters": [ + { + "type": "string", + "description": "Role name", + "name": "role", + "in": "path", + "required": true + }, + { + "description": "Token", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateAPITokenRequest" + } + } + ], + "responses": { + "201": { + "description": "Secret resource (k8s.io/api/core/v1.Secret)", + "schema": { + "$ref": "#/definitions/V1Secret" + } + } + } + } + }, + "/v1beta1/system/server-config": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve information a client may need to know about how the\nKargo API server is configured.", + "produces": [ + "application/json" + ], + "tags": [ + "System", + "Config" + ], + "summary": "Retrieve server configuration", + "operationId": "GetConfig", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/GetConfigResponse" + } + } + } + } + }, + "/v1beta1/system/server-version": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Retrieve API Server version information.", + "produces": [ + "application/json" + ], + "tags": [ + "System" + ], + "summary": "Retrieve API Server version information", + "operationId": "GetVersionInfo", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/VersionInfo" + } + } + } + } + } + }, + "definitions": { + "AdminLoginResponse": { + "type": "object", + "properties": { + "idToken": { + "type": "string" + } + } + }, + "ArgoCDShard": { + "type": "object", + "properties": { + "namespace": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "Claim": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateAPITokenRequest": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "CreateConfigMapRequest": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "CreateGenericCredentialsRequest": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "CreateOrUpdateResourceResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/CreateOrUpdateResourceResult" + } + } + } + }, + "CreateOrUpdateResourceResult": { + "type": "object", + "properties": { + "createdResourceManifest": { + "type": "object", + "additionalProperties": {} + }, + "error": { + "type": "string" + }, + "updatedResourceManifest": { + "type": "object", + "additionalProperties": {} + } + } + }, + "CreateRepoCredentialsRequest": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "password": { + "description": "#nosec G117 -- Request data is unmarshaled into this struct, but the struct\nis never marshaled and transmitted to anywhere.", + "type": "string" + }, + "repoUrl": { + "type": "string" + }, + "repoUrlIsRegex": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "CreateResourceResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/CreateResourceResult" + } + } + } + }, + "CreateResourceResult": { + "type": "object", + "properties": { + "createdResourceManifest": { + "type": "object", + "additionalProperties": {} + }, + "error": { + "type": "string" + } + } + }, + "DeleteResourceResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/definitions/DeleteResourceResult" + } + } + } + }, + "DeleteResourceResult": { + "type": "object", + "properties": { + "deletedResourceManifest": { + "type": "object", + "additionalProperties": {} + }, + "error": { + "type": "string" + } + } + }, + "GetConfigResponse": { + "type": "object", + "properties": { + "argocdShards": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ArgoCDShard" + } + }, + "hasAnalysisRunLogsUrlTemplate": { + "type": "boolean" + }, + "kargoNamespace": { + "type": "string" + }, + "secretManagementEnabled": { + "type": "boolean" + }, + "sharedResourcesNamespace": { + "type": "string" + }, + "systemResourcesNamespace": { + "type": "string" + } + } + }, + "GrantRequest": { + "type": "object", + "properties": { + "resourceDetails": { + "$ref": "#/definitions/ResourceDetails" + }, + "role": { + "type": "string" + }, + "userClaims": { + "$ref": "#/definitions/UserClaims" + } + } + }, + "ImageStageMap": { + "type": "object", + "properties": { + "stages": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + }, + "OIDCConfig": { + "type": "object", + "properties": { + "cliClientId": { + "type": "string" + }, + "clientId": { + "type": "string" + }, + "issuerUrl": { + "type": "string" + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PatchConfigMapRequest": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "removeKeys": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PatchGenericCredentialsRequest": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "removeKeys": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PatchRepoCredentialsRequest": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "password": { + "description": "#nosec G117 -- Request data is unmarshaled into this struct, but the struct\nis never marshaled and transmitted to anywhere.", + "type": "string" + }, + "repoUrl": { + "type": "string" + }, + "repoUrlIsRegex": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "PromoteDownstreamRequest": { + "type": "object", + "properties": { + "freight": { + "type": "string" + }, + "freightAlias": { + "type": "string" + } + } + }, + "PromoteToStageRequest": { + "type": "object", + "properties": { + "freight": { + "type": "string" + }, + "freightAlias": { + "type": "string" + } + } + }, + "PublicConfig": { + "type": "object", + "properties": { + "adminAccountEnabled": { + "type": "boolean" + }, + "oidcConfig": { + "$ref": "#/definitions/OIDCConfig" + }, + "skipAuth": { + "type": "boolean" + } + } + }, + "ResourceDetails": { + "type": "object", + "properties": { + "resourceName": { + "type": "string" + }, + "resourceType": { + "type": "string" + }, + "verbs": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "RevokeRequest": { + "type": "object", + "properties": { + "resourceDetails": { + "$ref": "#/definitions/ResourceDetails" + }, + "role": { + "type": "string" + }, + "userClaims": { + "$ref": "#/definitions/UserClaims" + } + } + }, + "TagMap": { + "type": "object", + "properties": { + "tags": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ImageStageMap" + } + } + } + }, + "UpdateConfigMapRequest": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + } + } + }, + "UpdateGenericCredentialsRequest": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "type": "string" + } + } + }, + "UpdateRepoCredentialsRequest": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "password": { + "description": "#nosec G117 -- Request data is unmarshaled into this struct, but the struct\nis never marshaled and transmitted to anywhere.", + "type": "string" + }, + "repoUrl": { + "type": "string" + }, + "repoUrlIsRegex": { + "type": "boolean" + }, + "type": { + "type": "string" + }, + "username": { + "type": "string" + } + } + }, + "UserClaims": { + "type": "object", + "properties": { + "claims": { + "type": "array", + "items": { + "$ref": "#/definitions/Claim" + } + } + } + }, + "VersionInfo": { + "type": "object", + "properties": { + "buildDate": { + "description": "BuildDate is the date/time on which the application was built.", + "type": "string" + }, + "compiler": { + "description": "Compiler indicates what Go compiler was used for the build.", + "type": "string" + }, + "gitCommit": { + "description": "GitCommit is the ID (sha) of the last commit to the application's source\ncode that is included in this build.", + "type": "string" + }, + "gitTreeDirty": { + "description": "GitTreeDirty is true if the application's source code contained\nuncommitted changes at the time it was built; otherwise it is false.", + "type": "boolean" + }, + "goVersion": { + "description": "GoVersion is the version of Go that was used to build the application.", + "type": "string" + }, + "platform": { + "description": "Platform indicates the OS and CPU architecture for which the application\nwas built.", + "type": "string" + }, + "version": { + "description": "Version is a human-friendly version string.", + "type": "string" + } + } + }, + "RbacRole": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "claims": { + "type": "array", + "items": { + "$ref": "#/definitions/Claim" + } + }, + "kargoManaged": { + "type": "boolean" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "rules": { + "type": "array", + "items": { + "$ref": "#/definitions/V1PolicyRule" + } + } + } + }, + "RolloutsAnalysisRun": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "$ref": "#/definitions/RolloutsAnalysisRunSpec" + }, + "status": { + "$ref": "#/definitions/RolloutsAnalysisRunStatus" + } + } + }, + "RolloutsAnalysisRunSpec": { + "type": "object", + "properties": { + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsArgument" + } + }, + "dryRun": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsDryRun" + } + }, + "measurementRetention": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsMeasurementRetention" + } + }, + "metrics": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsMetric" + } + }, + "terminate": { + "type": "boolean" + } + } + }, + "RolloutsAnalysisRunStatus": { + "type": "object", + "properties": { + "dryRunSummary": { + "$ref": "#/definitions/RolloutsRunSummary" + }, + "message": { + "type": "string" + }, + "metricResults": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsMetricResult" + } + }, + "phase": { + "type": "string" + }, + "runSummary": { + "$ref": "#/definitions/RolloutsRunSummary" + }, + "startedAt": { + "type": "string" + } + } + }, + "RolloutsAnalysisTemplate": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "$ref": "#/definitions/RolloutsAnalysisTemplateSpec" + } + } + }, + "RolloutsAnalysisTemplateList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsAnalysisTemplate" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "RolloutsAnalysisTemplateSpec": { + "type": "object", + "properties": { + "args": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsArgument" + } + }, + "dryRun": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsDryRun" + } + }, + "measurementRetention": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsMeasurementRetention" + } + }, + "metrics": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsMetric" + } + } + } + }, + "RolloutsArgument": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "valueFrom": { + "$ref": "#/definitions/RolloutsValueFrom" + } + } + }, + "RolloutsAuthentication": { + "type": "object", + "properties": { + "oauth2": { + "$ref": "#/definitions/RolloutsOAuth2Config" + }, + "sigv4": { + "$ref": "#/definitions/RolloutsSigv4Config" + } + } + }, + "RolloutsCloudWatchMetric": { + "type": "object", + "properties": { + "interval": { + "type": "string" + }, + "metricDataQueries": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsCloudWatchMetricDataQuery" + } + } + } + }, + "RolloutsCloudWatchMetricDataQuery": { + "type": "object", + "properties": { + "expression": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "metricStat": { + "$ref": "#/definitions/RolloutsCloudWatchMetricStat" + }, + "period": { + "$ref": "#/definitions/IntOrString" + }, + "returnData": { + "type": "boolean" + } + } + }, + "RolloutsCloudWatchMetricStat": { + "type": "object", + "properties": { + "metric": { + "$ref": "#/definitions/RolloutsCloudWatchMetricStatMetric" + }, + "period": { + "$ref": "#/definitions/IntOrString" + }, + "stat": { + "type": "string" + }, + "unit": { + "type": "string" + } + } + }, + "RolloutsCloudWatchMetricStatMetric": { + "type": "object", + "properties": { + "dimensions": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsCloudWatchMetricStatMetricDimension" + } + }, + "metricName": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "RolloutsCloudWatchMetricStatMetricDimension": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "RolloutsClusterAnalysisTemplate": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "$ref": "#/definitions/RolloutsAnalysisTemplateSpec" + } + } + }, + "RolloutsClusterAnalysisTemplateList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsClusterAnalysisTemplate" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "RolloutsDatadogMetric": { + "type": "object", + "properties": { + "aggregator": { + "type": "string" + }, + "apiVersion": { + "type": "string" + }, + "formula": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "queries": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "query": { + "type": "string" + } + } + }, + "RolloutsDryRun": { + "type": "object", + "properties": { + "metricName": { + "type": "string" + } + } + }, + "RolloutsFieldRef": { + "type": "object", + "properties": { + "fieldPath": { + "description": "Required: Path of the field to select in the specified API version", + "type": "string" + } + } + }, + "RolloutsGraphiteMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + } + }, + "RolloutsInfluxdbMetric": { + "type": "object", + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + } + }, + "RolloutsJobMetric": { + "type": "object", + "properties": { + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "$ref": "#/definitions/V1JobSpec" + } + } + }, + "RolloutsKayentaMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "application": { + "type": "string" + }, + "canaryConfigName": { + "type": "string" + }, + "configurationAccountName": { + "type": "string" + }, + "metricsAccountName": { + "type": "string" + }, + "scopes": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsKayentaScope" + } + }, + "storageAccountName": { + "type": "string" + }, + "threshold": { + "$ref": "#/definitions/RolloutsKayentaThreshold" + } + } + }, + "RolloutsKayentaScope": { + "type": "object", + "properties": { + "controlScope": { + "$ref": "#/definitions/RolloutsScopeDetail" + }, + "experimentScope": { + "$ref": "#/definitions/RolloutsScopeDetail" + }, + "name": { + "type": "string" + } + } + }, + "RolloutsKayentaThreshold": { + "type": "object", + "properties": { + "marginal": { + "type": "integer" + }, + "pass": { + "type": "integer" + } + } + }, + "RolloutsMeasurement": { + "type": "object", + "properties": { + "finishedAt": { + "type": "string" + }, + "message": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "phase": { + "type": "string" + }, + "resumeAt": { + "type": "string" + }, + "startedAt": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "RolloutsMeasurementRetention": { + "type": "object", + "properties": { + "limit": { + "type": "integer" + }, + "metricName": { + "type": "string" + } + } + }, + "RolloutsMetric": { + "type": "object", + "properties": { + "consecutiveErrorLimit": { + "$ref": "#/definitions/IntOrString" + }, + "consecutiveSuccessLimit": { + "$ref": "#/definitions/IntOrString" + }, + "count": { + "$ref": "#/definitions/IntOrString" + }, + "failureCondition": { + "type": "string" + }, + "failureLimit": { + "$ref": "#/definitions/IntOrString" + }, + "inconclusiveLimit": { + "$ref": "#/definitions/IntOrString" + }, + "initialDelay": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "name": { + "type": "string" + }, + "provider": { + "$ref": "#/definitions/RolloutsMetricProvider" + }, + "successCondition": { + "type": "string" + } + } + }, + "RolloutsMetricProvider": { + "type": "object", + "properties": { + "cloudWatch": { + "$ref": "#/definitions/RolloutsCloudWatchMetric" + }, + "datadog": { + "$ref": "#/definitions/RolloutsDatadogMetric" + }, + "graphite": { + "$ref": "#/definitions/RolloutsGraphiteMetric" + }, + "influxdb": { + "$ref": "#/definitions/RolloutsInfluxdbMetric" + }, + "job": { + "$ref": "#/definitions/RolloutsJobMetric" + }, + "kayenta": { + "$ref": "#/definitions/RolloutsKayentaMetric" + }, + "newRelic": { + "$ref": "#/definitions/RolloutsNewRelicMetric" + }, + "plugin": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "byte" + } + }, + "prometheus": { + "$ref": "#/definitions/RolloutsPrometheusMetric" + }, + "skywalking": { + "$ref": "#/definitions/RolloutsSkyWalkingMetric" + }, + "wavefront": { + "$ref": "#/definitions/RolloutsWavefrontMetric" + }, + "web": { + "$ref": "#/definitions/RolloutsWebMetric" + } + } + }, + "RolloutsMetricResult": { + "type": "object", + "properties": { + "consecutiveError": { + "type": "integer" + }, + "count": { + "type": "integer" + }, + "dryRun": { + "type": "boolean" + }, + "error": { + "type": "integer" + }, + "failed": { + "type": "integer" + }, + "inconclusive": { + "type": "integer" + }, + "measurements": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsMeasurement" + } + }, + "message": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "phase": { + "type": "string" + }, + "successful": { + "type": "integer" + } + } + }, + "RolloutsNewRelicMetric": { + "type": "object", + "properties": { + "profile": { + "type": "string" + }, + "query": { + "type": "string" + } + } + }, + "RolloutsOAuth2Config": { + "type": "object", + "properties": { + "clientId": { + "type": "string" + }, + "clientSecret": { + "type": "string" + }, + "scopes": { + "type": "array", + "items": { + "type": "string" + } + }, + "tokenUrl": { + "type": "string" + } + } + }, + "RolloutsPrometheusMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "authentication": { + "$ref": "#/definitions/RolloutsAuthentication" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsWebMetricHeader" + } + }, + "insecure": { + "type": "boolean" + }, + "query": { + "type": "string" + }, + "timeout": { + "type": "integer" + } + } + }, + "RolloutsRunSummary": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "error": { + "type": "integer" + }, + "failed": { + "type": "integer" + }, + "inconclusive": { + "type": "integer" + }, + "successful": { + "type": "integer" + } + } + }, + "RolloutsScopeDetail": { + "type": "object", + "properties": { + "end": { + "type": "string" + }, + "region": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "start": { + "type": "string" + }, + "step": { + "type": "integer" + } + } + }, + "RolloutsSecretKeyRef": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "RolloutsSigv4Config": { + "type": "object", + "properties": { + "profile": { + "type": "string" + }, + "region": { + "type": "string" + }, + "roleArn": { + "type": "string" + } + } + }, + "RolloutsSkyWalkingMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "interval": { + "type": "string" + }, + "query": { + "type": "string" + } + } + }, + "RolloutsValueFrom": { + "type": "object", + "properties": { + "fieldRef": { + "$ref": "#/definitions/RolloutsFieldRef" + }, + "secretKeyRef": { + "$ref": "#/definitions/RolloutsSecretKeyRef" + } + } + }, + "RolloutsWavefrontMetric": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "query": { + "type": "string" + } + } + }, + "RolloutsWebMetric": { + "type": "object", + "properties": { + "authentication": { + "$ref": "#/definitions/RolloutsAuthentication" + }, + "body": { + "type": "string" + }, + "headers": { + "type": "array", + "items": { + "$ref": "#/definitions/RolloutsWebMetricHeader" + } + }, + "insecure": { + "type": "boolean" + }, + "jsonBody": { + "type": "array", + "items": { + "type": "integer" + } + }, + "jsonPath": { + "type": "string" + }, + "method": { + "type": "string" + }, + "timeoutSeconds": { + "type": "integer" + }, + "url": { + "description": "URL is the address of the web metric", + "type": "string" + } + } + }, + "RolloutsWebMetricHeader": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "AnalysisRunArgument": { + "type": "object", + "properties": { + "name": { + "description": "Name is the name of the argument.\n\n+kubebuilder:validation:Required", + "type": "string" + }, + "value": { + "description": "Value is the value of the argument.\n\n+kubebuilder:validation:Required", + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + }, + "AnalysisRunMetadata": { + "type": "object", + "properties": { + "annotations": { + "description": "Additional annotations to apply to an AnalysisRun.", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "labels": { + "description": "Additional labels to apply to an AnalysisRun.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "AnalysisRunReference": { + "type": "object", + "properties": { + "name": { + "description": "Name is the name of the AnalysisRun.", + "type": "string" + }, + "namespace": { + "description": "Namespace is the namespace of the AnalysisRun.", + "type": "string" + }, + "phase": { + "description": "Phase is the last observed phase of the AnalysisRun referenced by Name.", + "type": "string" + } + } + }, + "AnalysisTemplateReference": { + "type": "object", + "properties": { + "kind": { + "description": "Kind is the type of the AnalysisTemplate. Can be either AnalysisTemplate or\nClusterAnalysisTemplate, default is AnalysisTemplate.\n\n+kubebuilder:validation:Optional\n+kubebuilder:validation:Enum=AnalysisTemplate;ClusterAnalysisTemplate", + "type": "string" + }, + "name": { + "description": "Name is the name of the AnalysisTemplate in the same project/namespace as\nthe Stage.\n\n+kubebuilder:validation:Required", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "ApprovedStage": { + "type": "object", + "properties": { + "approvedAt": { + "description": "ApprovedAt is the time at which the Freight was approved for the Stage.", + "type": "string" + } + } + }, + "ArtifactReference": { + "type": "object", + "properties": { + "artifactType": { + "description": "ArtifactType specifies the type of artifact this is. Often, but not always,\nit will be the media type (MIME type) of the artifact referenced by this\nArtifactReference.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + }, + "metadata": { + "description": "Metadata is a JSON object containing a mostly opaque collection of artifact\nattributes. (It must be an object. It may not be a list or a scalar value.)\n\"Mostly\" because Kargo may understand how to interpret some documented,\nwell-known, top-level keys. Those aside, this metadata is only understood\nby a corresponding Subscriber implementation that created it.\n\n+optional", + "type": "object" + }, + "subscriptionName": { + "description": "SubscriptionName is the name of the Subscription that discovered this\nartifact.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + }, + "version": { + "description": "Version identifies a specific revision of this artifact.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + } + } + }, + "ArtifactoryWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret-token` key whose\nvalue is the shared secret used to authenticate the webhook requests sent\nby JFrog Artifactory. For more information please refer to the JFrog\nArtifactory documentation:\n https://jfrog.com/help/r/jfrog-platform-administration-documentation/webhooks\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "virtualRepoName": { + "description": "VirtualRepoName is the name of an Artifactory virtual repository.\n\nWhen unspecified, the Artifactory webhook receiver depends on the value of\nthe webhook payload's `data.repo_key` field when inferring the URL of the\nrepository from which the webhook originated, which will always be an\nArtifactory \"local repository.\" In cases where a Warehouse subscribes to\nsuch a repository indirectly via a \"virtual repository,\" there will be a\ndiscrepancy between the inferred (local) repository URL and the URL\nactually used by the subscription, which can prevent the receiver from\nidentifying such a Warehouse as one in need of refreshing. When specified,\nthe value of the VirtualRepoName field supersedes the value of the webhook\npayload's `data.repo_key` field to compensate for that discrepancy.\n\nIn practice, when using virtual repositories, a separate Artifactory\nwebhook receiver should be configured for each, but one such receiver can\nhandle inbound webhooks from any number of local repositories that are\naggregated by that virtual repository. For example, if a virtual repository\n`proj-virtual` aggregates container images from all of the `proj`\nArtifactory project's local image repositories, with a single webhook\nconfigured to post to a single receiver configured for the `proj-virtual`\nvirtual repository, an image pushed to\n`example.frog.io/proj-//image`, will cause that\nreceiver to refresh all Warehouses subscribed to\n`example.frog.io/proj-virtual//image`.\n\n+optional", + "type": "string" + } + }, + "required": [ + "secretRef" + ] + }, + "AutoPromotionOptions": { + "type": "object", + "properties": { + "selectionPolicy": { + "description": "SelectionPolicy specifies the rules for identifying new Freight that is\neligible for auto-promotion to this Stage. This field is optional. When\nleft unspecified, the field is implicitly treated as if its value were\n\"NewestFreight\".\n\nAccepted Values:\n\n- \"NewestFreight\": The newest Freight that is available to the Stage is\n eligible for auto-promotion.\n\n- \"MatchUpstream\": Only the Freight currently used immediately upstream\n from this Stage is eligible for auto-promotion. This policy may only\n be applied when the Stage has exactly one upstream Stage.", + "type": "string" + } + } + }, + "AzureWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret` key whose value\ndoes NOT need to be shared directly with Azure when registering a webhook.\nIt is used only by Kargo to create a complex, hard-to-guess URL,\nwhich implicitly serves as a shared secret. For more information about\nAzure webhooks, please refer to the Azure documentation:\n\n Azure Container Registry:\n\thttps://learn.microsoft.com/en-us/azure/container-registry/container-registry-repositories\n\n Azure DevOps:\n\thttp://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "BitbucketWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret` key whose\nvalue is the shared secret used to authenticate the webhook requests sent\nby Bitbucket. For more information please refer to the Bitbucket\ndocumentation:\n https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "Chart": { + "type": "object", + "properties": { + "name": { + "description": "Name specifies the name of the chart.", + "type": "string" + }, + "repoURL": { + "description": "RepoURL specifies the URL of a Helm chart repository. Classic chart\nrepositories (using HTTP/S) can contain differently named charts. When this\nfield points to such a repository, the Name field will specify the name of\nthe chart within the repository. In the case of a repository within an OCI\nregistry, the URL implicitly points to a specific chart and the Name field\nwill be empty.", + "type": "string" + }, + "version": { + "description": "Version specifies a particular version of the chart.", + "type": "string" + } + } + }, + "ChartDiscoveryResult": { + "type": "object", + "properties": { + "name": { + "description": "Name is the name of the Helm chart, as specified in the ChartSubscription.", + "type": "string" + }, + "repoURL": { + "description": "RepoURL is the repository URL of the Helm chart, as specified in the\nChartSubscription.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + }, + "semverConstraint": { + "description": "SemverConstraint is the constraint for which versions were discovered.\nThis field is optional, and only populated if the ChartSubscription\nspecifies a SemverConstraint.", + "type": "string" + }, + "versions": { + "description": "Versions is a list of versions discovered by the Warehouse for the\nChartSubscription. An empty list indicates that the discovery operation was\nsuccessful, but no versions matching the ChartSubscription criteria were\nfound.\n\n+optional", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "ClusterConfig": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes the configuration of a cluster.", + "allOf": [ + { + "$ref": "#/definitions/ClusterConfigSpec" + } + ] + }, + "status": { + "description": "Status describes the current status of a ClusterConfig.", + "allOf": [ + { + "$ref": "#/definitions/ClusterConfigStatus" + } + ] + } + } + }, + "ClusterConfigSpec": { + "type": "object", + "properties": { + "webhookReceivers": { + "description": "WebhookReceivers describes cluster-scoped webhook receivers used for\nprocessing events from various external platforms", + "type": "array", + "items": { + "$ref": "#/definitions/WebhookReceiverConfig" + } + } + } + }, + "ClusterConfigStatus": { + "type": "object", + "properties": { + "conditions": { + "description": "Conditions contains the last observations of the ClusterConfig's current\nstate.\n\n+patchMergeKey=type\n+patchStrategy=merge\n+listType=map\n+listMapKey=type", + "type": "array", + "items": { + "$ref": "#/definitions/V1Condition" + } + }, + "lastHandledRefresh": { + "description": "LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh\nannotation that was handled by the controller. This field can be used to\ndetermine whether the request to refresh the resource has been handled.\n+optional", + "type": "string" + }, + "observedGeneration": { + "description": "ObservedGeneration represents the .metadata.generation that this\nClusterConfig was reconciled against.", + "type": "integer" + }, + "webhookReceivers": { + "description": "WebhookReceivers describes the status of cluster-scoped webhook receivers.", + "type": "array", + "items": { + "$ref": "#/definitions/WebhookReceiverDetails" + } + } + } + }, + "ClusterPromotionTask": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes the desired transition of a specific Stage into a specific\nFreight.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/PromotionTaskSpec" + } + ] + } + }, + "required": [ + "spec" + ] + }, + "ClusterPromotionTaskList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/ClusterPromotionTask" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "CurrentStage": { + "type": "object", + "properties": { + "since": { + "description": "Since is the time at which the Stage most recently started using the\nFreight. This can be used to calculate how long the Freight has been in use\nby the Stage.", + "type": "string" + } + } + }, + "DiscoveredArtifacts": { + "type": "object", + "properties": { + "charts": { + "description": "Charts holds the charts discovered by the Warehouse for the chart\nsubscriptions.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/ChartDiscoveryResult" + } + }, + "discoveredAt": { + "description": "DiscoveredAt is the time at which the Warehouse discovered the artifacts.\n\n+optional", + "type": "string" + }, + "git": { + "description": "Git holds the commits discovered by the Warehouse for the Git\nsubscriptions.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/GitDiscoveryResult" + } + }, + "images": { + "description": "Images holds the image references discovered by the Warehouse for the\nimage subscriptions.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/ImageDiscoveryResult" + } + }, + "results": { + "description": "Results holds the artifact references discovered by the Warehouse.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/DiscoveryResult" + } + } + } + }, + "DiscoveredCommit": { + "type": "object", + "properties": { + "author": { + "description": "Author is the author of the commit.", + "type": "string" + }, + "branch": { + "description": "Branch is the branch in which the commit was found. This field is\noptional, and populated based on the CommitSelectionStrategy of the\nGitSubscription.", + "type": "string" + }, + "committer": { + "description": "Committer is the person who committed the commit.", + "type": "string" + }, + "creatorDate": { + "description": "CreatorDate is the commit creation date as specified by the commit, or\nthe tagger date if the commit belongs to an annotated tag.", + "type": "string" + }, + "id": { + "description": "ID is the identifier of the commit. This typically is a SHA-1 hash.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + }, + "subject": { + "description": "Subject is the subject of the commit (i.e. the first line of the commit\nmessage).", + "type": "string" + }, + "tag": { + "description": "Tag is the tag that resolved to this commit. This field is optional, and\npopulated based on the CommitSelectionStrategy of the GitSubscription.", + "type": "string" + } + } + }, + "DiscoveredImageReference": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is a map of key-value pairs that provide additional\ninformation about the image.", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "createdAt": { + "description": "CreatedAt is the time the image was created. This field is optional, and\nnot populated for every ImageSelectionStrategy.", + "type": "string" + }, + "digest": { + "description": "Digest is the digest of the image.\n\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:Pattern=`^[a-z0-9]+:[a-f0-9]+$`\n+akuity:test-kubebuilder-pattern=Digest", + "type": "string" + }, + "tag": { + "description": "Tag is the tag of the image.\n\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:MaxLength=128\n+kubebuilder:validation:Pattern=`^[\\w.\\-\\_]+$`\n+akuity:test-kubebuilder-pattern=Tag", + "type": "string" + } + } + }, + "DiscoveryResult": { + "type": "object", + "properties": { + "artifactReferences": { + "description": "ArtifactReferences is a list of references to specific versions of an\nartifact.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/ArtifactReference" + } + }, + "name": { + "description": "SubscriptionName is the name of the Subscription that discovered these\nresults.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + } + } + }, + "DockerHubWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nThe Secret's data map is expected to contain a `secret` key whose value\ndoes NOT need to be shared directly with Docker Hub when registering a\nwebhook. It is used only by Kargo to create a complex, hard-to-guess URL,\nwhich implicitly serves as a shared secret. For more information about\nDocker Hub webhooks, please refer to the Docker documentation:\n https://docs.docker.com/docker-hub/webhooks/\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "ExpressionVariable": { + "type": "object", + "properties": { + "name": { + "description": "Name is the name of the variable.\n\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:Pattern=^[a-zA-Z_]\\w*$", + "type": "string" + }, + "value": { + "description": "Value is the value of the variable. It is allowed to utilize expressions\nin the value.\nSee https://docs.kargo.io/user-guide/reference-docs/expressions for details.", + "type": "string" + } + } + }, + "Freight": { + "type": "object", + "properties": { + "alias": { + "description": "Alias is a human-friendly alias for a piece of Freight. This is an optional\nfield. A defaulting webhook will sync this field with the value of the\nkargo.akuity.io/alias label. When the alias label is not present or differs\nfrom the value of this field, the defaulting webhook will set the label to\nthe value of this field. If the alias label is present and this field is\nempty, the defaulting webhook will set the value of this field to the value\nof the alias label. If this field is empty and the alias label is not\npresent, the defaulting webhook will choose an available alias and assign\nit to both the field and label.", + "type": "string" + }, + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "artifacts": { + "description": "Artifacts describes specific versions of artifacts other\nthan Git repository commits, container images, and Helm charts.", + "type": "array", + "items": { + "$ref": "#/definitions/ArtifactReference" + } + }, + "charts": { + "description": "Charts describes specific versions of specific Helm charts.", + "type": "array", + "items": { + "$ref": "#/definitions/Chart" + } + }, + "commits": { + "description": "Commits describes specific Git repository commits.", + "type": "array", + "items": { + "$ref": "#/definitions/GitCommit" + } + }, + "images": { + "description": "Images describes specific versions of specific container images.", + "type": "array", + "items": { + "$ref": "#/definitions/Image" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "origin": { + "description": "Origin describes a kind of Freight in terms of its origin.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/FreightOrigin" + } + ] + }, + "status": { + "description": "Status describes the current status of this Freight.", + "allOf": [ + { + "$ref": "#/definitions/FreightStatus" + } + ] + } + }, + "required": [ + "origin" + ] + }, + "FreightCollection": { + "type": "object", + "properties": { + "id": { + "description": "ID is a unique and deterministically calculated identifier for the\nFreightCollection. It is updated on each use of the UpdateOrPush method.", + "type": "string" + }, + "items": { + "description": "Freight is a map of FreightReference objects, indexed by their Warehouse\norigin.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/FreightReference" + } + }, + "verificationHistory": { + "description": "VerificationHistory is a stack of recent VerificationInfo. By default,\nthe last ten VerificationInfo are stored.", + "type": "array", + "items": { + "$ref": "#/definitions/VerificationInfo" + } + } + } + }, + "FreightCreationCriteria": { + "type": "object", + "properties": { + "expression": { + "description": "Expression is an expr-lang expression that must evaluate to true for\nFreight to be created automatically from new artifacts following discovery.", + "type": "string" + } + } + }, + "FreightOrigin": { + "type": "object", + "properties": { + "kind": { + "description": "Kind is the kind of resource from which Freight may have originated. At\npresent, this can only be \"Warehouse\".\n\n+kubebuilder:validation:Required", + "type": "string" + }, + "name": { + "description": "Name is the name of the resource of the kind indicated by the Kind field\nfrom which Freight may originate.\n\n+kubebuilder:validation:Required", + "type": "string" + } + }, + "required": [ + "kind", + "name" + ] + }, + "FreightReference": { + "type": "object", + "properties": { + "artifacts": { + "description": "Artifacts describes specific versions of artifacts other\nthan Git repository commits, container images, and Helm charts.", + "type": "array", + "items": { + "$ref": "#/definitions/ArtifactReference" + } + }, + "charts": { + "description": "Charts describes specific versions of specific Helm charts.", + "type": "array", + "items": { + "$ref": "#/definitions/Chart" + } + }, + "commits": { + "description": "Commits describes specific Git repository commits.", + "type": "array", + "items": { + "$ref": "#/definitions/GitCommit" + } + }, + "images": { + "description": "Images describes specific versions of specific container images.", + "type": "array", + "items": { + "$ref": "#/definitions/Image" + } + }, + "name": { + "description": "Name is a system-assigned identifier derived deterministically from\nthe contents of the Freight. I.e., two pieces of Freight can be compared\nfor equality by comparing their Names.", + "type": "string" + }, + "origin": { + "description": "Origin describes a kind of Freight in terms of its origin.", + "allOf": [ + { + "$ref": "#/definitions/FreightOrigin" + } + ] + } + } + }, + "FreightRequest": { + "type": "object", + "properties": { + "origin": { + "description": "Origin specifies from where the requested Freight must have originated.\nThis is a required field.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/FreightOrigin" + } + ] + }, + "sources": { + "description": "Sources describes where the requested Freight may be obtained from. This is\na required field.", + "allOf": [ + { + "$ref": "#/definitions/FreightSources" + } + ] + } + }, + "required": [ + "origin" + ] + }, + "FreightSources": { + "type": "object", + "properties": { + "autoPromotionOptions": { + "description": "AutoPromotionOptions specifies options pertaining to auto-promotion. These\nsettings have no effect if auto-promotion is not enabled for this Stage at\nthe ProjectConfig level.", + "allOf": [ + { + "$ref": "#/definitions/AutoPromotionOptions" + } + ] + }, + "availabilityStrategy": { + "description": "AvailabilityStrategy specifies the semantics for how requested Freight is\nmade available to the Stage. This field is optional. When left unspecified,\nthe field is implicitly treated as if its value were \"OneOf\".\n\nAccepted Values:\n\n- \"All\": Freight must be verified and, if applicable, soaked in all\n upstream Stages to be considered available for promotion.\n- \"OneOf\": Freight must be verified and, if applicable, soaked in at least\n one upstream Stage to be considered available for promotion.\n- \"\": Treated the same as \"OneOf\".\n\n+kubebuilder:validation:Optional", + "type": "string" + }, + "direct": { + "description": "Direct indicates the requested Freight may be obtained directly from the\nWarehouse from which it originated. If this field's value is false, then\nthe value of the Stages field must be non-empty. i.e. Between the two\nfields, at least one source must be specified.", + "type": "boolean" + }, + "requiredSoakTime": { + "description": "RequiredSoakTime specifies a minimum duration for which the requested\nFreight must have continuously occupied (\"soaked in\") in an upstream Stage\nbefore becoming available for promotion to this Stage. This is an optional\nfield. If nil or zero, no soak time is required. Any soak time requirement\nis in ADDITION to the requirement that Freight be verified in an upstream\nStage to become available for promotion to this Stage, although a manual\napproval for promotion to this Stage will supersede any soak time\nrequirement.\n\n+kubebuilder:validation:Type=string\n+kubebuilder:validation:Pattern=`^([0-9]+(\\.[0-9]+)?(s|m|h))+$`\n+akuity:test-kubebuilder-pattern=Duration", + "type": "string" + }, + "stages": { + "description": "Stages identifies other \"upstream\" Stages as potential sources of the\nrequested Freight. If this field's value is empty, then the value of the\nDirect field must be true. i.e. Between the two fields, at least on source\nmust be specified.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "FreightStatus": { + "type": "object", + "properties": { + "approvedFor": { + "description": "ApprovedFor describes the Stages for which this Freight has been approved\npreemptively/manually by a user. This is useful for hotfixes, where one\nmight wish to promote a piece of Freight to a given Stage without\ntransiting the entire pipeline.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ApprovedStage" + } + }, + "currentlyIn": { + "description": "CurrentlyIn describes the Stages in which this Freight is currently in use.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/CurrentStage" + } + }, + "metadata": { + "description": "Metadata is a map of arbitrary metadata associated with the Freight.\nThis is useful for storing additional information about the Freight\nor Promotion that can be shared across steps or stages.", + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "verifiedIn": { + "description": "VerifiedIn describes the Stages in which this Freight has been verified\nthrough promotion and subsequent health checks.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/VerifiedStage" + } + } + } + }, + "GenericWebhookAction": { + "type": "object", + "properties": { + "action": { + "description": "ActionType indicates the type of action to be performed. `Refresh` is the\nonly currently supported action.\n\n+kubebuilder:validation:Enum=Refresh;", + "type": "string" + }, + "parameters": { + "description": "Parameters contains additional, action-specific parameters. Values may be\nstatic or extracted from the request using expressions.\n\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "targetSelectionCriteria": { + "description": "TargetSelectionCriteria is a list of selection criteria for the resources on which the\naction should be performed.\n\n+kubebuilder:validation:MinItems=1", + "type": "array", + "items": { + "$ref": "#/definitions/GenericWebhookTargetSelectionCriteria" + } + }, + "whenExpression": { + "description": "WhenExpression defines criteria that a request must meet to run this\naction.\n\n+optional", + "type": "string" + } + } + }, + "GenericWebhookReceiverConfig": { + "type": "object", + "properties": { + "actions": { + "description": "Actions is a list of actions to be performed when a webhook event is received.\n\n+kubebuilder:validation:MinItems=1", + "type": "array", + "items": { + "$ref": "#/definitions/GenericWebhookAction" + } + }, + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret` key whose value\ndoes NOT need to be shared directly with the sender. It is used only by\nKargo to create a complex, hard-to-guess URL, which implicitly serves as a\nshared secret.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "GenericWebhookTargetSelectionCriteria": { + "type": "object", + "properties": { + "indexSelector": { + "description": "IndexSelector is a selector used to identify cached target resources by cache key.\nIf used with LabelSelector and/or Name, the results are the combined (logical AND) of all the criteria.\n\n+optional", + "allOf": [ + { + "$ref": "#/definitions/IndexSelector" + } + ] + }, + "kind": { + "description": "Kind is the kind of the target resource.\n\n+kubebuilder:validation:Enum=Warehouse;", + "type": "string" + }, + "labelSelector": { + "description": "LabelSelector is a label selector to identify the target resources.\nIf used with IndexSelector and/or Name, the results are the combined (logical AND) of all the criteria.\n\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "name": { + "description": "Name is the name of the target resource. If LabelSelector and/or IndexSelectors\nare also specified, the results are the combined (logical AND) of the criteria.\n\n+optional", + "type": "string" + } + } + }, + "GitCommit": { + "type": "object", + "properties": { + "author": { + "description": "Author is the author of the commit.", + "type": "string" + }, + "branch": { + "description": "Branch denotes the branch of the repository where this commit was found.", + "type": "string" + }, + "committer": { + "description": "Committer is the person who committed the commit.", + "type": "string" + }, + "id": { + "description": "ID is the ID of a specific commit in the Git repository specified by\nRepoURL.", + "type": "string" + }, + "message": { + "description": "Message is the message associated with the commit. At present, this only\ncontains the first line (subject) of the commit message.", + "type": "string" + }, + "repoURL": { + "description": "RepoURL is the URL of a Git repository.", + "type": "string" + }, + "tag": { + "description": "Tag denotes a tag in the repository that matched selection criteria and\nresolved to this commit.", + "type": "string" + } + } + }, + "GitDiscoveryResult": { + "type": "object", + "properties": { + "commits": { + "description": "Commits is a list of commits discovered by the Warehouse for the\nGitSubscription. An empty list indicates that the discovery operation was\nsuccessful, but no commits matching the GitSubscription criteria were found.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/DiscoveredCommit" + } + }, + "repoURL": { + "description": "RepoURL is the repository URL of the GitSubscription.\n\nTODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern.\n\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:Pattern=`(?:^(ssh|https?)://(?:([\\w-]+)(:(.+))?@)?([\\w-]+(?:\\.[\\w-]+)*)(?::(\\d{1,5}))?(/.*)$)|(?:^([\\w-]+)@([\\w+]+(?:\\.[\\w-]+)*):(/?.*))`\n+akuity:test-kubebuilder-pattern=GitRepoURLPattern", + "type": "string" + } + } + }, + "GitHubWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret` key whose value is\nthe shared secret used to authenticate the webhook requests sent by GitHub.\nFor more information please refer to GitHub documentation:\n https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "GitLabWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe secret is expected to contain a `secret-token` key containing the\nshared secret specified when registering the webhook in GitLab. For more\ninformation about this token, please refer to the GitLab documentation:\n https://docs.gitlab.com/user/project/integrations/webhooks/\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "GiteaWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret` key whose value is\nthe shared secret used to authenticate the webhook requests sent by Gitea.\nFor more information please refer to the Gitea documentation:\n https://docs.gitea.io/en-us/webhooks/\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "HarborWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe secret is expected to contain an `auth-header` key containing the \"auth\nheader\" specified when registering the webhook in Harbor. For more\ninformation, please refer to the Harbor documentation:\n https://goharbor.io/docs/main/working-with-projects/project-configuration/configure-webhooks/\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "Health": { + "type": "object", + "properties": { + "config": { + "description": "Config is the opaque configuration of all health checks performed on this\nStage.", + "type": "object" + }, + "issues": { + "description": "Issues clarifies why a Stage in any state other than Healthy is in that\nstate. This field will always be the empty when a Stage is Healthy.", + "type": "array", + "items": { + "type": "string" + } + }, + "output": { + "description": "Output is the opaque output of all health checks performed on this Stage.", + "type": "object" + }, + "status": { + "description": "Status describes the health of the Stage.", + "type": "string" + } + } + }, + "HealthCheckStep": { + "type": "object", + "properties": { + "config": { + "description": "Config is the configuration for the directive.", + "type": "object" + }, + "uses": { + "description": "Uses identifies a runner that can execute this step.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + } + } + }, + "HealthStats": { + "type": "object", + "properties": { + "healthy": { + "description": "Healthy contains the number of resources that are explicitly healthy.", + "type": "integer" + } + } + }, + "Image": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is a map of arbitrary metadata for the image.", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "digest": { + "description": "Digest identifies a specific version of the image in the repository\nspecified by RepoURL. This is a more precise identifier than Tag.", + "type": "string" + }, + "repoURL": { + "description": "RepoURL describes the repository in which the image can be found.", + "type": "string" + }, + "tag": { + "description": "Tag identifies a specific version of the image in the repository specified\nby RepoURL.", + "type": "string" + } + } + }, + "ImageDiscoveryResult": { + "type": "object", + "properties": { + "platform": { + "description": "Platform is the target platform constraint of the ImageSubscription\nfor which references were discovered. This field is optional, and\nonly populated if the ImageSubscription specifies a Platform.", + "type": "string" + }, + "references": { + "description": "References is a list of image references discovered by the Warehouse for\nthe ImageSubscription. An empty list indicates that the discovery\noperation was successful, but no images matching the ImageSubscription\ncriteria were found.\n\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/DiscoveredImageReference" + } + }, + "repoURL": { + "description": "RepoURL is the repository URL of the image, as specified in the\nImageSubscription.\n\n+kubebuilder:validation:MinLength=1", + "type": "string" + } + } + }, + "IndexSelector": { + "type": "object", + "properties": { + "matchIndices": { + "description": "MatchIndices is a list of index selector requirements.\n\n+kubebuilder:validation:MinItems=1", + "type": "array", + "items": { + "$ref": "#/definitions/IndexSelectorRequirement" + } + } + } + }, + "IndexSelectorRequirement": { + "type": "object", + "properties": { + "key": { + "description": "Key is the key of the index.\n\n+kubebuilder:validation:Enum=subscribedURLs;receiverPaths", + "type": "string" + }, + "operator": { + "description": "Operator indicates the operation that should be used to evaluate\nwhether the selection requirement is satisfied.\n\nkubebuilder:validation:Enum=Equal;NotEqual;", + "type": "string" + }, + "value": { + "description": "Value can be a static string or an expression that will be evaluated.\n\nkubebuilder:validation:Required", + "type": "string" + } + } + }, + "Project": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "status": { + "description": "Status describes the Project's current status.", + "allOf": [ + { + "$ref": "#/definitions/ProjectStatus" + } + ] + } + } + }, + "ProjectConfig": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes the configuration of a Project.", + "allOf": [ + { + "$ref": "#/definitions/ProjectConfigSpec" + } + ] + }, + "status": { + "description": "Status describes the current status of a ProjectConfig.", + "allOf": [ + { + "$ref": "#/definitions/ProjectConfigStatus" + } + ] + } + } + }, + "ProjectConfigSpec": { + "type": "object", + "properties": { + "promotionPolicies": { + "description": "PromotionPolicies defines policies governing the promotion of Freight to\nspecific Stages within the Project.", + "type": "array", + "items": { + "$ref": "#/definitions/PromotionPolicy" + } + }, + "webhookReceivers": { + "description": "WebhookReceivers describes Project-specific webhook receivers used for\nprocessing events from various external platforms", + "type": "array", + "items": { + "$ref": "#/definitions/WebhookReceiverConfig" + } + } + } + }, + "ProjectConfigStatus": { + "type": "object", + "properties": { + "conditions": { + "description": "Conditions contains the last observations of the Project Config's current\nstate.\n\n+patchMergeKey=type\n+patchStrategy=merge\n+listType=map\n+listMapKey=type", + "type": "array", + "items": { + "$ref": "#/definitions/V1Condition" + } + }, + "lastHandledRefresh": { + "description": "LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh\nannotation that was handled by the controller. This field can be used to\ndetermine whether the request to refresh the resource has been handled.\n+optional", + "type": "string" + }, + "observedGeneration": { + "description": "ObservedGeneration represents the .metadata.generation that this\nProjectConfig was reconciled against.", + "type": "integer" + }, + "webhookReceivers": { + "description": "WebhookReceivers describes the status of Project-specific webhook\nreceivers.", + "type": "array", + "items": { + "$ref": "#/definitions/WebhookReceiverDetails" + } + } + } + }, + "ProjectList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Project" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "ProjectStats": { + "type": "object", + "properties": { + "stages": { + "description": "Stages contains a summary of the collective state of the Project's Stages.", + "allOf": [ + { + "$ref": "#/definitions/StageStats" + } + ] + }, + "warehouses": { + "description": "Warehouses contains a summary of the collective state of the Project's\nWarehouses.", + "allOf": [ + { + "$ref": "#/definitions/WarehouseStats" + } + ] + } + } + }, + "ProjectStatus": { + "type": "object", + "properties": { + "conditions": { + "description": "Conditions contains the last observations of the Project's current\nstate.\n+patchMergeKey=type\n+patchStrategy=merge\n+listType=map\n+listMapKey=type", + "type": "array", + "items": { + "$ref": "#/definitions/V1Condition" + } + }, + "stats": { + "description": "Stats contains a summary of the collective state of a Project's\nconstituent resources.", + "allOf": [ + { + "$ref": "#/definitions/ProjectStats" + } + ] + } + } + }, + "Promotion": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes the desired transition of a specific Stage into a specific\nFreight.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/PromotionSpec" + } + ] + }, + "status": { + "description": "Status describes the current state of the transition represented by this\nPromotion.", + "allOf": [ + { + "$ref": "#/definitions/PromotionStatus" + } + ] + } + }, + "required": [ + "spec" + ] + }, + "PromotionList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Promotion" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "PromotionPolicy": { + "type": "object", + "properties": { + "autoPromotionEnabled": { + "description": "AutoPromotionEnabled indicates whether new Freight can automatically be\npromoted into the Stage referenced by the Stage field. Note: There are may\nbe other conditions also required for an auto-promotion to occur. This\nfield defaults to false, but is commonly set to true for Stages that\nsubscribe to Warehouses instead of other, upstream Stages. This allows\nusers to define Stages that are automatically updated as soon as new\nartifacts are detected.", + "type": "boolean" + }, + "stage": { + "description": "Stage is the name of the Stage to which this policy applies.\n\nDeprecated: Use StageSelector instead.\n\n+kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$", + "type": "string" + }, + "stageSelector": { + "description": "StageSelector is a selector that matches the Stage resource to which\nthis policy applies.", + "allOf": [ + { + "$ref": "#/definitions/PromotionPolicySelector" + } + ] + } + } + }, + "PromotionPolicySelector": { + "type": "object", + "properties": { + "matchExpressions": { + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1LabelSelectorRequirement" + } + }, + "matchLabels": { + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels\nmap is equivalent to an element of matchExpressions, whose key field is \"key\", the\noperator is \"In\", and the values array contains only \"value\". The requirements are ANDed.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "name": { + "description": "Name is the name of the resource to which this policy applies.\n\nIt can be an exact name, a regex pattern (with prefix \"regex:\"), or a\nglob pattern (with prefix \"glob:\").\n\nWhen both Name and LabelSelector are specified, the Name is ANDed with\nthe LabelSelector. I.e., the resource must match both the Name and\nLabelSelector to be selected by this policy.\n\nNOTE: Using a specific exact name is the most secure option. Pattern\nmatching via regex or glob can be exploited by users with permissions to\nmatch promotion policies that weren't intended to apply to their\nresources. For example, a user could create a resource with a name\ndeliberately crafted to match the pattern, potentially bypassing intended\npromotion controls.\n\n+optional", + "type": "string" + } + } + }, + "PromotionReference": { + "type": "object", + "properties": { + "finishedAt": { + "description": "FinishedAt is the time at which the Promotion was completed.", + "type": "string" + }, + "freight": { + "description": "Freight is the freight being promoted.", + "allOf": [ + { + "$ref": "#/definitions/FreightReference" + } + ] + }, + "name": { + "description": "Name is the name of the Promotion.", + "type": "string" + }, + "status": { + "description": "Status is the (optional) status of the Promotion.", + "allOf": [ + { + "$ref": "#/definitions/PromotionStatus" + } + ] + } + } + }, + "PromotionSpec": { + "type": "object", + "properties": { + "freight": { + "description": "Freight specifies the piece of Freight to be promoted into the Stage\nreferenced by the Stage field.\n\n+kubebuilder:validation:Required\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:MaxLength=253\n+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`\n+akuity:test-kubebuilder-pattern=KubernetesName", + "type": "string" + }, + "stage": { + "description": "Stage specifies the name of the Stage to which this Promotion\napplies. The Stage referenced by this field MUST be in the same\nnamespace as the Promotion.\n\n+kubebuilder:validation:Required\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:MaxLength=253\n+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`\n+akuity:test-kubebuilder-pattern=KubernetesName", + "type": "string" + }, + "steps": { + "description": "Steps specifies the directives to be executed as part of this Promotion.\nThe order in which the directives are executed is the order in which they\nare listed in this field.\n\n+kubebuilder:validation:Required\n+kubebuilder:validation:MinItems=1\n+kubebuilder:validation:items:XValidation:message=\"Promotion step must have uses set and must not reference a task\",rule=\"has(self.uses) && !has(self.task)\"", + "type": "array", + "items": { + "$ref": "#/definitions/PromotionStep" + } + }, + "vars": { + "description": "Vars is a list of variables that can be referenced by expressions in\npromotion steps.", + "type": "array", + "items": { + "$ref": "#/definitions/ExpressionVariable" + } + } + }, + "required": [ + "freight", + "stage", + "steps" + ] + }, + "PromotionStatus": { + "type": "object", + "properties": { + "currentStep": { + "description": "CurrentStep is the index of the current promotion step being executed. This\npermits steps that have already run successfully to be skipped on\nsubsequent reconciliations attempts.", + "type": "integer" + }, + "finishedAt": { + "description": "FinishedAt is the time when the promotion was completed.", + "type": "string" + }, + "freight": { + "description": "Freight is the detail of the piece of freight that was referenced by this promotion.", + "allOf": [ + { + "$ref": "#/definitions/FreightReference" + } + ] + }, + "freightCollection": { + "description": "FreightCollection contains the details of the piece of Freight referenced\nby this Promotion as well as any additional Freight that is carried over\nfrom the target Stage's current state.", + "allOf": [ + { + "$ref": "#/definitions/FreightCollection" + } + ] + }, + "healthChecks": { + "description": "HealthChecks contains the health check directives to be executed after\nthe Promotion has completed.", + "type": "array", + "items": { + "$ref": "#/definitions/HealthCheckStep" + } + }, + "lastHandledRefresh": { + "description": "LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh\nannotation that was handled by the controller. This field can be used to\ndetermine whether the request to refresh the resource has been handled.\n+optional", + "type": "string" + }, + "message": { + "description": "Message is a display message about the promotion, including any errors\npreventing the Promotion controller from executing this Promotion.\ni.e. If the Phase field has a value of Failed, this field can be expected\nto explain why.", + "type": "string" + }, + "phase": { + "description": "Phase describes where the Promotion currently is in its lifecycle.", + "type": "string" + }, + "startedAt": { + "description": "StartedAt is the time when the promotion started.", + "type": "string" + }, + "state": { + "description": "State stores the state of the promotion process between reconciliation\nattempts.", + "type": "object" + }, + "stepExecutionMetadata": { + "description": "StepExecutionMetadata tracks metadata pertaining to the execution\nof individual promotion steps.", + "type": "array", + "items": { + "$ref": "#/definitions/StepExecutionMetadata" + } + } + } + }, + "PromotionStep": { + "type": "object", + "properties": { + "as": { + "description": "As is the alias this step can be referred to as.", + "type": "string" + }, + "config": { + "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/user-guide/reference-docs/expressions for details.", + "type": "object" + }, + "continueOnError": { + "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.", + "type": "boolean" + }, + "if": { + "description": "If is an optional expression that, if present, must evaluate to a boolean\nvalue. If the expression evaluates to false, the step will be skipped.\nIf the expression does not evaluate to a boolean value, the step will be\nconsidered to have failed.", + "type": "string" + }, + "retry": { + "description": "Retry is the retry policy for this step.", + "allOf": [ + { + "$ref": "#/definitions/PromotionStepRetry" + } + ] + }, + "task": { + "description": "Task is a reference to a PromotionTask that should be inflated into a\nPromotion when it is built from a PromotionTemplate.", + "allOf": [ + { + "$ref": "#/definitions/PromotionTaskReference" + } + ] + }, + "uses": { + "description": "Uses identifies a runner that can execute this step.\n\n+kubebuilder:validation:Optional\n+kubebuilder:validation:MinLength=1", + "type": "string" + }, + "vars": { + "description": "Vars is a list of variables that can be referenced by expressions in\nthe step's Config. The values override the values specified in the\nPromotionSpec.", + "type": "array", + "items": { + "$ref": "#/definitions/ExpressionVariable" + } + } + } + }, + "PromotionStepRetry": { + "type": "object", + "properties": { + "errorThreshold": { + "description": "ErrorThreshold is the number of consecutive times the step must fail (for\nany reason) before retries are abandoned and the entire Promotion is marked\nas failed.\n\nIf this field is set to 0, the effective default will be a step-specific\none. If no step-specific default exists (i.e. is also 0), the effective\ndefault will be the system-wide default of 1.\n\nA value of 1 will cause the Promotion to be marked as failed after just\na single failure; i.e. no retries will be attempted.\n\nThere is no option to specify an infinite number of retries using a value\nsuch as -1.\n\nIn a future release, Kargo is likely to become capable of distinguishing\nbetween recoverable and non-recoverable step failures. At that time, it is\nplanned that unrecoverable failures will not be subject to this threshold\nand will immediately cause the Promotion to be marked as failed without\nfurther condition.", + "type": "integer" + }, + "timeout": { + "description": "Timeout is the soft maximum interval in which a step that returns a Running\nstatus (which typically indicates it's waiting for something to happen)\nmay be retried.\n\nThe maximum is a soft one because the check for whether the interval has\nelapsed occurs AFTER the step has run. This effectively means a step may\nrun ONCE beyond the close of the interval.\n\nIf this field is set to nil, the effective default will be a step-specific\none. If no step-specific default exists (i.e. is also nil), the effective\ndefault will be the system-wide default of 0.\n\nA value of 0 will cause the step to be retried indefinitely unless the\nErrorThreshold is reached.", + "type": "string" + } + } + }, + "PromotionTask": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes the composition of a PromotionTask, including the\nvariables available to the task and the steps.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/PromotionTaskSpec" + } + ] + } + }, + "required": [ + "spec" + ] + }, + "PromotionTaskList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/PromotionTask" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "PromotionTaskReference": { + "type": "object", + "properties": { + "kind": { + "description": "Kind is the type of the PromotionTask. Can be either PromotionTask or\nClusterPromotionTask, default is PromotionTask.\n\n+kubebuilder:validation:Optional\n+kubebuilder:validation:Enum=PromotionTask;ClusterPromotionTask", + "type": "string" + }, + "name": { + "description": "Name is the name of the (Cluster)PromotionTask.\n\n+kubebuilder:validation:Required\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:MaxLength=253\n+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`\n+akuity:test-kubebuilder-pattern=KubernetesName", + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "PromotionTaskSpec": { + "type": "object", + "properties": { + "steps": { + "description": "Steps specifies the directives to be executed as part of this\nPromotionTask. The steps as defined here are inflated into a\nPromotion when it is built from a PromotionTemplate.\n\n+kubebuilder:validation:Required\n+kubebuilder:validation:MinItems=1\n+kubebuilder:validation:items:XValidation:message=\"PromotionTask step must have uses set and must not reference another task\",rule=\"has(self.uses) && !has(self.task)\"", + "type": "array", + "items": { + "$ref": "#/definitions/PromotionStep" + } + }, + "vars": { + "description": "Vars specifies the variables available to the PromotionTask. The\nvalues of these variables are the default values that can be\noverridden by the step referencing the task.", + "type": "array", + "items": { + "$ref": "#/definitions/ExpressionVariable" + } + } + }, + "required": [ + "steps" + ] + }, + "PromotionTemplate": { + "type": "object", + "properties": { + "spec": { + "$ref": "#/definitions/PromotionTemplateSpec" + } + } + }, + "PromotionTemplateSpec": { + "type": "object", + "properties": { + "steps": { + "description": "Steps specifies the directives to be executed as part of a Promotion.\nThe order in which the directives are executed is the order in which they\nare listed in this field.\n\n+kubebuilder:validation:MinItems=1\n+kubebuilder:validation:items:XValidation:message=\"PromotionTemplate step must have exactly one of uses or task set\",rule=\"(has(self.uses) ? !has(self.task) : has(self.task))\"\n+kubebuilder:validation:items:XValidation:message=\"PromotionTemplate step referencing a task cannot set continueOnError\",rule=\"!has(self.task) || !has(self.continueOnError)\"\n+kubebuilder:validation:items:XValidation:message=\"PromotionTemplate step referencing a task cannot set retry\",rule=\"!has(self.task) || !has(self.retry)\"", + "type": "array", + "items": { + "$ref": "#/definitions/PromotionStep" + } + }, + "vars": { + "description": "Vars is a list of variables that can be referenced by expressions in\npromotion steps.", + "type": "array", + "items": { + "$ref": "#/definitions/ExpressionVariable" + } + } + } + }, + "QuayWebhookReceiverConfig": { + "type": "object", + "properties": { + "secretRef": { + "description": "SecretRef contains a reference to a Secret. For Project-scoped webhook\nreceivers, the referenced Secret must be in the same namespace as the\nProjectConfig.\n\nFor cluster-scoped webhook receivers, the referenced Secret must be in the\ndesignated \"system resources\" namespace.\n\nThe Secret's data map is expected to contain a `secret` key whose value\ndoes NOT need to be shared directly with Quay when registering a\nwebhook. It is used only by Kargo to create a complex, hard-to-guess URL,\nwhich implicitly serves as a shared secret. For more information about\nQuay webhooks, please refer to the Quay documentation:\n https://docs.quay.io/guides/notifications.html\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + }, + "required": [ + "secretRef" + ] + }, + "Stage": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes sources of Freight used by the Stage and how to incorporate\nFreight into the Stage.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/StageSpec" + } + ] + }, + "status": { + "description": "Status describes the Stage's current and recent Freight, health, and more.", + "allOf": [ + { + "$ref": "#/definitions/StageStatus" + } + ] + } + }, + "required": [ + "spec" + ] + }, + "StageList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Stage" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "StageSpec": { + "type": "object", + "properties": { + "promotionTemplate": { + "description": "PromotionTemplate describes how to incorporate Freight into the Stage\nusing a Promotion.", + "allOf": [ + { + "$ref": "#/definitions/PromotionTemplate" + } + ] + }, + "requestedFreight": { + "description": "RequestedFreight expresses the Stage's need for certain pieces of Freight,\neach having originated from a particular Warehouse. This list must be\nnon-empty. In the common case, a Stage will request Freight having\noriginated from just one specific Warehouse. In advanced cases, requesting\nFreight from multiple Warehouses provides a method of advancing new\nartifacts of different types through parallel pipelines at different\nspeeds. This can be useful, for instance, if a Stage is home to multiple\nmicroservices that are independently versioned.\n\n+kubebuilder:validation:MinItems=1", + "type": "array", + "items": { + "$ref": "#/definitions/FreightRequest" + } + }, + "shard": { + "description": "Shard is the name of the shard that this Stage belongs to. This is an\noptional field. If not specified, the Stage will belong to the default\nshard. A defaulting webhook will sync the value of the\nkargo.akuity.io/shard label with the value of this field. When this field\nis empty, the webhook will ensure that label is absent.", + "type": "string" + }, + "vars": { + "description": "Vars is a list of variables that can be referenced anywhere in the\nStageSpec that supports expressions. For example, the PromotionTemplate\nand arguments of the Verification.", + "type": "array", + "items": { + "$ref": "#/definitions/ExpressionVariable" + } + }, + "verification": { + "description": "Verification describes how to verify a Stage's current Freight is fit for\npromotion downstream.", + "allOf": [ + { + "$ref": "#/definitions/Verification" + } + ] + } + } + }, + "StageStats": { + "type": "object", + "properties": { + "count": { + "description": "Count contains the total number of Stages in the Project.", + "type": "integer" + }, + "health": { + "description": "Health contains a summary of the collective health of a Project's Stages.", + "allOf": [ + { + "$ref": "#/definitions/HealthStats" + } + ] + } + } + }, + "StageStatus": { + "type": "object", + "properties": { + "autoPromotionEnabled": { + "description": "AutoPromotionEnabled indicates whether automatic promotion is enabled\nfor the Stage based on the ProjectConfig.", + "type": "boolean" + }, + "conditions": { + "description": "Conditions contains the last observations of the Stage's current\nstate.\n+patchMergeKey=type\n+patchStrategy=merge\n+listType=map\n+listMapKey=type", + "type": "array", + "items": { + "$ref": "#/definitions/V1Condition" + } + }, + "currentPromotion": { + "description": "CurrentPromotion is a reference to the currently Running promotion.", + "allOf": [ + { + "$ref": "#/definitions/PromotionReference" + } + ] + }, + "freightHistory": { + "description": "FreightHistory is a list of recent Freight selections that were deployed\nto the Stage. By default, the last ten Freight selections are stored.\nThe first item in the list is the most recent Freight selection and\ncurrently deployed to the Stage, subsequent items are older selections.", + "type": "array", + "items": { + "$ref": "#/definitions/FreightCollection" + } + }, + "freightSummary": { + "description": "FreightSummary is human-readable text maintained by the controller that\nsummarizes what Freight is currently deployed to the Stage. For Stages that\nrequest a single piece of Freight AND the request has been fulfilled, this\nfield will simply contain the name of the Freight. For Stages that request\na single piece of Freight AND the request has NOT been fulfilled, or for\nStages that request multiple pieces of Freight, this field will contain a\nsummary of fulfilled/requested Freight. The existence of this field is a\nworkaround for kubectl limitations so that this complex but valuable\ninformation can be displayed in a column in response to `kubectl get\nstages`.", + "type": "string" + }, + "health": { + "description": "Health is the Stage's last observed health.", + "allOf": [ + { + "$ref": "#/definitions/Health" + } + ] + }, + "lastHandledRefresh": { + "description": "LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh\nannotation that was handled by the controller. This field can be used to\ndetermine whether the request to refresh the resource has been handled.\n+optional", + "type": "string" + }, + "lastPromotion": { + "description": "LastPromotion is a reference to the last completed promotion.", + "allOf": [ + { + "$ref": "#/definitions/PromotionReference" + } + ] + }, + "metadata": { + "description": "Metadata is a map of arbitrary metadata associated with the Stage.\nThis is useful for storing additional information about the Stage\nthat can be shared across promotions, verifications, or other processes.", + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "observedGeneration": { + "description": "ObservedGeneration represents the .metadata.generation that this Stage\nstatus was reconciled against.", + "type": "integer" + } + } + }, + "StepExecutionMetadata": { + "type": "object", + "properties": { + "alias": { + "description": "Alias is the alias of the step.", + "type": "string" + }, + "continueOnError": { + "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.", + "type": "boolean" + }, + "errorCount": { + "description": "ErrorCount tracks consecutive failed attempts to execute the step.", + "type": "integer" + }, + "finishedAt": { + "description": "FinishedAt is the time at which the final attempt to execute the step\ncompleted.", + "type": "string" + }, + "message": { + "description": "Message is a display message about the step, including any errors.", + "type": "string" + }, + "startedAt": { + "description": "StartedAt is the time at which the first attempt to execute the step\nbegan.", + "type": "string" + }, + "status": { + "description": "Status is the high-level outcome of the step.", + "type": "string" + } + } + }, + "Verification": { + "type": "object", + "properties": { + "analysisRunMetadata": { + "description": "AnalysisRunMetadata contains optional metadata that should be applied to\nall AnalysisRuns.", + "allOf": [ + { + "$ref": "#/definitions/AnalysisRunMetadata" + } + ] + }, + "analysisTemplates": { + "description": "AnalysisTemplates is a list of AnalysisTemplates from which AnalysisRuns\nshould be created to verify a Stage's current Freight is fit to be promoted\ndownstream.", + "type": "array", + "items": { + "$ref": "#/definitions/AnalysisTemplateReference" + } + }, + "args": { + "description": "Args lists arguments that should be added to all AnalysisRuns.", + "type": "array", + "items": { + "$ref": "#/definitions/AnalysisRunArgument" + } + } + } + }, + "VerificationInfo": { + "type": "object", + "properties": { + "actor": { + "description": "Actor is the name of the entity that initiated or aborted the\nVerification process.", + "type": "string" + }, + "analysisRun": { + "description": "AnalysisRun is a reference to the Argo Rollouts AnalysisRun that implements\nthe Verification process.", + "allOf": [ + { + "$ref": "#/definitions/AnalysisRunReference" + } + ] + }, + "finishTime": { + "description": "FinishTime is the time at which the Verification process finished.", + "type": "string" + }, + "id": { + "description": "ID is the identifier of the Verification process.", + "type": "string" + }, + "message": { + "description": "Message may contain additional information about why the verification\nprocess is in its current phase.", + "type": "string" + }, + "phase": { + "description": "Phase describes the current phase of the Verification process. Generally,\nthis will be a reflection of the underlying AnalysisRun's phase, however,\nthere are exceptions to this, such as in the case where an AnalysisRun\ncannot be launched successfully.", + "type": "string" + }, + "startTime": { + "description": "StartTime is the time at which the Verification process was started.", + "type": "string" + } + } + }, + "VerifiedStage": { + "type": "object", + "properties": { + "longestSoak": { + "description": "LongestCompletedSoak represents the longest definite time interval wherein\nthe Freight was in CONTINUOUS use by the Stage. This value is updated as\nFreight EXITS the Stage. If the Freight is currently in use by the Stage,\nthe time elapsed since the Freight ENTERED the Stage is its current soak\ntime, which may exceed the value of this field.", + "type": "string" + }, + "verifiedAt": { + "description": "VerifiedAt is the time at which the Freight was verified in the Stage.", + "type": "string" + } + } + }, + "Warehouse": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ObjectMeta" + }, + "spec": { + "description": "Spec describes sources of artifacts.\n\n+kubebuilder:validation:Required", + "allOf": [ + { + "$ref": "#/definitions/WarehouseSpec" + } + ] + }, + "status": { + "description": "Status describes the Warehouse's most recently observed state.", + "allOf": [ + { + "$ref": "#/definitions/WarehouseStatus" + } + ] + } + }, + "required": [ + "spec" + ] + }, + "WarehouseList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Warehouse" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/V1ListMeta" + } + } + }, + "WarehouseSpec": { + "type": "object", + "properties": { + "freightCreationCriteria": { + "description": "FreightCreationCriteria defines criteria that must be satisfied for Freight\nto be created automatically from new artifacts following discovery. This\nfield has no effect when the FreightCreationPolicy is `Manual`.\n\n+kubebuilder:validation:Optional", + "allOf": [ + { + "$ref": "#/definitions/FreightCreationCriteria" + } + ] + }, + "freightCreationPolicy": { + "description": "FreightCreationPolicy describes how Freight is created by this Warehouse.\nThis field is optional. When left unspecified, the field is implicitly\ntreated as if its value were \"Automatic\".\n\nAccepted values:\n\n- \"Automatic\": New Freight is created automatically when any new artifact\n is discovered.\n- \"Manual\": New Freight is never created automatically.\n\n+kubebuilder:default=Automatic\n+kubebuilder:validation:Optional", + "type": "string" + }, + "interval": { + "description": "Interval is the reconciliation interval for this Warehouse. On each\nreconciliation, the Warehouse will discover new artifacts and optionally\nproduce new Freight. This field is optional. When left unspecified, the\nfield is implicitly treated as if its value were \"5m0s\".\n\n+kubebuilder:validation:Type=string\n+kubebuilder:validation:Pattern=`^([0-9]+(\\.[0-9]+)?(s|m|h))+$`\n+kubebuilder:default=\"5m0s\"\n+akuity:test-kubebuilder-pattern=Duration", + "type": "string" + }, + "shard": { + "description": "Shard is the name of the shard that this Warehouse belongs to. This is an\noptional field. If not specified, the Warehouse will belong to the default\nshard. A defaulting webhook will sync this field with the value of the\nkargo.akuity.io/shard label. When the shard label is not present or differs\nfrom the value of this field, the defaulting webhook will set the label to\nthe value of this field. If the shard label is present and this field is\nempty, the defaulting webhook will set the value of this field to the value\nof the shard label.", + "type": "string" + }, + "subscriptions": { + "description": "Subscriptions describes sources of artifacts to be included in Freight\nproduced by this Warehouse.\n\n+kubebuilder:validation:MinItems=1", + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "WarehouseStats": { + "type": "object", + "properties": { + "count": { + "description": "Count contains the total number of Warehouses in the Project.", + "type": "integer" + }, + "health": { + "description": "Health contains a summary of the collective health of a Project's\nWarehouses.", + "allOf": [ + { + "$ref": "#/definitions/HealthStats" + } + ] + } + } + }, + "WarehouseStatus": { + "type": "object", + "properties": { + "conditions": { + "description": "Conditions contains the last observations of the Warehouse's current\nstate.\n+patchMergeKey=type\n+patchStrategy=merge\n+listType=map\n+listMapKey=type", + "type": "array", + "items": { + "$ref": "#/definitions/V1Condition" + } + }, + "discoveredArtifacts": { + "description": "DiscoveredArtifacts holds the artifacts discovered by the Warehouse.", + "allOf": [ + { + "$ref": "#/definitions/DiscoveredArtifacts" + } + ] + }, + "lastFreightID": { + "description": "LastFreightID is a reference to the system-assigned identifier (name) of\nthe most recent Freight produced by the Warehouse.", + "type": "string" + }, + "lastHandledRefresh": { + "description": "LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh\nannotation that was handled by the controller. This field can be used to\ndetermine whether the request to refresh the resource has been handled.\n+optional", + "type": "string" + }, + "observedGeneration": { + "description": "ObservedGeneration represents the .metadata.generation that this Warehouse\nwas reconciled against.", + "type": "integer" + } + } + }, + "WebhookReceiverConfig": { + "type": "object", + "properties": { + "artifactory": { + "description": "Artifactory contains the configuration for a webhook receiver that is\ncompatible with JFrog Artifactory payloads.", + "allOf": [ + { + "$ref": "#/definitions/ArtifactoryWebhookReceiverConfig" + } + ] + }, + "azure": { + "description": "Azure contains the configuration for a webhook receiver that is compatible\nwith Azure Container Registry (ACR) and Azure DevOps payloads.", + "allOf": [ + { + "$ref": "#/definitions/AzureWebhookReceiverConfig" + } + ] + }, + "bitbucket": { + "description": "Bitbucket contains the configuration for a webhook receiver that is\ncompatible with Bitbucket payloads.", + "allOf": [ + { + "$ref": "#/definitions/BitbucketWebhookReceiverConfig" + } + ] + }, + "dockerhub": { + "description": "DockerHub contains the configuration for a webhook receiver that is\ncompatible with DockerHub payloads.", + "allOf": [ + { + "$ref": "#/definitions/DockerHubWebhookReceiverConfig" + } + ] + }, + "generic": { + "description": "Generic contains the configuration for a generic webhook receiver.", + "allOf": [ + { + "$ref": "#/definitions/GenericWebhookReceiverConfig" + } + ] + }, + "gitea": { + "description": "Gitea contains the configuration for a webhook receiver that is compatible\nwith Gitea payloads.", + "allOf": [ + { + "$ref": "#/definitions/GiteaWebhookReceiverConfig" + } + ] + }, + "github": { + "description": "GitHub contains the configuration for a webhook receiver that is compatible\nwith GitHub payloads.", + "allOf": [ + { + "$ref": "#/definitions/GitHubWebhookReceiverConfig" + } + ] + }, + "gitlab": { + "description": "GitLab contains the configuration for a webhook receiver that is compatible\nwith GitLab payloads.", + "allOf": [ + { + "$ref": "#/definitions/GitLabWebhookReceiverConfig" + } + ] + }, + "harbor": { + "description": "Harbor contains the configuration for a webhook receiver that is compatible\nwith Harbor payloads.", + "allOf": [ + { + "$ref": "#/definitions/HarborWebhookReceiverConfig" + } + ] + }, + "name": { + "description": "Name is the name of the webhook receiver.\n\n+kubebuilder:validation:Required\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:MaxLength=253\n+kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`\n+akuity:test-kubebuilder-pattern=KubernetesName", + "type": "string" + }, + "quay": { + "description": "Quay contains the configuration for a webhook receiver that is compatible\nwith Quay payloads.", + "allOf": [ + { + "$ref": "#/definitions/QuayWebhookReceiverConfig" + } + ] + } + }, + "required": [ + "name" + ] + }, + "WebhookReceiverDetails": { + "type": "object", + "properties": { + "name": { + "description": "Name is the name of the webhook receiver.", + "type": "string" + }, + "path": { + "description": "Path is the path to the receiver's webhook endpoint.", + "type": "string" + }, + "url": { + "description": "URL includes the full address of the receiver's webhook endpoint.", + "type": "string" + } + } + }, + "IntOrString": { + "type": "object", + "properties": { + "intVal": { + "type": "integer" + }, + "strVal": { + "type": "string" + }, + "type": { + "type": "integer" + } + } + }, + "V1Event": { + "type": "object", + "properties": { + "action": { + "description": "What action was taken/failed regarding to the Regarding object.\n+optional", + "type": "string" + }, + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "count": { + "description": "The number of times this event has occurred.\n+optional", + "type": "integer" + }, + "eventTime": { + "description": "Time when this Event was first observed.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1MicroTime" + } + ] + }, + "firstTimestamp": { + "description": "The time at which the event was first recorded. (Time of server receipt is in TypeMeta.)\n+optional", + "type": "string" + }, + "involvedObject": { + "description": "The object that this event is about.", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectReference" + } + ] + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "lastTimestamp": { + "description": "The time at which the most recent occurrence of this event was recorded.\n+optional", + "type": "string" + }, + "message": { + "description": "A human-readable description of the status of this operation.\nTODO: decide on maximum length.\n+optional", + "type": "string" + }, + "metadata": { + "description": "Standard object's metadata.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectMeta" + } + ] + }, + "reason": { + "description": "This should be a short, machine understandable string that gives the reason\nfor the transition into the object's current status.\nTODO: provide exact specification for format.\n+optional", + "type": "string" + }, + "related": { + "description": "Optional secondary object for more complex actions.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectReference" + } + ] + }, + "reportingComponent": { + "description": "Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`.\n+optional", + "type": "string" + }, + "reportingInstance": { + "description": "ID of the controller instance, e.g. `kubelet-xyzf`.\n+optional", + "type": "string" + }, + "series": { + "description": "Data about the Event series this event represents or nil if it's a singleton Event.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1EventSeries" + } + ] + }, + "source": { + "description": "The component reporting this event. Should be a short machine understandable string.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1EventSource" + } + ] + }, + "type": { + "description": "Type of this event (Normal, Warning), new types could be added in the future\n+optional", + "type": "string" + } + } + }, + "V1EventList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "description": "List of events", + "type": "array", + "items": { + "$ref": "#/definitions/V1Event" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "description": "Standard list metadata.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ListMeta" + } + ] + } + } + }, + "V1EventSeries": { + "type": "object", + "properties": { + "count": { + "description": "Number of occurrences in this series up to the last heartbeat time", + "type": "integer" + }, + "lastObservedTime": { + "description": "Time of the last occurrence observed", + "allOf": [ + { + "$ref": "#/definitions/V1MicroTime" + } + ] + } + } + }, + "V1ResourceClaim": { + "type": "object", + "properties": { + "name": { + "description": "Name must match the name of one entry in pod.spec.resourceClaims of\nthe Pod where this field is used. It makes that resource available\ninside a container.", + "type": "string" + }, + "request": { + "description": "Request is the name chosen for a request in the referenced claim.\nIf empty, everything from the claim is made available, otherwise\nonly the result of this request.\n\n+optional", + "type": "string" + } + } + }, + "Quantity": { + "type": "object", + "properties": { + "Format": { + "type": "string", + "enum": [ + "DecimalExponent", + "BinarySI", + "DecimalSI" + ], + "x-enum-comments": { + "BinarySI": "e.g., 12Mi (12 * 2^20)", + "DecimalExponent": "e.g., 12e6", + "DecimalSI": "e.g., 12M (12 * 10^6)" + }, + "x-enum-descriptions": [ + "e.g., 12e6", + "e.g., 12Mi (12 * 2^20)", + "e.g., 12M (12 * 10^6)" + ], + "x-enum-varnames": [ + "DecimalExponent", + "BinarySI", + "DecimalSI" + ] + } + } + }, + "V1AWSElasticBlockStoreVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "partition": { + "description": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\n+optional", + "type": "integer" + }, + "readOnly": { + "description": "readOnly value true will force the readOnly setting in VolumeMounts.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional", + "type": "boolean" + }, + "volumeID": { + "description": "volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore", + "type": "string" + } + } + }, + "V1Affinity": { + "type": "object", + "properties": { + "nodeAffinity": { + "description": "Describes node affinity scheduling rules for the pod.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1NodeAffinity" + } + ] + }, + "podAffinity": { + "description": "Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)).\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodAffinity" + } + ] + }, + "podAntiAffinity": { + "description": "Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)).\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodAntiAffinity" + } + ] + } + } + }, + "V1AppArmorProfile": { + "type": "object", + "properties": { + "localhostProfile": { + "description": "localhostProfile indicates a profile loaded on the node that should be used.\nThe profile must be preconfigured on the node to work.\nMust match the loaded name of the profile.\nMust be set if and only if type is \"Localhost\".\n+optional", + "type": "string" + }, + "type": { + "description": "type indicates which kind of AppArmor profile will be applied.\nValid options are:\n Localhost - a profile pre-loaded on the node.\n RuntimeDefault - the container runtime's default profile.\n Unconfined - no AppArmor enforcement.\n+unionDiscriminator", + "type": "string" + } + } + }, + "V1AzureDiskVolumeSource": { + "type": "object", + "properties": { + "cachingMode": { + "description": "cachingMode is the Host Caching mode: None, Read Only, Read Write.\n+optional\n+default=ref(AzureDataDiskCachingReadWrite)", + "type": "string" + }, + "diskName": { + "description": "diskName is the Name of the data disk in the blob storage", + "type": "string" + }, + "diskURI": { + "description": "diskURI is the URI of data disk in the blob storage", + "type": "string" + }, + "fsType": { + "description": "fsType is Filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional\n+default=\"ext4\"", + "type": "string" + }, + "kind": { + "description": "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared\n+default=ref(AzureSharedBlobDisk)", + "type": "string" + }, + "readOnly": { + "description": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional\n+default=false", + "type": "boolean" + } + } + }, + "V1AzureFileVolumeSource": { + "type": "object", + "properties": { + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretName": { + "description": "secretName is the name of secret that contains Azure Storage Account Name and Key", + "type": "string" + }, + "shareName": { + "description": "shareName is the azure share Name", + "type": "string" + } + } + }, + "V1CSIVolumeSource": { + "type": "object", + "properties": { + "driver": { + "description": "driver is the name of the CSI driver that handles this volume.\nConsult with your admin for the correct name as registered in the cluster.", + "type": "string" + }, + "fsType": { + "description": "fsType to mount. Ex. \"ext4\", \"xfs\", \"ntfs\".\nIf not provided, the empty value is passed to the associated CSI driver\nwhich will determine the default filesystem to apply.\n+optional", + "type": "string" + }, + "nodePublishSecretRef": { + "description": "nodePublishSecretRef is a reference to the secret object containing\nsensitive information to pass to the CSI driver to complete the CSI\nNodePublishVolume and NodeUnpublishVolume calls.\nThis field is optional, and may be empty if no secret is required. If the\nsecret object contains more than one secret, all secret references are passed.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "readOnly": { + "description": "readOnly specifies a read-only configuration for the volume.\nDefaults to false (read/write).\n+optional", + "type": "boolean" + }, + "volumeAttributes": { + "description": "volumeAttributes stores driver-specific properties that are passed to the CSI\ndriver. Consult your driver's documentation for supported values.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "V1Capabilities": { + "type": "object", + "properties": { + "add": { + "description": "Added capabilities\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "drop": { + "description": "Removed capabilities\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1CephFSVolumeSource": { + "type": "object", + "properties": { + "monitors": { + "description": "monitors is Required: Monitors is a collection of Ceph monitors\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "path": { + "description": "path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "boolean" + }, + "secretFile": { + "description": "secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "string" + }, + "secretRef": { + "description": "secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty.\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "user": { + "description": "user is optional: User is the rados user name, default is admin\nMore info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it\n+optional", + "type": "string" + } + } + }, + "V1CinderVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is optional: points to a secret object containing parameters used to connect\nto OpenStack.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "volumeID": { + "description": "volumeID used to identify the volume in cinder.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md", + "type": "string" + } + } + }, + "V1ClusterTrustBundleProjection": { + "type": "object", + "properties": { + "labelSelector": { + "description": "Select all ClusterTrustBundles that match this label selector. Only has\neffect if signerName is set. Mutually-exclusive with name. If unset,\ninterpreted as \"match nothing\". If set but empty, interpreted as \"match\neverything\".\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "name": { + "description": "Select a single ClusterTrustBundle by object name. Mutually-exclusive\nwith signerName and labelSelector.\n+optional", + "type": "string" + }, + "optional": { + "description": "If true, don't block pod startup if the referenced ClusterTrustBundle(s)\naren't available. If using name, then the named ClusterTrustBundle is\nallowed not to exist. If using signerName, then the combination of\nsignerName and labelSelector is allowed to match zero\nClusterTrustBundles.\n+optional", + "type": "boolean" + }, + "path": { + "description": "Relative path from the volume root to write the bundle.", + "type": "string" + }, + "signerName": { + "description": "Select all ClusterTrustBundles that match this signer name.\nMutually-exclusive with name. The contents of all selected\nClusterTrustBundles will be unified and deduplicated.\n+optional", + "type": "string" + } + } + }, + "V1CompletionMode": { + "type": "string", + "enum": [ + "NonIndexed", + "Indexed" + ], + "x-enum-varnames": [ + "NonIndexedCompletion", + "IndexedCompletion" + ] + }, + "V1Condition": { + "type": "object", + "properties": { + "lastTransitionTime": { + "description": "lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.\n+required\n+kubebuilder:validation:Required\n+kubebuilder:validation:Type=string\n+kubebuilder:validation:Format=date-time", + "type": "string" + }, + "message": { + "description": "message is a human readable message indicating details about the transition.\nThis may be an empty string.\n+required\n+kubebuilder:validation:Required\n+kubebuilder:validation:MaxLength=32768", + "type": "string" + }, + "observedGeneration": { + "description": "observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.\n+optional\n+kubebuilder:validation:Minimum=0", + "type": "integer" + }, + "reason": { + "description": "reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.\n+required\n+kubebuilder:validation:Required\n+kubebuilder:validation:MaxLength=1024\n+kubebuilder:validation:MinLength=1\n+kubebuilder:validation:Pattern=`^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$`", + "type": "string" + }, + "status": { + "description": "status of the condition, one of True, False, Unknown.\n+required\n+kubebuilder:validation:Required\n+kubebuilder:validation:Enum=True;False;Unknown", + "type": "string" + }, + "type": { + "description": "type of condition in CamelCase or in foo.example.com/CamelCase.\n---\nMany .condition.type values are consistent across resources like Available, but because arbitrary conditions can be\nuseful (see .node.status.conditions), the ability to deconflict is important.\nThe regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)\n+required\n+kubebuilder:validation:Required\n+kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$`\n+kubebuilder:validation:MaxLength=316", + "type": "string" + } + }, + "required": [ + "lastTransitionTime", + "message", + "reason", + "status", + "type" + ] + }, + "V1ConfigMap": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "binaryData": { + "description": "BinaryData contains the binary data.\nEach key must consist of alphanumeric characters, '-', '_' or '.'.\nBinaryData can contain byte sequences that are not in the UTF-8 range.\nThe keys stored in BinaryData must not overlap with the ones in\nthe Data field, this is enforced during validation process.\nUsing this field will require 1.10+ apiserver and\nkubelet.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string", + "format": "byte" + } + }, + "data": { + "description": "Data contains the configuration data.\nEach key must consist of alphanumeric characters, '-', '_' or '.'.\nValues with non-UTF-8 byte sequences must use the BinaryData field.\nThe keys stored in Data must not overlap with the keys in\nthe BinaryData field, this is enforced during validation process.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "immutable": { + "description": "Immutable, if set to true, ensures that data stored in the ConfigMap cannot\nbe updated (only object metadata can be modified).\nIf not set to true, the field can be modified at any time.\nDefaulted to nil.\n+optional", + "type": "boolean" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "description": "Standard object's metadata.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectMeta" + } + ] + } + } + }, + "V1ConfigMapEnvSource": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "Specify whether the ConfigMap must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1ConfigMapKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key to select.", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "Specify whether the ConfigMap or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1ConfigMapList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "description": "Items is the list of ConfigMaps.", + "type": "array", + "items": { + "$ref": "#/definitions/V1ConfigMap" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "description": "More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ListMeta" + } + ] + } + } + }, + "V1ConfigMapProjection": { + "type": "object", + "properties": { + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "optional specify whether the ConfigMap or its keys must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1ConfigMapVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode is optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nConfigMap will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the ConfigMap,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "optional specify whether the ConfigMap or its keys must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1Container": { + "type": "object", + "properties": { + "args": { + "description": "Arguments to the entrypoint.\nThe container image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "command": { + "description": "Entrypoint array. Not executed within a shell.\nThe container image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "List of environment variables to set in the container.\nCannot be updated.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1EnvVar" + } + }, + "envFrom": { + "description": "List of sources to populate environment variables in the container.\nThe keys defined within a source may consist of any printable ASCII characters except '='.\nWhen a key exists in multiple\nsources, the value associated with the last source will take precedence.\nValues defined by an Env with a duplicate key will take precedence.\nCannot be updated.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1EnvFromSource" + } + }, + "image": { + "description": "Container image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images\nThis field is optional to allow higher level config management to default or override\ncontainer images in workload controllers like Deployments and StatefulSets.\n+optional", + "type": "string" + }, + "imagePullPolicy": { + "description": "Image pull policy.\nOne of Always, Never, IfNotPresent.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n+optional", + "type": "string" + }, + "lifecycle": { + "description": "Actions that the management system should take in response to container lifecycle events.\nCannot be updated.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Lifecycle" + } + ] + }, + "livenessProbe": { + "description": "Periodic probe of container liveness.\nContainer will be restarted if the probe fails.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Probe" + } + ] + }, + "name": { + "description": "Name of the container specified as a DNS_LABEL.\nEach container in a pod must have a unique name (DNS_LABEL).\nCannot be updated.", + "type": "string" + }, + "ports": { + "description": "List of ports to expose from the container. Not specifying a port here\nDOES NOT prevent that port from being exposed. Any port which is\nlistening on the default \"0.0.0.0\" address inside a container will be\naccessible from the network.\nModifying this array with strategic merge patch may corrupt the data.\nFor more information See https://github.com/kubernetes/kubernetes/issues/108255.\nCannot be updated.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol", + "type": "array", + "items": { + "$ref": "#/definitions/V1ContainerPort" + } + }, + "readinessProbe": { + "description": "Periodic probe of container service readiness.\nContainer will be removed from service endpoints if the probe fails.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Probe" + } + ] + }, + "resizePolicy": { + "description": "Resources resize policy for the container.\n+featureGate=InPlacePodVerticalScaling\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1ContainerResizePolicy" + } + }, + "resources": { + "description": "Compute Resources required by this container.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceRequirements" + } + ] + }, + "restartPolicy": { + "description": "RestartPolicy defines the restart behavior of individual containers in a pod.\nThis overrides the pod-level restart policy. When this field is not specified,\nthe restart behavior is defined by the Pod's restart policy and the container type.\nAdditionally, setting the RestartPolicy as \"Always\" for the init container will\nhave the following effect:\nthis init container will be continually restarted on\nexit until all regular containers have terminated. Once all regular\ncontainers have completed, all init containers with restartPolicy \"Always\"\nwill be shut down. This lifecycle differs from normal init containers and\nis often referred to as a \"sidecar\" container. Although this init\ncontainer still starts in the init container sequence, it does not wait\nfor the container to complete before proceeding to the next init\ncontainer. Instead, the next init container starts immediately after this\ninit container is started, or after any startupProbe has successfully\ncompleted.\n+featureGate=SidecarContainers\n+optional", + "type": "string" + }, + "restartPolicyRules": { + "description": "Represents a list of rules to be checked to determine if the\ncontainer should be restarted on exit. The rules are evaluated in\norder. Once a rule matches a container exit condition, the remaining\nrules are ignored. If no rule matches the container exit condition,\nthe Container-level restart policy determines the whether the container\nis restarted or not. Constraints on the rules:\n- At most 20 rules are allowed.\n- Rules can have the same action.\n- Identical rules are not forbidden in validations.\nWhen rules are specified, container MUST set RestartPolicy explicitly\neven it if matches the Pod's RestartPolicy.\n+featureGate=ContainerRestartRules\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1ContainerRestartRule" + } + }, + "securityContext": { + "description": "SecurityContext defines the security options the container should be run with.\nIf set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.\nMore info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SecurityContext" + } + ] + }, + "startupProbe": { + "description": "StartupProbe indicates that the Pod has successfully initialized.\nIf specified, no other probes are executed until this completes successfully.\nIf this probe fails, the Pod will be restarted, just as if the livenessProbe failed.\nThis can be used to provide different probe parameters at the beginning of a Pod's lifecycle,\nwhen it might take a long time to load data or warm a cache, than during steady-state operation.\nThis cannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Probe" + } + ] + }, + "stdin": { + "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this\nis not set, reads from stdin in the container will always result in EOF.\nDefault is false.\n+optional", + "type": "boolean" + }, + "stdinOnce": { + "description": "Whether the container runtime should close the stdin channel after it has been opened by\na single attach. When stdin is true the stdin stream will remain open across multiple attach\nsessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the\nfirst client attaches to stdin, and then remains open and accepts data until the client disconnects,\nat which time stdin is closed and remains closed until the container is restarted. If this\nflag is false, a container processes that reads from stdin will never receive an EOF.\nDefault is false\n+optional", + "type": "boolean" + }, + "terminationMessagePath": { + "description": "Optional: Path at which the file to which the container's termination message\nwill be written is mounted into the container's filesystem.\nMessage written is intended to be brief final status, such as an assertion failure message.\nWill be truncated by the node if greater than 4096 bytes. The total message length across\nall containers will be limited to 12kb.\nDefaults to /dev/termination-log.\nCannot be updated.\n+optional", + "type": "string" + }, + "terminationMessagePolicy": { + "description": "Indicate how the termination message should be populated. File will use the contents of\nterminationMessagePath to populate the container status message on both success and failure.\nFallbackToLogsOnError will use the last chunk of container log output if the termination\nmessage file is empty and the container exited with an error.\nThe log output is limited to 2048 bytes or 80 lines, whichever is smaller.\nDefaults to File.\nCannot be updated.\n+optional", + "type": "string" + }, + "tty": { + "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true.\nDefault is false.\n+optional", + "type": "boolean" + }, + "volumeDevices": { + "description": "volumeDevices is the list of block devices to be used by the container.\n+patchMergeKey=devicePath\n+patchStrategy=merge\n+listType=map\n+listMapKey=devicePath\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/V1VolumeDevice" + } + }, + "volumeMounts": { + "description": "Pod volumes to mount into the container's filesystem.\nCannot be updated.\n+optional\n+patchMergeKey=mountPath\n+patchStrategy=merge\n+listType=map\n+listMapKey=mountPath", + "type": "array", + "items": { + "$ref": "#/definitions/V1VolumeMount" + } + }, + "workingDir": { + "description": "Container's working directory.\nIf not specified, the container runtime's default will be used, which\nmight be configured in the container image.\nCannot be updated.\n+optional", + "type": "string" + } + } + }, + "V1ContainerPort": { + "type": "object", + "properties": { + "containerPort": { + "description": "Number of port to expose on the pod's IP address.\nThis must be a valid port number, 0 < x < 65536.", + "type": "integer" + }, + "hostIP": { + "description": "What host IP to bind the external port to.\n+optional", + "type": "string" + }, + "hostPort": { + "description": "Number of port to expose on the host.\nIf specified, this must be a valid port number, 0 < x < 65536.\nIf HostNetwork is specified, this must match ContainerPort.\nMost containers do not need this.\n+optional", + "type": "integer" + }, + "name": { + "description": "If specified, this must be an IANA_SVC_NAME and unique within the pod. Each\nnamed port in a pod must have a unique name. Name for the port that can be\nreferred to by services.\n+optional", + "type": "string" + }, + "protocol": { + "description": "Protocol for port. Must be UDP, TCP, or SCTP.\nDefaults to \"TCP\".\n+optional\n+default=\"TCP\"", + "type": "string" + } + } + }, + "V1ContainerResizePolicy": { + "type": "object", + "properties": { + "resourceName": { + "description": "Name of the resource to which this resource resize policy applies.\nSupported values: cpu, memory.", + "type": "string" + }, + "restartPolicy": { + "description": "Restart policy to apply when specified resource is resized.\nIf not specified, it defaults to NotRequired.", + "type": "string" + } + } + }, + "V1ContainerRestartRule": { + "type": "object", + "properties": { + "action": { + "description": "Specifies the action taken on a container exit if the requirements\nare satisfied. The only possible value is \"Restart\" to restart the\ncontainer.\n+required", + "type": "string" + }, + "exitCodes": { + "description": "Represents the exit codes to check on container exits.\n+optional\n+oneOf=when", + "allOf": [ + { + "$ref": "#/definitions/V1ContainerRestartRuleOnExitCodes" + } + ] + } + } + }, + "V1ContainerRestartRuleOnExitCodes": { + "type": "object", + "properties": { + "operator": { + "description": "Represents the relationship between the container exit code(s) and the\nspecified values. Possible values are:\n- In: the requirement is satisfied if the container exit code is in the\n set of specified values.\n- NotIn: the requirement is satisfied if the container exit code is\n not in the set of specified values.\n+required", + "type": "string" + }, + "values": { + "description": "Specifies the set of values to check for container exit codes.\nAt most 255 elements are allowed.\n+optional\n+listType=set", + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "V1DownwardAPIProjection": { + "type": "object", + "properties": { + "items": { + "description": "Items is a list of DownwardAPIVolume file\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1DownwardAPIVolumeFile" + } + } + } + }, + "V1DownwardAPIVolumeFile": { + "type": "object", + "properties": { + "fieldRef": { + "description": "Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectFieldSelector" + } + ] + }, + "mode": { + "description": "Optional: mode bits used to set permissions on this file, must be an octal value\nbetween 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "path": { + "description": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'", + "type": "string" + }, + "resourceFieldRef": { + "description": "Selects a resource of the container: only resources limits and requests\n(limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceFieldSelector" + } + ] + } + } + }, + "V1DownwardAPIVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "Optional: mode bits to use on created files by default. Must be a\nOptional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDefaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "Items is a list of downward API volume file\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1DownwardAPIVolumeFile" + } + } + } + }, + "V1EmptyDirVolumeSource": { + "type": "object", + "properties": { + "medium": { + "description": "medium represents what type of storage medium should back this directory.\nThe default is \"\" which means to use the node's default medium.\nMust be an empty string (default) or Memory.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "type": "string" + }, + "sizeLimit": { + "description": "sizeLimit is the total amount of local storage required for this EmptyDir volume.\nThe size limit is also applicable for memory medium.\nThe maximum usage on memory medium EmptyDir would be the minimum value between\nthe SizeLimit specified here and the sum of memory limits of all containers in a pod.\nThe default is nil which means that the limit is undefined.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "allOf": [ + { + "$ref": "#/definitions/Quantity" + } + ] + } + } + }, + "V1EnvFromSource": { + "type": "object", + "properties": { + "configMapRef": { + "description": "The ConfigMap to select from\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ConfigMapEnvSource" + } + ] + }, + "prefix": { + "description": "Optional text to prepend to the name of each environment variable.\nMay consist of any printable ASCII characters except '='.\n+optional", + "type": "string" + }, + "secretRef": { + "description": "The Secret to select from\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SecretEnvSource" + } + ] + } + } + }, + "V1EnvVar": { + "type": "object", + "properties": { + "name": { + "description": "Name of the environment variable.\nMay consist of any printable ASCII characters except '='.", + "type": "string" + }, + "value": { + "description": "Variable references $(VAR_NAME) are expanded\nusing the previously defined environment variables in the container and\nany service environment variables. If a variable cannot be resolved,\nthe reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.\n\"$$(VAR_NAME)\" will produce the string literal \"$(VAR_NAME)\".\nEscaped references will never be expanded, regardless of whether the variable\nexists or not.\nDefaults to \"\".\n+optional", + "type": "string" + }, + "valueFrom": { + "description": "Source for the environment variable's value. Cannot be used if value is not empty.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1EnvVarSource" + } + ] + } + } + }, + "V1EnvVarSource": { + "type": "object", + "properties": { + "configMapKeyRef": { + "description": "Selects a key of a ConfigMap.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ConfigMapKeySelector" + } + ] + }, + "fieldRef": { + "description": "Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`,\nspec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectFieldSelector" + } + ] + }, + "fileKeyRef": { + "description": "FileKeyRef selects a key of the env file.\nRequires the EnvFiles feature gate to be enabled.\n\n+featureGate=EnvFiles\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1FileKeySelector" + } + ] + }, + "resourceFieldRef": { + "description": "Selects a resource of the container: only resources limits and requests\n(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceFieldSelector" + } + ] + }, + "secretKeyRef": { + "description": "Selects a key of a secret in the pod's namespace\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SecretKeySelector" + } + ] + } + } + }, + "V1EphemeralContainer": { + "type": "object", + "properties": { + "args": { + "description": "Arguments to the entrypoint.\nThe image's CMD is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "command": { + "description": "Entrypoint array. Not executed within a shell.\nThe image's ENTRYPOINT is used if this is not provided.\nVariable references $(VAR_NAME) are expanded using the container's environment. If a variable\ncannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced\nto a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. \"$$(VAR_NAME)\" will\nproduce the string literal \"$(VAR_NAME)\". Escaped references will never be expanded, regardless\nof whether the variable exists or not. Cannot be updated.\nMore info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "env": { + "description": "List of environment variables to set in the container.\nCannot be updated.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1EnvVar" + } + }, + "envFrom": { + "description": "List of sources to populate environment variables in the container.\nThe keys defined within a source may consist of any printable ASCII characters except '='.\nWhen a key exists in multiple\nsources, the value associated with the last source will take precedence.\nValues defined by an Env with a duplicate key will take precedence.\nCannot be updated.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1EnvFromSource" + } + }, + "image": { + "description": "Container image name.\nMore info: https://kubernetes.io/docs/concepts/containers/images", + "type": "string" + }, + "imagePullPolicy": { + "description": "Image pull policy.\nOne of Always, Never, IfNotPresent.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n+optional", + "type": "string" + }, + "lifecycle": { + "description": "Lifecycle is not allowed for ephemeral containers.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Lifecycle" + } + ] + }, + "livenessProbe": { + "description": "Probes are not allowed for ephemeral containers.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Probe" + } + ] + }, + "name": { + "description": "Name of the ephemeral container specified as a DNS_LABEL.\nThis name must be unique among all containers, init containers and ephemeral containers.", + "type": "string" + }, + "ports": { + "description": "Ports are not allowed for ephemeral containers.\n+optional\n+patchMergeKey=containerPort\n+patchStrategy=merge\n+listType=map\n+listMapKey=containerPort\n+listMapKey=protocol", + "type": "array", + "items": { + "$ref": "#/definitions/V1ContainerPort" + } + }, + "readinessProbe": { + "description": "Probes are not allowed for ephemeral containers.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Probe" + } + ] + }, + "resizePolicy": { + "description": "Resources resize policy for the container.\n+featureGate=InPlacePodVerticalScaling\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1ContainerResizePolicy" + } + }, + "resources": { + "description": "Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources\nalready allocated to the pod.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceRequirements" + } + ] + }, + "restartPolicy": { + "description": "Restart policy for the container to manage the restart behavior of each\ncontainer within a pod.\nYou cannot set this field on ephemeral containers.\n+featureGate=SidecarContainers\n+optional", + "type": "string" + }, + "restartPolicyRules": { + "description": "Represents a list of rules to be checked to determine if the\ncontainer should be restarted on exit. You cannot set this field on\nephemeral containers.\n+featureGate=ContainerRestartRules\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1ContainerRestartRule" + } + }, + "securityContext": { + "description": "Optional: SecurityContext defines the security options the ephemeral container should be run with.\nIf set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SecurityContext" + } + ] + }, + "startupProbe": { + "description": "Probes are not allowed for ephemeral containers.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Probe" + } + ] + }, + "stdin": { + "description": "Whether this container should allocate a buffer for stdin in the container runtime. If this\nis not set, reads from stdin in the container will always result in EOF.\nDefault is false.\n+optional", + "type": "boolean" + }, + "stdinOnce": { + "description": "Whether the container runtime should close the stdin channel after it has been opened by\na single attach. When stdin is true the stdin stream will remain open across multiple attach\nsessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the\nfirst client attaches to stdin, and then remains open and accepts data until the client disconnects,\nat which time stdin is closed and remains closed until the container is restarted. If this\nflag is false, a container processes that reads from stdin will never receive an EOF.\nDefault is false\n+optional", + "type": "boolean" + }, + "targetContainerName": { + "description": "If set, the name of the container from PodSpec that this ephemeral container targets.\nThe ephemeral container will be run in the namespaces (IPC, PID, etc) of this container.\nIf not set then the ephemeral container uses the namespaces configured in the Pod spec.\n\nThe container runtime must implement support for this feature. If the runtime does not\nsupport namespace targeting then the result of setting this field is undefined.\n+optional", + "type": "string" + }, + "terminationMessagePath": { + "description": "Optional: Path at which the file to which the container's termination message\nwill be written is mounted into the container's filesystem.\nMessage written is intended to be brief final status, such as an assertion failure message.\nWill be truncated by the node if greater than 4096 bytes. The total message length across\nall containers will be limited to 12kb.\nDefaults to /dev/termination-log.\nCannot be updated.\n+optional", + "type": "string" + }, + "terminationMessagePolicy": { + "description": "Indicate how the termination message should be populated. File will use the contents of\nterminationMessagePath to populate the container status message on both success and failure.\nFallbackToLogsOnError will use the last chunk of container log output if the termination\nmessage file is empty and the container exited with an error.\nThe log output is limited to 2048 bytes or 80 lines, whichever is smaller.\nDefaults to File.\nCannot be updated.\n+optional", + "type": "string" + }, + "tty": { + "description": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true.\nDefault is false.\n+optional", + "type": "boolean" + }, + "volumeDevices": { + "description": "volumeDevices is the list of block devices to be used by the container.\n+patchMergeKey=devicePath\n+patchStrategy=merge\n+listType=map\n+listMapKey=devicePath\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/V1VolumeDevice" + } + }, + "volumeMounts": { + "description": "Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers.\nCannot be updated.\n+optional\n+patchMergeKey=mountPath\n+patchStrategy=merge\n+listType=map\n+listMapKey=mountPath", + "type": "array", + "items": { + "$ref": "#/definitions/V1VolumeMount" + } + }, + "workingDir": { + "description": "Container's working directory.\nIf not specified, the container runtime's default will be used, which\nmight be configured in the container image.\nCannot be updated.\n+optional", + "type": "string" + } + } + }, + "V1EphemeralVolumeSource": { + "type": "object", + "properties": { + "volumeClaimTemplate": { + "description": "Will be used to create a stand-alone PVC to provision the volume.\nThe pod in which this EphemeralVolumeSource is embedded will be the\nowner of the PVC, i.e. the PVC will be deleted together with the\npod. The name of the PVC will be `-` where\n`` is the name from the `PodSpec.Volumes` array\nentry. Pod validation will reject the pod if the concatenated name\nis not valid for a PVC (for example, too long).\n\nAn existing PVC with that name that is not owned by the pod\nwill *not* be used for the pod to avoid using an unrelated\nvolume by mistake. Starting the pod is then blocked until\nthe unrelated PVC is removed. If such a pre-created PVC is\nmeant to be used by the pod, the PVC has to updated with an\nowner reference to the pod once the pod exists. Normally\nthis should not be necessary, but it may be useful when\nmanually reconstructing a broken cluster.\n\nThis field is read-only and no changes will be made by Kubernetes\nto the PVC after it has been created.\n\nRequired, must not be nil.", + "allOf": [ + { + "$ref": "#/definitions/V1PersistentVolumeClaimTemplate" + } + ] + } + } + }, + "V1EventSource": { + "type": "object", + "properties": { + "component": { + "description": "Component from which the event is generated.\n+optional", + "type": "string" + }, + "host": { + "description": "Node name on which the event is generated.\n+optional", + "type": "string" + } + } + }, + "V1ExecAction": { + "type": "object", + "properties": { + "command": { + "description": "Command is the command line to execute inside the container, the working directory for the\ncommand is root ('/') in the container's filesystem. The command is simply exec'd, it is\nnot run inside a shell, so traditional shell instructions ('|', etc) won't work. To use\na shell, you need to explicitly call out to that shell.\nExit status of 0 is treated as live/healthy and non-zero is unhealthy.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1FCVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "lun": { + "description": "lun is Optional: FC target lun number\n+optional", + "type": "integer" + }, + "readOnly": { + "description": "readOnly is Optional: Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "targetWWNs": { + "description": "targetWWNs is Optional: FC target worldwide names (WWNs)\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "wwids": { + "description": "wwids Optional: FC volume world wide identifiers (wwids)\nEither wwids or combination of targetWWNs and lun must be set, but not both simultaneously.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1FieldsV1": { + "type": "object" + }, + "V1FileKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key within the env file. An invalid key will prevent the pod from starting.\nThe keys defined within a source may consist of any printable ASCII characters except '='.\nDuring Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters.\n+required", + "type": "string" + }, + "optional": { + "description": "Specify whether the file or its key must be defined. If the file or key\ndoes not exist, then the env var is not published.\nIf optional is set to true and the specified key does not exist,\nthe environment variable will not be set in the Pod's containers.\n\nIf optional is set to false and the specified key does not exist,\nan error will be returned during Pod creation.\n+optional\n+default=false", + "type": "boolean" + }, + "path": { + "description": "The path within the volume from which to select the file.\nMust be relative and may not contain the '..' path or start with '..'.\n+required", + "type": "string" + }, + "volumeName": { + "description": "The name of the volume mount containing the env file.\n+required", + "type": "string" + } + } + }, + "V1FlexVolumeSource": { + "type": "object", + "properties": { + "driver": { + "description": "driver is the name of the driver to use for this volume.", + "type": "string" + }, + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.\n+optional", + "type": "string" + }, + "options": { + "description": "options is Optional: this field holds extra command options if any.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "readOnly": { + "description": "readOnly is Optional: defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is Optional: secretRef is reference to the secret object containing\nsensitive information to pass to the plugin scripts. This may be\nempty if no secret object is specified. If the secret object\ncontains more than one secret, all secrets are passed to the plugin\nscripts.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + } + } + }, + "V1FlockerVolumeSource": { + "type": "object", + "properties": { + "datasetName": { + "description": "datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker\nshould be considered as deprecated\n+optional", + "type": "string" + }, + "datasetUUID": { + "description": "datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset\n+optional", + "type": "string" + } + } + }, + "V1GCEPersistentDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "partition": { + "description": "partition is the partition in the volume that you want to mount.\nIf omitted, the default is to mount by volume name.\nExamples: For volume /dev/sda1, you specify the partition as \"1\".\nSimilarly, the volume partition for /dev/sda is \"0\" (or you can leave the property empty).\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "type": "integer" + }, + "pdName": { + "description": "pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "type": "boolean" + } + } + }, + "V1GRPCAction": { + "type": "object", + "properties": { + "port": { + "description": "Port number of the gRPC service. Number must be in the range 1 to 65535.", + "type": "integer" + }, + "service": { + "description": "Service is the name of the service to place in the gRPC HealthCheckRequest\n(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).\n\nIf this is not specified, the default behavior is defined by gRPC.\n+optional\n+default=\"\"", + "type": "string" + } + } + }, + "V1GitRepoVolumeSource": { + "type": "object", + "properties": { + "directory": { + "description": "directory is the target directory name.\nMust not contain or start with '..'. If '.' is supplied, the volume directory will be the\ngit repository. Otherwise, if specified, the volume will contain the git repository in\nthe subdirectory with the given name.\n+optional", + "type": "string" + }, + "repository": { + "description": "repository is the URL", + "type": "string" + }, + "revision": { + "description": "revision is the commit hash for the specified revision.\n+optional", + "type": "string" + } + } + }, + "V1GlusterfsVolumeSource": { + "type": "object", + "properties": { + "endpoints": { + "description": "endpoints is the endpoint name that details Glusterfs topology.", + "type": "string" + }, + "path": { + "description": "path is the Glusterfs volume path.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the Glusterfs volume to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod\n+optional", + "type": "boolean" + } + } + }, + "V1HTTPGetAction": { + "type": "object", + "properties": { + "host": { + "description": "Host name to connect to, defaults to the pod IP. You probably want to set\n\"Host\" in httpHeaders instead.\n+optional", + "type": "string" + }, + "httpHeaders": { + "description": "Custom headers to set in the request. HTTP allows repeated headers.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1HTTPHeader" + } + }, + "path": { + "description": "Path to access on the HTTP server.\n+optional", + "type": "string" + }, + "port": { + "description": "Name or number of the port to access on the container.\nNumber must be in the range 1 to 65535.\nName must be an IANA_SVC_NAME.", + "allOf": [ + { + "$ref": "#/definitions/IntOrString" + } + ] + }, + "scheme": { + "description": "Scheme to use for connecting to the host.\nDefaults to HTTP.\n+optional", + "type": "string" + } + } + }, + "V1HTTPHeader": { + "type": "object", + "properties": { + "name": { + "description": "The header field name.\nThis will be canonicalized upon output, so case-variant names will be understood as the same header.", + "type": "string" + }, + "value": { + "description": "The header field value", + "type": "string" + } + } + }, + "V1HostAlias": { + "type": "object", + "properties": { + "hostnames": { + "description": "Hostnames for the above IP address.\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "ip": { + "description": "IP address of the host file entry.\n+required", + "type": "string" + } + } + }, + "V1HostPathVolumeSource": { + "type": "object", + "properties": { + "path": { + "description": "path of the directory on the host.\nIf the path is a symlink, it will follow the link to the real path.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + "type": "string" + }, + "type": { + "description": "type for HostPath Volume\nDefaults to \"\"\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n+optional", + "type": "string" + } + } + }, + "V1ISCSIVolumeSource": { + "type": "object", + "properties": { + "chapAuthDiscovery": { + "description": "chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication\n+optional", + "type": "boolean" + }, + "chapAuthSession": { + "description": "chapAuthSession defines whether support iSCSI Session CHAP authentication\n+optional", + "type": "boolean" + }, + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "initiatorName": { + "description": "initiatorName is the custom iSCSI Initiator Name.\nIf initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface\n: will be created for the connection.\n+optional", + "type": "string" + }, + "iqn": { + "description": "iqn is the target iSCSI Qualified Name.", + "type": "string" + }, + "iscsiInterface": { + "description": "iscsiInterface is the interface Name that uses an iSCSI transport.\nDefaults to 'default' (tcp).\n+optional\n+default=\"default\"", + "type": "string" + }, + "lun": { + "description": "lun represents iSCSI Target Lun number.", + "type": "integer" + }, + "portals": { + "description": "portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is the CHAP Secret for iSCSI target and initiator authentication\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "targetPortal": { + "description": "targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port\nis other than default (typically TCP ports 860 and 3260).", + "type": "string" + } + } + }, + "V1ImageVolumeSource": { + "type": "object", + "properties": { + "pullPolicy": { + "description": "Policy for pulling OCI objects. Possible values are:\nAlways: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\nNever: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\nIfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\nDefaults to Always if :latest tag is specified, or IfNotPresent otherwise.\n+optional", + "type": "string" + }, + "reference": { + "description": "Required: Image or artifact reference to be used.\nBehaves in the same way as pod.spec.containers[*].image.\nPull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets.\nMore info: https://kubernetes.io/docs/concepts/containers/images\nThis field is optional to allow higher level config management to default or override\ncontainer images in workload controllers like Deployments and StatefulSets.\n+optional", + "type": "string" + } + } + }, + "V1JobSpec": { + "type": "object", + "properties": { + "activeDeadlineSeconds": { + "description": "Specifies the duration in seconds relative to the startTime that the job\nmay be continuously active before the system tries to terminate it; value\nmust be positive integer. If a Job is suspended (at creation or through an\nupdate), this timer will effectively be stopped and reset when the Job is\nresumed again.\n+optional", + "type": "integer" + }, + "backoffLimit": { + "description": "Specifies the number of retries before marking this job failed.\nDefaults to 6, unless backoffLimitPerIndex (only Indexed Job) is specified.\nWhen backoffLimitPerIndex is specified, backoffLimit defaults to 2147483647.\n+optional", + "type": "integer" + }, + "backoffLimitPerIndex": { + "description": "Specifies the limit for the number of retries within an\nindex before marking this index as failed. When enabled the number of\nfailures per index is kept in the pod's\nbatch.kubernetes.io/job-index-failure-count annotation. It can only\nbe set when Job's completionMode=Indexed, and the Pod's restart\npolicy is Never. The field is immutable.\n+optional", + "type": "integer" + }, + "completionMode": { + "description": "completionMode specifies how Pod completions are tracked. It can be\n`NonIndexed` (default) or `Indexed`.\n\n`NonIndexed` means that the Job is considered complete when there have\nbeen .spec.completions successfully completed Pods. Each Pod completion is\nhomologous to each other.\n\n`Indexed` means that the Pods of a\nJob get an associated completion index from 0 to (.spec.completions - 1),\navailable in the annotation batch.kubernetes.io/job-completion-index.\nThe Job is considered complete when there is one successfully completed Pod\nfor each index.\nWhen value is `Indexed`, .spec.completions must be specified and\n`.spec.parallelism` must be less than or equal to 10^5.\nIn addition, The Pod name takes the form\n`$(job-name)-$(index)-$(random-string)`,\nthe Pod hostname takes the form `$(job-name)-$(index)`.\n\nMore completion modes can be added in the future.\nIf the Job controller observes a mode that it doesn't recognize, which\nis possible during upgrades due to version skew, the controller\nskips updates for the Job.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1CompletionMode" + } + ] + }, + "completions": { + "description": "Specifies the desired number of successfully finished pods the\njob should be run with. Setting to null means that the success of any\npod signals the success of all pods, and allows parallelism to have any positive\nvalue. Setting to 1 means that parallelism is limited to 1 and the success of that\npod signals the success of the job.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/\n+optional", + "type": "integer" + }, + "managedBy": { + "description": "ManagedBy field indicates the controller that manages a Job. The k8s Job\ncontroller reconciles jobs which don't have this field at all or the field\nvalue is the reserved string `kubernetes.io/job-controller`, but skips\nreconciling Jobs with a custom value for this field.\nThe value must be a valid domain-prefixed path (e.g. acme.io/foo) -\nall characters before the first \"/\" must be a valid subdomain as defined\nby RFC 1123. All characters trailing the first \"/\" must be valid HTTP Path\ncharacters as defined by RFC 3986. The value cannot exceed 63 characters.\nThis field is immutable.\n\nThis field is beta-level. The job controller accepts setting the field\nwhen the feature gate JobManagedBy is enabled (enabled by default).\n+optional", + "type": "string" + }, + "manualSelector": { + "description": "manualSelector controls generation of pod labels and pod selectors.\nLeave `manualSelector` unset unless you are certain what you are doing.\nWhen false or unset, the system pick labels unique to this job\nand appends those labels to the pod template. When true,\nthe user is responsible for picking unique labels and specifying\nthe selector. Failure to pick a unique label may cause this\nand other jobs to not function correctly. However, You may see\n`manualSelector=true` in jobs that were created with the old `extensions/v1beta1`\nAPI.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector\n+optional", + "type": "boolean" + }, + "maxFailedIndexes": { + "description": "Specifies the maximal number of failed indexes before marking the Job as\nfailed, when backoffLimitPerIndex is set. Once the number of failed\nindexes exceeds this number the entire Job is marked as Failed and its\nexecution is terminated. When left as null the job continues execution of\nall of its indexes and is marked with the `Complete` Job condition.\nIt can only be specified when backoffLimitPerIndex is set.\nIt can be null or up to completions. It is required and must be\nless than or equal to 10^4 when is completions greater than 10^5.\n+optional", + "type": "integer" + }, + "parallelism": { + "description": "Specifies the maximum desired number of pods the job should\nrun at any given time. The actual number of pods running in steady state will\nbe less than this number when ((.spec.completions - .status.successful) < .spec.parallelism),\ni.e. when the work left to do is less than max parallelism.\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/\n+optional", + "type": "integer" + }, + "podFailurePolicy": { + "description": "Specifies the policy of handling failed pods. In particular, it allows to\nspecify the set of actions and conditions which need to be\nsatisfied to take the associated action.\nIf empty, the default behaviour applies - the counter of failed pods,\nrepresented by the jobs's .status.failed field, is incremented and it is\nchecked against the backoffLimit. This field cannot be used in combination\nwith restartPolicy=OnFailure.\n\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodFailurePolicy" + } + ] + }, + "podReplacementPolicy": { + "description": "podReplacementPolicy specifies when to create replacement Pods.\nPossible values are:\n- TerminatingOrFailed means that we recreate pods\n when they are terminating (has a metadata.deletionTimestamp) or failed.\n- Failed means to wait until a previously created Pod is fully terminated (has phase\n Failed or Succeeded) before creating a replacement Pod.\n\nWhen using podFailurePolicy, Failed is the the only allowed value.\nTerminatingOrFailed and Failed are allowed values when podFailurePolicy is not in use.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodReplacementPolicy" + } + ] + }, + "selector": { + "description": "A label query over pods that should match the pod count.\nNormally, the system sets this field for you.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "successPolicy": { + "description": "successPolicy specifies the policy when the Job can be declared as succeeded.\nIf empty, the default behavior applies - the Job is declared as succeeded\nonly when the number of succeeded pods equals to the completions.\nWhen the field is specified, it must be immutable and works only for the Indexed Jobs.\nOnce the Job meets the SuccessPolicy, the lingering pods are terminated.\n\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SuccessPolicy" + } + ] + }, + "suspend": { + "description": "suspend specifies whether the Job controller should create Pods or not. If\na Job is created with suspend set to true, no Pods are created by the Job\ncontroller. If a Job is suspended after creation (i.e. the flag goes from\nfalse to true), the Job controller will delete all active Pods associated\nwith this Job. Users must design their workload to gracefully handle this.\nSuspending a Job will reset the StartTime field of the Job, effectively\nresetting the ActiveDeadlineSeconds timer too. Defaults to false.\n\n+optional", + "type": "boolean" + }, + "template": { + "description": "Describes the pod that will be created when executing a job.\nThe only allowed template.spec.restartPolicy values are \"Never\" or \"OnFailure\".\nMore info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/", + "allOf": [ + { + "$ref": "#/definitions/V1PodTemplateSpec" + } + ] + }, + "ttlSecondsAfterFinished": { + "description": "ttlSecondsAfterFinished limits the lifetime of a Job that has finished\nexecution (either Complete or Failed). If this field is set,\nttlSecondsAfterFinished after the Job finishes, it is eligible to be\nautomatically deleted. When the Job is being deleted, its lifecycle\nguarantees (e.g. finalizers) will be honored. If this field is unset,\nthe Job won't be automatically deleted. If this field is set to zero,\nthe Job becomes eligible to be deleted immediately after it finishes.\n+optional", + "type": "integer" + } + } + }, + "V1KeyToPath": { + "type": "object", + "properties": { + "key": { + "description": "key is the key to project.", + "type": "string" + }, + "mode": { + "description": "mode is Optional: mode bits used to set permissions on this file.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nIf not specified, the volume defaultMode will be used.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "path": { + "description": "path is the relative path of the file to map the key to.\nMay not be an absolute path.\nMay not contain the path element '..'.\nMay not start with the string '..'.", + "type": "string" + } + } + }, + "V1LabelSelector": { + "type": "object", + "properties": { + "matchExpressions": { + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1LabelSelectorRequirement" + } + }, + "matchLabels": { + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels\nmap is equivalent to an element of matchExpressions, whose key field is \"key\", the\noperator is \"In\", and the values array contains only \"value\". The requirements are ANDed.\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "V1LabelSelectorRequirement": { + "type": "object", + "properties": { + "key": { + "description": "key is the label key that the selector applies to.", + "type": "string" + }, + "operator": { + "description": "operator represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists and DoesNotExist.", + "type": "string" + }, + "values": { + "description": "values is an array of string values. If the operator is In or NotIn,\nthe values array must be non-empty. If the operator is Exists or DoesNotExist,\nthe values array must be empty. This array is replaced during a strategic\nmerge patch.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1Lifecycle": { + "type": "object", + "properties": { + "postStart": { + "description": "PostStart is called immediately after a container is created. If the handler fails,\nthe container is terminated and restarted according to its restart policy.\nOther management of the container blocks until the hook completes.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LifecycleHandler" + } + ] + }, + "preStop": { + "description": "PreStop is called immediately before a container is terminated due to an\nAPI request or management event such as liveness/startup probe failure,\npreemption, resource contention, etc. The handler is not called if the\ncontainer crashes or exits. The Pod's termination grace period countdown begins before the\nPreStop hook is executed. Regardless of the outcome of the handler, the\ncontainer will eventually terminate within the Pod's termination grace\nperiod (unless delayed by finalizers). Other management of the container blocks until the hook completes\nor until the termination grace period is reached.\nMore info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LifecycleHandler" + } + ] + }, + "stopSignal": { + "description": "StopSignal defines which signal will be sent to a container when it is being stopped.\nIf not specified, the default is defined by the container runtime in use.\nStopSignal can only be set for Pods with a non-empty .spec.os.name\n+optional", + "type": "string" + } + } + }, + "V1LifecycleHandler": { + "type": "object", + "properties": { + "exec": { + "description": "Exec specifies a command to execute in the container.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ExecAction" + } + ] + }, + "httpGet": { + "description": "HTTPGet specifies an HTTP GET request to perform.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1HTTPGetAction" + } + ] + }, + "sleep": { + "description": "Sleep represents a duration that the container should sleep.\n+featureGate=PodLifecycleSleepAction\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SleepAction" + } + ] + }, + "tcpSocket": { + "description": "Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept\nfor backward compatibility. There is no validation of this field and\nlifecycle hooks will fail at runtime when it is specified.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1TCPSocketAction" + } + ] + } + } + }, + "V1ListMeta": { + "type": "object", + "properties": { + "continue": { + "description": "continue may be set if the user set a limit on the number of items returned, and indicates that\nthe server has more data available. The value is opaque and may be used to issue another request\nto the endpoint that served this list to retrieve the next set of available objects. Continuing a\nconsistent list may not be possible if the server configuration has changed or more than a few\nminutes have passed. The resourceVersion field returned when using this continue value will be\nidentical to the value in the first response, unless you have received this token from an error\nmessage.", + "type": "string" + }, + "remainingItemCount": { + "description": "remainingItemCount is the number of subsequent items in the list which are not included in this\nlist response. If the list request contained label or field selectors, then the number of\nremaining items is unknown and the field will be left unset and omitted during serialization.\nIf the list is complete (either because it is not chunking or because this is the last chunk),\nthen there are no more remaining items and this field will be left unset and omitted during\nserialization.\nServers older than v1.15 do not set this field.\nThe intended use of the remainingItemCount is *estimating* the size of a collection. Clients\nshould not rely on the remainingItemCount to be set or to be exact.\n+optional", + "type": "integer" + }, + "resourceVersion": { + "description": "String that identifies the server's internal version of this object that\ncan be used by clients to determine when objects have changed.\nValue must be treated as opaque by clients and passed unmodified back to the server.\nPopulated by the system.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + } + } + }, + "V1LocalObjectReference": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + } + } + }, + "V1ManagedFieldsEntry": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the version of this resource that this field set\napplies to. The format is \"group/version\" just like the top-level\nAPIVersion field. It is necessary to track the version of a field\nset because it cannot be automatically converted.", + "type": "string" + }, + "fieldsType": { + "description": "FieldsType is the discriminator for the different fields format and version.\nThere is currently only one possible value: \"FieldsV1\"", + "type": "string" + }, + "fieldsV1": { + "description": "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1FieldsV1" + } + ] + }, + "manager": { + "description": "Manager is an identifier of the workflow managing these fields.", + "type": "string" + }, + "operation": { + "description": "Operation is the type of operation which lead to this ManagedFieldsEntry being created.\nThe only valid values for this field are 'Apply' and 'Update'.", + "type": "string" + }, + "subresource": { + "description": "Subresource is the name of the subresource used to update that object, or\nempty string if the object was updated through the main resource. The\nvalue of this field is used to distinguish between managers, even if they\nshare the same name. For example, a status update will be distinct from a\nregular update using the same manager name.\nNote that the APIVersion field is not related to the Subresource field and\nit always corresponds to the version of the main resource.", + "type": "string" + }, + "time": { + "description": "Time is the timestamp of when the ManagedFields entry was added. The\ntimestamp will also be updated if a field is added, the manager\nchanges any of the owned fields value or removes a field. The\ntimestamp does not update when a field is removed from the entry\nbecause another manager took it over.\n+optional", + "type": "string" + } + } + }, + "V1MicroTime": { + "type": "object", + "properties": { + "time.Time": { + "type": "string" + } + } + }, + "V1NFSVolumeSource": { + "type": "object", + "properties": { + "path": { + "description": "path that is exported by the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the NFS export to be mounted with read-only permissions.\nDefaults to false.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional", + "type": "boolean" + }, + "server": { + "description": "server is the hostname or IP address of the NFS server.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs", + "type": "string" + } + } + }, + "V1NodeAffinity": { + "type": "object", + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "description": "The scheduler will prefer to schedule pods to nodes that satisfy\nthe affinity expressions specified by this field, but it may choose\na node that violates one or more of the expressions. The node that is\nmost preferred is the one with the greatest sum of weights, i.e.\nfor each node that meets all of the scheduling requirements (resource\nrequest, requiredDuringScheduling affinity expressions, etc.),\ncompute a sum by iterating through the elements of this field and adding\n\"weight\" to the sum if the node matches the corresponding matchExpressions; the\nnode(s) with the highest sum are the most preferred.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1PreferredSchedulingTerm" + } + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "description": "If the affinity requirements specified by this field are not met at\nscheduling time, the pod will not be scheduled onto the node.\nIf the affinity requirements specified by this field cease to be met\nat some point during pod execution (e.g. due to an update), the system\nmay or may not try to eventually evict the pod from its node.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1NodeSelector" + } + ] + } + } + }, + "V1NodeSelector": { + "type": "object", + "properties": { + "nodeSelectorTerms": { + "description": "Required. A list of node selector terms. The terms are ORed.\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1NodeSelectorTerm" + } + } + } + }, + "V1NodeSelectorRequirement": { + "type": "object", + "properties": { + "key": { + "description": "The label key that the selector applies to.", + "type": "string" + }, + "operator": { + "description": "Represents a key's relationship to a set of values.\nValid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.", + "type": "string" + }, + "values": { + "description": "An array of string values. If the operator is In or NotIn,\nthe values array must be non-empty. If the operator is Exists or DoesNotExist,\nthe values array must be empty. If the operator is Gt or Lt, the values\narray must have a single element, which will be interpreted as an integer.\nThis array is replaced during a strategic merge patch.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1NodeSelectorTerm": { + "type": "object", + "properties": { + "matchExpressions": { + "description": "A list of node selector requirements by node's labels.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1NodeSelectorRequirement" + } + }, + "matchFields": { + "description": "A list of node selector requirements by node's fields.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1NodeSelectorRequirement" + } + } + } + }, + "V1ObjectFieldSelector": { + "type": "object", + "properties": { + "apiVersion": { + "description": "Version of the schema the FieldPath is written in terms of, defaults to \"v1\".\n+optional", + "type": "string" + }, + "fieldPath": { + "description": "Path of the field to select in the specified API version.", + "type": "string" + } + } + }, + "V1ObjectMeta": { + "type": "object", + "properties": { + "annotations": { + "description": "Annotations is an unstructured key value map stored with a resource that may be\nset by external tools to store and retrieve arbitrary metadata. They are not\nqueryable and should be preserved when modifying objects.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "creationTimestamp": { + "description": "CreationTimestamp is a timestamp representing the server time when this object was\ncreated. It is not guaranteed to be set in happens-before order across separate operations.\nClients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system.\nRead-only.\nNull for lists.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "deletionGracePeriodSeconds": { + "description": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional", + "type": "integer" + }, + "deletionTimestamp": { + "description": "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This\nfield is set by the server when a graceful deletion is requested by the user, and is not\ndirectly settable by a client. The resource is expected to be deleted (no longer visible\nfrom resource lists, and not reachable by name) after the time in this field, once the\nfinalizers list is empty. As long as the finalizers list contains items, deletion is blocked.\nOnce the deletionTimestamp is set, this value may not be unset or be set further into the\nfuture, although it may be shortened or the resource may be deleted prior to this time.\nFor example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react\nby sending a graceful termination signal to the containers in the pod. After that 30 seconds,\nthe Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup,\nremove the pod from the API. In the presence of network partitions, this object may still\nexist after this timestamp, until an administrator or automated process can determine the\nresource is fully terminated.\nIf not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested.\nRead-only.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "type": "string" + }, + "finalizers": { + "description": "Must be empty before the object is deleted from the registry. Each entry\nis an identifier for the responsible component that will remove the entry\nfrom the list. If the deletionTimestamp of the object is non-nil, entries\nin this list can only be removed.\nFinalizers may be processed and removed in any order. Order is NOT enforced\nbecause it introduces significant risk of stuck finalizers.\nfinalizers is a shared field, any actor with permission can reorder it.\nIf the finalizer list is processed in order, then this can lead to a situation\nin which the component responsible for the first finalizer in the list is\nwaiting for a signal (field value, external system, or other) produced by a\ncomponent responsible for a finalizer later in the list, resulting in a deadlock.\nWithout enforced ordering finalizers are free to order amongst themselves and\nare not vulnerable to ordering changes in the list.\n+optional\n+patchStrategy=merge\n+listType=set", + "type": "array", + "items": { + "type": "string" + } + }, + "generateName": { + "description": "GenerateName is an optional prefix, used by the server, to generate a unique\nname ONLY IF the Name field has not been provided.\nIf this field is used, the name returned to the client will be different\nthan the name passed. This value will also be combined with a unique suffix.\nThe provided value has the same validation rules as the Name field,\nand may be truncated by the length of the suffix required to make the value\nunique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency\n+optional", + "type": "string" + }, + "generation": { + "description": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional", + "type": "integer" + }, + "labels": { + "description": "Map of string keys and values that can be used to organize and categorize\n(scope and select) objects. May match selectors of replication controllers\nand services.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "managedFields": { + "description": "ManagedFields maps workflow-id and version to the set of fields\nthat are managed by that workflow. This is mostly for internal\nhousekeeping, and users typically shouldn't need to set or\nunderstand this field. A workflow can be the user's name, a\ncontroller's name, or the name of a specific apply path like\n\"ci-cd\". The set of fields is always in the version that the\nworkflow used when modifying the object.\n\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1ManagedFieldsEntry" + } + }, + "name": { + "description": "Name must be unique within a namespace. Is required when creating resources, although\nsome resources may allow a client to request the generation of an appropriate name\nautomatically. Name is primarily intended for creation idempotence and configuration\ndefinition.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace defines the space within which each name must be unique. An empty namespace is\nequivalent to the \"default\" namespace, but \"default\" is the canonical representation.\nNot all objects are required to be scoped to a namespace - the value of this field for\nthose objects will be empty.\n\nMust be a DNS_LABEL.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces\n+optional", + "type": "string" + }, + "ownerReferences": { + "description": "List of objects depended by this object. If ALL objects in the list have\nbeen deleted, this object will be garbage collected. If this object is managed by a controller,\nthen an entry in this list will point to this controller, with the controller field set to true.\nThere cannot be more than one managing controller.\n+optional\n+patchMergeKey=uid\n+patchStrategy=merge\n+listType=map\n+listMapKey=uid", + "type": "array", + "items": { + "$ref": "#/definitions/V1OwnerReference" + } + }, + "resourceVersion": { + "description": "An opaque value that represents the internal version of this object that can\nbe used by clients to determine when objects have changed. May be used for optimistic\nconcurrency, change detection, and the watch operation on a resource or set of resources.\nClients must treat these values as opaque and passed unmodified back to the server.\nThey may only be valid for a particular resource or set of resources.\n\nPopulated by the system.\nRead-only.\nValue must be treated as opaque by clients and .\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "selfLink": { + "description": "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.\n+optional", + "type": "string" + }, + "uid": { + "description": "UID is the unique in time and space value for this object. It is typically generated by\nthe server on successful creation of a resource and is not allowed to change on PUT\noperations.\n\nPopulated by the system.\nRead-only.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids\n+optional", + "type": "string" + } + } + }, + "V1ObjectReference": { + "type": "object", + "properties": { + "apiVersion": { + "description": "API version of the referent.\n+optional", + "type": "string" + }, + "fieldPath": { + "description": "If referring to a piece of an object instead of an entire object, this string\nshould contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2].\nFor example, if the object reference is to a container within a pod, this would take on a value like:\n\"spec.containers{name}\" (where \"name\" refers to the name of the container that triggered\nthe event) or if no container name is specified \"spec.containers[2]\" (container with\nindex 2 in this pod). This syntax is chosen only to have some well-defined way of\nreferencing a part of an object.\nTODO: this design is not final and this field is subject to change in the future.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind of the referent.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional", + "type": "string" + }, + "namespace": { + "description": "Namespace of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/\n+optional", + "type": "string" + }, + "resourceVersion": { + "description": "Specific resourceVersion to which this reference is made, if any.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency\n+optional", + "type": "string" + }, + "uid": { + "description": "UID of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids\n+optional", + "type": "string" + } + } + }, + "V1OwnerReference": { + "type": "object", + "properties": { + "apiVersion": { + "description": "API version of the referent.", + "type": "string" + }, + "blockOwnerDeletion": { + "description": "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then\nthe owner cannot be deleted from the key-value store until this\nreference is removed.\nSee https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion\nfor how the garbage collector interacts with this field and enforces the foreground deletion.\nDefaults to false.\nTo set this field, a user needs \"delete\" permission of the owner,\notherwise 422 (Unprocessable Entity) will be returned.\n+optional", + "type": "boolean" + }, + "controller": { + "description": "If true, this reference points to the managing controller.\n+optional", + "type": "boolean" + }, + "kind": { + "description": "Kind of the referent.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names", + "type": "string" + }, + "uid": { + "description": "UID of the referent.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids", + "type": "string" + } + } + }, + "V1PersistentVolumeClaimSpec": { + "type": "object", + "properties": { + "accessModes": { + "description": "accessModes contains the desired access modes the volume should have.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "dataSource": { + "description": "dataSource field can be used to specify either:\n* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)\n* An existing PVC (PersistentVolumeClaim)\nIf the provisioner or an external controller can support the specified data source,\nit will create a new volume based on the contents of the specified data source.\nWhen the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef,\nand dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified.\nIf the namespace is specified, then dataSourceRef will not be copied to dataSource.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1TypedLocalObjectReference" + } + ] + }, + "dataSourceRef": { + "description": "dataSourceRef specifies the object from which to populate the volume with data, if a non-empty\nvolume is desired. This may be any object from a non-empty API group (non\ncore object) or a PersistentVolumeClaim object.\nWhen this field is specified, volume binding will only succeed if the type of\nthe specified object matches some installed volume populator or dynamic\nprovisioner.\nThis field will replace the functionality of the dataSource field and as such\nif both fields are non-empty, they must have the same value. For backwards\ncompatibility, when namespace isn't specified in dataSourceRef,\nboth fields (dataSource and dataSourceRef) will be set to the same\nvalue automatically if one of them is empty and the other is non-empty.\nWhen namespace is specified in dataSourceRef,\ndataSource isn't set to the same value and must be empty.\nThere are three important differences between dataSource and dataSourceRef:\n* While dataSource only allows two specific types of objects, dataSourceRef\n allows any non-core object, as well as PersistentVolumeClaim objects.\n* While dataSource ignores disallowed values (dropping them), dataSourceRef\n preserves all values, and generates an error if a disallowed value is\n specified.\n* While dataSource only allows local objects, dataSourceRef allows objects\n in any namespaces.\n(Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled.\n(Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1TypedObjectReference" + } + ] + }, + "resources": { + "description": "resources represents the minimum resources the volume should have.\nIf RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements\nthat are lower than previous value but must still be higher than capacity recorded in the\nstatus field of the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1VolumeResourceRequirements" + } + ] + }, + "selector": { + "description": "selector is a label query over volumes to consider for binding.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "storageClassName": { + "description": "storageClassName is the name of the StorageClass required by the claim.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1\n+optional", + "type": "string" + }, + "volumeAttributesClassName": { + "description": "volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim.\nIf specified, the CSI driver will create or update the volume with the attributes defined\nin the corresponding VolumeAttributesClass. This has a different purpose than storageClassName,\nit can be changed after the claim is created. An empty string or nil value indicates that no\nVolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state,\nthis field can be reset to its previous value (including nil) to cancel the modification.\nIf the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be\nset to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource\nexists.\nMore info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/\n+featureGate=VolumeAttributesClass\n+optional", + "type": "string" + }, + "volumeMode": { + "description": "volumeMode defines what type of volume is required by the claim.\nValue of Filesystem is implied when not included in claim spec.\n+optional", + "type": "string" + }, + "volumeName": { + "description": "volumeName is the binding reference to the PersistentVolume backing this claim.\n+optional", + "type": "string" + } + } + }, + "V1PersistentVolumeClaimTemplate": { + "type": "object", + "properties": { + "metadata": { + "description": "May contain labels and annotations that will be copied into the PVC\nwhen creating it. No other fields are allowed and will be rejected during\nvalidation.\n\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectMeta" + } + ] + }, + "spec": { + "description": "The specification for the PersistentVolumeClaim. The entire content is\ncopied unchanged into the PVC that gets created from this\ntemplate. The same fields as in a PersistentVolumeClaim\nare also valid here.", + "allOf": [ + { + "$ref": "#/definitions/V1PersistentVolumeClaimSpec" + } + ] + } + } + }, + "V1PersistentVolumeClaimVolumeSource": { + "type": "object", + "properties": { + "claimName": { + "description": "claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims", + "type": "string" + }, + "readOnly": { + "description": "readOnly Will force the ReadOnly setting in VolumeMounts.\nDefault false.\n+optional", + "type": "boolean" + } + } + }, + "V1PhotonPersistentDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.", + "type": "string" + }, + "pdID": { + "description": "pdID is the ID that identifies Photon Controller persistent disk", + "type": "string" + } + } + }, + "V1PodAffinity": { + "type": "object", + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "description": "The scheduler will prefer to schedule pods to nodes that satisfy\nthe affinity expressions specified by this field, but it may choose\na node that violates one or more of the expressions. The node that is\nmost preferred is the one with the greatest sum of weights, i.e.\nfor each node that meets all of the scheduling requirements (resource\nrequest, requiredDuringScheduling affinity expressions, etc.),\ncompute a sum by iterating through the elements of this field and adding\n\"weight\" to the sum if the node has pods which matches the corresponding podAffinityTerm; the\nnode(s) with the highest sum are the most preferred.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1WeightedPodAffinityTerm" + } + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "description": "If the affinity requirements specified by this field are not met at\nscheduling time, the pod will not be scheduled onto the node.\nIf the affinity requirements specified by this field cease to be met\nat some point during pod execution (e.g. due to a pod label update), the\nsystem may or may not try to eventually evict the pod from its node.\nWhen there are multiple elements, the lists of nodes corresponding to each\npodAffinityTerm are intersected, i.e. all terms must be satisfied.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodAffinityTerm" + } + } + } + }, + "V1PodAffinityTerm": { + "type": "object", + "properties": { + "labelSelector": { + "description": "A label query over a set of resources, in this case pods.\nIf it's null, this PodAffinityTerm matches with no Pods.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "matchLabelKeys": { + "description": "MatchLabelKeys is a set of pod label keys to select which pods will\nbe taken into consideration. The keys are used to lookup values from the\nincoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)`\nto select the group of existing pods which pods will be taken into consideration\nfor the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming\npod labels will be ignored. The default value is empty.\nThe same key is forbidden to exist in both matchLabelKeys and labelSelector.\nAlso, matchLabelKeys cannot be set when labelSelector isn't set.\n\n+listType=atomic\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "mismatchLabelKeys": { + "description": "MismatchLabelKeys is a set of pod label keys to select which pods will\nbe taken into consideration. The keys are used to lookup values from the\nincoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)`\nto select the group of existing pods which pods will be taken into consideration\nfor the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming\npod labels will be ignored. The default value is empty.\nThe same key is forbidden to exist in both mismatchLabelKeys and labelSelector.\nAlso, mismatchLabelKeys cannot be set when labelSelector isn't set.\n\n+listType=atomic\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "namespaceSelector": { + "description": "A label query over the set of namespaces that the term applies to.\nThe term is applied to the union of the namespaces selected by this field\nand the ones listed in the namespaces field.\nnull selector and null or empty namespaces list means \"this pod's namespace\".\nAn empty selector ({}) matches all namespaces.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "namespaces": { + "description": "namespaces specifies a static list of namespace names that the term applies to.\nThe term is applied to the union of the namespaces listed in this field\nand the ones selected by namespaceSelector.\nnull or empty namespaces list and null namespaceSelector means \"this pod's namespace\".\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "topologyKey": { + "description": "This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching\nthe labelSelector in the specified namespaces, where co-located is defined as running on a node\nwhose value of the label with key topologyKey matches that of any node on which any of the\nselected pods is running.\nEmpty topologyKey is not allowed.", + "type": "string" + } + } + }, + "V1PodAntiAffinity": { + "type": "object", + "properties": { + "preferredDuringSchedulingIgnoredDuringExecution": { + "description": "The scheduler will prefer to schedule pods to nodes that satisfy\nthe anti-affinity expressions specified by this field, but it may choose\na node that violates one or more of the expressions. The node that is\nmost preferred is the one with the greatest sum of weights, i.e.\nfor each node that meets all of the scheduling requirements (resource\nrequest, requiredDuringScheduling anti-affinity expressions, etc.),\ncompute a sum by iterating through the elements of this field and subtracting\n\"weight\" from the sum if the node has pods which matches the corresponding podAffinityTerm; the\nnode(s) with the highest sum are the most preferred.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1WeightedPodAffinityTerm" + } + }, + "requiredDuringSchedulingIgnoredDuringExecution": { + "description": "If the anti-affinity requirements specified by this field are not met at\nscheduling time, the pod will not be scheduled onto the node.\nIf the anti-affinity requirements specified by this field cease to be met\nat some point during pod execution (e.g. due to a pod label update), the\nsystem may or may not try to eventually evict the pod from its node.\nWhen there are multiple elements, the lists of nodes corresponding to each\npodAffinityTerm are intersected, i.e. all terms must be satisfied.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodAffinityTerm" + } + } + } + }, + "V1PodCertificateProjection": { + "type": "object", + "properties": { + "certificateChainPath": { + "description": "Write the certificate chain at this path in the projected volume.\n\nMost applications should use credentialBundlePath. When using keyPath\nand certificateChainPath, your application needs to check that the key\nand leaf certificate are consistent, because it is possible to read the\nfiles mid-rotation.\n\n+optional", + "type": "string" + }, + "credentialBundlePath": { + "description": "Write the credential bundle at this path in the projected volume.\n\nThe credential bundle is a single file that contains multiple PEM blocks.\nThe first PEM block is a PRIVATE KEY block, containing a PKCS#8 private\nkey.\n\nThe remaining blocks are CERTIFICATE blocks, containing the issued\ncertificate chain from the signer (leaf and any intermediates).\n\nUsing credentialBundlePath lets your Pod's application code make a single\natomic read that retrieves a consistent key and certificate chain. If you\nproject them to separate files, your application code will need to\nadditionally check that the leaf certificate was issued to the key.\n\n+optional", + "type": "string" + }, + "keyPath": { + "description": "Write the key at this path in the projected volume.\n\nMost applications should use credentialBundlePath. When using keyPath\nand certificateChainPath, your application needs to check that the key\nand leaf certificate are consistent, because it is possible to read the\nfiles mid-rotation.\n\n+optional", + "type": "string" + }, + "keyType": { + "description": "The type of keypair Kubelet will generate for the pod.\n\nValid values are \"RSA3072\", \"RSA4096\", \"ECDSAP256\", \"ECDSAP384\",\n\"ECDSAP521\", and \"ED25519\".\n\n+required", + "type": "string" + }, + "maxExpirationSeconds": { + "description": "maxExpirationSeconds is the maximum lifetime permitted for the\ncertificate.\n\nKubelet copies this value verbatim into the PodCertificateRequests it\ngenerates for this projection.\n\nIf omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver\nwill reject values shorter than 3600 (1 hour). The maximum allowable\nvalue is 7862400 (91 days).\n\nThe signer implementation is then free to issue a certificate with any\nlifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600\nseconds (1 hour). This constraint is enforced by kube-apiserver.\n`kubernetes.io` signers will never issue certificates with a lifetime\nlonger than 24 hours.\n\n+optional", + "type": "integer" + }, + "signerName": { + "description": "Kubelet's generated CSRs will be addressed to this signer.\n\n+required", + "type": "string" + } + } + }, + "V1PodDNSConfig": { + "type": "object", + "properties": { + "nameservers": { + "description": "A list of DNS name server IP addresses.\nThis will be appended to the base nameservers generated from DNSPolicy.\nDuplicated nameservers will be removed.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "options": { + "description": "A list of DNS resolver options.\nThis will be merged with the base options generated from DNSPolicy.\nDuplicated entries will be removed. Resolution options given in Options\nwill override those that appear in the base DNSPolicy.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodDNSConfigOption" + } + }, + "searches": { + "description": "A list of DNS search domains for host-name lookup.\nThis will be appended to the base search paths generated from DNSPolicy.\nDuplicated search paths will be removed.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1PodDNSConfigOption": { + "type": "object", + "properties": { + "name": { + "description": "Name is this DNS resolver option's name.\nRequired.", + "type": "string" + }, + "value": { + "description": "Value is this DNS resolver option's value.\n+optional", + "type": "string" + } + } + }, + "V1PodFailurePolicy": { + "type": "object", + "properties": { + "rules": { + "description": "A list of pod failure policy rules. The rules are evaluated in order.\nOnce a rule matches a Pod failure, the remaining of the rules are ignored.\nWhen no rule matches the Pod failure, the default handling applies - the\ncounter of pod failures is incremented and it is checked against\nthe backoffLimit. At most 20 elements are allowed.\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodFailurePolicyRule" + } + } + } + }, + "V1PodFailurePolicyAction": { + "type": "string", + "enum": [ + "FailJob", + "FailIndex", + "Ignore", + "Count" + ], + "x-enum-varnames": [ + "PodFailurePolicyActionFailJob", + "PodFailurePolicyActionFailIndex", + "PodFailurePolicyActionIgnore", + "PodFailurePolicyActionCount" + ] + }, + "V1PodFailurePolicyOnExitCodesOperator": { + "type": "string", + "enum": [ + "In", + "NotIn" + ], + "x-enum-varnames": [ + "PodFailurePolicyOnExitCodesOpIn", + "PodFailurePolicyOnExitCodesOpNotIn" + ] + }, + "V1PodFailurePolicyOnExitCodesRequirement": { + "type": "object", + "properties": { + "containerName": { + "description": "Restricts the check for exit codes to the container with the\nspecified name. When null, the rule applies to all containers.\nWhen specified, it should match one the container or initContainer\nnames in the pod template.\n+optional", + "type": "string" + }, + "operator": { + "description": "Represents the relationship between the container exit code(s) and the\nspecified values. Containers completed with success (exit code 0) are\nexcluded from the requirement check. Possible values are:\n\n- In: the requirement is satisfied if at least one container exit code\n (might be multiple if there are multiple containers not restricted\n by the 'containerName' field) is in the set of specified values.\n- NotIn: the requirement is satisfied if at least one container exit code\n (might be multiple if there are multiple containers not restricted\n by the 'containerName' field) is not in the set of specified values.\nAdditional values are considered to be added in the future. Clients should\nreact to an unknown operator by assuming the requirement is not satisfied.", + "allOf": [ + { + "$ref": "#/definitions/V1PodFailurePolicyOnExitCodesOperator" + } + ] + }, + "values": { + "description": "Specifies the set of values. Each returned container exit code (might be\nmultiple in case of multiple containers) is checked against this set of\nvalues with respect to the operator. The list of values must be ordered\nand must not contain duplicates. Value '0' cannot be used for the In operator.\nAt least one element is required. At most 255 elements are allowed.\n+listType=set", + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "V1PodFailurePolicyOnPodConditionsPattern": { + "type": "object", + "properties": { + "status": { + "description": "Specifies the required Pod condition status. To match a pod condition\nit is required that the specified status equals the pod condition status.\nDefaults to True.", + "type": "string" + }, + "type": { + "description": "Specifies the required Pod condition type. To match a pod condition\nit is required that specified type equals the pod condition type.", + "type": "string" + } + } + }, + "V1PodFailurePolicyRule": { + "type": "object", + "properties": { + "action": { + "description": "Specifies the action taken on a pod failure when the requirements are satisfied.\nPossible values are:\n\n- FailJob: indicates that the pod's job is marked as Failed and all\n running pods are terminated.\n- FailIndex: indicates that the pod's index is marked as Failed and will\n not be restarted.\n- Ignore: indicates that the counter towards the .backoffLimit is not\n incremented and a replacement pod is created.\n- Count: indicates that the pod is handled in the default way - the\n counter towards the .backoffLimit is incremented.\nAdditional values are considered to be added in the future. Clients should\nreact to an unknown action by skipping the rule.", + "allOf": [ + { + "$ref": "#/definitions/V1PodFailurePolicyAction" + } + ] + }, + "onExitCodes": { + "description": "Represents the requirement on the container exit codes.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodFailurePolicyOnExitCodesRequirement" + } + ] + }, + "onPodConditions": { + "description": "Represents the requirement on the pod conditions. The requirement is represented\nas a list of pod condition patterns. The requirement is satisfied if at\nleast one pattern matches an actual pod condition. At most 20 elements are allowed.\n+listType=atomic\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodFailurePolicyOnPodConditionsPattern" + } + } + } + }, + "V1PodOS": { + "type": "object", + "properties": { + "name": { + "description": "Name is the name of the operating system. The currently supported values are linux and windows.\nAdditional value may be defined in future and can be one of:\nhttps://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration\nClients should expect to handle additional values and treat unrecognized values in this field as os: null", + "type": "string" + } + } + }, + "V1PodReadinessGate": { + "type": "object", + "properties": { + "conditionType": { + "description": "ConditionType refers to a condition in the pod's condition list with matching type.", + "type": "string" + } + } + }, + "V1PodReplacementPolicy": { + "type": "string", + "enum": [ + "TerminatingOrFailed", + "Failed" + ], + "x-enum-varnames": [ + "TerminatingOrFailed", + "Failed" + ] + }, + "V1PodResourceClaim": { + "type": "object", + "properties": { + "name": { + "description": "Name uniquely identifies this resource claim inside the pod.\nThis must be a DNS_LABEL.", + "type": "string" + }, + "resourceClaimName": { + "description": "ResourceClaimName is the name of a ResourceClaim object in the same\nnamespace as this pod.\n\nExactly one of ResourceClaimName and ResourceClaimTemplateName must\nbe set.", + "type": "string" + }, + "resourceClaimTemplateName": { + "description": "ResourceClaimTemplateName is the name of a ResourceClaimTemplate\nobject in the same namespace as this pod.\n\nThe template will be used to create a new ResourceClaim, which will\nbe bound to this pod. When this pod is deleted, the ResourceClaim\nwill also be deleted. The pod name and resource name, along with a\ngenerated component, will be used to form a unique name for the\nResourceClaim, which will be recorded in pod.status.resourceClaimStatuses.\n\nThis field is immutable and no changes will be made to the\ncorresponding ResourceClaim by the control plane after creating the\nResourceClaim.\n\nExactly one of ResourceClaimName and ResourceClaimTemplateName must\nbe set.", + "type": "string" + } + } + }, + "V1PodSchedulingGate": { + "type": "object", + "properties": { + "name": { + "description": "Name of the scheduling gate.\nEach scheduling gate must have a unique name field.", + "type": "string" + } + } + }, + "V1PodSecurityContext": { + "type": "object", + "properties": { + "appArmorProfile": { + "description": "appArmorProfile is the AppArmor options to use by the containers in this pod.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1AppArmorProfile" + } + ] + }, + "fsGroup": { + "description": "A special supplemental group that applies to all containers in a pod.\nSome volume types allow the Kubelet to change the ownership of that volume\nto be owned by the pod:\n\n1. The owning GID will be the FSGroup\n2. The setgid bit is set (new files created in the volume will be owned by FSGroup)\n3. The permission bits are OR'd with rw-rw----\n\nIf unset, the Kubelet will not modify the ownership and permissions of any volume.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "fsGroupChangePolicy": { + "description": "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume\nbefore being exposed inside Pod. This field will only apply to\nvolume types which support fsGroup based ownership(and permissions).\nIt will have no effect on ephemeral volume types such as: secret, configmaps\nand emptydir.\nValid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "string" + }, + "runAsGroup": { + "description": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence\nfor that container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "runAsNonRoot": { + "description": "Indicates that the container must run as a non-root user.\nIf true, the Kubelet will validate the image at runtime to ensure that it\ndoes not run as UID 0 (root) and fail to start the container if it does.\nIf unset or false, no such validation will be performed.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "boolean" + }, + "runAsUser": { + "description": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in SecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence\nfor that container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "seLinuxChangePolicy": { + "description": "seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.\nIt has no effect on nodes that do not support SELinux or to volumes does not support SELinux.\nValid values are \"MountOption\" and \"Recursive\".\n\n\"Recursive\" means relabeling of all files on all Pod volumes by the container runtime.\nThis may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.\n\n\"MountOption\" mounts all eligible Pod volumes with `-o context` mount option.\nThis requires all Pods that share the same volume to use the same SELinux label.\nIt is not possible to share the same volume among privileged and unprivileged Pods.\nEligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes\nwhose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their\nCSIDriver instance. Other volumes are always re-labelled recursively.\n\"MountOption\" value is allowed only when SELinuxMount feature gate is enabled.\n\nIf not specified and SELinuxMount feature gate is enabled, \"MountOption\" is used.\nIf not specified and SELinuxMount feature gate is disabled, \"MountOption\" is used for ReadWriteOncePod volumes\nand \"Recursive\" for all other volumes.\n\nThis field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.\n\nAll Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.\nNote that this field cannot be set when spec.os.name is windows.\n+featureGate=SELinuxChangePolicy\n+optional", + "type": "string" + }, + "seLinuxOptions": { + "description": "The SELinux context to be applied to all containers.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in SecurityContext. If set in\nboth SecurityContext and PodSecurityContext, the value specified in SecurityContext\ntakes precedence for that container.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SELinuxOptions" + } + ] + }, + "seccompProfile": { + "description": "The seccomp options to use by the containers in this pod.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SeccompProfile" + } + ] + }, + "supplementalGroups": { + "description": "A list of groups applied to the first process run in each container, in\naddition to the container's primary GID and fsGroup (if specified). If\nthe SupplementalGroupsPolicy feature is enabled, the\nsupplementalGroupsPolicy field determines whether these are in addition\nto or instead of any group memberships defined in the container image.\nIf unspecified, no additional groups are added, though group memberships\ndefined in the container image may still be used, depending on the\nsupplementalGroupsPolicy field.\nNote that this field cannot be set when spec.os.name is windows.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "integer" + } + }, + "supplementalGroupsPolicy": { + "description": "Defines how supplemental groups of the first container processes are calculated.\nValid values are \"Merge\" and \"Strict\". If not specified, \"Merge\" is used.\n(Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled\nand the container runtime must implement support for this feature.\nNote that this field cannot be set when spec.os.name is windows.\nTODO: update the default value to \"Merge\" when spec.os.name is not windows in v1.34\n+featureGate=SupplementalGroupsPolicy\n+optional", + "type": "string" + }, + "sysctls": { + "description": "Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported\nsysctls (by the container runtime) might fail to launch.\nNote that this field cannot be set when spec.os.name is windows.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1Sysctl" + } + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers.\nIf unspecified, the options within a container's SecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is linux.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1WindowsSecurityContextOptions" + } + ] + } + } + }, + "V1PodSpec": { + "type": "object", + "properties": { + "activeDeadlineSeconds": { + "description": "Optional duration in seconds the pod may be active on the node relative to\nStartTime before the system will actively try to mark it failed and kill associated containers.\nValue must be a positive integer.\n+optional", + "type": "integer" + }, + "affinity": { + "description": "If specified, the pod's scheduling constraints\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Affinity" + } + ] + }, + "automountServiceAccountToken": { + "description": "AutomountServiceAccountToken indicates whether a service account token should be automatically mounted.\n+optional", + "type": "boolean" + }, + "containers": { + "description": "List of containers belonging to the pod.\nContainers cannot currently be added or removed.\nThere must be at least one container in a Pod.\nCannot be updated.\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1Container" + } + }, + "dnsConfig": { + "description": "Specifies the DNS parameters of a pod.\nParameters specified here will be merged to the generated DNS\nconfiguration based on DNSPolicy.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodDNSConfig" + } + ] + }, + "dnsPolicy": { + "description": "Set DNS policy for the pod.\nDefaults to \"ClusterFirst\".\nValid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'.\nDNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy.\nTo have DNS options set along with hostNetwork, you have to specify DNS policy\nexplicitly to 'ClusterFirstWithHostNet'.\n+optional", + "type": "string" + }, + "enableServiceLinks": { + "description": "EnableServiceLinks indicates whether information about services should be injected into pod's\nenvironment variables, matching the syntax of Docker links.\nOptional: Defaults to true.\n+optional", + "type": "boolean" + }, + "ephemeralContainers": { + "description": "List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing\npod to perform user-initiated actions such as debugging. This list cannot be specified when\ncreating a pod, and it cannot be modified by updating the pod spec. In order to add an\nephemeral container to an existing pod, use the pod's ephemeralcontainers subresource.\n+optional\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1EphemeralContainer" + } + }, + "hostAliases": { + "description": "HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts\nfile if specified.\n+optional\n+patchMergeKey=ip\n+patchStrategy=merge\n+listType=map\n+listMapKey=ip", + "type": "array", + "items": { + "$ref": "#/definitions/V1HostAlias" + } + }, + "hostIPC": { + "description": "Use the host's ipc namespace.\nOptional: Default to false.\n+k8s:conversion-gen=false\n+optional", + "type": "boolean" + }, + "hostNetwork": { + "description": "Host networking requested for this pod. Use the host's network namespace.\nWhen using HostNetwork you should specify ports so the scheduler is aware.\nWhen `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`,\nand unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`.\nDefault to false.\n+k8s:conversion-gen=false\n+optional", + "type": "boolean" + }, + "hostPID": { + "description": "Use the host's pid namespace.\nOptional: Default to false.\n+k8s:conversion-gen=false\n+optional", + "type": "boolean" + }, + "hostUsers": { + "description": "Use the host's user namespace.\nOptional: Default to true.\nIf set to true or not present, the pod will be run in the host user namespace, useful\nfor when the pod needs a feature only available to the host user namespace, such as\nloading a kernel module with CAP_SYS_MODULE.\nWhen set to false, a new userns is created for the pod. Setting false is useful for\nmitigating container breakout vulnerabilities even allowing users to run their\ncontainers as root without actually having root privileges on the host.\nThis field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature.\n+k8s:conversion-gen=false\n+optional", + "type": "boolean" + }, + "hostname": { + "description": "Specifies the hostname of the Pod\nIf not specified, the pod's hostname will be set to a system-defined value.\n+optional", + "type": "string" + }, + "hostnameOverride": { + "description": "HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod.\nThis field only specifies the pod's hostname and does not affect its DNS records.\nWhen this field is set to a non-empty string:\n- It takes precedence over the values set in `hostname` and `subdomain`.\n- The Pod's hostname will be set to this value.\n- `setHostnameAsFQDN` must be nil or set to false.\n- `hostNetwork` must be set to false.\n\nThis field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters.\nRequires the HostnameOverride feature gate to be enabled.\n\n+featureGate=HostnameOverride\n+optional", + "type": "string" + }, + "imagePullSecrets": { + "description": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec.\nIf specified, these secrets will be passed to individual puller implementations for them to use.\nMore info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod\n+optional\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1LocalObjectReference" + } + }, + "initContainers": { + "description": "List of initialization containers belonging to the pod.\nInit containers are executed in order prior to containers being started. If any\ninit container fails, the pod is considered to have failed and is handled according\nto its restartPolicy. The name for an init container or normal container must be\nunique among all containers.\nInit containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes.\nThe resourceRequirements of an init container are taken into account during scheduling\nby finding the highest request/limit for each resource type, and then using the max of\nthat value or the sum of the normal containers. Limits are applied to init containers\nin a similar fashion.\nInit containers cannot currently be added or removed.\nCannot be updated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1Container" + } + }, + "nodeName": { + "description": "NodeName indicates in which node this pod is scheduled.\nIf empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName.\nOnce this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod.\nThis field should not be used to express a desire for the pod to be scheduled on a specific node.\nhttps://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename\n+optional", + "type": "string" + }, + "nodeSelector": { + "description": "NodeSelector is a selector which must be true for the pod to fit on a node.\nSelector which must match a node's labels for the pod to be scheduled on that node.\nMore info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/\n+optional\n+mapType=atomic", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "os": { + "description": "Specifies the OS of the containers in the pod.\nSome pod and container fields are restricted if this is set.\n\nIf the OS field is set to linux, the following fields must be unset:\n-securityContext.windowsOptions\n\nIf the OS field is set to windows, following fields must be unset:\n- spec.hostPID\n- spec.hostIPC\n- spec.hostUsers\n- spec.resources\n- spec.securityContext.appArmorProfile\n- spec.securityContext.seLinuxOptions\n- spec.securityContext.seccompProfile\n- spec.securityContext.fsGroup\n- spec.securityContext.fsGroupChangePolicy\n- spec.securityContext.sysctls\n- spec.shareProcessNamespace\n- spec.securityContext.runAsUser\n- spec.securityContext.runAsGroup\n- spec.securityContext.supplementalGroups\n- spec.securityContext.supplementalGroupsPolicy\n- spec.containers[*].securityContext.appArmorProfile\n- spec.containers[*].securityContext.seLinuxOptions\n- spec.containers[*].securityContext.seccompProfile\n- spec.containers[*].securityContext.capabilities\n- spec.containers[*].securityContext.readOnlyRootFilesystem\n- spec.containers[*].securityContext.privileged\n- spec.containers[*].securityContext.allowPrivilegeEscalation\n- spec.containers[*].securityContext.procMount\n- spec.containers[*].securityContext.runAsUser\n- spec.containers[*].securityContext.runAsGroup\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodOS" + } + ] + }, + "overhead": { + "description": "Overhead represents the resource overhead associated with running a pod for a given RuntimeClass.\nThis field will be autopopulated at admission time by the RuntimeClass admission controller. If\nthe RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests.\nThe RuntimeClass admission controller will reject Pod create requests which have the overhead already\nset. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value\ndefined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceList" + } + ] + }, + "preemptionPolicy": { + "description": "PreemptionPolicy is the Policy for preempting pods with lower priority.\nOne of Never, PreemptLowerPriority.\nDefaults to PreemptLowerPriority if unset.\n+optional", + "type": "string" + }, + "priority": { + "description": "The priority value. Various system components use this field to find the\npriority of the pod. When Priority Admission Controller is enabled, it\nprevents users from setting this field. The admission controller populates\nthis field from PriorityClassName.\nThe higher the value, the higher the priority.\n+optional", + "type": "integer" + }, + "priorityClassName": { + "description": "If specified, indicates the pod's priority. \"system-node-critical\" and\n\"system-cluster-critical\" are two special keywords which indicate the\nhighest priorities with the former being the highest priority. Any other\nname must be defined by creating a PriorityClass object with that name.\nIf not specified, the pod priority will be default or zero if there is no\ndefault.\n+optional", + "type": "string" + }, + "readinessGates": { + "description": "If specified, all readiness gates will be evaluated for pod readiness.\nA pod is ready when all its containers are ready AND\nall conditions specified in the readiness gates have status equal to \"True\"\nMore info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodReadinessGate" + } + }, + "resourceClaims": { + "description": "ResourceClaims defines which ResourceClaims must be allocated\nand reserved before the Pod is allowed to start. The resources\nwill be made available to those containers which consume them\nby name.\n\nThis is an alpha field and requires enabling the\nDynamicResourceAllocation feature gate.\n\nThis field is immutable.\n\n+patchMergeKey=name\n+patchStrategy=merge,retainKeys\n+listType=map\n+listMapKey=name\n+featureGate=DynamicResourceAllocation\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodResourceClaim" + } + }, + "resources": { + "description": "Resources is the total amount of CPU and Memory resources required by all\ncontainers in the pod. It supports specifying Requests and Limits for\n\"cpu\", \"memory\" and \"hugepages-\" resource names only. ResourceClaims are not supported.\n\nThis field enables fine-grained control over resource allocation for the\nentire pod, allowing resource sharing among containers in a pod.\nTODO: For beta graduation, expand this comment with a detailed explanation.\n\nThis is an alpha field and requires enabling the PodLevelResources feature\ngate.\n\n+featureGate=PodLevelResources\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceRequirements" + } + ] + }, + "restartPolicy": { + "description": "Restart policy for all containers within the pod.\nOne of Always, OnFailure, Never. In some contexts, only a subset of those values may be permitted.\nDefault to Always.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy\n+optional", + "type": "string" + }, + "runtimeClassName": { + "description": "RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used\nto run this pod. If no RuntimeClass resource matches the named class, the pod will not be run.\nIf unset or empty, the \"legacy\" RuntimeClass will be used, which is an implicit class with an\nempty definition that uses the default runtime handler.\nMore info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class\n+optional", + "type": "string" + }, + "schedulerName": { + "description": "If specified, the pod will be dispatched by specified scheduler.\nIf not specified, the pod will be dispatched by default scheduler.\n+optional", + "type": "string" + }, + "schedulingGates": { + "description": "SchedulingGates is an opaque list of values that if specified will block scheduling the pod.\nIf schedulingGates is not empty, the pod will stay in the SchedulingGated state and the\nscheduler will not attempt to schedule the pod.\n\nSchedulingGates can only be set at pod creation time, and be removed only afterwards.\n\n+patchMergeKey=name\n+patchStrategy=merge\n+listType=map\n+listMapKey=name\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/V1PodSchedulingGate" + } + }, + "securityContext": { + "description": "SecurityContext holds pod-level security attributes and common container settings.\nOptional: Defaults to empty. See type description for default values of each field.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodSecurityContext" + } + ] + }, + "serviceAccount": { + "description": "DeprecatedServiceAccount is a deprecated alias for ServiceAccountName.\nDeprecated: Use serviceAccountName instead.\n+k8s:conversion-gen=false\n+optional", + "type": "string" + }, + "serviceAccountName": { + "description": "ServiceAccountName is the name of the ServiceAccount to use to run this pod.\nMore info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/\n+optional", + "type": "string" + }, + "setHostnameAsFQDN": { + "description": "If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default).\nIn Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname).\nIn Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlSet\\\\Services\\\\Tcpip\\\\Parameters to FQDN.\nIf a pod does not have FQDN, this has no effect.\nDefault to false.\n+optional", + "type": "boolean" + }, + "shareProcessNamespace": { + "description": "Share a single process namespace between all of the containers in a pod.\nWhen this is set containers will be able to view and signal processes from other containers\nin the same pod, and the first process in each container will not be assigned PID 1.\nHostPID and ShareProcessNamespace cannot both be set.\nOptional: Default to false.\n+k8s:conversion-gen=false\n+optional", + "type": "boolean" + }, + "subdomain": { + "description": "If specified, the fully qualified Pod hostname will be \"...svc.\".\nIf not specified, the pod will not have a domainname at all.\n+optional", + "type": "string" + }, + "terminationGracePeriodSeconds": { + "description": "Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request.\nValue must be non-negative integer. The value zero indicates stop immediately via\nthe kill signal (no opportunity to shut down).\nIf this value is nil, the default grace period will be used instead.\nThe grace period is the duration in seconds after the processes running in the pod are sent\na termination signal and the time when the processes are forcibly halted with a kill signal.\nSet this value longer than the expected cleanup time for your process.\nDefaults to 30 seconds.\n+optional", + "type": "integer" + }, + "tolerations": { + "description": "If specified, the pod's tolerations.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1Toleration" + } + }, + "topologySpreadConstraints": { + "description": "TopologySpreadConstraints describes how a group of pods ought to spread across topology\ndomains. Scheduler will schedule pods in a way which abides by the constraints.\nAll topologySpreadConstraints are ANDed.\n+optional\n+patchMergeKey=topologyKey\n+patchStrategy=merge\n+listType=map\n+listMapKey=topologyKey\n+listMapKey=whenUnsatisfiable", + "type": "array", + "items": { + "$ref": "#/definitions/V1TopologySpreadConstraint" + } + }, + "volumes": { + "description": "List of volumes that can be mounted by containers belonging to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes\n+optional\n+patchMergeKey=name\n+patchStrategy=merge,retainKeys\n+listType=map\n+listMapKey=name", + "type": "array", + "items": { + "$ref": "#/definitions/V1Volume" + } + } + } + }, + "V1PodTemplateSpec": { + "type": "object", + "properties": { + "metadata": { + "description": "Standard object's metadata.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectMeta" + } + ] + }, + "spec": { + "description": "Specification of the desired behavior of the pod.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodSpec" + } + ] + } + } + }, + "V1PolicyRule": { + "type": "object", + "properties": { + "apiGroups": { + "description": "APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of\nthe enumerated resources in any API group will be allowed. \"\" represents the core API group and \"*\" represents all API groups.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "nonResourceURLs": { + "description": "NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path\nSince non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding.\nRules can either apply to API resources (such as \"pods\" or \"secrets\") or non-resource URL paths (such as \"/api\"), but not both.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "resourceNames": { + "description": "ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "description": "Resources is a list of resources this rule applies to. '*' represents all resources.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "verbs": { + "description": "Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs.\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "V1PortworxVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fSType represents the filesystem type to mount\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\". Implicitly inferred to be \"ext4\" if unspecified.", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "volumeID": { + "description": "volumeID uniquely identifies a Portworx volume", + "type": "string" + } + } + }, + "V1PreferredSchedulingTerm": { + "type": "object", + "properties": { + "preference": { + "description": "A node selector term, associated with the corresponding weight.", + "allOf": [ + { + "$ref": "#/definitions/V1NodeSelectorTerm" + } + ] + }, + "weight": { + "description": "Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100.", + "type": "integer" + } + } + }, + "V1Probe": { + "type": "object", + "properties": { + "exec": { + "description": "Exec specifies a command to execute in the container.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ExecAction" + } + ] + }, + "failureThreshold": { + "description": "Minimum consecutive failures for the probe to be considered failed after having succeeded.\nDefaults to 3. Minimum value is 1.\n+optional", + "type": "integer" + }, + "grpc": { + "description": "GRPC specifies a GRPC HealthCheckRequest.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1GRPCAction" + } + ] + }, + "httpGet": { + "description": "HTTPGet specifies an HTTP GET request to perform.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1HTTPGetAction" + } + ] + }, + "initialDelaySeconds": { + "description": "Number of seconds after the container has started before liveness probes are initiated.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "type": "integer" + }, + "periodSeconds": { + "description": "How often (in seconds) to perform the probe.\nDefault to 10 seconds. Minimum value is 1.\n+optional", + "type": "integer" + }, + "successThreshold": { + "description": "Minimum consecutive successes for the probe to be considered successful after having failed.\nDefaults to 1. Must be 1 for liveness and startup. Minimum value is 1.\n+optional", + "type": "integer" + }, + "tcpSocket": { + "description": "TCPSocket specifies a connection to a TCP port.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1TCPSocketAction" + } + ] + }, + "terminationGracePeriodSeconds": { + "description": "Optional duration in seconds the pod needs to terminate gracefully upon probe failure.\nThe grace period is the duration in seconds after the processes running in the pod are sent\na termination signal and the time when the processes are forcibly halted with a kill signal.\nSet this value longer than the expected cleanup time for your process.\nIf this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this\nvalue overrides the value provided by the pod spec.\nValue must be non-negative integer. The value zero indicates stop immediately via\nthe kill signal (no opportunity to shut down).\nThis is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.\nMinimum value is 1. spec.terminationGracePeriodSeconds is used if unset.\n+optional", + "type": "integer" + }, + "timeoutSeconds": { + "description": "Number of seconds after which the probe times out.\nDefaults to 1 second. Minimum value is 1.\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes\n+optional", + "type": "integer" + } + } + }, + "V1ProjectedVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode are the mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values for mode bits.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "sources": { + "description": "sources is the list of volume projections. Each entry in this list\nhandles one source.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1VolumeProjection" + } + } + } + }, + "V1QuobyteVolumeSource": { + "type": "object", + "properties": { + "group": { + "description": "group to map volume access to\nDefault is no group\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the Quobyte volume to be mounted with read-only permissions.\nDefaults to false.\n+optional", + "type": "boolean" + }, + "registry": { + "description": "registry represents a single or multiple Quobyte Registry services\nspecified as a string as host:port pair (multiple entries are separated with commas)\nwhich acts as the central registry for volumes", + "type": "string" + }, + "tenant": { + "description": "tenant owning the given Quobyte volume in the Backend\nUsed with dynamically provisioned Quobyte volumes, value is set by the plugin\n+optional", + "type": "string" + }, + "user": { + "description": "user to map volume access to\nDefaults to serivceaccount user\n+optional", + "type": "string" + }, + "volume": { + "description": "volume is a string that references an already created Quobyte volume by name.", + "type": "string" + } + } + }, + "V1RBDVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type of the volume that you want to mount.\nTip: Ensure that the filesystem type is supported by the host operating system.\nExamples: \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#rbd\nTODO: how do we prevent errors in the filesystem from compromising the machine\n+optional", + "type": "string" + }, + "image": { + "description": "image is the rados image name.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it", + "type": "string" + }, + "keyring": { + "description": "keyring is the path to key ring for RBDUser.\nDefault is /etc/ceph/keyring.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional\n+default=\"/etc/ceph/keyring\"", + "type": "string" + }, + "monitors": { + "description": "monitors is a collection of Ceph monitors.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+listType=atomic", + "type": "array", + "items": { + "type": "string" + } + }, + "pool": { + "description": "pool is the rados pool name.\nDefault is rbd.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional\n+default=\"rbd\"", + "type": "string" + }, + "readOnly": { + "description": "readOnly here will force the ReadOnly setting in VolumeMounts.\nDefaults to false.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef is name of the authentication secret for RBDUser. If provided\noverrides keyring.\nDefault is nil.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "user": { + "description": "user is the rados user name.\nDefault is admin.\nMore info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it\n+optional\n+default=\"admin\"", + "type": "string" + } + } + }, + "V1ResourceFieldSelector": { + "type": "object", + "properties": { + "containerName": { + "description": "Container name: required for volumes, optional for env vars\n+optional", + "type": "string" + }, + "divisor": { + "description": "Specifies the output format of the exposed resources, defaults to \"1\"\n+optional", + "allOf": [ + { + "$ref": "#/definitions/Quantity" + } + ] + }, + "resource": { + "description": "Required: resource to select", + "type": "string" + } + } + }, + "V1ResourceList": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Quantity" + } + }, + "V1ResourceRequirements": { + "type": "object", + "properties": { + "claims": { + "description": "Claims lists the names of resources, defined in spec.resourceClaims,\nthat are used by this container.\n\nThis field depends on the\nDynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.\n\n+listType=map\n+listMapKey=name\n+featureGate=DynamicResourceAllocation\n+optional", + "type": "array", + "items": { + "$ref": "#/definitions/V1ResourceClaim" + } + }, + "limits": { + "description": "Limits describes the maximum amount of compute resources allowed.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceList" + } + ] + }, + "requests": { + "description": "Requests describes the minimum amount of compute resources required.\nIf Requests is omitted for a container, it defaults to Limits if that is explicitly specified,\notherwise to an implementation-defined value. Requests cannot exceed Limits.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceList" + } + ] + } + } + }, + "V1SELinuxOptions": { + "type": "object", + "properties": { + "level": { + "description": "Level is SELinux level label that applies to the container.\n+optional", + "type": "string" + }, + "role": { + "description": "Role is a SELinux role label that applies to the container.\n+optional", + "type": "string" + }, + "type": { + "description": "Type is a SELinux type label that applies to the container.\n+optional", + "type": "string" + }, + "user": { + "description": "User is a SELinux user label that applies to the container.\n+optional", + "type": "string" + } + } + }, + "V1ScaleIOVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\".\nDefault is \"xfs\".\n+optional\n+default=\"xfs\"", + "type": "string" + }, + "gateway": { + "description": "gateway is the host address of the ScaleIO API Gateway.", + "type": "string" + }, + "protectionDomain": { + "description": "protectionDomain is the name of the ScaleIO Protection Domain for the configured storage.\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly Defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef references to the secret for ScaleIO user and other\nsensitive information. If this is not provided, Login operation will fail.", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "sslEnabled": { + "description": "sslEnabled Flag enable/disable SSL communication with Gateway, default false\n+optional", + "type": "boolean" + }, + "storageMode": { + "description": "storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned.\nDefault is ThinProvisioned.\n+optional\n+default=\"ThinProvisioned\"", + "type": "string" + }, + "storagePool": { + "description": "storagePool is the ScaleIO Storage Pool associated with the protection domain.\n+optional", + "type": "string" + }, + "system": { + "description": "system is the name of the storage system as configured in ScaleIO.", + "type": "string" + }, + "volumeName": { + "description": "volumeName is the name of a volume already created in the ScaleIO system\nthat is associated with this volume source.", + "type": "string" + } + } + }, + "V1SeccompProfile": { + "type": "object", + "properties": { + "localhostProfile": { + "description": "localhostProfile indicates a profile defined in a file on the node should be used.\nThe profile must be preconfigured on the node to work.\nMust be a descending path, relative to the kubelet's configured seccomp profile location.\nMust be set if type is \"Localhost\". Must NOT be set for any other type.\n+optional", + "type": "string" + }, + "type": { + "description": "type indicates which kind of seccomp profile will be applied.\nValid options are:\n\nLocalhost - a profile defined in a file on the node should be used.\nRuntimeDefault - the container runtime default profile should be used.\nUnconfined - no profile should be applied.\n+unionDiscriminator", + "type": "string" + } + } + }, + "V1Secret": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "data": { + "description": "Data contains the secret data. Each key must consist of alphanumeric\ncharacters, '-', '_' or '.'. The serialized form of the secret data is a\nbase64 encoded string, representing the arbitrary (possibly non-string)\ndata value here. Described in https://tools.ietf.org/html/rfc4648#section-4\n+optional", + "type": "object", + "additionalProperties": { + "type": "string", + "format": "byte" + } + }, + "immutable": { + "description": "Immutable, if set to true, ensures that data stored in the Secret cannot\nbe updated (only object metadata can be modified).\nIf not set to true, the field can be modified at any time.\nDefaulted to nil.\n+optional", + "type": "boolean" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "description": "Standard object's metadata.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ObjectMeta" + } + ] + }, + "stringData": { + "description": "stringData allows specifying non-binary secret data in string form.\nIt is provided as a write-only input field for convenience.\nAll keys and values are merged into the data field on write, overwriting any existing values.\nThe stringData field is never output when reading from the API.\n+k8s:conversion-gen=false\n+optional", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "type": { + "description": "Used to facilitate programmatic handling of secret data.\nMore info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types\n+optional", + "type": "string" + } + } + }, + "V1SecretEnvSource": { + "type": "object", + "properties": { + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "Specify whether the Secret must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1SecretKeySelector": { + "type": "object", + "properties": { + "key": { + "description": "The key of the secret to select from. Must be a valid secret key.", + "type": "string" + }, + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "Specify whether the Secret or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1SecretList": { + "type": "object", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object.\nServers should convert recognized schemas to the latest internal value, and\nmay reject unrecognized values.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources\n+optional", + "type": "string" + }, + "items": { + "description": "Items is a list of secret objects.\nMore info: https://kubernetes.io/docs/concepts/configuration/secret", + "type": "array", + "items": { + "$ref": "#/definitions/V1Secret" + } + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents.\nServers may infer this from the endpoint the client submits requests to.\nCannot be updated.\nIn CamelCase.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "type": "string" + }, + "metadata": { + "description": "Standard list metadata.\nMore info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ListMeta" + } + ] + } + } + }, + "V1SecretProjection": { + "type": "object", + "properties": { + "items": { + "description": "items if unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1KeyToPath" + } + }, + "name": { + "description": "Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names\n+optional\n+default=\"\"\n+kubebuilder:default=\"\"\nTODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896.", + "type": "string" + }, + "optional": { + "description": "optional field specify whether the Secret or its key must be defined\n+optional", + "type": "boolean" + } + } + }, + "V1SecretVolumeSource": { + "type": "object", + "properties": { + "defaultMode": { + "description": "defaultMode is Optional: mode bits used to set permissions on created files by default.\nMust be an octal value between 0000 and 0777 or a decimal value between 0 and 511.\nYAML accepts both octal and decimal values, JSON requires decimal values\nfor mode bits. Defaults to 0644.\nDirectories within the path are not affected by this setting.\nThis might be in conflict with other options that affect the file\nmode, like fsGroup, and the result can be other mode bits set.\n+optional", + "type": "integer" + }, + "items": { + "description": "items If unspecified, each key-value pair in the Data field of the referenced\nSecret will be projected into the volume as a file whose name is the\nkey and content is the value. If specified, the listed keys will be\nprojected into the specified paths, and unlisted keys will not be\npresent. If a key is specified which is not present in the Secret,\nthe volume setup will error unless it is marked optional. Paths must be\nrelative and may not contain the '..' path or start with '..'.\n+optional\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1KeyToPath" + } + }, + "optional": { + "description": "optional field specify whether the Secret or its keys must be defined\n+optional", + "type": "boolean" + }, + "secretName": { + "description": "secretName is the name of the secret in the pod's namespace to use.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional", + "type": "string" + } + } + }, + "V1SecurityContext": { + "type": "object", + "properties": { + "allowPrivilegeEscalation": { + "description": "AllowPrivilegeEscalation controls whether a process can gain more\nprivileges than its parent process. This bool directly controls if\nthe no_new_privs flag will be set on the container process.\nAllowPrivilegeEscalation is true always when the container is:\n1) run as Privileged\n2) has CAP_SYS_ADMIN\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "appArmorProfile": { + "description": "appArmorProfile is the AppArmor options to use by this container. If set, this profile\noverrides the pod's appArmorProfile.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1AppArmorProfile" + } + ] + }, + "capabilities": { + "description": "The capabilities to add/drop when running containers.\nDefaults to the default set of capabilities granted by the container runtime.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1Capabilities" + } + ] + }, + "privileged": { + "description": "Run container in privileged mode.\nProcesses in privileged containers are essentially equivalent to root on the host.\nDefaults to false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "procMount": { + "description": "procMount denotes the type of proc mount to use for the containers.\nThe default value is Default which uses the container runtime defaults for\nreadonly paths and masked paths.\nThis requires the ProcMountType feature flag to be enabled.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "string" + }, + "readOnlyRootFilesystem": { + "description": "Whether this container has a read-only root filesystem.\nDefault is false.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "boolean" + }, + "runAsGroup": { + "description": "The GID to run the entrypoint of the container process.\nUses runtime default if unset.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "runAsNonRoot": { + "description": "Indicates that the container must run as a non-root user.\nIf true, the Kubelet will validate the image at runtime to ensure that it\ndoes not run as UID 0 (root) and fail to start the container if it does.\nIf unset or false, no such validation will be performed.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "boolean" + }, + "runAsUser": { + "description": "The UID to run the entrypoint of the container process.\nDefaults to user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "type": "integer" + }, + "seLinuxOptions": { + "description": "The SELinux context to be applied to the container.\nIf unspecified, the container runtime will allocate a random SELinux context for each\ncontainer. May also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SELinuxOptions" + } + ] + }, + "seccompProfile": { + "description": "The seccomp options to use by this container. If seccomp options are\nprovided at both the pod & container level, the container options\noverride the pod options.\nNote that this field cannot be set when spec.os.name is windows.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SeccompProfile" + } + ] + }, + "windowsOptions": { + "description": "The Windows specific settings applied to all containers.\nIf unspecified, the options from the PodSecurityContext will be used.\nIf set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.\nNote that this field cannot be set when spec.os.name is linux.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1WindowsSecurityContextOptions" + } + ] + } + } + }, + "V1ServiceAccountTokenProjection": { + "type": "object", + "properties": { + "audience": { + "description": "audience is the intended audience of the token. A recipient of a token\nmust identify itself with an identifier specified in the audience of the\ntoken, and otherwise should reject the token. The audience defaults to the\nidentifier of the apiserver.\n+optional", + "type": "string" + }, + "expirationSeconds": { + "description": "expirationSeconds is the requested duration of validity of the service\naccount token. As the token approaches expiration, the kubelet volume\nplugin will proactively rotate the service account token. The kubelet will\nstart trying to rotate the token if the token is older than 80 percent of\nits time to live or if the token is older than 24 hours.Defaults to 1 hour\nand must be at least 10 minutes.\n+optional", + "type": "integer" + }, + "path": { + "description": "path is the path relative to the mount point of the file to project the\ntoken into.", + "type": "string" + } + } + }, + "V1SleepAction": { + "type": "object", + "properties": { + "seconds": { + "description": "Seconds is the number of seconds to sleep.", + "type": "integer" + } + } + }, + "V1StorageOSVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is the filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "readOnly": { + "description": "readOnly defaults to false (read/write). ReadOnly here will force\nthe ReadOnly setting in VolumeMounts.\n+optional", + "type": "boolean" + }, + "secretRef": { + "description": "secretRef specifies the secret to use for obtaining the StorageOS API\ncredentials. If not specified, default values will be attempted.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LocalObjectReference" + } + ] + }, + "volumeName": { + "description": "volumeName is the human-readable name of the StorageOS volume. Volume\nnames are only unique within a namespace.", + "type": "string" + }, + "volumeNamespace": { + "description": "volumeNamespace specifies the scope of the volume within StorageOS. If no\nnamespace is specified then the Pod's namespace will be used. This allows the\nKubernetes name scoping to be mirrored within StorageOS for tighter integration.\nSet VolumeName to any name to override the default behaviour.\nSet to \"default\" if you are not using namespaces within StorageOS.\nNamespaces that do not pre-exist within StorageOS will be created.\n+optional", + "type": "string" + } + } + }, + "V1SuccessPolicy": { + "type": "object", + "properties": { + "rules": { + "description": "rules represents the list of alternative rules for the declaring the Jobs\nas successful before `.status.succeeded >= .spec.completions`. Once any of the rules are met,\nthe \"SuccessCriteriaMet\" condition is added, and the lingering pods are removed.\nThe terminal state for such a Job has the \"Complete\" condition.\nAdditionally, these rules are evaluated in order; Once the Job meets one of the rules,\nother rules are ignored. At most 20 elements are allowed.\n+listType=atomic", + "type": "array", + "items": { + "$ref": "#/definitions/V1SuccessPolicyRule" + } + } + } + }, + "V1SuccessPolicyRule": { + "type": "object", + "properties": { + "succeededCount": { + "description": "succeededCount specifies the minimal required size of the actual set of the succeeded indexes\nfor the Job. When succeededCount is used along with succeededIndexes, the check is\nconstrained only to the set of indexes specified by succeededIndexes.\nFor example, given that succeededIndexes is \"1-4\", succeededCount is \"3\",\nand completed indexes are \"1\", \"3\", and \"5\", the Job isn't declared as succeeded\nbecause only \"1\" and \"3\" indexes are considered in that rules.\nWhen this field is null, this doesn't default to any value and\nis never evaluated at any time.\nWhen specified it needs to be a positive integer.\n\n+optional", + "type": "integer" + }, + "succeededIndexes": { + "description": "succeededIndexes specifies the set of indexes\nwhich need to be contained in the actual set of the succeeded indexes for the Job.\nThe list of indexes must be within 0 to \".spec.completions-1\" and\nmust not contain duplicates. At least one element is required.\nThe indexes are represented as intervals separated by commas.\nThe intervals can be a decimal integer or a pair of decimal integers separated by a hyphen.\nThe number are listed in represented by the first and last element of the series,\nseparated by a hyphen.\nFor example, if the completed indexes are 1, 3, 4, 5 and 7, they are\nrepresented as \"1,3-5,7\".\nWhen this field is null, this field doesn't default to any value\nand is never evaluated at any time.\n\n+optional", + "type": "string" + } + } + }, + "V1Sysctl": { + "type": "object", + "properties": { + "name": { + "description": "Name of a property to set", + "type": "string" + }, + "value": { + "description": "Value of a property to set", + "type": "string" + } + } + }, + "V1TCPSocketAction": { + "type": "object", + "properties": { + "host": { + "description": "Optional: Host name to connect to, defaults to the pod IP.\n+optional", + "type": "string" + }, + "port": { + "description": "Number or name of the port to access on the container.\nNumber must be in the range 1 to 65535.\nName must be an IANA_SVC_NAME.", + "allOf": [ + { + "$ref": "#/definitions/IntOrString" + } + ] + } + } + }, + "V1Toleration": { + "type": "object", + "properties": { + "effect": { + "description": "Effect indicates the taint effect to match. Empty means match all taint effects.\nWhen specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.\n+optional", + "type": "string" + }, + "key": { + "description": "Key is the taint key that the toleration applies to. Empty means match all taint keys.\nIf the key is empty, operator must be Exists; this combination means to match all values and all keys.\n+optional", + "type": "string" + }, + "operator": { + "description": "Operator represents a key's relationship to the value.\nValid operators are Exists and Equal. Defaults to Equal.\nExists is equivalent to wildcard for value, so that a pod can\ntolerate all taints of a particular category.\n+optional", + "type": "string" + }, + "tolerationSeconds": { + "description": "TolerationSeconds represents the period of time the toleration (which must be\nof effect NoExecute, otherwise this field is ignored) tolerates the taint. By default,\nit is not set, which means tolerate the taint forever (do not evict). Zero and\nnegative values will be treated as 0 (evict immediately) by the system.\n+optional", + "type": "integer" + }, + "value": { + "description": "Value is the taint value the toleration matches to.\nIf the operator is Exists, the value should be empty, otherwise just a regular string.\n+optional", + "type": "string" + } + } + }, + "V1TopologySpreadConstraint": { + "type": "object", + "properties": { + "labelSelector": { + "description": "LabelSelector is used to find matching pods.\nPods that match this label selector are counted to determine the number of pods\nin their corresponding topology domain.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1LabelSelector" + } + ] + }, + "matchLabelKeys": { + "description": "MatchLabelKeys is a set of pod label keys to select the pods over which\nspreading will be calculated. The keys are used to lookup values from the\nincoming pod labels, those key-value labels are ANDed with labelSelector\nto select the group of existing pods over which spreading will be calculated\nfor the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector.\nMatchLabelKeys cannot be set when LabelSelector isn't set.\nKeys that don't exist in the incoming pod labels will\nbe ignored. A null or empty list means only match against labelSelector.\n\nThis is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default).\n+listType=atomic\n+optional", + "type": "array", + "items": { + "type": "string" + } + }, + "maxSkew": { + "description": "MaxSkew describes the degree to which pods may be unevenly distributed.\nWhen `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference\nbetween the number of matching pods in the target topology and the global minimum.\nThe global minimum is the minimum number of matching pods in an eligible domain\nor zero if the number of eligible domains is less than MinDomains.\nFor example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same\nlabelSelector spread as 2/2/1:\nIn this case, the global minimum is 1.\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P | P P | P |\n+-------+-------+-------+\n- if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2;\nscheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2)\nviolate MaxSkew(1).\n- if MaxSkew is 2, incoming pod can be scheduled onto any zone.\nWhen `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence\nto topologies that satisfy it.\nIt's a required field. Default value is 1 and 0 is not allowed.", + "type": "integer" + }, + "minDomains": { + "description": "MinDomains indicates a minimum number of eligible domains.\nWhen the number of eligible domains with matching topology keys is less than minDomains,\nPod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed.\nAnd when the number of eligible domains with matching topology keys equals or greater than minDomains,\nthis value has no effect on scheduling.\nAs a result, when the number of eligible domains is less than minDomains,\nscheduler won't schedule more than maxSkew Pods to those domains.\nIf value is nil, the constraint behaves as if MinDomains is equal to 1.\nValid values are integers greater than 0.\nWhen value is not nil, WhenUnsatisfiable must be DoNotSchedule.\n\nFor example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same\nlabelSelector spread as 2/2/2:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P | P P | P P |\n+-------+-------+-------+\nThe number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0.\nIn this situation, new pod with the same labelSelector cannot be scheduled,\nbecause computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones,\nit will violate MaxSkew.\n+optional", + "type": "integer" + }, + "nodeAffinityPolicy": { + "description": "NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector\nwhen calculating pod topology spread skew. Options are:\n- Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations.\n- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.\n\nIf this value is nil, the behavior is equivalent to the Honor policy.\n+optional", + "type": "string" + }, + "nodeTaintsPolicy": { + "description": "NodeTaintsPolicy indicates how we will treat node taints when calculating\npod topology spread skew. Options are:\n- Honor: nodes without taints, along with tainted nodes for which the incoming pod\nhas a toleration, are included.\n- Ignore: node taints are ignored. All nodes are included.\n\nIf this value is nil, the behavior is equivalent to the Ignore policy.\n+optional", + "type": "string" + }, + "topologyKey": { + "description": "TopologyKey is the key of node labels. Nodes that have a label with this key\nand identical values are considered to be in the same topology.\nWe consider each as a \"bucket\", and try to put balanced number\nof pods into each bucket.\nWe define a domain as a particular instance of a topology.\nAlso, we define an eligible domain as a domain whose nodes meet the requirements of\nnodeAffinityPolicy and nodeTaintsPolicy.\ne.g. If TopologyKey is \"kubernetes.io/hostname\", each Node is a domain of that topology.\nAnd, if TopologyKey is \"topology.kubernetes.io/zone\", each zone is a domain of that topology.\nIt's a required field.", + "type": "string" + }, + "whenUnsatisfiable": { + "description": "WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy\nthe spread constraint.\n- DoNotSchedule (default) tells the scheduler not to schedule it.\n- ScheduleAnyway tells the scheduler to schedule the pod in any location,\n but giving higher precedence to topologies that would help reduce the\n skew.\nA constraint is considered \"Unsatisfiable\" for an incoming pod\nif and only if every possible node assignment for that pod would violate\n\"MaxSkew\" on some topology.\nFor example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same\nlabelSelector spread as 3/1/1:\n+-------+-------+-------+\n| zone1 | zone2 | zone3 |\n+-------+-------+-------+\n| P P P | P | P |\n+-------+-------+-------+\nIf WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled\nto zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies\nMaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler\nwon't make it *more* imbalanced.\nIt's a required field.", + "type": "string" + } + } + }, + "V1TypedLocalObjectReference": { + "type": "object", + "properties": { + "apiGroup": { + "description": "APIGroup is the group for the resource being referenced.\nIf APIGroup is not specified, the specified Kind must be in the core API group.\nFor any other third-party types, APIGroup is required.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is the type of resource being referenced", + "type": "string" + }, + "name": { + "description": "Name is the name of resource being referenced", + "type": "string" + } + } + }, + "V1TypedObjectReference": { + "type": "object", + "properties": { + "apiGroup": { + "description": "APIGroup is the group for the resource being referenced.\nIf APIGroup is not specified, the specified Kind must be in the core API group.\nFor any other third-party types, APIGroup is required.\n+optional", + "type": "string" + }, + "kind": { + "description": "Kind is the type of resource being referenced", + "type": "string" + }, + "name": { + "description": "Name is the name of resource being referenced", + "type": "string" + }, + "namespace": { + "description": "Namespace is the namespace of resource being referenced\nNote that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details.\n(Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled.\n+featureGate=CrossNamespaceVolumeDataSource\n+optional", + "type": "string" + } + } + }, + "V1Volume": { + "type": "object", + "properties": { + "awsElasticBlockStore": { + "description": "awsElasticBlockStore represents an AWS Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nDeprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree\nawsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1AWSElasticBlockStoreVolumeSource" + } + ] + }, + "azureDisk": { + "description": "azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.\nDeprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type\nare redirected to the disk.csi.azure.com CSI driver.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1AzureDiskVolumeSource" + } + ] + }, + "azureFile": { + "description": "azureFile represents an Azure File Service mount on the host and bind mount to the pod.\nDeprecated: AzureFile is deprecated. All operations for the in-tree azureFile type\nare redirected to the file.csi.azure.com CSI driver.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1AzureFileVolumeSource" + } + ] + }, + "cephfs": { + "description": "cephFS represents a Ceph FS mount on the host that shares a pod's lifetime.\nDeprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1CephFSVolumeSource" + } + ] + }, + "cinder": { + "description": "cinder represents a cinder volume attached and mounted on kubelets host machine.\nDeprecated: Cinder is deprecated. All operations for the in-tree cinder type\nare redirected to the cinder.csi.openstack.org CSI driver.\nMore info: https://examples.k8s.io/mysql-cinder-pd/README.md\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1CinderVolumeSource" + } + ] + }, + "configMap": { + "description": "configMap represents a configMap that should populate this volume\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ConfigMapVolumeSource" + } + ] + }, + "csi": { + "description": "csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1CSIVolumeSource" + } + ] + }, + "downwardAPI": { + "description": "downwardAPI represents downward API about the pod that should populate this volume\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1DownwardAPIVolumeSource" + } + ] + }, + "emptyDir": { + "description": "emptyDir represents a temporary directory that shares a pod's lifetime.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1EmptyDirVolumeSource" + } + ] + }, + "ephemeral": { + "description": "ephemeral represents a volume that is handled by a cluster storage driver.\nThe volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts,\nand deleted when the pod is removed.\n\nUse this if:\na) the volume is only needed while the pod runs,\nb) features of normal volumes like restoring from snapshot or capacity\n tracking are needed,\nc) the storage driver is specified through a storage class, and\nd) the storage driver supports dynamic volume provisioning through\n a PersistentVolumeClaim (see EphemeralVolumeSource for more\n information on the connection between this volume type\n and PersistentVolumeClaim).\n\nUse PersistentVolumeClaim or one of the vendor-specific\nAPIs for volumes that persist for longer than the lifecycle\nof an individual pod.\n\nUse CSI for light-weight local ephemeral volumes if the CSI driver is meant to\nbe used that way - see the documentation of the driver for\nmore information.\n\nA pod can use both types of ephemeral volumes and\npersistent volumes at the same time.\n\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1EphemeralVolumeSource" + } + ] + }, + "fc": { + "description": "fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1FCVolumeSource" + } + ] + }, + "flexVolume": { + "description": "flexVolume represents a generic volume resource that is\nprovisioned/attached using an exec based plugin.\nDeprecated: FlexVolume is deprecated. Consider using a CSIDriver instead.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1FlexVolumeSource" + } + ] + }, + "flocker": { + "description": "flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running.\nDeprecated: Flocker is deprecated and the in-tree flocker type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1FlockerVolumeSource" + } + ] + }, + "gcePersistentDisk": { + "description": "gcePersistentDisk represents a GCE Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nDeprecated: GCEPersistentDisk is deprecated. All operations for the in-tree\ngcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1GCEPersistentDiskVolumeSource" + } + ] + }, + "gitRepo": { + "description": "gitRepo represents a git repository at a particular revision.\nDeprecated: GitRepo is deprecated. To provision a container with a git repo, mount an\nEmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir\ninto the Pod's container.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1GitRepoVolumeSource" + } + ] + }, + "glusterfs": { + "description": "glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime.\nDeprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1GlusterfsVolumeSource" + } + ] + }, + "hostPath": { + "description": "hostPath represents a pre-existing file or directory on the host\nmachine that is directly exposed to the container. This is generally\nused for system agents or other privileged things that are allowed\nto see the host machine. Most containers will NOT need this.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n---\nTODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not\nmount host directories as read/write.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1HostPathVolumeSource" + } + ] + }, + "image": { + "description": "image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine.\nThe volume is resolved at pod startup depending on which PullPolicy value is provided:\n\n- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails.\n- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present.\n- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails.\n\nThe volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation.\nA failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message.\nThe types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field.\nThe OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images.\nThe volume will be mounted read-only (ro) and non-executable files (noexec).\nSub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33.\nThe field spec.securityContext.fsGroupChangePolicy has no effect on this volume type.\n+featureGate=ImageVolume\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ImageVolumeSource" + } + ] + }, + "iscsi": { + "description": "iscsi represents an ISCSI Disk resource that is attached to a\nkubelet's host machine and then exposed to the pod.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ISCSIVolumeSource" + } + ] + }, + "name": { + "description": "name of the volume.\nMust be a DNS_LABEL and unique within the pod.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + "type": "string" + }, + "nfs": { + "description": "nfs represents an NFS mount on the host that shares a pod's lifetime\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#nfs\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1NFSVolumeSource" + } + ] + }, + "persistentVolumeClaim": { + "description": "persistentVolumeClaimVolumeSource represents a reference to a\nPersistentVolumeClaim in the same namespace.\nMore info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PersistentVolumeClaimVolumeSource" + } + ] + }, + "photonPersistentDisk": { + "description": "photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine.\nDeprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported.", + "allOf": [ + { + "$ref": "#/definitions/V1PhotonPersistentDiskVolumeSource" + } + ] + }, + "portworxVolume": { + "description": "portworxVolume represents a portworx volume attached and mounted on kubelets host machine.\nDeprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type\nare redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate\nis on.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1PortworxVolumeSource" + } + ] + }, + "projected": { + "description": "projected items for all in one resources secrets, configmaps, and downward API", + "allOf": [ + { + "$ref": "#/definitions/V1ProjectedVolumeSource" + } + ] + }, + "quobyte": { + "description": "quobyte represents a Quobyte mount on the host that shares a pod's lifetime.\nDeprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1QuobyteVolumeSource" + } + ] + }, + "rbd": { + "description": "rbd represents a Rados Block Device mount on the host that shares a pod's lifetime.\nDeprecated: RBD is deprecated and the in-tree rbd type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1RBDVolumeSource" + } + ] + }, + "scaleIO": { + "description": "scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes.\nDeprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ScaleIOVolumeSource" + } + ] + }, + "secret": { + "description": "secret represents a secret that should populate this volume.\nMore info: https://kubernetes.io/docs/concepts/storage/volumes#secret\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SecretVolumeSource" + } + ] + }, + "storageos": { + "description": "storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes.\nDeprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1StorageOSVolumeSource" + } + ] + }, + "vsphereVolume": { + "description": "vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine.\nDeprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type\nare redirected to the csi.vsphere.vmware.com CSI driver.\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1VsphereVirtualDiskVolumeSource" + } + ] + } + } + }, + "V1VolumeDevice": { + "type": "object", + "properties": { + "devicePath": { + "description": "devicePath is the path inside of the container that the device will be mapped to.", + "type": "string" + }, + "name": { + "description": "name must match the name of a persistentVolumeClaim in the pod", + "type": "string" + } + } + }, + "V1VolumeMount": { + "type": "object", + "properties": { + "mountPath": { + "description": "Path within the container at which the volume should be mounted. Must\nnot contain ':'.", + "type": "string" + }, + "mountPropagation": { + "description": "mountPropagation determines how mounts are propagated from the host\nto container and the other way around.\nWhen not set, MountPropagationNone is used.\nThis field is beta in 1.10.\nWhen RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified\n(which defaults to None).\n+optional", + "type": "string" + }, + "name": { + "description": "This must match the Name of a Volume.", + "type": "string" + }, + "readOnly": { + "description": "Mounted read-only if true, read-write otherwise (false or unspecified).\nDefaults to false.\n+optional", + "type": "boolean" + }, + "recursiveReadOnly": { + "description": "RecursiveReadOnly specifies whether read-only mounts should be handled\nrecursively.\n\nIf ReadOnly is false, this field has no meaning and must be unspecified.\n\nIf ReadOnly is true, and this field is set to Disabled, the mount is not made\nrecursively read-only. If this field is set to IfPossible, the mount is made\nrecursively read-only, if it is supported by the container runtime. If this\nfield is set to Enabled, the mount is made recursively read-only if it is\nsupported by the container runtime, otherwise the pod will not be started and\nan error will be generated to indicate the reason.\n\nIf this field is set to IfPossible or Enabled, MountPropagation must be set to\nNone (or be unspecified, which defaults to None).\n\nIf this field is not specified, it is treated as an equivalent of Disabled.\n\n+featureGate=RecursiveReadOnlyMounts\n+optional", + "type": "string" + }, + "subPath": { + "description": "Path within the volume from which the container's volume should be mounted.\nDefaults to \"\" (volume's root).\n+optional", + "type": "string" + }, + "subPathExpr": { + "description": "Expanded path within the volume from which the container's volume should be mounted.\nBehaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment.\nDefaults to \"\" (volume's root).\nSubPathExpr and SubPath are mutually exclusive.\n+optional", + "type": "string" + } + } + }, + "V1VolumeProjection": { + "type": "object", + "properties": { + "clusterTrustBundle": { + "description": "ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field\nof ClusterTrustBundle objects in an auto-updating file.\n\nAlpha, gated by the ClusterTrustBundleProjection feature gate.\n\nClusterTrustBundle objects can either be selected by name, or by the\ncombination of signer name and a label selector.\n\nKubelet performs aggressive normalization of the PEM contents written\ninto the pod filesystem. Esoteric PEM features such as inter-block\ncomments and block headers are stripped. Certificates are deduplicated.\nThe ordering of certificates within the file is arbitrary, and Kubelet\nmay change the order over time.\n\n+featureGate=ClusterTrustBundleProjection\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ClusterTrustBundleProjection" + } + ] + }, + "configMap": { + "description": "configMap information about the configMap data to project\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ConfigMapProjection" + } + ] + }, + "downwardAPI": { + "description": "downwardAPI information about the downwardAPI data to project\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1DownwardAPIProjection" + } + ] + }, + "podCertificate": { + "description": "Projects an auto-rotating credential bundle (private key and certificate\nchain) that the pod can use either as a TLS client or server.\n\nKubelet generates a private key and uses it to send a\nPodCertificateRequest to the named signer. Once the signer approves the\nrequest and issues a certificate chain, Kubelet writes the key and\ncertificate chain to the pod filesystem. The pod does not start until\ncertificates have been issued for each podCertificate projected volume\nsource in its spec.\n\nKubelet will begin trying to rotate the certificate at the time indicated\nby the signer using the PodCertificateRequest.Status.BeginRefreshAt\ntimestamp.\n\nKubelet can write a single file, indicated by the credentialBundlePath\nfield, or separate files, indicated by the keyPath and\ncertificateChainPath fields.\n\nThe credential bundle is a single file in PEM format. The first PEM\nentry is the private key (in PKCS#8 format), and the remaining PEM\nentries are the certificate chain issued by the signer (typically,\nsigners will return their certificate chain in leaf-to-root order).\n\nPrefer using the credential bundle format, since your application code\ncan read it atomically. If you use keyPath and certificateChainPath,\nyour application must make two separate file reads. If these coincide\nwith a certificate rotation, it is possible that the private key and leaf\ncertificate you read may not correspond to each other. Your application\nwill need to check for this condition, and re-read until they are\nconsistent.\n\nThe named signer controls chooses the format of the certificate it\nissues; consult the signer implementation's documentation to learn how to\nuse the certificates it issues.\n\n+featureGate=PodCertificateProjection +optional", + "allOf": [ + { + "$ref": "#/definitions/V1PodCertificateProjection" + } + ] + }, + "secret": { + "description": "secret information about the secret data to project\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1SecretProjection" + } + ] + }, + "serviceAccountToken": { + "description": "serviceAccountToken is information about the serviceAccountToken data to project\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ServiceAccountTokenProjection" + } + ] + } + } + }, + "V1VolumeResourceRequirements": { + "type": "object", + "properties": { + "limits": { + "description": "Limits describes the maximum amount of compute resources allowed.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceList" + } + ] + }, + "requests": { + "description": "Requests describes the minimum amount of compute resources required.\nIf Requests is omitted for a container, it defaults to Limits if that is explicitly specified,\notherwise to an implementation-defined value. Requests cannot exceed Limits.\nMore info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n+optional", + "allOf": [ + { + "$ref": "#/definitions/V1ResourceList" + } + ] + } + } + }, + "V1VsphereVirtualDiskVolumeSource": { + "type": "object", + "properties": { + "fsType": { + "description": "fsType is filesystem type to mount.\nMust be a filesystem type supported by the host operating system.\nEx. \"ext4\", \"xfs\", \"ntfs\". Implicitly inferred to be \"ext4\" if unspecified.\n+optional", + "type": "string" + }, + "storagePolicyID": { + "description": "storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName.\n+optional", + "type": "string" + }, + "storagePolicyName": { + "description": "storagePolicyName is the storage Policy Based Management (SPBM) profile name.\n+optional", + "type": "string" + }, + "volumePath": { + "description": "volumePath is the path that identifies vSphere volume vmdk", + "type": "string" + } + } + }, + "V1WeightedPodAffinityTerm": { + "type": "object", + "properties": { + "podAffinityTerm": { + "description": "Required. A pod affinity term, associated with the corresponding weight.", + "allOf": [ + { + "$ref": "#/definitions/V1PodAffinityTerm" + } + ] + }, + "weight": { + "description": "weight associated with matching the corresponding podAffinityTerm,\nin the range 1-100.", + "type": "integer" + } + } + }, + "V1WindowsSecurityContextOptions": { + "type": "object", + "properties": { + "gmsaCredentialSpec": { + "description": "GMSACredentialSpec is where the GMSA admission webhook\n(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the\nGMSA credential spec named by the GMSACredentialSpecName field.\n+optional", + "type": "string" + }, + "gmsaCredentialSpecName": { + "description": "GMSACredentialSpecName is the name of the GMSA credential spec to use.\n+optional", + "type": "string" + }, + "hostProcess": { + "description": "HostProcess determines if a container should be run as a 'Host Process' container.\nAll of a Pod's containers must have the same effective HostProcess value\n(it is not allowed to have a mix of HostProcess containers and non-HostProcess containers).\nIn addition, if HostProcess is true then HostNetwork must also be set to true.\n+optional", + "type": "boolean" + }, + "runAsUserName": { + "description": "The UserName in Windows to run the entrypoint of the container process.\nDefaults to the user specified in image metadata if unspecified.\nMay also be set in PodSecurityContext. If set in both SecurityContext and\nPodSecurityContext, the value specified in SecurityContext takes precedence.\n+optional", + "type": "string" + } + } + } + }, + "securityDefinitions": { + "BearerAuth": { + "description": "Bearer token authentication. Obtain token via OIDC/PKCE flow with your identity provider.", + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + }, + "tags": [ + { + "description": "Manage the primary Kargo resources that make up a promotion pipeline: Projects (tenancy boundaries), Warehouses (artifact sources), Freight (versioned artifact bundles), Stages (promotion targets), and Promotions (records of a Freight moving through a Stage).", + "name": "Core" + }, + { + "description": "Cluster-wide administrative operations for Kargo operators: retrieving server and API version info, authenticating as the built-in admin user, and reading or modifying cluster-level server configuration.", + "name": "System" + }, + { + "description": "Manage Kargo's role-based access control model. Kargo Roles are named collections of Kubernetes RBAC rules scoped to a project; API tokens are service-account-backed credentials that can be bound to a Role for non-human access.", + "name": "Rbac" + }, + { + "description": "Top-level grouping for all credential types that Kargo uses to authenticate with external systems. See the Repo Credentials and Generic Credentials sub-tags for the specific credential kinds.", + "name": "Credentials" + }, + { + "description": "Interact with Argo Rollouts AnalysisRun and AnalysisTemplate resources used to verify Stage health after a promotion. Includes triggering, aborting, and re-running analysis, as well as reading run logs.", + "name": "Verifications" + }, + { + "description": "Low-level operations for creating, updating, and deleting arbitrary Kargo Kubernetes resources by raw manifest. Useful for tooling that needs to manage resource types not covered by dedicated endpoints.", + "name": "Resources" + }, + { + "description": "Read Kubernetes Events emitted by Kargo controllers. Events record notable state transitions (e.g. a Promotion starting, completing, or failing) and are useful for auditing and debugging.", + "name": "Events" + }, + { + "description": "Manage structured configuration resources: ProjectConfig holds per-project promotion policy settings; ClusterConfig holds cluster-wide defaults and feature flags applied by the Kargo operator.", + "name": "Config" + }, + { + "description": "Manage free-form ConfigMap-backed configuration that Kargo promotion steps can read at runtime. Supports project-scoped, system-scoped, and shared ConfigMaps, allowing pipelines to consume environment-specific values without embedding them in Git.", + "name": "Generic Config" + }, + { + "description": "Credentials for authenticating with artifact repositories: Git repositories, Helm chart registries, and container image registries. Kargo uses these when polling for new artifacts and when running promotion steps that read from or write to a repository.", + "name": "Repo Credentials" + }, + { + "description": "Arbitrary key-value secrets that promotion steps can consume at runtime for any purpose not covered by repository credentials — for example, API tokens, signing keys, or connection strings for external services.", + "name": "Generic Credentials" + }, + { + "description": "The resource or operation is scoped to a single Kargo project (Kubernetes namespace). Access is governed by the requesting user's permissions within that project.", + "name": "Project-Level" + }, + { + "description": "The resource or operation lives in the Kargo system namespace and applies across all projects. Typically restricted to cluster administrators.", + "name": "System-Level" + }, + { + "description": "The resource is a Kubernetes cluster-scoped object (not namespaced), such as a Project or ClusterAnalysisTemplate. These exist at the cluster level and are accessible to users with appropriate cluster-wide permissions.", + "name": "Cluster-Scoped Resource" + }, + { + "description": "The resource is defined once and shared across multiple projects or scopes. For example, a shared ConfigMap or credential can be referenced by any project without being duplicated per namespace.", + "name": "Shared" + }, + { + "description": "At most, one instance of this resource kind exists per scope. For example, each project has, at most, one ProjectConfig and each cluster has, at most, one ClusterConfig.", + "name": "Singleton" + } + ] +} diff --git a/swagger.yaml b/swagger.yaml deleted file mode 100644 index 3b6b3f6c53..0000000000 --- a/swagger.yaml +++ /dev/null @@ -1,3584 +0,0 @@ -basePath: / -definitions: - AdminLoginResponse: - properties: - idToken: - type: string - type: object - ArgoCDShard: - properties: - namespace: - type: string - url: - type: string - type: object - Claim: - properties: - name: - type: string - values: - items: - type: string - type: array - type: object - CreateAPITokenRequest: - properties: - name: - type: string - type: object - CreateConfigMapRequest: - properties: - data: - additionalProperties: - type: string - type: object - description: - type: string - name: - type: string - type: object - CreateGenericCredentialsRequest: - properties: - data: - additionalProperties: - type: string - type: object - description: - type: string - name: - type: string - type: object - CreateOrUpdateResourceResponse: - properties: - results: - items: - $ref: '#/definitions/CreateOrUpdateResourceResult' - type: array - type: object - CreateOrUpdateResourceResult: - properties: - createdResourceManifest: - additionalProperties: {} - type: object - error: - type: string - updatedResourceManifest: - additionalProperties: {} - type: object - type: object - CreateRepoCredentialsRequest: - properties: - description: - type: string - name: - type: string - password: - description: |- - #nosec G117 -- Request data is unmarshaled into this struct, but the struct - is never marshaled and transmitted to anywhere. - type: string - repoUrl: - type: string - repoUrlIsRegex: - type: boolean - type: - type: string - username: - type: string - type: object - CreateResourceResponse: - properties: - results: - items: - $ref: '#/definitions/CreateResourceResult' - type: array - type: object - CreateResourceResult: - properties: - createdResourceManifest: - additionalProperties: {} - type: object - error: - type: string - type: object - DeleteResourceResponse: - properties: - results: - items: - $ref: '#/definitions/DeleteResourceResult' - type: array - type: object - DeleteResourceResult: - properties: - deletedResourceManifest: - additionalProperties: {} - type: object - error: - type: string - type: object - GetConfigResponse: - properties: - argocdShards: - additionalProperties: - $ref: '#/definitions/ArgoCDShard' - type: object - hasAnalysisRunLogsUrlTemplate: - type: boolean - kargoNamespace: - type: string - secretManagementEnabled: - type: boolean - sharedResourcesNamespace: - type: string - systemResourcesNamespace: - type: string - type: object - GrantRequest: - properties: - resourceDetails: - $ref: '#/definitions/ResourceDetails' - role: - type: string - userClaims: - $ref: '#/definitions/UserClaims' - type: object - ImageStageMap: - properties: - stages: - additionalProperties: - format: int32 - type: integer - type: object - type: object - OIDCConfig: - properties: - cliClientId: - type: string - clientId: - type: string - issuerUrl: - type: string - scopes: - items: - type: string - type: array - type: object - PatchConfigMapRequest: - properties: - data: - additionalProperties: - type: string - type: object - description: - type: string - removeKeys: - items: - type: string - type: array - type: object - PatchGenericCredentialsRequest: - properties: - data: - additionalProperties: - type: string - type: object - description: - type: string - removeKeys: - items: - type: string - type: array - type: object - PatchRepoCredentialsRequest: - properties: - description: - type: string - password: - description: |- - #nosec G117 -- Request data is unmarshaled into this struct, but the struct - is never marshaled and transmitted to anywhere. - type: string - repoUrl: - type: string - repoUrlIsRegex: - type: boolean - type: - type: string - username: - type: string - type: object - PromoteDownstreamRequest: - properties: - freight: - type: string - freightAlias: - type: string - type: object - PromoteToStageRequest: - properties: - freight: - type: string - freightAlias: - type: string - type: object - PublicConfig: - properties: - adminAccountEnabled: - type: boolean - oidcConfig: - $ref: '#/definitions/OIDCConfig' - skipAuth: - type: boolean - type: object - ResourceDetails: - properties: - resourceName: - type: string - resourceType: - type: string - verbs: - items: - type: string - type: array - type: object - RevokeRequest: - properties: - resourceDetails: - $ref: '#/definitions/ResourceDetails' - role: - type: string - userClaims: - $ref: '#/definitions/UserClaims' - type: object - TagMap: - properties: - tags: - additionalProperties: - $ref: '#/definitions/ImageStageMap' - type: object - type: object - UpdateConfigMapRequest: - properties: - data: - additionalProperties: - type: string - type: object - description: - type: string - type: object - UpdateGenericCredentialsRequest: - properties: - data: - additionalProperties: - type: string - type: object - description: - type: string - type: object - UpdateRepoCredentialsRequest: - properties: - description: - type: string - password: - description: |- - #nosec G117 -- Request data is unmarshaled into this struct, but the struct - is never marshaled and transmitted to anywhere. - type: string - repoUrl: - type: string - repoUrlIsRegex: - type: boolean - type: - type: string - username: - type: string - type: object - UserClaims: - properties: - claims: - items: - $ref: '#/definitions/Claim' - type: array - type: object - VersionInfo: - properties: - buildDate: - description: BuildDate is the date/time on which the application was built. - type: string - compiler: - description: Compiler indicates what Go compiler was used for the build. - type: string - gitCommit: - description: |- - GitCommit is the ID (sha) of the last commit to the application's source - code that is included in this build. - type: string - gitTreeDirty: - description: |- - GitTreeDirty is true if the application's source code contained - uncommitted changes at the time it was built; otherwise it is false. - type: boolean - goVersion: - description: GoVersion is the version of Go that was used to build the application. - type: string - platform: - description: |- - Platform indicates the OS and CPU architecture for which the application - was built. - type: string - version: - description: Version is a human-friendly version string. - type: string - type: object -info: - contact: {} - description: REST API for Kargo - title: Kargo API - version: v1alpha1 -paths: - /v1beta1/login: - post: - description: Authenticate as the admin user if enabled. - operationId: AdminLogin - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/AdminLoginResponse' - security: - - BearerAuth: [] - summary: Admin login - tags: - - System - /v1beta1/projects: - get: - description: List all Projects resources. Returns a ProjectList resource. - operationId: ListProjects - produces: - - application/json - responses: - "200": - description: ProjectList custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectList) - schema: - type: object - security: - - BearerAuth: [] - summary: List projects - tags: - - Core - - Cluster-Scoped Resource - /v1beta1/projects/{project}: - delete: - description: Delete a Project resource and its associated namespace. - operationId: DeleteProject - parameters: - - description: Project name - in: path - name: project - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a Project - tags: - - Core - - Cluster-Scoped Resource - get: - description: Retrieve a Project resource. - operationId: GetProject - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: Project custom resource (github.com/akuity/kargo/api/v1alpha1.Project) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a Project resource - tags: - - Core - - Cluster-Scoped Resource - /v1beta1/projects/{project}/analysis-runs/{analysis-run}: - get: - description: Retrieve an AnalysisRun resource from a project's namespace. - operationId: GetAnalysisRun - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: AnalysisRun name - in: path - name: analysis-run - required: true - type: string - produces: - - application/json - responses: - "200": - description: AnalysisRun custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisRun) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve an AnalysisRun - tags: - - Verifications - - Project-Level - /v1beta1/projects/{project}/analysis-runs/{analysis-run}/logs: - get: - description: Stream logs from an AnalysisRun job as Server-Sent Events (SSE). - operationId: GetAnalysisRunLogs - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: AnalysisRun name - in: path - name: analysis-run - required: true - type: string - - description: Metric name - in: query - name: metricName - type: string - - description: Container name - in: query - name: containerName - type: string - produces: - - text/event-stream - responses: - "200": - description: Log stream (SSE) - schema: - type: string - security: - - BearerAuth: [] - summary: Stream AnalysisRun logs - tags: - - Verifications - - Project-Level - /v1beta1/projects/{project}/analysis-templates: - get: - description: List AnalysisTemplate resources from a project's namespace. - operationId: ListAnalysisTemplates - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: AnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplateList) - schema: - type: object - security: - - BearerAuth: [] - summary: List AnalysisTemplates - tags: - - Verifications - - Project-Level - /v1beta1/projects/{project}/analysis-templates/{analysis-template}: - delete: - description: Delete an AnalysisTemplate resource from a project's namespace. - operationId: DeleteAnalysisTemplate - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: AnalysisTemplate name - in: path - name: analysis-template - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete an AnalysisTemplate - tags: - - Verifications - - Project-Level - get: - description: |- - Retrieve an AnalysisTemplate resource from a project's - namespace. - operationId: GetAnalysisTemplate - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: AnalysisTemplate name - in: path - name: analysis-template - required: true - type: string - produces: - - application/json - responses: - "200": - description: AnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.AnalysisTemplate) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve an AnalysisTemplate - tags: - - Verifications - - Project-Level - /v1beta1/projects/{project}/api-tokens: - get: - description: |- - List project-level API tokens. Returns a Kubernetes SecretList - resource containing heavily redacted Secrets. - operationId: ListProjectAPITokens - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Role name filter - in: query - name: role - type: string - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List project-level API tokens - tags: - - Rbac - - Credentials - - Project-Level - /v1beta1/projects/{project}/api-tokens/{apitoken}: - delete: - description: Delete a project-level API token from a project's namespace. - operationId: DeleteProjectAPIToken - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: API token name - in: path - name: apitoken - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a project-level API token - tags: - - Rbac - - Credentials - - Project-Level - get: - description: |- - Retrieve a project-level API token by name. Returns a heavily - redacted Kubernetes Secret resource. - operationId: GetProjectAPIToken - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: API token name - in: path - name: apitoken - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a project-level API token - tags: - - Rbac - - Credentials - - Project-Level - /v1beta1/projects/{project}/config: - delete: - description: |- - Delete the single ProjectConfig resource from a project's - namespace. - operationId: DeleteProjectConfig - parameters: - - description: Project name - in: path - name: project - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a ProjectConfig resource - tags: - - Core - - Project-Level - - Config - - Singleton - get: - description: |- - Retrieve the single ProjectConfig resource from a project's - namespace. - operationId: GetProjectConfig - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: ProjectConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ProjectConfig) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve ProjectConfig - tags: - - Core - - Project-Level - - Config - - Singleton - /v1beta1/projects/{project}/config/refresh: - post: - description: |- - Refresh the single ProjectConfig resource in a project's - namespace. Refreshing enqueues the resource for reconciliation - by its corresponding controller. - operationId: RefreshProjectConfig - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Refresh ProjectConfig - tags: - - Core - - Config - - Project-Level - - Singleton - /v1beta1/projects/{project}/configmaps: - get: - description: |- - List ConfigMap resources from a project's namespace. Returns a - Kubernetes ConfigMapList resource. - operationId: ListProjectConfigMaps - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList) - schema: - type: object - security: - - BearerAuth: [] - summary: List project-level ConfigMaps - tags: - - Core - - Generic Config - - Project-Level - post: - consumes: - - application/json - description: |- - Create a ConfigMap in a project's namespace. Returns the created - Kubernetes ConfigMap resource. - operationId: CreateProjectConfigMap - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: ConfigMap - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateConfigMapRequest' - produces: - - application/json - responses: - "201": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Create a project-level ConfigMap - tags: - - Core - - Generic Config - - Project-Level - /v1beta1/projects/{project}/configmaps/{configmap}: - delete: - description: Delete a ConfigMap from a project's namespace. - operationId: DeleteProjectConfigMap - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a project-level ConfigMap - tags: - - Core - - Generic Config - - Project-Level - get: - description: Retrieve a ConfigMap by name from a project's namespace. - operationId: GetProjectConfigMap - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a project-level ConfigMap - tags: - - Core - - Generic Config - - Project-Level - patch: - consumes: - - application/json - description: |- - Patch a ConfigMap in a project's namespace. Merges provided data - with existing data. Use removeKeys to delete specific keys. - Returns the updated Kubernetes ConfigMap resource. - operationId: PatchProjectConfigMap - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - - description: ConfigMap patch - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchConfigMapRequest' - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch a project-level ConfigMap - tags: - - Core - - Generic Config - - Project-Level - put: - consumes: - - application/json - description: |- - Replace a ConfigMap in a project's namespace. All existing data - is replaced. Returns the updated Kubernetes ConfigMap resource. - operationId: UpdateProjectConfigMap - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - - description: ConfigMap - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateConfigMapRequest' - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace a project-level ConfigMap - tags: - - Core - - Generic Config - - Project-Level - /v1beta1/projects/{project}/events: - get: - description: |- - List Kubernetes Events from a project's namespace. Returns a - Kubernetes EventList resource. - operationId: ListProjectEvents - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: EventList resource (k8s.io/api/core/v1.EventList) - schema: - type: object - security: - - BearerAuth: [] - summary: List project-level Kubernetes Events - tags: - - Events - - Project-Level - /v1beta1/projects/{project}/freight: - get: - description: Query and filter Freight resources from a project's namespace. - operationId: QueryFreightsRest - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name to get available freight for - in: query - name: stage - type: string - - collectionFormat: csv - description: Warehouse names to get freight from - in: query - items: - type: string - name: origins - type: array - - description: Group filter - in: query - name: group - type: string - - description: Group by (image_repo, git_repo, chart_repo) - in: query - name: groupBy - type: string - - description: Order by (first_seen, tag) - in: query - name: orderBy - type: string - - description: Reverse order - in: query - name: reverse - type: boolean - produces: - - application/json - responses: - "200": - description: Map of freight groups - schema: - type: object - security: - - BearerAuth: [] - summary: Query Freight - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/freight/{freight-name-or-alias}: - delete: - description: |- - Delete a Freight resource from a project's namespace by name or - alias. - operationId: DeleteFreight - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Freight name or alias - in: path - name: freight-name-or-alias - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a Freight resource - tags: - - Core - - Project-Level - get: - description: |- - Retrieve a Freight resource from a project's namespace by name - or alias. - operationId: GetFreight - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Freight name or alias - in: path - name: freight-name-or-alias - required: true - type: string - produces: - - application/json - responses: - "200": - description: Freight custom resource (github.com/akuity/kargo/api/v1alpha1.Freight) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a Freight resource - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/freight/{freight-name-or-alias}/alias: - patch: - consumes: - - application/json - description: Patch a Freight resource's human-friendly alias. - operationId: PatchFreightAlias - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Freight name or alias - in: path - name: freight-name-or-alias - required: true - type: string - - description: New alias - in: query - name: newAlias - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Patch a Freight resource's alias - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/freight/{freight-name-or-alias}/approve: - post: - description: Approve Freight for promotion to a Stage. - operationId: ApproveFreight - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Freight name or alias - in: path - name: freight-name-or-alias - required: true - type: string - - description: Stage name - in: query - name: stage - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Approve Freight for promotion to a Stage - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/generic-credentials: - get: - description: |- - List project-level generic credentials. Returns a Kubernetes - SecretList resource containing heavily redacted Secrets. - operationId: ListProjectGenericCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List project-level generic credentials - tags: - - Credentials - - Generic Credentials - - Project-Level - post: - consumes: - - application/json - description: |- - Create project-level generic credentials. Returns a heavily - redacted Kubernetes Secret resource. - operationId: CreateProjectGenericCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Generic credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateGenericCredentialsRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create project-level generic credentials - tags: - - Credentials - - Generic Credentials - - Project-Level - /v1beta1/projects/{project}/generic-credentials/{generic-credentials}: - delete: - description: Delete generic credentials from a project's namespace. - operationId: DeleteProjectGenericCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete project-level generic credentials - tags: - - Credentials - - Generic Credentials - - Project-Level - get: - description: |- - Retrieve project-level generic credentials by name. Returns a - heavily redacted Kubernetes Secret resource. - operationId: GetProjectGenericCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Credentials name - in: path - name: generic-credentials - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve project-level generic credentials - tags: - - Credentials - - Generic Credentials - - Project-Level - patch: - consumes: - - application/json - description: |- - Patch project-level generic credentials. Merges provided data - with existing data. Use removeKeys to delete specific keys. - Returns a heavily redacted Kubernetes Secret resource. - operationId: PatchProjectGenericCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - - description: GenericCredentials patch - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchGenericCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch project-level generic credentials - tags: - - Credentials - - Generic Credentials - - Project-Level - put: - consumes: - - application/json - description: |- - Replace project-level generic credentials. All existing data is - replaced. Returns a heavily redacted Kubernetes Secret resource. - operationId: UpdateProjectGenericCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - - description: GenericCredentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateGenericCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace project-level generic credentials - tags: - - Credentials - - Generic Credentials - - Project-Level - /v1beta1/projects/{project}/images: - get: - description: |- - List container images referenced by Freight resources in a - project's namespace. - operationId: ListImages - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - additionalProperties: - $ref: '#/definitions/TagMap' - type: object - security: - - BearerAuth: [] - summary: List container images - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/promotion-tasks: - get: - description: |- - List PromotionTask resources from a project's namespace. Returns - a PromotionTaskList resource. - operationId: ListPromotionTasks - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: PromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTaskList) - schema: - type: object - security: - - BearerAuth: [] - summary: List PromotionTasks - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/promotion-tasks/{promotion-task}: - get: - description: Retrieve a PromotionTask resource from a project's namespace. - operationId: GetPromotionTask - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: PromotionTask name - in: path - name: promotion-task - required: true - type: string - produces: - - application/json - responses: - "200": - description: PromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionTask) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a PromotionTask - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/promotions: - get: - description: |- - List Promotion resources from a project's namespace. Returns a - PromotionList resource. - operationId: ListPromotions - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage filter - in: query - name: stage - type: string - produces: - - application/json - responses: - "200": - description: PromotionList custom resource (github.com/akuity/kargo/api/v1alpha1.PromotionList) - schema: - type: object - security: - - BearerAuth: [] - summary: List Promotions - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/promotions/{promotion}: - get: - description: Retrieve a Promotion resource from a project's namespace. - operationId: GetPromotion - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Promotion name - in: path - name: promotion - required: true - type: string - produces: - - application/json - responses: - "200": - description: Promotion custom resource (github.com/akuity/kargo/api/v1alpha1.Promotion) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a Promotion - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/promotions/{promotion}/abort: - post: - description: Abort a running Promotion. - operationId: AbortPromotion - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Promotion name - in: path - name: promotion - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Abort a Promotion - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/promotions/{promotion}/refresh: - post: - description: |- - Refresh a Promotion resource in a project's namespace. - Refreshing enqueues the resource for reconciliation by its - corresponding controller. - operationId: RefreshPromotion - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Promotion name - in: path - name: promotion - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Refresh a Promotion - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/repo-credentials: - get: - description: |- - List project-level repository credentials. Returns a SecretList - resource containing heavily redacted Secrets. - operationId: ListProjectRepoCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List project-level repository credentials - tags: - - Credentials - - Repo Credentials - - Project-Level - post: - consumes: - - application/json - description: |- - Create project-level repository credentials. Returns a heavily - redacted Kubernetes Secret resource. - operationId: CreateProjectRepoCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateRepoCredentialsRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create project-level repository credentials - tags: - - Credentials - - Repo Credentials - - Project-Level - /v1beta1/projects/{project}/repo-credentials/{repo-credentials}: - delete: - description: Delete repository credentials from a project's namespace. - operationId: DeleteProjectRepoCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Credentials name - in: path - name: repo-credentials - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete project-level repository credentials - tags: - - Credentials - - Repo Credentials - - Project-Level - get: - description: |- - Retrieve project-level repository credentials by name. Returns a - heavily redacted Kubernetes Secret resource. - operationId: GetProjectRepoCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Credentials name - in: path - name: repo-credentials - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve project-level repository credentials - tags: - - Credentials - - Repo Credentials - - Project-Level - patch: - consumes: - - application/json - description: |- - Patch project-level repository credentials. Only provided fields - are updated. Returns a heavily redacted Kubernetes Secret resource. - operationId: PatchProjectRepoCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Repo credentials name - in: path - name: repo-credentials - required: true - type: string - - description: Credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchRepoCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch project-level repository credentials - tags: - - Credentials - - Repo Credentials - - Project-Level - put: - consumes: - - application/json - description: |- - Replace project-level repository credentials. All fields are replaced. - Returns a heavily redacted Kubernetes Secret resource. - operationId: UpdateProjectRepoCredentials - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Repo credentials name - in: path - name: repo-credentials - required: true - type: string - - description: Credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateRepoCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace project-level repository credentials - tags: - - Credentials - - Repo Credentials - - Project-Level - /v1beta1/projects/{project}/roles: - get: - description: |- - List project-level Kargo Role virtual resources. Returns a - RoleList resource. - operationId: ListProjectRoles - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList) - schema: - type: object - security: - - BearerAuth: [] - summary: List project-level Kargo Role virtual resources - tags: - - Rbac - - Project-Level - post: - consumes: - - application/json - description: |- - Create a project-level Kargo Role virtual resource by creating - the underlying Kubernetes ServiceAccount, Role, and RoleBinding - resources. - operationId: CreateProjectRole - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) - in: body - name: body - required: true - schema: - type: object - produces: - - application/json - responses: - "201": - description: Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) - schema: - type: object - security: - - BearerAuth: [] - summary: Create a project-level Kargo Role virtual resource - tags: - - Rbac - - Project-Level - /v1beta1/projects/{project}/roles/{role}: - delete: - description: |- - Delete a project-level Kargo Role virtual resource by deleting - the underlying Kubernetes ServiceAccount, Role, and RoleBinding - resources from the project's namespace. - operationId: DeleteProjectRole - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Role name - in: path - name: role - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a project-level Kargo Role virtual resource - tags: - - Rbac - - Project-Level - get: - description: |- - Retrieve a project-level Kargo Role virtual resource by name. - Returns a Kargo Role virtual resource or its underlying - Kubernetes resources. - operationId: GetProjectRole - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Role name - in: path - name: role - required: true - type: string - produces: - - application/json - responses: - "200": - description: Role resource (k8s.io/api/rbac/v1.Role) or its underlying Kubernetes - resources - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a project-level Kargo Role virtual resource - tags: - - Rbac - - Project-Level - put: - consumes: - - application/json - description: |- - Update a project-level Kargo Role virtual resource by updating - the underlying Kubernetes ServiceAccount, Role, and RoleBinding - resources. - operationId: UpdateRole - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Role name - in: path - name: role - required: true - type: string - - description: Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) - in: body - name: body - required: true - schema: - type: object - produces: - - application/json - responses: - "200": - description: Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) - schema: - type: object - security: - - BearerAuth: [] - summary: Update a project-level Kargo Role virtual resource - tags: - - Rbac - - Project-Level - /v1beta1/projects/{project}/roles/{role}/api-tokens: - post: - consumes: - - application/json - description: |- - Create a project-level API token associated with a Kargo Role - virtual resource. Returns a Kubernetes Secret resource - representing the token. Store it securely. The token is not - retrievable via the Kargo API after creation except in a - redacted form. - operationId: CreateProjectAPIToken - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Role name - in: path - name: role - required: true - type: string - - description: Token - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateAPITokenRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create a project-level API token - tags: - - Rbac - - Credentials - - Project-Level - /v1beta1/projects/{project}/roles/grants: - post: - consumes: - - application/json - description: |- - Grant a project-level Kargo Role to users or grant permissions - to a project-level Kargo Role. - operationId: Grant - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Grant request - in: body - name: body - required: true - schema: - $ref: '#/definitions/GrantRequest' - produces: - - application/json - responses: - "200": - description: Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) - schema: - type: object - security: - - BearerAuth: [] - summary: Grant permissions - tags: - - Rbac - - Project-Level - /v1beta1/projects/{project}/roles/revocations: - post: - consumes: - - application/json - description: |- - Revoke a project-level Kargo Role from users or revoke - permissions from a project-level Kargo Role. - operationId: Revoke - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Revoke request - in: body - name: body - required: true - schema: - $ref: '#/definitions/RevokeRequest' - produces: - - application/json - responses: - "200": - description: Role resource (github.com/akuity/kargo/api/rbac/v1alpha1.Role) - schema: - type: object - security: - - BearerAuth: [] - summary: Revoke permissions - tags: - - Rbac - - Project-Level - /v1beta1/projects/{project}/stages: - get: - description: |- - List Stage resources from a project's namespace. Returns a - StageList resource. - operationId: ListStages - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: StageList custom resource (github.com/akuity/kargo/api/v1alpha1.StageList) - schema: - type: object - security: - - BearerAuth: [] - summary: List Stages - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/stages/{stage}: - delete: - description: Delete a Stage resource from a project's namespace. - operationId: DeleteStage - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a Stage - tags: - - Core - - Project-Level - get: - description: Retrieve a Stage resource from a project's namespace. - operationId: GetStage - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - produces: - - application/json - responses: - "200": - description: Stage custom resource (github.com/akuity/kargo/api/v1alpha1.Stage) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a Stage - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/stages/{stage}/promotions: - post: - consumes: - - application/json - description: |- - Create a Promotion resource to transition a specified Stage into - the state represented by the specified Freight. - operationId: PromoteToStage - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - - description: Promote request - in: body - name: body - required: true - schema: - $ref: '#/definitions/PromoteToStageRequest' - produces: - - application/json - responses: - "201": - description: Promotion resource (github.com/akuity/kargo/api/v1alpha1.Promotion) - schema: - type: object - security: - - BearerAuth: [] - summary: Promote to Stage - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/stages/{stage}/promotions/downstream: - post: - consumes: - - application/json - description: |- - Creates a Promotion resource for each of a Stage's immediately - downstream Stages. - operationId: PromoteDownstream - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - - description: Promote request - in: body - name: body - required: true - schema: - $ref: '#/definitions/PromoteDownstreamRequest' - produces: - - application/json - responses: - "201": - description: Promotions created - schema: - type: object - security: - - BearerAuth: [] - summary: Promote downstream - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/stages/{stage}/refresh: - post: - description: |- - Refresh a Stage resource in a project's namespace. Refreshing - enqueues the resource for reconciliation by its corresponding - controller. - operationId: RefreshStage - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Refresh a Stage - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/stages/{stage}/verification: - post: - description: |- - Trigger re-verification of the Freight currently in use by a - Stage. - operationId: Reverify - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Reverify Freight - tags: - - Verifications - - Project-Level - /v1beta1/projects/{project}/stages/{stage}/verification/abort: - post: - description: Abort a running Verification process. - operationId: AbortVerification - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Stage name - in: path - name: stage - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Abort a running Verification process - tags: - - Verifications - - Project-Level - /v1beta1/projects/{project}/warehouses: - get: - description: |- - List Warehouse resources from a project's namespace. Returns a - WarehouseList resource. - operationId: ListWarehouses - parameters: - - description: Project name - in: path - name: project - required: true - type: string - produces: - - application/json - responses: - "200": - description: WarehouseList custom resource (github.com/akuity/kargo/api/v1alpha1.WarehouseList) - schema: - type: object - security: - - BearerAuth: [] - summary: List Warehouses - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/warehouses/{warehouse}: - delete: - description: Delete a Warehouse resource from a project's namespace. - operationId: DeleteWarehouse - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Warehouse name - in: path - name: warehouse - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a Warehouse - tags: - - Core - - Project-Level - get: - description: Retrieve a Warehouse resource from a project's namespace. - operationId: GetWarehouse - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Warehouse name - in: path - name: warehouse - required: true - type: string - produces: - - application/json - responses: - "200": - description: Warehouse custom resource (github.com/akuity/kargo/api/v1alpha1.Warehouse) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a Warehouse - tags: - - Core - - Project-Level - /v1beta1/projects/{project}/warehouses/{warehouse}/refresh: - post: - description: |- - Refresh a Warehouse resource in a project's namespace. - Refreshing enqueues the resource for reconciliation by its - corresponding controller. - operationId: RefreshWarehouse - parameters: - - description: Project name - in: path - name: project - required: true - type: string - - description: Warehouse name - in: path - name: warehouse - required: true - type: string - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Refresh a Warehouse - tags: - - Core - - Project-Level - /v1beta1/resources: - delete: - consumes: - - text/plain - description: |- - Delete one or more Kargo resources using namespaces and names - obtained from YAML or JSON manifests. - operationId: DeleteResource - parameters: - - description: YAML or JSON manifest(s) - in: body - name: manifest - required: true - schema: - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/DeleteResourceResponse' - security: - - BearerAuth: [] - summary: Delete resources - tags: - - Resources - post: - consumes: - - text/plain - description: Create one or more Kargo resources from YAML or JSON manifests. - operationId: CreateResource - parameters: - - description: YAML or JSON manifest(s) - in: body - name: manifest - required: true - schema: - type: string - produces: - - application/json - responses: - "201": - description: Created successfully - schema: - $ref: '#/definitions/CreateResourceResponse' - security: - - BearerAuth: [] - summary: Create resources - tags: - - Resources - put: - consumes: - - text/plain - description: Update (or optionally, upsert) one or more Kargo resources from - operationId: UpdateResource - parameters: - - description: If true, create a resource if it does not exist - in: query - name: upsert - type: boolean - - description: YAML or JSON manifest(s) - in: body - name: manifest - required: true - schema: - type: string - produces: - - application/json - responses: - "200": - description: Update results - schema: - $ref: '#/definitions/CreateOrUpdateResourceResponse' - security: - - BearerAuth: [] - summary: Update resources - tags: - - Resources - /v1beta1/shared/cluster-analysis-templates: - get: - description: |- - List ClusterAnalysisTemplate resources. Returns a - ClusterAnalysisTemplateList resource. - operationId: ListClusterAnalysisTemplates - produces: - - application/json - responses: - "200": - description: ClusterAnalysisTemplateList custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplateList) - schema: - type: object - security: - - BearerAuth: [] - summary: List ClusterAnalysisTemplates - tags: - - Verifications - - Shared - - Cluster-Scoped Resource - /v1beta1/shared/cluster-analysis-templates/{cluster-analysis-template}: - delete: - description: Delete a ClusterAnalysisTemplate resource. - operationId: DeleteClusterAnalysisTemplate - parameters: - - description: ClusterAnalysisTemplate name - in: path - name: cluster-analysis-template - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a ClusterAnalysisTemplate - tags: - - Verifications - - Shared - - Cluster-Scoped Resource - get: - description: Retrieve a ClusterAnalysisTemplate by name. - operationId: GetClusterAnalysisTemplate - parameters: - - description: ClusterAnalysisTemplate name - in: path - name: cluster-analysis-template - required: true - type: string - produces: - - application/json - responses: - "200": - description: ClusterAnalysisTemplate custom resource (github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1.ClusterAnalysisTemplate) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a ClusterAnalysisTemplate - tags: - - Verifications - - Shared - - Cluster-Scoped Resource - /v1beta1/shared/cluster-promotion-tasks: - get: - description: |- - List ClusterPromotionTask resources. Returns a - ClusterPromotionTaskList resource. - operationId: ListClusterPromotionTasks - produces: - - application/json - responses: - "200": - description: ClusterPromotionTaskList custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTaskList) - schema: - type: object - security: - - BearerAuth: [] - summary: List ClusterPromotionTasks - tags: - - Core - - Shared - - Cluster-Scoped Resource - /v1beta1/shared/cluster-promotion-tasks/{cluster-promotion-task}: - get: - description: Retrieve a ClusterPromotionTask by name. - operationId: GetClusterPromotionTask - parameters: - - description: ClusterPromotionTask name - in: path - name: cluster-promotion-task - required: true - type: string - produces: - - application/json - responses: - "200": - description: ClusterPromotionTask custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterPromotionTask) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a ClusterPromotionTask - tags: - - Core - - Shared - - Cluster-Scoped Resource - /v1beta1/shared/configmaps: - get: - description: |- - List shared ConfigMap resources referenceable by all projects. - Returns a Kubernetes ConfigMapList resource. - operationId: ListSharedConfigMaps - produces: - - application/json - responses: - "200": - description: ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList) - schema: - type: object - security: - - BearerAuth: [] - summary: List shared ConfigMaps - tags: - - Core - - Generic Config - - Shared - post: - consumes: - - application/json - description: |- - Create a shared ConfigMap referenceable by all projects. Returns - the created Kubernetes ConfigMap resource. - operationId: CreateSharedConfigMap - parameters: - - description: ConfigMap - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateConfigMapRequest' - produces: - - application/json - responses: - "201": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Create a shared ConfigMap - tags: - - Core - - Generic Config - - Shared - /v1beta1/shared/configmaps/{configmap}: - delete: - description: Delete a shared ConfigMap. - operationId: DeleteSharedConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a shared ConfigMap - tags: - - Core - - Generic Config - - Shared - get: - description: Retrieve a shared ConfigMap by name. - operationId: GetSharedConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a shared ConfigMap - tags: - - Core - - Generic Config - - Shared - patch: - consumes: - - application/json - description: |- - Patch a shared ConfigMap. Merges provided data - with existing data. Use removeKeys to delete specific keys. - Returns the updated Kubernetes ConfigMap resource. - operationId: PatchSharedConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - - description: ConfigMap patch - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchConfigMapRequest' - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch a shared ConfigMap - tags: - - Core - - Generic Config - - Shared - put: - consumes: - - application/json - description: |- - Replace a shared ConfigMap. All existing data is replaced. - Returns the updated Kubernetes ConfigMap resource. - operationId: UpdateSharedConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - - description: ConfigMap - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateConfigMapRequest' - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace a shared ConfigMap - tags: - - Core - - Generic Config - - Shared - /v1beta1/shared/generic-credentials: - get: - description: |- - List shared generic credentials. Returns a Kubernetes SecretList - resource containing heavily redacted Secrets. - operationId: ListSharedGenericCredentials - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List shared generic credentials - tags: - - Credentials - - Generic Credentials - - Shared - post: - consumes: - - application/json - description: |- - Create shared generic credentials referenceable by all - projects. Returns a heavily redacted Kubernetes Secret resource. - operationId: CreateSharedGenericCredentials - parameters: - - description: Generic credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateGenericCredentialsRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create shared generic credentials - tags: - - Credentials - - Generic Credentials - - Shared - /v1beta1/shared/generic-credentials/{generic-credentials}: - delete: - description: Delete shared generic credentials. - operationId: DeleteSharedGenericCredentials - parameters: - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete shared generic credentials - tags: - - Credentials - - Generic Credentials - - Shared - get: - description: |- - Retrieve shared generic credentials by name. Returns a - heavily redacted Kubernetes Secret resource. - operationId: GetSharedGenericCredentials - parameters: - - description: Credentials name - in: path - name: generic-credentials - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve shared generic credentials - tags: - - Credentials - - Generic Credentials - - Shared - patch: - consumes: - - application/json - description: |- - Patch shared generic credentials. Merges provided data - with existing data. Use removeKeys to delete specific keys. - Returns a heavily redacted Kubernetes Secret resource. - operationId: PatchSharedGenericCredentials - parameters: - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - - description: GenericCredentials patch - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchGenericCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch shared generic credentials - tags: - - Credentials - - Generic Credentials - - Shared - put: - consumes: - - application/json - description: |- - Replace shared generic credentials. All existing data is replaced. - Returns a heavily redacted Kubernetes Secret resource. - operationId: UpdateSharedGenericCredentials - parameters: - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - - description: GenericCredentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateGenericCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace shared generic credentials - tags: - - Credentials - - Generic Credentials - - Shared - /v1beta1/shared/repo-credentials: - get: - description: |- - List shared repository credentials. Returns a SecretList - resource containing heavily redacted Secrets. - operationId: ListSharedRepoCredentials - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List shared repository credentials - tags: - - Credentials - - Repo Credentials - - Shared - post: - consumes: - - application/json - description: |- - Create shared repository credentials. Returns a heavily - redacted Kubernetes Secret resource. - operationId: CreateSharedRepoCredentials - parameters: - - description: Credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateRepoCredentialsRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create shared repository credentials - tags: - - Credentials - - Repo Credentials - - Shared - /v1beta1/shared/repo-credentials/{repo-credentials}: - delete: - description: Delete shared repository credentials. - operationId: DeleteSharedRepoCredentials - parameters: - - description: Credentials name - in: path - name: repo-credentials - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete shared repository credentials - tags: - - Credentials - - Repo Credentials - - Shared - get: - description: |- - Retrieve shared repository credentials by name. Returns a - heavily redacted Kubernetes Secret resource. - operationId: GetSharedRepoCredentials - parameters: - - description: Credentials name - in: path - name: repo-credentials - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve shared repository credentials - tags: - - Credentials - - Repo Credentials - - Shared - patch: - consumes: - - application/json - description: |- - Patch shared repository credentials. Only provided fields - are updated. Returns a heavily redacted Kubernetes Secret resource. - operationId: PatchSharedRepoCredentials - parameters: - - description: Repo credentials name - in: path - name: repo-credentials - required: true - type: string - - description: Credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchRepoCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch shared repository credentials - tags: - - Credentials - - Repo Credentials - - Shared - put: - consumes: - - application/json - description: |- - Replace shared repository credentials. All fields are replaced. - Returns a heavily redacted Kubernetes Secret resource. - operationId: UpdateSharedRepoCredentials - parameters: - - description: Repo credentials name - in: path - name: repo-credentials - required: true - type: string - - description: Credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateRepoCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace shared repository credentials - tags: - - Credentials - - Repo Credentials - - Shared - /v1beta1/system/api-tokens: - get: - description: |- - List system-level API tokens. Returns a Kubernetes SecretList - resource containing heavily redacted Secrets. - operationId: ListSystemAPITokens - parameters: - - description: Role name filter - in: query - name: role - type: string - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List system-level API tokens - tags: - - Rbac - - Credentials - - System-Level - /v1beta1/system/api-tokens/{apitoken}: - delete: - description: Delete a system-level API token. - operationId: DeleteSystemAPIToken - parameters: - - description: API token name - in: path - name: apitoken - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a system-level API token - tags: - - Rbac - - Credentials - - System-Level - get: - description: |- - Retrieve a system-level API token by name. Returns a heavily - redacted Kubernetes Secret resource. - operationId: GetSystemAPIToken - parameters: - - description: API token name - in: path - name: apitoken - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a system-level API token - tags: - - Rbac - - Credentials - - System-Level - /v1beta1/system/cluster-config: - delete: - description: Deletes the single ClusterConfig resource. - operationId: DeleteClusterConfig - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete the ClusterConfig - tags: - - System - - Config - - Cluster-Scoped Resource - - Singleton - get: - description: Retrieve the single ClusterConfig resource. - operationId: GetClusterConfig - produces: - - application/json - responses: - "200": - description: ClusterConfig custom resource (github.com/akuity/kargo/api/v1alpha1.ClusterConfig) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve the ClusterConfig - tags: - - System - - Config - - Cluster-Scoped Resource - - Singleton - /v1beta1/system/cluster-config/refresh: - post: - description: |- - Refresh the single ClusterConfig resource. Refreshing enqueues - the resource for reconciliation by its corresponding controller. - operationId: RefreshClusterConfig - produces: - - application/json - responses: - "200": - description: Success - security: - - BearerAuth: [] - summary: Refresh the ClusterConfig - tags: - - System - - Config - - Cluster-Scoped Resource - - Singleton - /v1beta1/system/configmaps: - get: - description: |- - List system-level ConfigMap resources. Returns a Kubernetes - ConfigMapList resource. - operationId: ListSystemConfigMaps - produces: - - application/json - responses: - "200": - description: ConfigMapList resource (k8s.io/api/core/v1.ConfigMapList) - schema: - type: object - security: - - BearerAuth: [] - summary: List system-level ConfigMaps - tags: - - Core - - Generic Config - - System-Level - post: - consumes: - - application/json - description: |- - Create a system-level ConfigMap. Returns the created Kubernetes - ConfigMap resource. - operationId: CreateSystemConfigMap - parameters: - - description: ConfigMap - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateConfigMapRequest' - produces: - - application/json - responses: - "201": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Create a system-level ConfigMap - tags: - - Core - - Generic Config - - System-Level - /v1beta1/system/configmaps/{configmap}: - delete: - description: Delete a system-level ConfigMap. - operationId: DeleteSystemConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete a system-level ConfigMap - tags: - - Core - - Generic Config - - System-Level - get: - description: Retrieve a system-level ConfigMap by name. - operationId: GetSystemConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a system-level ConfigMap - tags: - - Core - - Generic Config - - System-Level - patch: - consumes: - - application/json - description: |- - Patch a system-level ConfigMap. Merges provided data - with existing data. Use removeKeys to delete specific keys. - Returns the updated Kubernetes ConfigMap resource. - operationId: PatchSystemConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - - description: ConfigMap patch - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchConfigMapRequest' - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch a system-level ConfigMap - tags: - - Core - - Generic Config - - System-Level - put: - consumes: - - application/json - description: |- - Replace a system-level ConfigMap. All existing data is replaced. - Returns the updated Kubernetes ConfigMap resource. - operationId: UpdateSystemConfigMap - parameters: - - description: ConfigMap name - in: path - name: configmap - required: true - type: string - - description: ConfigMap - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateConfigMapRequest' - produces: - - application/json - responses: - "200": - description: ConfigMap resource (k8s.io/api/core/v1.ConfigMap) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace a system-level ConfigMap - tags: - - Core - - Generic Config - - System-Level - /v1beta1/system/generic-credentials: - get: - description: |- - List system-level generic credentials. Returns a Kubernetes - SecretList resource containing heavily redacted Secrets. - operationId: ListSystemGenericCredentials - produces: - - application/json - responses: - "200": - description: SecretList resource (k8s.io/api/core/v1.SecretList) - schema: - type: object - security: - - BearerAuth: [] - summary: List system-level generic credentials - tags: - - Credentials - - Generic Credentials - - System-Level - post: - consumes: - - application/json - description: |- - Create system-level generic credentials. Returns a heavily - redacted Kubernetes Secret resource. - operationId: CreateSystemGenericCredentials - parameters: - - description: Generic credentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateGenericCredentialsRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create system-level generic credentials - tags: - - Credentials - - Generic Credentials - - System-Level - /v1beta1/system/generic-credentials/{generic-credentials}: - delete: - description: Delete system-level generic credentials. - operationId: DeleteSystemGenericCredentials - parameters: - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - responses: - "204": - description: Deleted successfully - security: - - BearerAuth: [] - summary: Delete system-level generic credentials - tags: - - Credentials - - Generic Credentials - - System-Level - get: - description: |- - Retrieve system-level generic credentials by name. Returns a - heavily redacted Kubernetes Secret resource. - operationId: GetSystemGenericCredentials - parameters: - - description: Credentials name - in: path - name: generic-credentials - required: true - type: string - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve system-level generic credentials - tags: - - Credentials - - Generic Credentials - - System-Level - patch: - consumes: - - application/json - description: |- - Patch system-level generic credentials. Merges provided data - with existing data. Use removeKeys to delete specific keys. - Returns a heavily redacted Kubernetes Secret resource. - operationId: PatchSystemGenericCredentials - parameters: - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - - description: GenericCredentials patch - in: body - name: body - required: true - schema: - $ref: '#/definitions/PatchGenericCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Patch system-level generic credentials - tags: - - Credentials - - Generic Credentials - - System-Level - put: - consumes: - - application/json - description: |- - Replace system-level generic credentials. All existing data is - replaced. Returns a heavily redacted Kubernetes Secret resource. - operationId: UpdateSystemGenericCredentials - parameters: - - description: Generic credentials name - in: path - name: generic-credentials - required: true - type: string - - description: GenericCredentials - in: body - name: body - required: true - schema: - $ref: '#/definitions/UpdateGenericCredentialsRequest' - produces: - - application/json - responses: - "200": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Replace system-level generic credentials - tags: - - Credentials - - Generic Credentials - - System-Level - /v1beta1/system/public-server-config: - get: - description: |- - Retrieve information a client may need to know about how the - Kargo API server is configured in order to proceed with - authentication. - operationId: GetPublicConfig - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/PublicConfig' - summary: Retrieve public server configuration - tags: - - System - - Config - /v1beta1/system/roles: - get: - description: |- - List system-level Kargo Role virtual resources. Returns a - RoleList resource. - operationId: ListSystemRoles - produces: - - application/json - responses: - "200": - description: RoleList custom resource (github.com/akuity/kargo/api/rbac/v1alpha1.RoleList) - schema: - type: object - security: - - BearerAuth: [] - summary: List system-level Kargo Role virtual resources - tags: - - Rbac - - System-Level - /v1beta1/system/roles/{role}: - get: - description: |- - Retrieve a system-level Kargo Role virtual resource by name. - Returns a Kargo Role virtual resource or its underlying - Kubernetes resources. - operationId: GetSystemRole - parameters: - - description: Role name - in: path - name: role - required: true - type: string - produces: - - application/json - responses: - "200": - description: Role resource (k8s.io/api/rbac/v1.Role) or its underlying Kubernetes - resources - schema: - type: object - security: - - BearerAuth: [] - summary: Retrieve a system-level Kargo Role virtual resource - tags: - - Rbac - - System-Level - /v1beta1/system/roles/{role}/api-tokens: - post: - consumes: - - application/json - description: |- - Create a system-level API token associated with a system-level - Kargo Role virtual resource. Returns a Kubernetes Secret - resource representing the token. Store it securely. The token - is not retrievable via the Kargo API after creation except in - a redacted form. - operationId: CreateSystemAPIToken - parameters: - - description: Role name - in: path - name: role - required: true - type: string - - description: Token - in: body - name: body - required: true - schema: - $ref: '#/definitions/CreateAPITokenRequest' - produces: - - application/json - responses: - "201": - description: Secret resource (k8s.io/api/core/v1.Secret) - schema: - type: object - security: - - BearerAuth: [] - summary: Create a system-level API token - tags: - - Rbac - - Credentials - - System-Level - /v1beta1/system/server-config: - get: - description: |- - Retrieve information a client may need to know about how the - Kargo API server is configured. - operationId: GetConfig - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/GetConfigResponse' - security: - - BearerAuth: [] - summary: Retrieve server configuration - tags: - - System - - Config - /v1beta1/system/server-version: - get: - description: Retrieve API Server version information. - operationId: GetVersionInfo - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/VersionInfo' - security: - - BearerAuth: [] - summary: Retrieve API Server version information - tags: - - System -securityDefinitions: - BearerAuth: - description: Bearer token authentication. Obtain token via OIDC/PKCE flow with - your identity provider. - in: header - name: Authorization - type: apiKey -swagger: "2.0" -tags: -- description: 'Manage the primary Kargo resources that make up a promotion pipeline: - Projects (tenancy boundaries), Warehouses (artifact sources), Freight (versioned - artifact bundles), Stages (promotion targets), and Promotions (records of a Freight - moving through a Stage).' - name: Core -- description: 'Cluster-wide administrative operations for Kargo operators: retrieving - server and API version info, authenticating as the built-in admin user, and reading - or modifying cluster-level server configuration.' - name: System -- description: Manage Kargo's role-based access control model. Kargo Roles are named - collections of Kubernetes RBAC rules scoped to a project; API tokens are service-account-backed - credentials that can be bound to a Role for non-human access. - name: Rbac -- description: Top-level grouping for all credential types that Kargo uses to authenticate - with external systems. See the Repo Credentials and Generic Credentials sub-tags - for the specific credential kinds. - name: Credentials -- description: Interact with Argo Rollouts AnalysisRun and AnalysisTemplate resources - used to verify Stage health after a promotion. Includes triggering, aborting, - and re-running analysis, as well as reading run logs. - name: Verifications -- description: Low-level operations for creating, updating, and deleting arbitrary - Kargo Kubernetes resources by raw manifest. Useful for tooling that needs to manage - resource types not covered by dedicated endpoints. - name: Resources -- description: Read Kubernetes Events emitted by Kargo controllers. Events record - notable state transitions (e.g. a Promotion starting, completing, or failing) - and are useful for auditing and debugging. - name: Events -- description: 'Manage structured configuration resources: ProjectConfig holds per-project - promotion policy settings; ClusterConfig holds cluster-wide defaults and feature - flags applied by the Kargo operator.' - name: Config -- description: Manage free-form ConfigMap-backed configuration that Kargo promotion - steps can read at runtime. Supports project-scoped, system-scoped, and shared - ConfigMaps, allowing pipelines to consume environment-specific values without - embedding them in Git. - name: Generic Config -- description: 'Credentials for authenticating with artifact repositories: Git repositories, - Helm chart registries, and container image registries. Kargo uses these when polling - for new artifacts and when running promotion steps that read from or write to - a repository.' - name: Repo Credentials -- description: Arbitrary key-value secrets that promotion steps can consume at runtime - for any purpose not covered by repository credentials — for example, API tokens, - signing keys, or connection strings for external services. - name: Generic Credentials -- description: The resource or operation is scoped to a single Kargo project (Kubernetes - namespace). Access is governed by the requesting user's permissions within that - project. - name: Project-Level -- description: The resource or operation lives in the Kargo system namespace and applies - across all projects. Typically restricted to cluster administrators. - name: System-Level -- description: The resource is a Kubernetes cluster-scoped object (not namespaced), - such as a Project or ClusterAnalysisTemplate. These exist at the cluster level - and are accessible to users with appropriate cluster-wide permissions. - name: Cluster-Scoped Resource -- description: The resource is defined once and shared across multiple projects or - scopes. For example, a shared ConfigMap or credential can be referenced by any - project without being duplicated per namespace. - name: Shared -- description: At most, one instance of this resource kind exists per scope. For example, - each project has, at most, one ProjectConfig and each cluster has, at most, one - ClusterConfig. - name: Singleton diff --git a/ui/src/config/query-client.ts b/ui/src/config/query-client.ts index 387bb44723..4a9468a578 100644 --- a/ui/src/config/query-client.ts +++ b/ui/src/config/query-client.ts @@ -1,6 +1,45 @@ -import { QueryClient } from '@tanstack/react-query'; +import { MutationCache, QueryCache, QueryClient } from '@tanstack/react-query'; +import { notification } from 'antd'; + +import { ApiError } from '@ui/lib/api/custom-fetch'; + +const showErrorNotification = (error: unknown) => { + let message: string; + if (error instanceof ApiError) { + const body = error.body; + if (typeof body === 'object' && body !== null) { + const b = body as Record; + message = String(b.message ?? b.error ?? error.message); + } else { + message = error.message; + } + } else if (error instanceof Error) { + message = error.message; + } else { + message = 'Unexpected API error'; + } + notification.error({ message, placement: 'bottomRight' }); +}; export const queryClient = new QueryClient({ + queryCache: new QueryCache({ + onError: (error, query) => { + // Allow queries to opt out of 404 notifications (e.g. ClusterConfig/ProjectConfig + // which may not exist yet on first setup) + if (query.meta?.silent404 && error instanceof ApiError && error.isNotFound()) { + return; + } + showErrorNotification(error); + } + }), + mutationCache: new MutationCache({ + onError: (error) => { + // ConnectRPC errors are handled by the transport interceptor (transport.ts) + if (error instanceof ApiError) { + showErrorNotification(error); + } + } + }), defaultOptions: { queries: { retry: false, diff --git a/ui/src/features/assemble-freight/assemble-freight.tsx b/ui/src/features/assemble-freight/assemble-freight.tsx index 47ff1c3862..8cac04425c 100644 --- a/ui/src/features/assemble-freight/assemble-freight.tsx +++ b/ui/src/features/assemble-freight/assemble-freight.tsx @@ -78,6 +78,11 @@ const constructFreight = ( } as Chart); } else if ('commits' in artifact) { const commitRef = info as DiscoveredCommit; + + if (!commitRef) { + continue; + } + freight.commits.push({ repoURL: artifact.repoURL, id: commitRef.id, diff --git a/ui/src/features/common/promotion-directive-step-status/utils.ts b/ui/src/features/common/promotion-directive-step-status/utils.ts index 0ac71d8b07..911c09bfb9 100644 --- a/ui/src/features/common/promotion-directive-step-status/utils.ts +++ b/ui/src/features/common/promotion-directive-step-status/utils.ts @@ -33,3 +33,7 @@ export const getPromotionDirectiveStepStatus = ( return PromotionDirectiveStepStatus.WONT_RUN; }; + +export const isFailedStep = (stepIndex: number, promotionStatus?: PromotionStatus) => + getPromotionDirectiveStepStatus(stepIndex, promotionStatus) === + PromotionDirectiveStepStatus.FAILED; diff --git a/ui/src/features/common/settings/access/api-tokens/api-tokens-list.tsx b/ui/src/features/common/settings/access/api-tokens/api-tokens-list.tsx index 1c94d09380..f96fca48aa 100644 --- a/ui/src/features/common/settings/access/api-tokens/api-tokens-list.tsx +++ b/ui/src/features/common/settings/access/api-tokens/api-tokens-list.tsx @@ -1,13 +1,11 @@ -import { timestampDate } from '@bufbuild/protobuf/wkt'; -import { useQuery } from '@connectrpc/connect-query'; import { faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Card, Table } from 'antd'; import { format } from 'date-fns'; import { useModal } from '@ui/features/common/modal/use-modal'; -import { listAPITokens } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { Secret } from '@ui/gen/k8s.io/api/core/v1/generated_pb'; +import { V1Secret } from '@ui/gen/api/v2/models'; +import { useListProjectAPITokens, useListSystemAPITokens } from '@ui/gen/api/v2/rbac/rbac'; import { CreateAPITokenModal } from './create-api-token-modal'; import { DeleteAPITokenButton } from './delete-api-token-button'; @@ -18,7 +16,11 @@ type Props = { }; export const APITokensList = ({ project = '', systemLevel = false }: Props) => { - const listAPITokensQuery = useQuery(listAPITokens, { project, systemLevel }); + const systemTokensQuery = useListSystemAPITokens(undefined, { query: { enabled: systemLevel } }); + const projectTokensQuery = useListProjectAPITokens(project, undefined, { + query: { enabled: !systemLevel && !!project } + }); + const listAPITokensQuery = systemLevel ? systemTokensQuery : projectTokensQuery; const { show } = useModal((p) => ( @@ -35,33 +37,35 @@ export const APITokensList = ({ project = '', systemLevel = false }: Props) => { } > - + className='my-2 overflow-x-auto' - dataSource={listAPITokensQuery.data?.tokenSecrets || []} - rowKey={(record: Secret) => record?.metadata?.name || ''} + dataSource={listAPITokensQuery.data?.data?.items || []} + rowKey={(record: V1Secret) => record?.metadata?.name || ''} pagination={{ defaultPageSize: 5, hideOnSinglePage: true }} loading={listAPITokensQuery.isLoading} > { - const date = timestampDate(template.metadata?.creationTimestamp); - return date ? format(date, 'MMM do yyyy HH:mm:ss') : ''; + render={(_, template: V1Secret) => { + const ts = template.metadata?.creationTimestamp; + if (!ts) return ''; + const date = new Date(ts); + return isNaN(date.getTime()) ? '' : format(date, 'MMM do yyyy HH:mm:ss'); }} width={220} /> - title='Name' dataIndex={['metadata', 'name']} /> - + title='Name' dataIndex={['metadata', 'name']} /> + title='Role' dataIndex={['metadata', 'annotations', 'kubernetes.io/service-account.name']} /> - + title='Last usage' dataIndex={['metadata', 'labels', 'kubernetes.io/legacy-token-last-used']} width={140} /> - + render={(_, record) => ( { const [token, setToken] = React.useState(''); - const listRolesQuery = useQuery(listRoles, { systemLevel, project }); - const { mutate: createAPITokenMutation, isPending } = useMutation(createAPIToken, { - onSuccess: (d) => { - setToken( - decodeRawData({ - result: { - case: 'raw', - value: d.tokenSecret?.data.token || new Uint8Array() - } - }) - ); - queryClient.refetchQueries({ - queryKey: createConnectQueryKey({ - schema: listAPITokens, - cardinality: 'finite' - }) + const queryClient = useQueryClient(); + + const systemRolesQuery = useListSystemRoles({ query: { enabled: systemLevel } }); + const projectRolesQuery = useListProjectRoles(project, { + query: { enabled: !systemLevel && !!project } + }); + const listRolesQuery = systemLevel ? systemRolesQuery : projectRolesQuery; + // backend returns json object instead of array of RbacRole for some reason, so we need to cast it + const roles = (listRolesQuery.data?.data as unknown as RbacRole[]) || []; + + const { mutate: createAPITokenMutation, isPending } = useMutation({ + mutationFn: ({ name, roleName }: { name: string; roleName: string }) => + systemLevel + ? createSystemAPIToken(roleName, { name }) + : createProjectAPIToken(project, roleName, { name }), + onSuccess: (response) => { + const tokenB64 = (response.data?.data as Record)?.token; + setToken(tokenB64 ? atob(tokenB64) : ''); + queryClient.invalidateQueries({ + queryKey: systemLevel + ? getListSystemAPITokensQueryKey() + : getListProjectAPITokensQueryKey(project) }); } }); @@ -48,11 +56,7 @@ export const CreateAPITokenModal = ({ hide, visible, systemLevel, project }: Pro }); const onSubmit = handleSubmit((data) => - createAPITokenMutation({ - systemLevel, - project, - ...data - }) + createAPITokenMutation({ name: data.name, roleName: data.roleName }) ); // On successful creation, show token @@ -94,7 +98,7 @@ export const CreateAPITokenModal = ({ hide, visible, systemLevel, project }: Pro onChange={onChange} loading={listRolesQuery.isLoading} placeholder='Select Role' - options={(listRolesQuery.data?.roles || []).map((sa) => ({ + options={roles.map((sa) => ({ label: sa.metadata?.name || '', value: sa.metadata?.name || '' }))} diff --git a/ui/src/features/common/settings/access/api-tokens/delete-api-token-button.tsx b/ui/src/features/common/settings/access/api-tokens/delete-api-token-button.tsx index b4b854221c..12b84b97c4 100644 --- a/ui/src/features/common/settings/access/api-tokens/delete-api-token-button.tsx +++ b/ui/src/features/common/settings/access/api-tokens/delete-api-token-button.tsx @@ -1,14 +1,16 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useQueryClient } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; import { Button, Typography } from 'antd'; -import { queryClient } from '@ui/config/query-client'; import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-modal'; import { - deleteAPIToken, - listAPITokens -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; + deleteProjectAPIToken, + deleteSystemAPIToken, + getListProjectAPITokensQueryKey, + getListSystemAPITokensQueryKey +} from '@ui/gen/api/v2/rbac/rbac'; type Props = { systemLevel: boolean; @@ -18,25 +20,22 @@ type Props = { export const DeleteAPITokenButton = ({ name, project, systemLevel }: Props) => { const confirm = useConfirmModal(); + const queryClient = useQueryClient(); - const { mutate, isPending: isLoadingDelete } = useMutation(deleteAPIToken); + const { mutate, isPending: isLoadingDelete } = useMutation({ + mutationFn: () => + systemLevel ? deleteSystemAPIToken(name) : deleteProjectAPIToken(project, name), + onSuccess: () => + queryClient.invalidateQueries({ + queryKey: systemLevel + ? getListSystemAPITokensQueryKey() + : getListProjectAPITokensQueryKey(project) + }) + }); const onDelete = () => { confirm({ - onOk: () => { - mutate( - { name, project, systemLevel }, - { - onSuccess: () => - queryClient.refetchQueries({ - queryKey: createConnectQueryKey({ - schema: listAPITokens, - cardinality: 'finite' - }) - }) - } - ); - }, + onOk: () => mutate(), title: 'Delete API Token', content: ( <> diff --git a/ui/src/features/common/settings/access/roles/create-role.tsx b/ui/src/features/common/settings/access/roles/create-role.tsx index 2114673d3d..2300ba8e8f 100644 --- a/ui/src/features/common/settings/access/roles/create-role.tsx +++ b/ui/src/features/common/settings/access/roles/create-role.tsx @@ -1,5 +1,3 @@ -import { create } from '@bufbuild/protobuf'; -import { useMutation } from '@connectrpc/connect-query'; import { zodResolver } from '@hookform/resolvers/zod'; import { Button, Drawer, Input } from 'antd'; import { useState } from 'react'; @@ -9,12 +7,8 @@ import { z } from 'zod'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { MultiStringEditor } from '@ui/features/common/form/multi-string-editor'; import { DESCRIPTION_ANNOTATION_KEY, dnsRegex } from '@ui/features/common/utils'; -import { Claim, ClaimSchema, Role } from '@ui/gen/api/rbac/v1alpha1/generated_pb'; -import { - createRole, - updateRole -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { PolicyRule } from '@ui/gen/k8s.io/api/rbac/v1/generated_pb'; +import { Claim, RbacRole, V1PolicyRule } from '@ui/gen/api/v2/models'; +import { useCreateProjectRole, useUpdateRole } from '@ui/gen/api/v2/rbac/rbac'; import { zodValidators } from '@ui/utils/validators'; import { RuleEditor } from './rule-editor'; @@ -23,7 +17,7 @@ import { RulesTable } from './rules-table'; type Props = { project: string; onSuccess: () => void; - editing?: Role; + editing?: RbacRole; hide: () => void; }; @@ -55,44 +49,28 @@ export const CreateRole = ({ editing, onSuccess, project, hide }: Props) => { resolver: zodResolver(formSchema), values: { name: editing?.metadata?.name || '', - description: editing?.metadata?.annotations[DESCRIPTION_ANNOTATION_KEY] || '', - email: - editing?.claims.find((claim: Claim) => { - if (claim.name === 'email') { - return claim; - } else { - return undefined; - } - })?.values || [], - sub: - editing?.claims.find((claim: Claim) => { - if (claim.name === 'sub') { - return claim; - } else { - return undefined; - } - })?.values || [], - groups: - editing?.claims.find((claim: Claim) => { - if (claim.name === 'groups') { - return claim; - } else { - return undefined; - } - })?.values || [] + description: editing?.metadata?.annotations?.[DESCRIPTION_ANNOTATION_KEY] || '', + email: editing?.claims?.find((claim: Claim) => claim.name === 'email')?.values || [], + sub: editing?.claims?.find((claim: Claim) => claim.name === 'sub')?.values || [], + groups: editing?.claims?.find((claim: Claim) => claim.name === 'groups')?.values || [] } }); - const { mutate } = useMutation(createRole, { - onSuccess: () => { - hide(); - onSuccess(); + + const { mutate } = useCreateProjectRole({ + mutation: { + onSuccess: () => { + hide(); + onSuccess(); + } } }); - const { mutate: update } = useMutation(updateRole, { - onSuccess: () => { - hide(); - onSuccess(); + const { mutate: update } = useUpdateRole({ + mutation: { + onSuccess: () => { + hide(); + onSuccess(); + } } }); @@ -101,9 +79,7 @@ export const CreateRole = ({ editing, onSuccess, project, hide }: Props) => { const getClaims = (): Claim[] => { const claimsArray: Claim[] = []; multiFields.map((field) => { - const newClaim = create(ClaimSchema, { - name: String(field.name) - }); + const newClaim: Claim = { name: String(field.name) }; if (newClaim.name === 'email') { if (values.email.length === 0) { return; @@ -131,26 +107,29 @@ export const CreateRole = ({ editing, onSuccess, project, hide }: Props) => { }; if (editing) { return update({ - role: { + project, + role: editing?.metadata?.name || '', + data: { ...values, rules, metadata: { namespace: project, name: editing?.metadata?.name, annotations }, claims: getClaims() - } + } as unknown as { [key: string]: unknown } }); } else { mutate({ - role: { + project, + data: { ...values, rules, metadata: { name: values.name, namespace: project, annotations }, claims: getClaims() - } + } as unknown as { [key: string]: unknown } }); } }); - const [rules, setRules] = useState(editing?.rules || []); + const [rules, setRules] = useState(editing?.rules || []); return ( diff --git a/ui/src/features/common/settings/access/roles/delete-role-modal.tsx b/ui/src/features/common/settings/access/roles/delete-role-modal.tsx deleted file mode 100644 index 2b67d10621..0000000000 --- a/ui/src/features/common/settings/access/roles/delete-role-modal.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useMutation } from '@connectrpc/connect-query'; -import { Modal } from 'antd'; -import { useParams } from 'react-router-dom'; - -import { deleteRole } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; - -export const DeleteRoleModal = ({ - name, - hide, - onSuccess -}: { - name: string; - hide: () => void; - onSuccess: () => void; -}) => { - const { name: project } = useParams(); - const { mutate } = useMutation(deleteRole, { - onSuccess: () => { - hide(); - onSuccess(); - } - }); - - return ( - { - mutate({ project, name }); - }} - onCancel={hide} - > -

Are you sure you want to delete the role {name}?

-
- ); -}; diff --git a/ui/src/features/common/settings/access/roles/roles-list.tsx b/ui/src/features/common/settings/access/roles/roles-list.tsx index d387d58d0b..0ba04943f6 100644 --- a/ui/src/features/common/settings/access/roles/roles-list.tsx +++ b/ui/src/features/common/settings/access/roles/roles-list.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faInfoCircle, faPencil, @@ -14,11 +13,12 @@ import { useState } from 'react'; import { ConfirmModal } from '@ui/features/common/confirm-modal/confirm-modal'; import { descriptionExpandable } from '@ui/features/common/description-expandable'; import { useModal } from '@ui/features/common/modal/use-modal'; -import { Role } from '@ui/gen/api/rbac/v1alpha1/generated_pb'; +import { RbacRole } from '@ui/gen/api/v2/models'; import { - deleteRole, - listRoles -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; + useDeleteProjectRole, + useListProjectRoles, + useListSystemRoles +} from '@ui/gen/api/v2/rbac/rbac'; import { CreateRole } from './create-role'; import { RulesModal } from './rules-modal'; @@ -27,8 +27,8 @@ const renderColumn = (key: string) => { return { title: key.charAt(0).toUpperCase() + key.slice(1), key, - render: (record: Role) => { - const claimValues = record.claims.find((claim) => claim.name === key)?.values; + render: (record: RbacRole) => { + const claimValues = (record.claims || []).find((claim) => claim.name === key)?.values; return (
{((claimValues as string[]) || []).length > 0 ? ( @@ -48,17 +48,27 @@ type Props = { }; export const RolesList = ({ project = '', systemLevel = false }: Props) => { - const { data, refetch, isLoading } = useQuery(listRoles, { project, systemLevel }); + const systemRolesQuery = useListSystemRoles({ query: { enabled: systemLevel } }); + const projectRolesQuery = useListProjectRoles(project, { + query: { enabled: !systemLevel && !!project } + }); + const activeQuery = systemLevel ? systemRolesQuery : projectRolesQuery; + + const { data, refetch, isLoading } = activeQuery; + // backend returns json object instead of array of RbacRole for some reason, so we need to cast it + const roles = (data?.data as unknown as RbacRole[]) || []; const [showCreateRole, setShowCreateRole] = useState(false); - const [editingRole, setEditingRole] = useState(); + const [editingRole, setEditingRole] = useState(); const { show, hide } = useModal(); - const { mutate: deleteRoleAction } = useMutation(deleteRole, { - onSuccess: () => { - hide(); - setTimeout(() => refetch(), 500); + const { mutate: deleteRoleAction } = useDeleteProjectRole({ + mutation: { + onSuccess: () => { + hide(); + setTimeout(() => refetch(), 500); + } } }); @@ -95,8 +105,8 @@ export const RolesList = ({ project = '', systemLevel = false }: Props) => { )} { + key={roles.length} + dataSource={roles.sort((a, b) => { if (a.metadata?.name && b.metadata?.name) { return a.metadata?.name.localeCompare(b.metadata?.name); } else { @@ -104,12 +114,12 @@ export const RolesList = ({ project = '', systemLevel = false }: Props) => { } })} loading={isLoading} - rowKey={(record: Role) => record?.metadata?.name || ''} + rowKey={(record: RbacRole) => record?.metadata?.name || ''} columns={[ { title: 'Name', key: 'name', - render: (record: Role) => <>{record.metadata?.name} + render: (record: RbacRole) => <>{record.metadata?.name} }, renderColumn('email'), renderColumn('sub'), @@ -117,18 +127,19 @@ export const RolesList = ({ project = '', systemLevel = false }: Props) => { { title: 'Rules', key: 'rules', - render: (record: Role) => { + render: (record: RbacRole) => { + const rulesCount = record?.rules?.length || 0; return ( 0 ? faInfoCircle : faQuestionCircle} + icon={rulesCount > 0 ? faInfoCircle : faQuestionCircle} className={classNames({ - 'cursor-pointer text-blue-500': record?.rules?.length > 0, - 'text-gray-200': record?.rules?.length === 0 + 'cursor-pointer text-blue-500': rulesCount > 0, + 'text-gray-200': rulesCount === 0 })} onClick={() => { - if (record?.rules?.length === 0) return; + if (rulesCount === 0) return; show((p) => ( - + )); }} /> @@ -137,10 +148,10 @@ export const RolesList = ({ project = '', systemLevel = false }: Props) => { }, { key: 'actions', - render: (record: Role) => { + render: (record: RbacRole) => { return (
- {record?.kargoManaged && ( + {!systemLevel && (
{ - const listProjectConfigMapsQuery = useQuery(listConfigMaps, { project, systemLevel }); +export const ConfigMaps = ({ project = '' }: Props) => { + const sharedQuery = useListSharedConfigMaps({ query: { enabled: !project } }); + const projectQuery = useListProjectConfigMaps(project, { query: { enabled: !!project } }); + const listQuery = project ? projectQuery : sharedQuery; const actionModal = useModal(); const { show: showCreateConfigMapModal } = useModal((p) => ( - + )); return ( @@ -37,20 +37,20 @@ export const ConfigMaps = ({ systemLevel = false, project = '' }: Props) => { } > -
className='my-2' scroll={{ x: 'max-content' }} - dataSource={listProjectConfigMapsQuery.data?.configMaps || []} - loading={listProjectConfigMapsQuery.isLoading} + dataSource={listQuery.data?.data?.items || []} + loading={listQuery.isLoading} pagination={{ defaultPageSize: 10, hideOnSinglePage: true }} size='small' > - title='Name' dataIndex={['metadata', 'name']} /> - + title='Name' dataIndex={['metadata', 'name']} /> + title='Keys' dataIndex='data' render={(data) => { - const configMapKeys = Object.keys(data); + const configMapKeys = Object.keys(data || {}); if (!configMapKeys.length) { return It looks like this configmap is empty.; @@ -63,31 +63,36 @@ export const ConfigMaps = ({ systemLevel = false, project = '' }: Props) => { )); }} /> - + align='right' width={200} - render={(_, record) => ( - - - - - )} + render={(_, record) => { + if (record?.metadata?.labels?.['kargo.akuity.io/replicated-from']) { + return ( + + Replicated + + ); + } + return ( + + + + + ); + }} />
diff --git a/ui/src/features/common/settings/config-maps/create-config-map-modal.tsx b/ui/src/features/common/settings/config-maps/create-config-map-modal.tsx index 1190fe0ad6..8106b2247b 100644 --- a/ui/src/features/common/settings/config-maps/create-config-map-modal.tsx +++ b/ui/src/features/common/settings/config-maps/create-config-map-modal.tsx @@ -1,13 +1,15 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { zodResolver } from '@hookform/resolvers/zod'; +import { useMutation } from '@tanstack/react-query'; import { Input, Modal } from 'antd'; import { useForm } from 'react-hook-form'; import { queryClient } from '@ui/config/query-client'; import { - createConfigMap, - listConfigMaps -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; + createProjectConfigMap, + createSharedConfigMap, + getListProjectConfigMapsQueryKey, + getListSharedConfigMapsQueryKey +} from '@ui/gen/api/v2/core/core'; import { FieldContainer } from '../../form/field-container'; import { ModalProps } from '../../modal/use-modal'; @@ -16,32 +18,35 @@ import { ObjectEditor } from '../../object-editor'; import { confgMapSchema } from './schema'; type Props = ModalProps & { - systemLevel: boolean; project: string; }; -export const CreateConfigMapModal = ({ project, systemLevel, hide, visible }: Props) => { +export const CreateConfigMapModal = ({ project, hide, visible }: Props) => { const { control, handleSubmit } = useForm({ defaultValues: { name: '', - data: {} + data: {} as Record }, resolver: zodResolver(confgMapSchema) }); - const { mutate, isPending } = useMutation(createConfigMap, { + const mutationFn = project + ? (values: { name: string; data: Record }) => + createProjectConfigMap(project, values) + : (values: { name: string; data: Record }) => createSharedConfigMap(values); + const queryKey = project + ? getListProjectConfigMapsQueryKey(project) + : getListSharedConfigMapsQueryKey(); + + const { mutate, isPending } = useMutation({ + mutationFn, onSuccess: () => { - queryClient.refetchQueries({ - queryKey: createConnectQueryKey({ - schema: listConfigMaps, - cardinality: 'finite' - }) - }); + queryClient.refetchQueries({ queryKey }); hide(); } }); - const onSubmit = handleSubmit((data) => mutate({ ...data, project, systemLevel })); + const onSubmit = handleSubmit((data) => mutate(data)); return ( { +export const DeleteConfigMapButton = ({ name, project }: Props) => { const confirm = useConfirmModal(); - const { mutate, isPending } = useMutation(deleteConfigMap); + const mutationFn = project + ? () => deleteProjectConfigMap(project, name) + : () => deleteSharedConfigMap(name); + const queryKey = project + ? getListProjectConfigMapsQueryKey(project) + : getListSharedConfigMapsQueryKey(); + + const { mutate, isPending } = useMutation({ + mutationFn, + onSuccess: () => queryClient.refetchQueries({ queryKey }) + }); const onDelete = () => { confirm({ - onOk: () => { - mutate( - { name, project, systemLevel }, - { - onSuccess: () => - queryClient.refetchQueries({ - queryKey: createConnectQueryKey({ - schema: listConfigMaps, - cardinality: 'finite' - }) - }) - } - ); - }, + onOk: () => mutate(), title: 'Delete ConfigMap', content: ( <> diff --git a/ui/src/features/common/settings/config-maps/edit-config-map-modal.tsx b/ui/src/features/common/settings/config-maps/edit-config-map-modal.tsx index 712dccc718..a3f64ae6ff 100644 --- a/ui/src/features/common/settings/config-maps/edit-config-map-modal.tsx +++ b/ui/src/features/common/settings/config-maps/edit-config-map-modal.tsx @@ -1,14 +1,16 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { zodResolver } from '@hookform/resolvers/zod'; +import { useMutation } from '@tanstack/react-query'; import { Input, Modal } from 'antd'; import { useForm } from 'react-hook-form'; import { queryClient } from '@ui/config/query-client'; import { - listConfigMaps, - updateConfigMap -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { ConfigMap } from '@ui/gen/k8s.io/api/core/v1/generated_pb'; + getListProjectConfigMapsQueryKey, + getListSharedConfigMapsQueryKey, + updateProjectConfigMap, + updateSharedConfigMap +} from '@ui/gen/api/v2/core/core'; +import { V1ConfigMap } from '@ui/gen/api/v2/models'; import { FieldContainer } from '../../form/field-container'; import { ModalProps } from '../../modal/use-modal'; @@ -18,31 +20,37 @@ import { confgMapSchema } from './schema'; type Props = ModalProps & { project: string; - configMap: ConfigMap; + configMap: V1ConfigMap; }; export const EditConfigMapModal = ({ configMap, project, hide, visible }: Props) => { const { control, handleSubmit } = useForm({ defaultValues: { name: configMap.metadata?.name, - data: { ...configMap.data } + data: { ...(configMap.data || {}) } }, resolver: zodResolver(confgMapSchema) }); - const { mutate, isPending } = useMutation(updateConfigMap, { + const name = configMap.metadata?.name || ''; + const mutationFn = project + ? (values: { data: Record }) => + updateProjectConfigMap(project, name, { data: values.data }) + : (values: { data: Record }) => + updateSharedConfigMap(name, { data: values.data }); + const queryKey = project + ? getListProjectConfigMapsQueryKey(project) + : getListSharedConfigMapsQueryKey(); + + const { mutate, isPending } = useMutation({ + mutationFn, onSuccess: () => { - queryClient.refetchQueries({ - queryKey: createConnectQueryKey({ - schema: listConfigMaps, - cardinality: 'finite' - }) - }); + queryClient.refetchQueries({ queryKey }); hide(); } }); - const onSubmit = handleSubmit((data) => mutate({ ...data, project })); + const onSubmit = handleSubmit((data) => mutate(data)); return ( { - props.hide(); - onSuccess(); - } + const onMutationSuccess = () => { + props.hide(); + onSuccess(); + }; + + const createRepoMutation = useMutation({ + mutationFn: (values: ReturnType) => { + const body = { + name: values.name, + type: values.type, + repoUrl: values.repoUrl, + repoUrlIsRegex: values.repoUrlIsRegex, + username: values.username, + password: values.password, + description: values.description + }; + return project + ? createProjectRepoCredentials(project, body) + : createSharedRepoCredentials(body); + }, + onSuccess: onMutationSuccess }); - const updateCredentialsMutation = useMutation(updateRepoCredentials, { - onSuccess: () => { - props.hide(); - onSuccess(); - } + const updateRepoMutation = useMutation({ + mutationFn: (values: ReturnType) => { + const name = init?.metadata?.name || ''; + const body = { + type: values.type, + repoUrl: values.repoUrl, + repoUrlIsRegex: values.repoUrlIsRegex, + username: values.username, + password: values.password, + description: values.description + }; + return project + ? updateProjectRepoCredentials(project, name, body) + : updateSharedRepoCredentials(name, body); + }, + onSuccess: onMutationSuccess }); - const createSecretsMutation = useMutation(createGenericCredentials, { - onSuccess: () => { - props.hide(); - onSuccess(); - } + const createGenericMutation = useMutation({ + mutationFn: (payload: { name: string; data: Record; description?: string }) => + project + ? createProjectGenericCredentials(project, payload) + : createSharedGenericCredentials(payload), + onSuccess: onMutationSuccess }); - const updateSecretsMutation = useMutation(updateGenericCredentials, { - onSuccess: () => { - props.hide(); - onSuccess(); - } + const updateGenericMutation = useMutation({ + mutationFn: (payload: { data: Record; description?: string }) => { + const name = init?.metadata?.name || ''; + return project + ? updateProjectGenericCredentials(project, name, payload) + : updateSharedGenericCredentials(name, payload); + }, + onSuccess: onMutationSuccess }); const repoUrlIsRegex = watch('repoUrlIsRegex'); @@ -108,33 +143,32 @@ export const CreateCredentialsModal = ({ project, onSuccess, editing, init, ...p } if (editing) { - return updateSecretsMutation.mutate({ - ...values, - project, - name: init?.metadata?.name || '', - data - }); + return updateGenericMutation.mutate({ data, description: values.description }); } - return createSecretsMutation.mutate({ ...values, project, data }); + return createGenericMutation.mutate({ + name: values.name, + data, + description: values.description + }); } if (editing) { - return updateCredentialsMutation.mutate({ - ...values, - project, - name: init?.metadata?.name || '' - }); + return updateRepoMutation.mutate(values as ReturnType); } - return createCredentialsMutation.mutate({ ...values, project }); + return createRepoMutation.mutate(values as ReturnType); }); + const isPending = + createRepoMutation.isPending || + updateRepoMutation.isPending || + createGenericMutation.isPending || + updateGenericMutation.isPending; + return ( {({ field }) => ( - // @ts-expect-error expectedtype is there + // @ts-expect-error expected type is there )} diff --git a/ui/src/features/common/settings/secrets/credentials-list.tsx b/ui/src/features/common/settings/secrets/credentials-list.tsx index 52e428a0c6..ef02d58537 100644 --- a/ui/src/features/common/settings/secrets/credentials-list.tsx +++ b/ui/src/features/common/settings/secrets/credentials-list.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faCode, faExternalLink, @@ -8,14 +7,17 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useMutation } from '@tanstack/react-query'; import { Button, Popover, Space, Table, Typography } from 'antd'; import Card from 'antd/es/card/Card'; import { - deleteRepoCredentials, - listRepoCredentials -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { Secret } from '@ui/gen/k8s.io/api/core/v1/generated_pb'; + deleteProjectRepoCredentials, + deleteSharedRepoCredentials, + useListProjectRepoCredentials, + useListSharedRepoCredentials +} from '@ui/gen/api/v2/credentials/credentials'; +import { V1Secret } from '@ui/gen/api/v2/models'; import { useConfirmModal } from '../../confirm-modal/use-confirm-modal'; import { descriptionExpandable } from '../../description-expandable'; @@ -33,7 +35,9 @@ type Props = { export const CredentialsList = ({ project = '' }: Props) => { const confirm = useConfirmModal(); - const listCredentialsQuery = useQuery(listRepoCredentials, { project }); + const sharedQuery = useListSharedRepoCredentials({ query: { enabled: !project } }); + const projectQuery = useListProjectRepoCredentials(project, { query: { enabled: !!project } }); + const listCredentialsQuery = project ? projectQuery : sharedQuery; const { show: showCreate } = useModal((p) => ( { {...p} /> )); - const deleteCredentialsMutation = useMutation(deleteRepoCredentials, { - onSuccess: () => { - listCredentialsQuery.refetch(); - } + + const deleteCredentialsMutation = useMutation({ + mutationFn: (name: string) => + project ? deleteProjectRepoCredentials(project, name) : deleteSharedRepoCredentials(name), + onSuccess: () => listCredentialsQuery.refetch() }); - const specificCredentials: Secret[] = listCredentialsQuery.data?.credentials || []; + const specificCredentials: V1Secret[] = listCredentialsQuery.data?.data?.items || []; return ( { } type='inner' > - className='my-2' scroll={{ x: 'max-content' }} key={specificCredentials.length} dataSource={specificCredentials} - rowKey={(record: Secret) => record?.metadata?.name || ''} + rowKey={(record) => record?.metadata?.name || ''} loading={listCredentialsQuery.isLoading} pagination={{ defaultPageSize: 5, hideOnSinglePage: true }} size='small' @@ -84,105 +89,111 @@ export const CredentialsList = ({ project = '' }: Props) => { { title: 'Name', key: 'name', - render: (record) => { + render: (_, record) => { return
{record?.metadata?.name}
; } }, { title: 'Type', key: 'type', - render: (record) => ( + render: (_, record) => (
- {record?.metadata?.labels[CredentialTypeLabelKey].toUpperCase()} + {record?.metadata?.labels?.[CredentialTypeLabelKey]?.toUpperCase()}
) }, { title: 'Repo URL / Pattern', key: 'createdAt', - render: (record) => ( + render: (_, record) => (
- {record?.stringData[CredentialsDataKey.RepoUrl]} + {record?.stringData?.[CredentialsDataKey.RepoUrl]}
) }, { title: 'Username', key: 'username', - render: (record) =>
{record?.stringData[CredentialsDataKey.Username]}
+ render: (_, record) =>
{record?.stringData?.[CredentialsDataKey.Username]}
}, { key: 'actions', fixed: 'right', - render: (record) => ( - - - - - ) + render: (_, record) => { + if (record?.metadata?.labels?.['kargo.akuity.io/replicated-from']) { + return ( + + Replicated + + ); + } + return ( + + + + + ); + } } ]} expandable={descriptionExpandable()} diff --git a/ui/src/features/common/settings/secrets/generic-credentials-list.tsx b/ui/src/features/common/settings/secrets/generic-credentials-list.tsx index 8a682abfde..39e01e70ba 100644 --- a/ui/src/features/common/settings/secrets/generic-credentials-list.tsx +++ b/ui/src/features/common/settings/secrets/generic-credentials-list.tsx @@ -1,6 +1,6 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPencil, faPlus, faQuestionCircle, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useMutation } from '@tanstack/react-query'; import { Button, Card, Popover, Space, Table, Tag, Typography } from 'antd'; import React from 'react'; @@ -8,10 +8,12 @@ import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-m import { descriptionExpandable } from '@ui/features/common/description-expandable'; import { useModal } from '@ui/features/common/modal/use-modal'; import { - deleteGenericCredentials, - listGenericCredentials -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { Secret } from '@ui/gen/k8s.io/api/core/v1/generated_pb'; + deleteProjectGenericCredentials, + deleteSharedGenericCredentials, + useListProjectGenericCredentials, + useListSharedGenericCredentials +} from '@ui/gen/api/v2/credentials/credentials'; +import { V1Secret } from '@ui/gen/api/v2/models'; import { CreateCredentialsModal } from './create-credentials-modal'; @@ -24,13 +26,19 @@ type Props = { export const GenericCredentialsList = ({ project = '', description }: Props) => { const confirm = useConfirmModal(); - const listSecretsQuery = useQuery(listGenericCredentials, { project }); + const sharedQuery = useListSharedGenericCredentials({ query: { enabled: !project } }); + const projectQuery = useListProjectGenericCredentials(project, { query: { enabled: !!project } }); + const listSecretsQuery = project ? projectQuery : sharedQuery; - const deleteSecretsMutation = useMutation(deleteGenericCredentials, { + const deleteSecretsMutation = useMutation({ + mutationFn: (name: string) => + project + ? deleteProjectGenericCredentials(project, name) + : deleteSharedGenericCredentials(name), onSuccess: () => listSecretsQuery.refetch() }); - const genericCredentials: Secret[] = listSecretsQuery.data?.credentials || []; + const genericCredentials: V1Secret[] = listSecretsQuery.data?.data?.items || []; const { show: showCreateGeneric } = useModal((p) => ( } > -
className='my-2' scroll={{ x: 'max-content' }} key={genericCredentials.length} dataSource={genericCredentials} - rowKey={(record: Secret) => record?.metadata?.name || ''} + rowKey={(record) => record?.metadata?.name || ''} pagination={{ defaultPageSize: 5, hideOnSinglePage: true }} size='small' columns={[ { title: 'Name', key: 'name', - render: (record) => record?.metadata?.name + render: (_, record) => record?.metadata?.name }, { title: 'Keys', key: 'secrets', render: (_, record) => { - const secretsKeys = Object.keys(record?.stringData) || []; + const secretsKeys = Object.keys(record?.stringData || {}); if (!secretsKeys.length) { return It looks like this secret is empty.; @@ -97,61 +105,67 @@ export const GenericCredentialsList = ({ project = '', description }: Props) => { key: 'actions', fixed: 'right', - render: (record) => ( - - - - - ) + render: (_, record) => { + if (record?.metadata?.labels?.['kargo.akuity.io/replicated-from']) { + return ( + + Replicated + + ); + } + return ( + + + + + ); + } } ]} expandable={descriptionExpandable()} diff --git a/ui/src/features/common/settings/secrets/utils.tsx b/ui/src/features/common/settings/secrets/utils.tsx index c3c7620de3..a4ea9aff5f 100644 --- a/ui/src/features/common/settings/secrets/utils.tsx +++ b/ui/src/features/common/settings/secrets/utils.tsx @@ -3,7 +3,7 @@ import { faAnchor, faDharmachakra, faQuestionCircle } from '@fortawesome/free-so import { SegmentLabel } from '@ui/features/common/segment-label'; import { DESCRIPTION_ANNOTATION_KEY } from '@ui/features/common/utils'; -import { Secret } from '@ui/gen/k8s.io/api/core/v1/generated_pb'; +import { V1Secret } from '@ui/gen/api/v2/models'; import { CredentialTypeLabelKey, CredentialsDataKey, CredentialsType } from './types'; @@ -34,7 +34,7 @@ export const labelForKey = (s: string) => .replace(/^./, (str) => str.toUpperCase()) .replace('Url', 'URL'); -export const constructDefaults = (init?: Secret, type?: string) => { +export const constructDefaults = (init?: V1Secret, type?: string) => { if (!init) { return { name: '', @@ -48,20 +48,24 @@ export const constructDefaults = (init?: Secret, type?: string) => { }; } + const stringData = init?.stringData ?? {}; + const annotations = init?.metadata?.annotations ?? {}; + const labels = init?.metadata?.labels ?? {}; + return { name: init?.metadata?.name || '', - description: init?.metadata?.annotations[DESCRIPTION_ANNOTATION_KEY], - type: init?.metadata?.labels[CredentialTypeLabelKey] || type || 'git', - repoUrl: init?.stringData[CredentialsDataKey.RepoUrl], - repoUrlIsRegex: init?.stringData[CredentialsDataKey.RepoUrlIsRegex] === 'true', - username: init?.stringData[CredentialsDataKey.Username], + description: annotations[DESCRIPTION_ANNOTATION_KEY], + type: labels[CredentialTypeLabelKey] || type || 'git', + repoUrl: stringData[CredentialsDataKey.RepoUrl], + repoUrlIsRegex: stringData[CredentialsDataKey.RepoUrlIsRegex] === 'true', + username: stringData[CredentialsDataKey.Username], password: '', data: redactSecretStringData(init) }; }; -export const redactSecretStringData = (secret: Secret) => { - const data = secret?.stringData; +export const redactSecretStringData = (secret: V1Secret) => { + const data = { ...(secret?.stringData ?? {}) }; for (const key of Object.keys(data)) { data[key] = ''; diff --git a/ui/src/features/project/list/projects-list.tsx b/ui/src/features/project/list/projects-list.tsx index 8d97d40bf0..43b92fe443 100644 --- a/ui/src/features/project/list/projects-list.tsx +++ b/ui/src/features/project/list/projects-list.tsx @@ -1,7 +1,7 @@ import { useQuery } from '@connectrpc/connect-query'; import { faStar, faUser } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Button, Empty, Flex, Pagination, Space } from 'antd'; +import { Empty, Flex, Pagination, Space, Tag, Tooltip } from 'antd'; import { useEffect, useState } from 'react'; import { LoadingState } from '@ui/features/common'; @@ -25,7 +25,7 @@ export const ProjectsList = () => { 'starred-projects-view', false ); - const [myProjectsView, setMyProjectsView] = useLocalStorage('my-projects-view', true); + const [myProjectsView, setMyProjectsView] = useLocalStorage('my-projects-view', false); const [starred, toggleStar] = useStarProjects(); @@ -63,31 +63,37 @@ export const ProjectsList = () => { - - + - + ); } @@ -97,28 +103,28 @@ export const ProjectsList = () => { - - +
diff --git a/ui/src/features/project/pipelines/use-watch-freight.ts b/ui/src/features/project/pipelines/use-watch-freight.ts index 5945f53c31..4912c0948a 100644 --- a/ui/src/features/project/pipelines/use-watch-freight.ts +++ b/ui/src/features/project/pipelines/use-watch-freight.ts @@ -6,7 +6,43 @@ import { useEffect } from 'react'; import { transportWithAuth } from '@ui/config/transport'; import { queryCache } from '@ui/features/utils/cache'; import { queryFreight } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { KargoService } from '@ui/gen/api/service/v1alpha1/service_pb'; +import { KargoService, QueryFreightResponse } from '@ui/gen/api/service/v1alpha1/service_pb'; +import { Freight } from '@ui/gen/api/v1alpha1/generated_pb'; + +const upsertFreight = ( + current: QueryFreightResponse | undefined, + freight: Freight +): QueryFreightResponse => { + const existing = current?.groups?.['']?.freight || []; + const found = existing.some((f) => f?.metadata?.name === freight?.metadata?.name); + const updated = found + ? existing.map((f) => (f?.metadata?.name === freight?.metadata?.name ? freight : f)) + : [...existing, freight]; + return { + ...current, + groups: { + ...current?.groups, + '': { ...current?.groups?.[''], freight: updated } + } + } as QueryFreightResponse; +}; + +const deleteFreight = ( + current: QueryFreightResponse | undefined, + freight: Freight +): QueryFreightResponse => + ({ + ...current, + groups: { + ...current?.groups, + '': { + ...current?.groups?.[''], + freight: (current?.groups?.['']?.freight || []).filter( + (f) => f?.metadata?.name !== freight?.metadata?.name + ) + } + } + }) as QueryFreightResponse; export const useWatchFreight = (project: string) => { const client = useQueryClient(); @@ -31,51 +67,11 @@ export const useWatchFreight = (project: string) => { continue; } - let currentFreight = queryCache.freight.get(project); - - if (e.type === 'DELETED') { - // Remove the deleted freight from the cache - if (currentFreight?.groups?.['']?.freight) { - currentFreight = { - ...currentFreight, - groups: { - ...currentFreight?.groups, - '': { - ...currentFreight?.groups?.[''], - freight: currentFreight?.groups?.['']?.freight?.filter( - (f) => f?.metadata?.name !== freight?.metadata?.name - ) - } - } - }; - } - } else { - // Handle ADDED and MODIFIED events - const exist = currentFreight?.groups?.['']?.freight?.find( - (f) => f?.metadata?.name === freight?.metadata?.name - ); - - if (!exist) { - currentFreight?.groups?.['']?.freight?.push(freight); - } else { - currentFreight = { - ...currentFreight, - groups: { - ...currentFreight?.groups, - '': { - ...currentFreight?.groups?.[''], - freight: currentFreight?.groups?.['']?.freight?.map((f) => { - if (f?.metadata?.name === freight?.metadata?.name) { - return freight; - } - - return f; - }) - } - } - }; - } - } + const currentFreight = queryCache.freight.get(project); + const updatedFreight = + e.type === 'DELETED' + ? deleteFreight(currentFreight, freight) + : upsertFreight(currentFreight, freight); const queryFreightKey = createConnectQueryKey({ cardinality: 'finite', @@ -86,7 +82,7 @@ export const useWatchFreight = (project: string) => { transport: transportWithAuth }); - client.setQueryData(queryFreightKey, currentFreight); + client.setQueryData(queryFreightKey, updatedFreight); } }; diff --git a/ui/src/features/project/settings/project-settings.tsx b/ui/src/features/project/settings/project-settings.tsx index ecb43bd5a1..f2489af30a 100644 --- a/ui/src/features/project/settings/project-settings.tsx +++ b/ui/src/features/project/settings/project-settings.tsx @@ -1,4 +1,3 @@ -import { useQuery } from '@connectrpc/connect-query'; import { faAsterisk, faChartBar, @@ -16,7 +15,7 @@ import { NavLink, Route, Routes, useLocation, useParams, Navigate } from 'react- import { useExtensionsContext } from '@ui/extensions/extensions-context'; import { useDocumentTitle } from '@ui/features/common/document-title/use-document-title'; import { BaseHeader } from '@ui/features/common/layout/base-header'; -import { getConfig } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; +import { useGetConfig } from '@ui/gen/api/v2/system/system'; import { useProjectBreadcrumbs } from '../project-utils'; @@ -31,8 +30,8 @@ import { SecretsSettings } from './views/secrets/secrets-settings'; export const ProjectSettings = () => { const location = useLocation(); - const getConfigQuery = useQuery(getConfig); - const config = getConfigQuery.data; + const getConfigQuery = useGetConfig(); + const config = getConfigQuery.data?.data; const { projectSettingsExtensions } = useExtensionsContext(); diff --git a/ui/src/features/project/settings/views/analysis-templates/analysis-templates.tsx b/ui/src/features/project/settings/views/analysis-templates/analysis-templates.tsx index 6b2736ccda..9ca51eb7ee 100644 --- a/ui/src/features/project/settings/views/analysis-templates/analysis-templates.tsx +++ b/ui/src/features/project/settings/views/analysis-templates/analysis-templates.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPencil, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Card, Space, Table } from 'antd'; @@ -8,12 +7,11 @@ import { useParams } from 'react-router-dom'; import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-modal'; import { descriptionExpandable } from '@ui/features/common/description-expandable'; import { useModal } from '@ui/features/common/modal/use-modal'; +import { RolloutsAnalysisTemplate } from '@ui/gen/api/v2/models'; import { - deleteAnalysisTemplate, - listAnalysisTemplates -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { AnalysisTemplate } from '@ui/gen/api/stubs/rollouts/v1alpha1/generated_pb'; -import { timestampDate } from '@ui/utils/connectrpc-utils'; + useDeleteAnalysisTemplate, + useListAnalysisTemplates +} from '@ui/gen/api/v2/verifications/verifications'; import { CreateAnalysisTemplateModal } from './create-analysis-template-modal'; import { EditAnalysisTemplateModal } from './edit-analysis-template-modal'; @@ -22,13 +20,13 @@ export const AnalysisTemplatesSettings = () => { const { name } = useParams(); const confirm = useConfirmModal(); - const { data, isLoading, refetch } = useQuery(listAnalysisTemplates, { project: name }); + const { data, isLoading, refetch } = useListAnalysisTemplates(name || ''); const { show: showEdit } = useModal(); const { show: showCreate } = useModal((p) => ( )); - const { mutate: deleteTemplate, isPending: isDeleting } = useMutation(deleteAnalysisTemplate, { - onSuccess: () => refetch() + const { mutate: deleteTemplate, isPending: isDeleting } = useDeleteAnalysisTemplate({ + mutation: { onSuccess: () => refetch() } }); return ( @@ -42,24 +40,26 @@ export const AnalysisTemplatesSettings = () => { } > - - dataSource={data?.analysisTemplates} + + dataSource={data?.data?.items} pagination={{ hideOnSinglePage: true }} rowKey={(i) => i.metadata?.name || ''} loading={isLoading} expandable={descriptionExpandable()} className='my-2' > - + title='Creation Date' width={200} render={(_, template) => { - const date = timestampDate(template.metadata?.creationTimestamp); - return date ? format(date, 'MMM do yyyy HH:mm:ss') : ''; + const ts = template.metadata?.creationTimestamp; + if (!ts) return ''; + const date = new Date(ts); + return isNaN(date.getTime()) ? '' : format(date, 'MMM do yyyy HH:mm:ss'); }} /> - title='Name' dataIndex={['metadata', 'name']} /> - + title='Name' dataIndex={['metadata', 'name']} /> + width={150} render={(_, template) => ( @@ -101,7 +101,10 @@ export const AnalysisTemplatesSettings = () => {

), onOk: () => { - deleteTemplate({ project: name || '', name: template?.metadata?.name || '' }); + deleteTemplate({ + project: name || '', + analysisTemplate: template?.metadata?.name || '' + }); }, hide: () => {} }); diff --git a/ui/src/features/project/settings/views/analysis-templates/create-analysis-template-modal.tsx b/ui/src/features/project/settings/views/analysis-templates/create-analysis-template-modal.tsx index 354a26e7ce..ce1c062c81 100644 --- a/ui/src/features/project/settings/views/analysis-templates/create-analysis-template-modal.tsx +++ b/ui/src/features/project/settings/views/analysis-templates/create-analysis-template-modal.tsx @@ -1,4 +1,3 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { useQueryClient } from '@tanstack/react-query'; import { Modal } from 'antd'; import { useForm } from 'react-hook-form'; @@ -6,12 +5,8 @@ import { useForm } from 'react-hook-form'; import YamlEditor from '@ui/features/common/code-editor/yaml-editor-lazy'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { ModalProps } from '@ui/features/common/modal/use-modal'; -import { queryCache } from '@ui/features/utils/cache'; -import { - createResource, - listAnalysisTemplates -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { decodeUint8ArrayYamlManifestToJson } from '@ui/utils/decode-raw-data'; +import { useCreateResource } from '@ui/gen/api/v2/resources/resources'; +import { getListAnalysisTemplatesQueryKey } from '@ui/gen/api/v2/verifications/verifications'; import { getAnalysisTemplateYAMLExample } from './utils/analysis-template-example'; @@ -22,16 +17,14 @@ type Props = ModalProps & { export const CreateAnalysisTemplateModal = ({ visible, hide, namespace }: Props) => { const queryClient = useQueryClient(); - const { mutateAsync, isPending } = useMutation(createResource, { - onSuccess: (response) => { - for (const result of response?.results || []) { - if (result?.result?.case === 'createdResourceManifest') { - queryCache.analysisTemplates.add(namespace || '', [ - decodeUint8ArrayYamlManifestToJson(result?.result?.value) - ]); - } + const { mutate, isPending } = useCreateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListAnalysisTemplatesQueryKey(namespace) + }); + hide(); } - hide(); } }); @@ -41,23 +34,7 @@ export const CreateAnalysisTemplateModal = ({ visible, hide, namespace }: Props) } }); - const onSubmit = handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - await mutateAsync( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listAnalysisTemplates, - cardinality: 'finite' - }) - }) - } - ); - }); + const onSubmit = handleSubmit((data) => mutate({ data: data.value })); return ( { const queryClient = useQueryClient(); - const { mutateAsync, isPending } = useMutation(updateResource, { - onSuccess: () => hide() + const { mutate, isPending } = useUpdateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListAnalysisTemplatesQueryKey(projectName) + }); + hide(); + } + } }); - const { data: templateResponse, isLoading } = useQuery(getAnalysisTemplate, { - project: projectName, - name: templateName, - format: RawFormat.YAML - }); + const { data: templateResponse, isLoading } = useGetAnalysisTemplate(projectName, templateName); const { control, handleSubmit } = useForm({ values: { - value: decodeRawData(templateResponse) + value: templateResponse?.data ? stringify(templateResponse.data) : '' } }); - const onSubmit = handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - - await mutateAsync( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listAnalysisTemplates, - cardinality: 'finite' - }) - }) - } - ); - }); + const onSubmit = handleSubmit((data) => mutate({ data: data.value })); return ( { const { name } = useParams(); @@ -19,25 +12,17 @@ export const DeleteProject = () => { const navigate = useNavigate(); const [inputValue, setInputValue] = React.useState(''); - const { mutate, isPending } = useMutation(deleteResource, { - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ schema: listProjects, cardinality: 'finite' }) - }); - navigate(paths.projects); + const { mutate, isPending } = useDeleteProject({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: getListProjectsQueryKey() }); + navigate(paths.projects); + } } }); const onDelete = () => { - const textEncoder = new TextEncoder(); - const manifest = { - ...projectYAMLExample, - metadata: { - name - } - }; - - mutate({ manifest: textEncoder.encode(yaml.stringify(manifest)) }); + mutate({ project: name || '' }); }; return ( diff --git a/ui/src/features/project/settings/views/general/general-settings.tsx b/ui/src/features/project/settings/views/general/general-settings.tsx index 85d8552c7a..02681dde98 100644 --- a/ui/src/features/project/settings/views/general/general-settings.tsx +++ b/ui/src/features/project/settings/views/general/general-settings.tsx @@ -1,22 +1,17 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { zodResolver } from '@hookform/resolvers/zod'; import { Button, Card, Flex, message } from 'antd'; import type { JSONSchema4 } from 'json-schema'; import { useForm } from 'react-hook-form'; import { useParams } from 'react-router-dom'; -import yaml from 'yaml'; +import yaml, { stringify } from 'yaml'; import { z } from 'zod'; import { YamlEditor } from '@ui/features/common/code-editor/yaml-editor'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { projectYAMLExample } from '@ui/features/project/list/utils/project-yaml-example'; -import { - getProject, - updateResource -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { RawFormat } from '@ui/gen/api/service/v1alpha1/service_pb'; +import { useGetProject } from '@ui/gen/api/v2/core/core'; +import { useUpdateResource } from '@ui/gen/api/v2/resources/resources'; import schema from '@ui/gen/schema/projects.kargo.akuity.io_v1alpha1.json'; -import { decodeRawData } from '@ui/utils/decode-raw-data'; import { zodValidators } from '@ui/utils/validators'; const formSchema = z.object({ @@ -27,28 +22,25 @@ import { DeleteProject } from './delete-project-modal'; export const GeneralSettings = () => { const { name } = useParams(); - const { data, isLoading } = useQuery(getProject, { name, format: RawFormat.YAML }); + const { data, isLoading } = useGetProject(name || ''); - const { mutateAsync, isPending } = useMutation(updateResource, { - onSuccess: () => - message.success({ - content: `Project Configuration has been updated.` - }) + const { mutate, isPending } = useUpdateResource({ + mutation: { + onSuccess: () => + message.success({ + content: `Project Configuration has been updated.` + }) + } }); const { control, handleSubmit } = useForm({ values: { - value: decodeRawData(data) + value: data?.data ? stringify(data.data) : '' }, resolver: zodResolver(formSchema) }); - const onSubmit = handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - await mutateAsync({ - manifest: textEncoder.encode(data.value) - }); - }); + const onSubmit = handleSubmit((data) => mutate({ data: data.value })); return ( diff --git a/ui/src/features/project/settings/views/project-config/project-config.tsx b/ui/src/features/project/settings/views/project-config/project-config.tsx index daf9fc52bf..ac46f6274e 100644 --- a/ui/src/features/project/settings/views/project-config/project-config.tsx +++ b/ui/src/features/project/settings/views/project-config/project-config.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -7,25 +6,19 @@ import type { JSONSchema4 } from 'json-schema'; import { useMemo } from 'react'; import { useForm } from 'react-hook-form'; import { useParams } from 'react-router-dom'; -import yaml, { parse } from 'yaml'; +import yaml, { parse, stringify } from 'yaml'; import { z } from 'zod'; import { YamlEditor } from '@ui/features/common/code-editor/yaml-editor'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { useModal } from '@ui/features/common/modal/use-modal'; import { projectConfigYAMLExample } from '@ui/features/project/list/utils/project-yaml-example'; -import { - createOrUpdateResource, - getProjectConfig -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { RawFormat } from '@ui/gen/api/service/v1alpha1/service_pb'; -import { ProjectConfig as ProjectConfigT } from '@ui/gen/api/v1alpha1/generated_pb'; +import { useGetProjectConfig } from '@ui/gen/api/v2/core/core'; +import { useUpdateResource } from '@ui/gen/api/v2/resources/resources'; import projectConfigSchema from '@ui/gen/schema/projectconfigs.kargo.akuity.io_v1alpha1.json'; -import { decodeRawData } from '@ui/utils/decode-raw-data'; import { zodValidators } from '@ui/utils/validators'; import { Refresh } from './refresh'; -import { projectConfigTransport } from './transport'; import { CreateWebhookModal } from './webhook/create-webhook-modal'; import { Webhooks } from './webhooks'; @@ -36,19 +29,31 @@ const formSchema = z.object({ export const ProjectConfig = () => { const { name } = useParams(); - const projectConfigQuery = useQuery( - getProjectConfig, - { project: name, format: RawFormat.YAML }, - { - transport: projectConfigTransport - } - ); + const projectConfigQuery = useGetProjectConfig(name || '', { + query: { meta: { silent404: true } } + }); - const projectConfigYAML = decodeRawData(projectConfigQuery.data); + const projectConfigYAML = useMemo(() => { + if (!projectConfigQuery.data?.data) { + return ''; + } + try { + return stringify(projectConfigQuery.data.data); + } catch (e) { + notification.error({ + message: (e as Error)?.message || 'Failed to stringify ProjectConfig', + placement: 'bottomRight' + }); + return ''; + } + }, [projectConfigQuery.data?.data]); const projectConfig = useMemo(() => { + if (!projectConfigYAML) { + return undefined; + } try { - return parse(projectConfigYAML) as ProjectConfigT; + return parse(projectConfigYAML); } catch (e) { notification.error({ message: (e as Error)?.message || 'Failed to parse ProjectConfig YAML', @@ -68,19 +73,18 @@ export const ProjectConfig = () => { resolver: zodResolver(formSchema) }); - const createOrUpdateMutation = useMutation(createOrUpdateResource, { - onSuccess: () => { - message.success({ content: `ProjectConfig has been ${creation ? 'created' : 'updated'}` }); - projectConfigQuery.refetch(); + const createOrUpdateMutation = useUpdateResource({ + mutation: { + onSuccess: () => { + message.success({ content: `ProjectConfig has been ${creation ? 'created' : 'updated'}` }); + projectConfigQuery.refetch(); + } } }); - const onSubmitConfig = projectConfigForm.handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - await createOrUpdateMutation.mutateAsync({ - manifest: textEncoder.encode(data.value) - }); - }); + const onSubmitConfig = projectConfigForm.handleSubmit((data) => + createOrUpdateMutation.mutate({ data: data.value }) + ); const createWebhookModal = useModal((props) => ( diff --git a/ui/src/features/project/settings/views/project-config/refresh.tsx b/ui/src/features/project/settings/views/project-config/refresh.tsx index 8ccad9f71d..51059f792f 100644 --- a/ui/src/features/project/settings/views/project-config/refresh.tsx +++ b/ui/src/features/project/settings/views/project-config/refresh.tsx @@ -1,28 +1,23 @@ -import { useMutation } from '@connectrpc/connect-query'; import { faUndo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Tooltip } from 'antd'; import { queryCache } from '@ui/features/utils/cache'; -import { refreshResource } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; +import { useRefreshProjectConfig } from '@ui/gen/api/v2/core/core'; export const Refresh = (props: { project: string }) => { - const refreshResourceTypeProjectConfig = 'ProjectConfig'; - const refreshResourceMutation = useMutation(refreshResource, { - onSuccess: () => queryCache.projectConfig.refetch() + const refreshProjectConfigMutation = useRefreshProjectConfig({ + mutation: { + onSuccess: () => queryCache.projectConfig.refetch() + } }); return ( diff --git a/ui/src/features/project/settings/views/project-config/transport.ts b/ui/src/features/project/settings/views/project-config/transport.ts deleted file mode 100644 index 67fe42b7a8..0000000000 --- a/ui/src/features/project/settings/views/project-config/transport.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Code } from '@connectrpc/connect'; - -import { defaultErrorHandler, newErrorHandler, newTransportWithAuth } from '@ui/config/transport'; - -export const projectConfigTransport = newTransportWithAuth( - newErrorHandler((err) => { - if (err.code === Code.NotFound) { - // ignore 404 because ProjectConfig may not be created when we create a new Project - // and we need to ignore the error - return; - } - - defaultErrorHandler(err); - }) -); diff --git a/ui/src/features/project/settings/views/project-config/webhook/use-create-webhook-mutation.ts b/ui/src/features/project/settings/views/project-config/webhook/use-create-webhook-mutation.ts index 5c40a35161..86aef57759 100644 --- a/ui/src/features/project/settings/views/project-config/webhook/use-create-webhook-mutation.ts +++ b/ui/src/features/project/settings/views/project-config/webhook/use-create-webhook-mutation.ts @@ -1,16 +1,22 @@ -import { useMutation } from '@connectrpc/connect-query'; -import { useMutation as useReactQueryMutation } from '@tanstack/react-query'; +import { useMutation as useReactQueryMutation, useQueryClient } from '@tanstack/react-query'; import { notification } from 'antd'; import { parse, stringify } from 'yaml'; -import { queryCache } from '@ui/features/utils/cache'; +import { getGetProjectConfigQueryKey } from '@ui/gen/api/v2/core/core'; import { - createOrUpdateResource, - createGenericCredentials, - deleteGenericCredentials -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { ProjectConfig } from '@ui/gen/api/v1alpha1/generated_pb'; -import { PartialRecursive } from '@ui/utils/connectrpc-utils'; + useCreateProjectGenericCredentials, + useDeleteProjectGenericCredentials +} from '@ui/gen/api/v2/credentials/credentials'; +import { useCreateResource, useUpdateResource } from '@ui/gen/api/v2/resources/resources'; + +type ProjectConfigPartial = { + apiVersion?: string; + kind?: string; + metadata?: { name?: string; namespace?: string }; + spec?: { + webhookReceivers?: Array>; + }; +}; type createWebhookPayload = { projectConfigYAML: string; @@ -24,23 +30,26 @@ type createWebhookPayload = { }; export const useCreateWebhookMutation = (opts?: { onSuccess?: () => void }) => { - const createOrUpdateMutation = useMutation(createOrUpdateResource); - const createProjectSecretMutation = useMutation(createGenericCredentials); - const deleteProjectSecretMutation = useMutation(deleteGenericCredentials); + const queryClient = useQueryClient(); + const createResourceMutation = useCreateResource(); + const updateResourceMutation = useUpdateResource(); + const createProjectSecretMutation = useCreateProjectGenericCredentials(); + const deleteProjectSecretMutation = useDeleteProjectGenericCredentials(); return useReactQueryMutation({ mutationFn: async (payload: createWebhookPayload) => { await createProjectSecretMutation.mutateAsync({ project: payload.secret.namespace, - name: payload.secret.name, - data: payload.secret.data + data: { + name: payload.secret.name, + data: payload.secret.data + } }); - let projectConfig = parse(payload.projectConfigYAML) as PartialRecursive; + let projectConfig: ProjectConfigPartial = parse(payload.projectConfigYAML); if (payload.projectConfigYAML === '') { projectConfig = { - // @ts-expect-error apiVersion required when creating resource apiVersion: 'kargo.akuity.io/v1alpha1', kind: 'ProjectConfig', metadata: { @@ -72,16 +81,15 @@ export const useCreateWebhookMutation = (opts?: { onSuccess?: () => void }) => { } }); - const textEncoder = new TextEncoder(); + const resourceMutation = + payload.projectConfigYAML === '' ? createResourceMutation : updateResourceMutation; try { - await createOrUpdateMutation.mutateAsync({ - manifest: textEncoder.encode(stringify(projectConfig)) - }); + await resourceMutation.mutateAsync({ data: stringify(projectConfig) }); } catch { await deleteProjectSecretMutation.mutateAsync({ - name: payload.secret.name, - project: payload.secret.namespace + project: payload.secret.namespace, + genericCredentials: payload.secret.name }); } }, @@ -90,7 +98,9 @@ export const useCreateWebhookMutation = (opts?: { onSuccess?: () => void }) => { message: `Successfully added webhook for ${vars.webhookReceiver}`, placement: 'bottomRight' }); - queryCache.projectConfig.refetch(); + queryClient.invalidateQueries({ + queryKey: getGetProjectConfigQueryKey(vars.secret.namespace) + }); opts?.onSuccess?.(); } }); diff --git a/ui/src/features/project/settings/views/project-config/webhooks.tsx b/ui/src/features/project/settings/views/project-config/webhooks.tsx index 7d57da61f7..b0fd321e5a 100644 --- a/ui/src/features/project/settings/views/project-config/webhooks.tsx +++ b/ui/src/features/project/settings/views/project-config/webhooks.tsx @@ -5,7 +5,7 @@ import Card from 'antd/es/card/Card'; import classNames from 'classnames'; import { useState } from 'react'; -import { WebhookReceiverDetails } from '@ui/gen/api/v1alpha1/generated_pb'; +import { WebhookReceiverDetails } from '@ui/gen/api/v2/models'; type WebhooksProps = { webhookReceivers: WebhookReceiverDetails[]; @@ -58,7 +58,7 @@ const WebhookURLColumn = (props: { details: WebhookReceiverDetails }) => { size='small' icon={} onClick={async () => { - await navigator.clipboard.writeText(props.details?.url); + await navigator.clipboard.writeText(props.details?.url || ''); notification.success({ message: 'URL copied.', placement: 'bottomRight' }); }} type='text' diff --git a/ui/src/features/project/settings/views/promotion-tasks/create-promotion-task.tsx b/ui/src/features/project/settings/views/promotion-tasks/create-promotion-task.tsx index 55c0a537dc..934ad9e2e1 100644 --- a/ui/src/features/project/settings/views/promotion-tasks/create-promotion-task.tsx +++ b/ui/src/features/project/settings/views/promotion-tasks/create-promotion-task.tsx @@ -1,4 +1,3 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { useQueryClient } from '@tanstack/react-query'; import Modal from 'antd/es/modal/Modal'; import Link from 'antd/es/typography/Link'; @@ -7,10 +6,8 @@ import { useForm } from 'react-hook-form'; import YamlEditor from '@ui/features/common/code-editor/yaml-editor-lazy'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { ModalComponentProps } from '@ui/features/common/modal/modal-context'; -import { - createResource, - listPromotionTasks -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; +import { getListPromotionTasksQueryKey } from '@ui/gen/api/v2/core/core'; +import { useCreateResource } from '@ui/gen/api/v2/resources/resources'; import { getPromotionTaskYAMLExample } from './promotion-task-example'; @@ -21,7 +18,16 @@ type CreatePromotionTaskModalProps = ModalComponentProps & { export const CreatePromotionTaskModal = (props: CreatePromotionTaskModalProps) => { const queryClient = useQueryClient(); - const createResourceMutation = useMutation(createResource); + const createResourceMutation = useCreateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListPromotionTasksQueryKey(props.namespace) + }); + props.hide(); + } + } + }); const promotionTaskForm = useForm({ defaultValues: { @@ -30,24 +36,7 @@ export const CreatePromotionTaskModal = (props: CreatePromotionTaskModalProps) = }); const onSubmit = promotionTaskForm.handleSubmit((data) => { - const textEncoder = new TextEncoder(); - - createResourceMutation.mutate( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listPromotionTasks, - cardinality: 'finite' - }) - }); - props.hide(); - } - } - ); + createResourceMutation.mutate({ data: data.value }); }); return ( diff --git a/ui/src/features/project/settings/views/promotion-tasks/edit-promotion-task-modal.tsx b/ui/src/features/project/settings/views/promotion-tasks/edit-promotion-task-modal.tsx index 30579cbdde..7edcfc9b74 100644 --- a/ui/src/features/project/settings/views/promotion-tasks/edit-promotion-task-modal.tsx +++ b/ui/src/features/project/settings/views/promotion-tasks/edit-promotion-task-modal.tsx @@ -1,19 +1,14 @@ -import { createConnectQueryKey, useMutation, useQuery } from '@connectrpc/connect-query'; import { useQueryClient } from '@tanstack/react-query'; import { Modal } from 'antd'; import { useForm } from 'react-hook-form'; +import { stringify } from 'yaml'; import YamlEditor from '@ui/features/common/code-editor/yaml-editor-lazy'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { ModalComponentProps } from '@ui/features/common/modal/modal-context'; -import { - getPromotionTask, - listPromotionTasks, - updateResource -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { RawFormat } from '@ui/gen/api/service/v1alpha1/service_pb'; -import { PromotionTask } from '@ui/gen/api/v1alpha1/generated_pb'; -import { decodeRawData } from '@ui/utils/decode-raw-data'; +import { getListPromotionTasksQueryKey, useGetPromotionTask } from '@ui/gen/api/v2/core/core'; +import { PromotionTask } from '@ui/gen/api/v2/models'; +import { useUpdateResource } from '@ui/gen/api/v2/resources/resources'; import { getPromotionTaskYAMLExample } from './promotion-task-example'; @@ -23,38 +18,30 @@ type EditPromotionTaskModalProps = ModalComponentProps & { export const EditPromotionTaskModal = (props: EditPromotionTaskModalProps) => { const queryClient = useQueryClient(); + const project = props.promotionTask?.metadata?.namespace || ''; + const taskName = props.promotionTask?.metadata?.name || ''; - const getPromotionTaskQuery = useQuery(getPromotionTask, { - project: props.promotionTask?.metadata?.namespace, - name: props.promotionTask?.metadata?.name, - format: RawFormat.YAML - }); + const getPromotionTaskQuery = useGetPromotionTask(project, taskName); - const updateResourceMutation = useMutation(updateResource, { onSuccess: () => props.hide() }); + const updateResourceMutation = useUpdateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListPromotionTasksQueryKey(project) + }); + props.hide(); + } + } + }); const editPromotionTaskForm = useForm({ values: { - value: decodeRawData(getPromotionTaskQuery.data) + value: getPromotionTaskQuery.data?.data ? stringify(getPromotionTaskQuery.data.data) : '' } }); const onSubmit = editPromotionTaskForm.handleSubmit((data) => { - const textEncoder = new TextEncoder(); - - updateResourceMutation.mutate( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listPromotionTasks, - cardinality: 'infinite' - }) - }) - } - ); + updateResourceMutation.mutate({ data: data.value }); }); return ( @@ -74,9 +61,7 @@ export const EditPromotionTaskModal = (props: EditPromotionTaskModalProps) => { onChange={(e) => field.onChange(e || '')} isLoading={getPromotionTaskQuery.isFetching} height='500px' - placeholder={getPromotionTaskYAMLExample( - props.promotionTask?.metadata?.name || 'custom-promotion-task' - )} + placeholder={getPromotionTaskYAMLExample(taskName || 'custom-promotion-task')} label='Spec' /> )} diff --git a/ui/src/features/project/settings/views/promotion-tasks/promotion-tasks.tsx b/ui/src/features/project/settings/views/promotion-tasks/promotion-tasks.tsx index 7e53cff999..39b10efca1 100644 --- a/ui/src/features/project/settings/views/promotion-tasks/promotion-tasks.tsx +++ b/ui/src/features/project/settings/views/promotion-tasks/promotion-tasks.tsx @@ -1,19 +1,15 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPencil, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Card, Flex, Table } from 'antd'; import { format } from 'date-fns'; import { useParams } from 'react-router-dom'; +import { stringify } from 'yaml'; import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-modal'; import { useModal } from '@ui/features/common/modal/use-modal'; -import { promotionTaskManifestsGen } from '@ui/features/utils/manifest-generator'; -import { - deleteResource, - listPromotionTasks -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { PromotionTask } from '@ui/gen/api/v1alpha1/generated_pb'; -import { timestampDate } from '@ui/utils/connectrpc-utils'; +import { useListPromotionTasks } from '@ui/gen/api/v2/core/core'; +import { PromotionTask } from '@ui/gen/api/v2/models'; +import { useDeleteResource } from '@ui/gen/api/v2/resources/resources'; import { CreatePromotionTaskModal } from './create-promotion-task'; import { EditPromotionTaskModal } from './edit-promotion-task-modal'; @@ -22,9 +18,11 @@ export const PromotionTasks = () => { const { name } = useParams(); const confirm = useConfirmModal(); - const listPromotionTasksQuery = useQuery(listPromotionTasks, { project: name }); + const listPromotionTasksQuery = useListPromotionTasks(name || ''); - const deletePromotionTaskMutation = useMutation(deleteResource); + const deletePromotionTaskMutation = useDeleteResource({ + mutation: { onSuccess: () => listPromotionTasksQuery.refetch() } + }); const promotionTasksModal = useModal(); @@ -45,13 +43,7 @@ export const PromotionTasks = () => {

), onOk: () => { - const manifest = new TextEncoder().encode( - promotionTaskManifestsGen.v1alpha1(promotionTask) - ); - deletePromotionTaskMutation.mutate( - { manifest }, - { onSuccess: () => listPromotionTasksQuery.refetch() } - ); + deletePromotionTaskMutation.mutate({ data: stringify(promotionTask) }); }, hide: () => {} }); @@ -74,8 +66,9 @@ export const PromotionTasks = () => { > className='my-2' - dataSource={listPromotionTasksQuery.data?.promotionTasks} + dataSource={listPromotionTasksQuery.data?.data?.items} loading={listPromotionTasksQuery.isFetching} + rowKey={(r) => r.metadata?.name || ''} locale={{ emptyText: ( <> @@ -95,9 +88,10 @@ export const PromotionTasks = () => { title: 'Creation Date', width: 200, render: (_, template) => { - const date = timestampDate(template.metadata?.creationTimestamp); - - return date ? format(date, 'MMM do yyyy HH:mm:ss') : ''; + const ts = template.metadata?.creationTimestamp; + if (!ts) return ''; + const date = new Date(ts); + return isNaN(date.getTime()) ? '' : format(date, 'MMM do yyyy HH:mm:ss'); } }, { diff --git a/ui/src/features/promotion-directives/registry/use-discover-registries.ts b/ui/src/features/promotion-directives/registry/use-discover-registries.ts index f2342cc89f..2bcc0a8d60 100644 --- a/ui/src/features/promotion-directives/registry/use-discover-registries.ts +++ b/ui/src/features/promotion-directives/registry/use-discover-registries.ts @@ -18,6 +18,8 @@ import jsonParseConfig from '@ui/gen/directives/json-parse-config.json'; import jsonUpdateConfig from '@ui/gen/directives/json-update-config.json'; import kustomizeBuildConfig from '@ui/gen/directives/kustomize-build-config.json'; import kustomizeSetImageConfig from '@ui/gen/directives/kustomize-set-image-config.json'; +import tomlParseConfig from '@ui/gen/directives/toml-parse-config.json'; +import tomlUpdateConfig from '@ui/gen/directives/toml-update-config.json'; import yamlMergeConfig from '@ui/gen/directives/yaml-merge-config.json'; import yamlParseConfig from '@ui/gen/directives/yaml-parse-config.json'; import yamlUpdateConfig from '@ui/gen/directives/yaml-update-config.json'; @@ -83,6 +85,14 @@ export const useDiscoverPromotionDirectivesRegistries = (): PromotionDirectivesR identifier: 'json-update', config: jsonUpdateConfig as unknown as JSONSchema7 }, + { + identifier: 'toml-parse', + config: tomlParseConfig as JSONSchema7 + }, + { + identifier: 'toml-update', + config: tomlUpdateConfig as unknown as JSONSchema7 + }, { identifier: 'git-push', config: gitPushConfig as unknown as JSONSchema7 diff --git a/ui/src/features/settings/analysis-templates/analysis-templates.tsx b/ui/src/features/settings/analysis-templates/analysis-templates.tsx index d75a48e315..a73814057d 100644 --- a/ui/src/features/settings/analysis-templates/analysis-templates.tsx +++ b/ui/src/features/settings/analysis-templates/analysis-templates.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPencil, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Card, Table } from 'antd'; @@ -7,12 +6,11 @@ import { format } from 'date-fns'; import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-modal'; import { descriptionExpandable } from '@ui/features/common/description-expandable'; import { useModal } from '@ui/features/common/modal/use-modal'; +import { RolloutsClusterAnalysisTemplate } from '@ui/gen/api/v2/models'; import { - deleteClusterAnalysisTemplate, - listClusterAnalysisTemplates -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { ClusterAnalysisTemplate } from '@ui/gen/api/stubs/rollouts/v1alpha1/generated_pb'; -import { timestampDate } from '@ui/utils/connectrpc-utils'; + useDeleteClusterAnalysisTemplate, + useListClusterAnalysisTemplates +} from '@ui/gen/api/v2/verifications/verifications'; import { CreateClusterAnalysisTemplateModal } from './create-cluster-analysis-template-modal'; import { EditClusterAnalysisTemplateModal } from './edit-cluster-analysis-template-modal'; @@ -20,18 +18,17 @@ import { EditClusterAnalysisTemplateModal } from './edit-cluster-analysis-templa export const ClusterAnalysisTemplatesList = () => { const confirm = useConfirmModal(); - const { data, isLoading, refetch } = useQuery(listClusterAnalysisTemplates); + const { data, isLoading, refetch } = useListClusterAnalysisTemplates(); const { show: showEdit } = useModal(); const { show: showCreate } = useModal((p) => ); - const { mutate: deleteTemplate, isPending: isDeleting } = useMutation( - deleteClusterAnalysisTemplate, - { + const { mutate: deleteTemplate, isPending: isDeleting } = useDeleteClusterAnalysisTemplate({ + mutation: { onSuccess: () => refetch() } - ); + }); return ( { } > - - dataSource={data?.clusterAnalysisTemplates} + + dataSource={data?.data?.items} pagination={{ hideOnSinglePage: true }} rowKey={(i) => i.metadata?.name || ''} loading={isLoading} expandable={descriptionExpandable()} className='w-full' > - + title='Creation Date' width={200} render={(_, template) => { - const date = timestampDate(template.metadata?.creationTimestamp); - return date ? format(date, 'MMM do yyyy HH:mm:ss') : ''; + const ts = template.metadata?.creationTimestamp; + if (!ts) return ''; + const date = new Date(ts); + return isNaN(date.getTime()) ? '' : format(date, 'MMM do yyyy HH:mm:ss'); }} /> - title='Name' dataIndex={['metadata', 'name']} /> - + + title='Name' + dataIndex={['metadata', 'name']} + /> + width={260} render={(_, template) => (
@@ -100,7 +102,9 @@ export const ClusterAnalysisTemplatesList = () => {

), onOk: () => { - deleteTemplate({ name: template?.metadata?.name || '' }); + deleteTemplate({ + clusterAnalysisTemplate: template?.metadata?.name || '' + }); }, hide: () => {} }); diff --git a/ui/src/features/settings/analysis-templates/create-cluster-analysis-template-modal.tsx b/ui/src/features/settings/analysis-templates/create-cluster-analysis-template-modal.tsx index 0b45023a05..806098fe58 100644 --- a/ui/src/features/settings/analysis-templates/create-cluster-analysis-template-modal.tsx +++ b/ui/src/features/settings/analysis-templates/create-cluster-analysis-template-modal.tsx @@ -1,24 +1,26 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { useQueryClient } from '@tanstack/react-query'; import { Modal } from 'antd'; import { useForm } from 'react-hook-form'; -import { transportWithAuth } from '@ui/config/transport'; import YamlEditor from '@ui/features/common/code-editor/yaml-editor-lazy'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { ModalProps } from '@ui/features/common/modal/use-modal'; -import { - createResource, - listClusterAnalysisTemplates -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; - -import { getClusterAnalysisTemplateYAMLExample } from '../../utils/cluster-analysis-template-example'; +import { getClusterAnalysisTemplateYAMLExample } from '@ui/features/utils/cluster-analysis-template-example'; +import { useCreateResource } from '@ui/gen/api/v2/resources/resources'; +import { getListClusterAnalysisTemplatesQueryKey } from '@ui/gen/api/v2/verifications/verifications'; export const CreateClusterAnalysisTemplateModal = ({ visible, hide }: ModalProps) => { const queryClient = useQueryClient(); - const { mutateAsync, isPending } = useMutation(createResource, { - onSuccess: () => hide() + const { mutate, isPending } = useCreateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListClusterAnalysisTemplatesQueryKey() + }); + hide(); + } + } }); const { control, handleSubmit } = useForm({ @@ -27,24 +29,7 @@ export const CreateClusterAnalysisTemplateModal = ({ visible, hide }: ModalProps } }); - const onSubmit = handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - await mutateAsync( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listClusterAnalysisTemplates, - cardinality: 'finite', - transport: transportWithAuth - }) - }) - } - ); - }); + const onSubmit = handleSubmit((data) => mutate({ data: data.value })); return ( { const queryClient = useQueryClient(); - const { mutateAsync, isPending } = useMutation(updateResource, { - onSuccess: () => hide() + const { mutate, isPending } = useUpdateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListClusterAnalysisTemplatesQueryKey() + }); + hide(); + } + } }); - const { data: templateResponse, isLoading } = useQuery(getClusterAnalysisTemplate, { - name: templateName, - format: RawFormat.YAML - }); + const { data: templateResponse, isLoading } = useGetClusterAnalysisTemplate(templateName); + + const templateYAML = templateResponse?.data ? stringify(templateResponse.data) : ''; const { control, handleSubmit } = useForm({ values: { - value: decodeRawData(templateResponse) + value: templateYAML } }); - const onSubmit = handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - - await mutateAsync( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listClusterAnalysisTemplates, - cardinality: 'finite', - transport: transportWithAuth - }) - }) - } - ); - }); + const onSubmit = handleSubmit((data) => mutate({ data: data.value })); return ( { const { name } = useParams(); - const getClusterConfigQuery = useQuery( - getClusterConfig, - { format: RawFormat.YAML }, - { transport: clusterConfigTransport } - ); + const getClusterConfigQuery = useGetClusterConfig({ + query: { meta: { silent404: true } } + }); - const clusterConfigYAML = decodeRawData(getClusterConfigQuery.data); + const clusterConfigObject = getClusterConfigQuery.data?.data; + const clusterConfigYAML = useMemo(() => { + if (!clusterConfigObject) { + return ''; + } + try { + return stringify(clusterConfigObject); + } catch (e) { + notification.error({ + message: (e as Error)?.message || 'Failed to stringify ClusterConfig', + placement: 'bottomRight' + }); + return ''; + } + }, [clusterConfigObject]); const clusterConfig = useMemo(() => { + if (!clusterConfigYAML) { + return undefined; + } try { - return parse(clusterConfigYAML) as ClusterConfigT; + return parse(clusterConfigYAML); } catch (e) { notification.error({ message: (e as Error)?.message || 'Failed to parse ClusterConfig YAML', @@ -67,12 +75,14 @@ export const ClusterConfig = () => { resolver: zodResolver(formSchema) }); - const createOrUpdateMutation = useMutation(createOrUpdateResource, { - onSuccess: () => { - message.success({ - content: `ClusterConfig has been ${creation ? 'created' : 'updated'}` - }); - getClusterConfigQuery.refetch(); + const updateResourceMutation = useUpdateResource({ + mutation: { + onSuccess: () => { + message.success({ + content: `ClusterConfig has been ${creation ? 'created' : 'updated'}` + }); + getClusterConfigQuery.refetch(); + } } }); @@ -80,13 +90,9 @@ export const ClusterConfig = () => { )); - const onSubmitConfig = clusterConfigForm.handleSubmit(async (data) => { - const textEncoder = new TextEncoder(); - - await createOrUpdateMutation.mutateAsync({ - manifest: textEncoder.encode(data.value) - }); - }); + const onSubmitConfig = clusterConfigForm.handleSubmit((data) => + updateResourceMutation.mutate({ data: data.value }) + ); return ( @@ -115,7 +121,7 @@ export const ClusterConfig = () => { className='ml-auto' type='primary' onClick={onSubmitConfig} - loading={createOrUpdateMutation.isPending} + loading={updateResourceMutation.isPending} > {creation ? 'Create' : 'Update'} diff --git a/ui/src/features/settings/cluster-config/refresh.tsx b/ui/src/features/settings/cluster-config/refresh.tsx index 6da0056efe..701dde2fae 100644 --- a/ui/src/features/settings/cluster-config/refresh.tsx +++ b/ui/src/features/settings/cluster-config/refresh.tsx @@ -1,27 +1,23 @@ -import { useMutation } from '@connectrpc/connect-query'; import { faUndo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Tooltip } from 'antd'; import { queryCache } from '@ui/features/utils/cache'; -import { refreshResource } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; +import { useRefreshClusterConfig } from '@ui/gen/api/v2/system/system'; export const Refresh = () => { - const refreshResourceTypeClusterConfig = 'ClusterConfig'; - const refreshResourceMutation = useMutation(refreshResource, { - onSuccess: () => queryCache.clusterConfig.refetch() + const refreshMutation = useRefreshClusterConfig({ + mutation: { + onSuccess: () => queryCache.clusterConfig.refetch() + } }); return ( diff --git a/ui/src/features/settings/cluster-config/transport.ts b/ui/src/features/settings/cluster-config/transport.ts deleted file mode 100644 index c352bea622..0000000000 --- a/ui/src/features/settings/cluster-config/transport.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Code } from '@connectrpc/connect'; - -import { defaultErrorHandler, newErrorHandler, newTransportWithAuth } from '@ui/config/transport'; - -export const clusterConfigTransport = newTransportWithAuth( - newErrorHandler((err) => { - if (err.code === Code.NotFound) { - // ignore 404 because ClusterConfig may not be created - // and we need to ignore the error - return; - } - - defaultErrorHandler(err); - }) -); diff --git a/ui/src/features/settings/cluster-config/webhook/use-create-webhook-mutation.ts b/ui/src/features/settings/cluster-config/webhook/use-create-webhook-mutation.ts index 3cb5d88881..72be8cda68 100644 --- a/ui/src/features/settings/cluster-config/webhook/use-create-webhook-mutation.ts +++ b/ui/src/features/settings/cluster-config/webhook/use-create-webhook-mutation.ts @@ -1,16 +1,22 @@ -import { useMutation } from '@connectrpc/connect-query'; import { useMutation as useReactQueryMutation } from '@tanstack/react-query'; import { notification } from 'antd'; import { parse, stringify } from 'yaml'; import { queryCache } from '@ui/features/utils/cache'; import { - createGenericCredentials, - createOrUpdateResource, - deleteGenericCredentials -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { ClusterConfig } from '@ui/gen/api/v1alpha1/generated_pb'; -import { PartialRecursive } from '@ui/utils/connectrpc-utils'; + useCreateSystemGenericCredentials, + useDeleteSystemGenericCredentials +} from '@ui/gen/api/v2/credentials/credentials'; +import { useCreateResource, useUpdateResource } from '@ui/gen/api/v2/resources/resources'; + +type ClusterConfigPartial = { + apiVersion?: string; + kind?: string; + metadata?: { name?: string }; + spec?: { + webhookReceivers?: Array>; + }; +}; type createWebhookPayload = { clusterConfigYAML: string; @@ -23,24 +29,25 @@ type createWebhookPayload = { }; export const useCreateWebhookMutation = (opts?: { onSuccess?: () => void }) => { - const createOrUpdateMutation = useMutation(createOrUpdateResource); - const createSystemSecretMutation = useMutation(createGenericCredentials); - const deleteSystemSecretMutation = useMutation(deleteGenericCredentials); + const createResourceMutation = useCreateResource(); + const updateResourceMutation = useUpdateResource(); + const createSystemSecretMutation = useCreateSystemGenericCredentials(); + const deleteSystemSecretMutation = useDeleteSystemGenericCredentials(); return useReactQueryMutation({ mutationFn: async (payload: createWebhookPayload) => { await createSystemSecretMutation.mutateAsync({ - systemLevel: true, - name: payload.secret.name, - data: payload.secret.data + data: { + name: payload.secret.name, + data: payload.secret.data + } }); try { - let clusterConfig = parse(payload.clusterConfigYAML) as PartialRecursive; + let clusterConfig: ClusterConfigPartial = parse(payload.clusterConfigYAML); if (payload.clusterConfigYAML === '') { clusterConfig = { - // @ts-expect-error apiVersion required when creating resource apiVersion: 'kargo.akuity.io/v1alpha1', kind: 'ClusterConfig', metadata: { @@ -71,15 +78,12 @@ export const useCreateWebhookMutation = (opts?: { onSuccess?: () => void }) => { } }); - const textEncoder = new TextEncoder(); - - await createOrUpdateMutation.mutateAsync({ - manifest: textEncoder.encode(stringify(clusterConfig)) - }); + const resourceMutation = + payload.clusterConfigYAML === '' ? createResourceMutation : updateResourceMutation; + await resourceMutation.mutateAsync({ data: stringify(clusterConfig) }); } catch (e) { await deleteSystemSecretMutation.mutateAsync({ - systemLevel: true, - name: payload.secret.name + genericCredentials: payload.secret.name }); throw e; diff --git a/ui/src/features/settings/cluster-promotion-tasks/cluster-promotion-tasks.tsx b/ui/src/features/settings/cluster-promotion-tasks/cluster-promotion-tasks.tsx index 49a4d31d26..ac1af179b3 100644 --- a/ui/src/features/settings/cluster-promotion-tasks/cluster-promotion-tasks.tsx +++ b/ui/src/features/settings/cluster-promotion-tasks/cluster-promotion-tasks.tsx @@ -1,18 +1,14 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPencil, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Card, Flex, Table } from 'antd'; import { format } from 'date-fns'; +import { stringify } from 'yaml'; import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-modal'; import { useModal } from '@ui/features/common/modal/use-modal'; -import { clusterPromotionTaskManifestsGen } from '@ui/features/utils/manifest-generator'; -import { - deleteResource, - listClusterPromotionTasks -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { ClusterPromotionTask } from '@ui/gen/api/v1alpha1/generated_pb'; -import { timestampDate } from '@ui/utils/connectrpc-utils'; +import { useListClusterPromotionTasks } from '@ui/gen/api/v2/core/core'; +import { ClusterPromotionTask } from '@ui/gen/api/v2/models'; +import { useDeleteResource } from '@ui/gen/api/v2/resources/resources'; import { CreateClusterPromotionTaskModal } from './create-cluster-promotion-task'; import { EditClusterPromotionTaskModal } from './edit-cluster-promotion-task-modal'; @@ -20,9 +16,13 @@ import { EditClusterPromotionTaskModal } from './edit-cluster-promotion-task-mod export const ClusterPromotionTasks = () => { const confirm = useConfirmModal(); - const listClusterPromotionTasksQuery = useQuery(listClusterPromotionTasks); + const listClusterPromotionTasksQuery = useListClusterPromotionTasks(); - const deleteClusterPromotionTaskMutation = useMutation(deleteResource); + const deleteClusterPromotionTaskMutation = useDeleteResource({ + mutation: { + onSuccess: () => listClusterPromotionTasksQuery.refetch() + } + }); const clusterPromotionTasksModal = useModal(); @@ -44,13 +44,9 @@ export const ClusterPromotionTasks = () => {

), onOk: () => { - const manifest = new TextEncoder().encode( - clusterPromotionTaskManifestsGen.v1alpha1(clusterPromotionTask) - ); - deleteClusterPromotionTaskMutation.mutate( - { manifest }, - { onSuccess: () => listClusterPromotionTasksQuery.refetch() } - ); + deleteClusterPromotionTaskMutation.mutate({ + data: stringify(clusterPromotionTask) + }); }, hide: () => {} }); @@ -75,7 +71,7 @@ export const ClusterPromotionTasks = () => { } > - dataSource={listClusterPromotionTasksQuery.data?.clusterPromotionTasks} + dataSource={listClusterPromotionTasksQuery.data?.data?.items} loading={listClusterPromotionTasksQuery.isFetching} locale={{ emptyText: ( @@ -97,9 +93,10 @@ export const ClusterPromotionTasks = () => { title: 'Creation Date', width: 200, render: (_, template) => { - const date = timestampDate(template.metadata?.creationTimestamp); - - return date ? format(date, 'MMM do yyyy HH:mm:ss') : ''; + const ts = template.metadata?.creationTimestamp; + if (!ts) return ''; + const date = new Date(ts); + return isNaN(date.getTime()) ? '' : format(date, 'MMM do yyyy HH:mm:ss'); } }, { diff --git a/ui/src/features/settings/cluster-promotion-tasks/create-cluster-promotion-task.tsx b/ui/src/features/settings/cluster-promotion-tasks/create-cluster-promotion-task.tsx index 71570c4dfe..84094dce42 100644 --- a/ui/src/features/settings/cluster-promotion-tasks/create-cluster-promotion-task.tsx +++ b/ui/src/features/settings/cluster-promotion-tasks/create-cluster-promotion-task.tsx @@ -1,4 +1,3 @@ -import { createConnectQueryKey, useMutation } from '@connectrpc/connect-query'; import { useQueryClient } from '@tanstack/react-query'; import { Button, Flex, Space } from 'antd'; import Modal from 'antd/es/modal/Modal'; @@ -8,10 +7,8 @@ import { useForm } from 'react-hook-form'; import YamlEditor from '@ui/features/common/code-editor/yaml-editor-lazy'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { ModalComponentProps } from '@ui/features/common/modal/modal-context'; -import { - createResource, - listClusterPromotionTasks -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; +import { getListClusterPromotionTasksQueryKey } from '@ui/gen/api/v2/core/core'; +import { useCreateResource } from '@ui/gen/api/v2/resources/resources'; import { getClusterPromotionTaskYAMLExample } from './cluster-promotion-task-example'; @@ -20,7 +17,16 @@ type CreateClusterPromotionTaskModalProps = ModalComponentProps; export const CreateClusterPromotionTaskModal = (props: CreateClusterPromotionTaskModalProps) => { const queryClient = useQueryClient(); - const createResourceMutation = useMutation(createResource); + const createResourceMutation = useCreateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListClusterPromotionTasksQueryKey() + }); + props.hide(); + } + } + }); const clusterPromotionTaskForm = useForm({ defaultValues: { @@ -29,24 +35,7 @@ export const CreateClusterPromotionTaskModal = (props: CreateClusterPromotionTas }); const onSubmit = clusterPromotionTaskForm.handleSubmit((data) => { - const textEncoder = new TextEncoder(); - - createResourceMutation.mutate( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => { - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listClusterPromotionTasks, - cardinality: 'finite' - }) - }); - props.hide(); - } - } - ); + createResourceMutation.mutate({ data: data.value }); }); return ( diff --git a/ui/src/features/settings/cluster-promotion-tasks/edit-cluster-promotion-task-modal.tsx b/ui/src/features/settings/cluster-promotion-tasks/edit-cluster-promotion-task-modal.tsx index 11820716c4..aadf1121e0 100644 --- a/ui/src/features/settings/cluster-promotion-tasks/edit-cluster-promotion-task-modal.tsx +++ b/ui/src/features/settings/cluster-promotion-tasks/edit-cluster-promotion-task-modal.tsx @@ -1,20 +1,18 @@ -import { createConnectQueryKey, useMutation, useQuery } from '@connectrpc/connect-query'; import { useQueryClient } from '@tanstack/react-query'; import { Modal } from 'antd'; import { useForm } from 'react-hook-form'; +import { stringify } from 'yaml'; import YamlEditor from '@ui/features/common/code-editor/yaml-editor-lazy'; import { FieldContainer } from '@ui/features/common/form/field-container'; import { ModalComponentProps } from '@ui/features/common/modal/modal-context'; import { getClusterAnalysisTemplateYAMLExample } from '@ui/features/utils/cluster-analysis-template-example'; import { - getClusterPromotionTask, - listClusterPromotionTasks, - updateResource -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { RawFormat } from '@ui/gen/api/service/v1alpha1/service_pb'; -import { ClusterPromotionTask } from '@ui/gen/api/v1alpha1/generated_pb'; -import { decodeRawData } from '@ui/utils/decode-raw-data'; + getListClusterPromotionTasksQueryKey, + useGetClusterPromotionTask +} from '@ui/gen/api/v2/core/core'; +import { ClusterPromotionTask } from '@ui/gen/api/v2/models'; +import { useUpdateResource } from '@ui/gen/api/v2/resources/resources'; type EditClusterPromotionTaskModalProps = ModalComponentProps & { clusterPromotionTask: ClusterPromotionTask; @@ -23,36 +21,33 @@ type EditClusterPromotionTaskModalProps = ModalComponentProps & { export const EditClusterPromotionTaskModal = (props: EditClusterPromotionTaskModalProps) => { const queryClient = useQueryClient(); - const getClusterPromotionTaskQuery = useQuery(getClusterPromotionTask, { - name: props.clusterPromotionTask?.metadata?.name, - format: RawFormat.YAML + const getClusterPromotionTaskQuery = useGetClusterPromotionTask( + props.clusterPromotionTask?.metadata?.name || '' + ); + + const updateResourceMutation = useUpdateResource({ + mutation: { + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: getListClusterPromotionTasksQueryKey() + }); + props.hide(); + } + } }); - const updateResourceMutation = useMutation(updateResource, { onSuccess: () => props.hide() }); + const taskYAML = getClusterPromotionTaskQuery.data?.data + ? stringify(getClusterPromotionTaskQuery.data.data) + : ''; const editClusterPromotionTaskForm = useForm({ values: { - value: decodeRawData(getClusterPromotionTaskQuery.data) + value: taskYAML } }); const onSubmit = editClusterPromotionTaskForm.handleSubmit((data) => { - const textEncoder = new TextEncoder(); - - updateResourceMutation.mutate( - { - manifest: textEncoder.encode(data.value) - }, - { - onSuccess: () => - queryClient.invalidateQueries({ - queryKey: createConnectQueryKey({ - schema: listClusterPromotionTasks, - cardinality: 'infinite' - }) - }) - } - ); + updateResourceMutation.mutate({ data: data.value }); }); return ( diff --git a/ui/src/features/settings/cluster-secret/cluster-secret.tsx b/ui/src/features/settings/cluster-secret/cluster-secret.tsx index 265c53a67f..06e75e7573 100644 --- a/ui/src/features/settings/cluster-secret/cluster-secret.tsx +++ b/ui/src/features/settings/cluster-secret/cluster-secret.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQuery } from '@connectrpc/connect-query'; import { faPencil, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, Card, Flex, Table, Tag } from 'antd'; @@ -6,26 +5,29 @@ import { Button, Card, Flex, Table, Tag } from 'antd'; import { useConfirmModal } from '@ui/features/common/confirm-modal/use-confirm-modal'; import { useModal } from '@ui/features/common/modal/use-modal'; import { - deleteGenericCredentials, - getConfig, - listGenericCredentials -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; + useDeleteSystemGenericCredentials, + useListSystemGenericCredentials +} from '@ui/gen/api/v2/credentials/credentials'; +import { V1Secret } from '@ui/gen/api/v2/models'; +import { useGetConfig } from '@ui/gen/api/v2/system/system'; import { CreateSystemSecretModal } from './create-system-secret-modal'; export const ClusterSecret = () => { - const listSystemSecretsQuery = useQuery(listGenericCredentials, { systemLevel: true }); + const listSystemSecretsQuery = useListSystemGenericCredentials(); const confirm = useConfirmModal(); - const getConfigQuery = useQuery(getConfig); - const config = getConfigQuery.data; + const getConfigQuery = useGetConfig(); + const config = getConfigQuery.data?.data; const createSecretModal = useModal((p) => ( )); - const deleteSecretsMutation = useMutation(deleteGenericCredentials, { - onSuccess: () => listSystemSecretsQuery.refetch() + const deleteSecretsMutation = useDeleteSystemGenericCredentials({ + mutation: { + onSuccess: () => listSystemSecretsQuery.refetch() + } }); return ( @@ -45,10 +47,10 @@ export const ClusterSecret = () => { } > -
className='my-2' scroll={{ x: 'max-content' }} - dataSource={listSystemSecretsQuery.data?.credentials || []} + dataSource={listSystemSecretsQuery.data?.data?.items || []} rowKey={(record) => record?.metadata?.name || ''} loading={listSystemSecretsQuery.isLoading} pagination={{ defaultPageSize: 10, hideOnSinglePage: true }} @@ -57,13 +59,13 @@ export const ClusterSecret = () => { { title: 'Name', key: 'name', - render: (record) => record?.metadata?.name + render: (_, record) => record?.metadata?.name }, { title: 'Keys', key: 'secrets', render: (_, record) => { - const secretKeys = Object.keys(record?.stringData) || []; + const secretKeys = Object.keys(record?.stringData || {}); if (!secretKeys.length) { return It looks like this secret is empty.; @@ -111,8 +113,7 @@ export const ClusterSecret = () => { ), onOk: () => deleteSecretsMutation.mutate({ - systemLevel: true, - name: record?.metadata?.name + genericCredentials: record?.metadata?.name || '' }) }); }} diff --git a/ui/src/features/settings/cluster-secret/create-system-secret-modal.tsx b/ui/src/features/settings/cluster-secret/create-system-secret-modal.tsx index 4094104016..e7a0af8ff6 100644 --- a/ui/src/features/settings/cluster-secret/create-system-secret-modal.tsx +++ b/ui/src/features/settings/cluster-secret/create-system-secret-modal.tsx @@ -1,4 +1,3 @@ -import { useMutation } from '@connectrpc/connect-query'; import { zodResolver } from '@hookform/resolvers/zod'; import { Input, Modal } from 'antd'; import { useForm } from 'react-hook-form'; @@ -9,10 +8,10 @@ import { ModalComponentProps } from '@ui/features/common/modal/modal-context'; import { SecretEditor } from '@ui/features/common/settings/secrets/secret-editor'; import { dnsRegex } from '@ui/features/common/utils'; import { - createGenericCredentials, - updateGenericCredentials -} from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; -import { Secret } from '@ui/gen/k8s.io/api/core/v1/generated_pb'; + useCreateSystemGenericCredentials, + useUpdateSystemGenericCredentials +} from '@ui/gen/api/v2/credentials/credentials'; +import { V1Secret } from '@ui/gen/api/v2/models'; import { zodValidators } from '@ui/utils/validators'; const createFormSchema = z.object({ @@ -21,7 +20,7 @@ const createFormSchema = z.object({ }); type CreateSystemSecretModalProps = ModalComponentProps & { - init?: Secret; + init?: V1Secret; onSuccess?(): void; }; @@ -36,17 +35,21 @@ export const CreateSystemSecretModal = (props: CreateSystemSecretModalProps) => const editing = !!props.init; - const createSystemSecretsMutation = useMutation(createGenericCredentials, { - onSuccess: () => { - props.hide(); - props.onSuccess?.(); + const createSystemSecretsMutation = useCreateSystemGenericCredentials({ + mutation: { + onSuccess: () => { + props.hide(); + props.onSuccess?.(); + } } }); - const updateSystemSecretMutation = useMutation(updateGenericCredentials, { - onSuccess: () => { - props.hide(); - props.onSuccess?.(); + const updateSystemSecretMutation = useUpdateSystemGenericCredentials({ + mutation: { + onSuccess: () => { + props.hide(); + props.onSuccess?.(); + } } }); @@ -61,16 +64,13 @@ export const CreateSystemSecretModal = (props: CreateSystemSecretModalProps) => if (editing) { return updateSystemSecretMutation.mutate({ - systemLevel: true, - ...values, - data + genericCredentials: values.name, + data: { data } }); } return createSystemSecretsMutation.mutate({ - systemLevel: true, - ...values, - data + data: { name: values.name, data } }); }); @@ -89,6 +89,7 @@ export const CreateSystemSecretModal = (props: CreateSystemSecretModalProps) => value={field.value as string} placeholder='secret-1' onChange={(e) => field.onChange(e.target.value)} + disabled={editing} /> )} diff --git a/ui/src/features/stage/promotion-steps.tsx b/ui/src/features/stage/promotion-steps.tsx index 676cc3fb7d..1516d7a45d 100644 --- a/ui/src/features/stage/promotion-steps.tsx +++ b/ui/src/features/stage/promotion-steps.tsx @@ -3,7 +3,10 @@ import { useMemo } from 'react'; import { Promotion } from '@ui/gen/api/v1alpha1/generated_pb'; -import { getPromotionDirectiveStepStatus } from '../common/promotion-directive-step-status/utils'; +import { + getPromotionDirectiveStepStatus, + isFailedStep +} from '../common/promotion-directive-step-status/utils'; import { getPromotionStatusPhase, isPromotionPhaseTerminal, @@ -28,23 +31,33 @@ export const PromotionSteps = (props: PromotionStepsProps) => { const shouldShowMessage = isPromotionPhaseTerminal(phase) && phase !== PromotionStatusPhase.SUCCEEDED && + phase !== PromotionStatusPhase.ERRORED && // because its already handled at individual step level !!props.promotion?.status?.message; + const steps = props.promotion?.spec?.steps ?? []; + + const errorItem = { + key: 'error', + label: , + showArrow: false, + collapsible: 'disabled' as const, + styles: { header: { paddingTop: 0 } } + }; + + const items = steps.flatMap((step, i) => { + const result = getPromotionDirectiveStepStatus(i, props.promotion.status); + const item = Step({ step, result, output: outputsByStepAlias[step.as || ''] }); + + return isFailedStep(i, props.promotion.status) + ? [{ ...item, className: `${item.className || ''} !border-none` }, errorItem] + : [item]; + }); + return ( <> - { - return Step({ - step, - result: getPromotionDirectiveStepStatus(i, props.promotion.status), - output: outputsByStepAlias?.[step?.as || ''] - }); - })} - /> + {shouldShowMessage && ( - + )} ); diff --git a/ui/src/features/utils/cache/cluster-config.ts b/ui/src/features/utils/cache/cluster-config.ts index da5a3d667e..838ffd7238 100644 --- a/ui/src/features/utils/cache/cluster-config.ts +++ b/ui/src/features/utils/cache/cluster-config.ts @@ -1,14 +1,9 @@ -import { createConnectQueryKey } from '@connectrpc/connect-query'; - import { queryClient } from '@ui/config/query-client'; -import { getClusterConfig } from '@ui/gen/api/service/v1alpha1/service-KargoService_connectquery'; +import { getGetClusterConfigQueryKey } from '@ui/gen/api/v2/system/system'; export default { refetch: () => queryClient.refetchQueries({ - queryKey: createConnectQueryKey({ - schema: getClusterConfig, - cardinality: 'finite' - }) + queryKey: getGetClusterConfigQueryKey() }) }; diff --git a/ui/src/gen/api/v1alpha1/generated_pb.ts b/ui/src/gen/api/v1alpha1/generated_pb.ts index 6ed1902ad7..3504ed057c 100644 --- a/ui/src/gen/api/v1alpha1/generated_pb.ts +++ b/ui/src/gen/api/v1alpha1/generated_pb.ts @@ -20,7 +20,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file api/v1alpha1/generated.proto. */ export const file_api_v1alpha1_generated: GenFile = /*@__PURE__*/ - fileDesc("ChxhcGkvdjFhbHBoYTEvZ2VuZXJhdGVkLnByb3RvEiRnaXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEiMgoTQW5hbHlzaXNSdW5Bcmd1bWVudBIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIrACChNBbmFseXNpc1J1bk1ldGFkYXRhElUKBmxhYmVscxgBIAMoCzJFLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1bk1ldGFkYXRhLkxhYmVsc0VudHJ5El8KC2Fubm90YXRpb25zGAIgAygLMkouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuTWV0YWRhdGEuQW5ub3RhdGlvbnNFbnRyeRotCgtMYWJlbHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJGChRBbmFseXNpc1J1blJlZmVyZW5jZRIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRINCgVwaGFzZRgDIAEoCSI3ChlBbmFseXNpc1RlbXBsYXRlUmVmZXJlbmNlEgwKBG5hbWUYASABKAkSDAoEa2luZBgCIAEoCSJPCg1BcHByb3ZlZFN0YWdlEj4KCmFwcHJvdmVkQXQYASABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSI4ChVBcmdvQ0RBcHBIZWFsdGhTdGF0dXMSDgoGc3RhdHVzGAEgASgJEg8KB21lc3NhZ2UYAiABKAki1AEKD0FyZ29DREFwcFN0YXR1cxIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRJRCgxoZWFsdGhTdGF0dXMYAyABKAsyOy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwSGVhbHRoU3RhdHVzEk0KCnN5bmNTdGF0dXMYBCABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwU3luY1N0YXR1cyJKChNBcmdvQ0RBcHBTeW5jU3RhdHVzEg4KBnN0YXR1cxgBIAEoCRIQCghyZXZpc2lvbhgCIAEoCRIRCglyZXZpc2lvbnMYAyADKAkipgEKEUFydGlmYWN0UmVmZXJlbmNlEhQKDGFydGlmYWN0VHlwZRgBIAEoCRIYChBzdWJzY3JpcHRpb25OYW1lGAIgASgJEg8KB3ZlcnNpb24YAyABKAkSUAoIbWV0YWRhdGEYBCABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIngKIEFydGlmYWN0b3J5V2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZRIXCg92aXJ0dWFsUmVwb05hbWUYAiABKAkiLwoUQXV0b1Byb21vdGlvbk9wdGlvbnMSFwoPc2VsZWN0aW9uUG9saWN5GAEgASgJIlkKGkF6dXJlV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZSJdCh5CaXRidWNrZXRXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlIjcKBUNoYXJ0Eg8KB3JlcG9VUkwYASABKAkSDAoEbmFtZRgCIAEoCRIPCgd2ZXJzaW9uGAMgASgJImEKFENoYXJ0RGlzY292ZXJ5UmVzdWx0Eg8KB3JlcG9VUkwYASABKAkSDAoEbmFtZRgCIAEoCRIYChBzZW12ZXJDb25zdHJhaW50GAMgASgJEhAKCHZlcnNpb25zGAQgAygJImQKEUNoYXJ0U3Vic2NyaXB0aW9uEhYKDmRpc2NvdmVyeUxpbWl0GAEgASgDEgwKBG5hbWUYAiABKAkSDwoHcmVwb1VSTBgDIAEoCRIYChBzZW12ZXJDb25zdHJhaW50GAQgASgJIuUBCg1DbHVzdGVyQ29uZmlnEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESRQoEc3BlYxgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DbHVzdGVyQ29uZmlnU3BlYxJJCgZzdGF0dXMYAyABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2x1c3RlckNvbmZpZ1N0YXR1cyKZAQoRQ2x1c3RlckNvbmZpZ0xpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESQgoFaXRlbXMYAiADKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2x1c3RlckNvbmZpZyJqChFDbHVzdGVyQ29uZmlnU3BlYxJVChB3ZWJob29rUmVjZWl2ZXJzGAEgAygLMjsuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldlYmhvb2tSZWNlaXZlckNvbmZpZyLqAQoTQ2x1c3RlckNvbmZpZ1N0YXR1cxJDCgpjb25kaXRpb25zGAEgAygLMi8uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkNvbmRpdGlvbhIaChJvYnNlcnZlZEdlbmVyYXRpb24YAyABKAMSGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAQgASgJElYKEHdlYmhvb2tSZWNlaXZlcnMYAiADKAsyPC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2ViaG9va1JlY2VpdmVyRGV0YWlscyKhAQoUQ2x1c3RlclByb21vdGlvblRhc2sSQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJFCgRzcGVjGAIgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRhc2tTcGVjIqcBChhDbHVzdGVyUHJvbW90aW9uVGFza0xpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESSQoFaXRlbXMYAiADKAsyOi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2x1c3RlclByb21vdGlvblRhc2siSQoMQ3VycmVudFN0YWdlEjkKBXNpbmNlGAEgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUi/gIKE0Rpc2NvdmVyZWRBcnRpZmFjdHMSQAoMZGlzY292ZXJlZEF0GAQgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSRQoDZ2l0GAEgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdpdERpc2NvdmVyeVJlc3VsdBJKCgZpbWFnZXMYAiADKAsyOi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSW1hZ2VEaXNjb3ZlcnlSZXN1bHQSSgoGY2hhcnRzGAMgAygLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkNoYXJ0RGlzY292ZXJ5UmVzdWx0EkYKB3Jlc3VsdHMYBSADKAsyNS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRGlzY292ZXJ5UmVzdWx0IrABChBEaXNjb3ZlcmVkQ29tbWl0EgoKAmlkGAEgASgJEg4KBmJyYW5jaBgCIAEoCRILCgN0YWcYAyABKAkSDwoHc3ViamVjdBgEIAEoCRIOCgZhdXRob3IYBSABKAkSEQoJY29tbWl0dGVyGAYgASgJEj8KC2NyZWF0b3JEYXRlGAcgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUikAIKGERpc2NvdmVyZWRJbWFnZVJlZmVyZW5jZRILCgN0YWcYASABKAkSDgoGZGlnZXN0GAIgASgJEmQKC2Fubm90YXRpb25zGAUgAygLMk8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkRpc2NvdmVyZWRJbWFnZVJlZmVyZW5jZS5Bbm5vdGF0aW9uc0VudHJ5Ej0KCWNyZWF0ZWRBdBgEIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJ0Cg9EaXNjb3ZlcnlSZXN1bHQSDAoEbmFtZRgDIAEoCRJTChJhcnRpZmFjdFJlZmVyZW5jZXMYAiADKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJ0aWZhY3RSZWZlcmVuY2UiXQoeRG9ja2VySHViV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZSIxChJFeHByZXNzaW9uVmFyaWFibGUSDAoEbmFtZRgBIAEoCRINCgV2YWx1ZRgCIAEoCSLuAwoHRnJlaWdodBJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEg0KBWFsaWFzGAcgASgJEkMKBm9yaWdpbhgJIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0T3JpZ2luEkAKB2NvbW1pdHMYAyADKAsyLy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0Q29tbWl0EjsKBmltYWdlcxgEIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZRI7CgZjaGFydHMYBSADKAsyKy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2hhcnQSSgoJYXJ0aWZhY3RzGAogAygLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFydGlmYWN0UmVmZXJlbmNlEkMKBnN0YXR1cxgGIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U3RhdHVzIq0CChFGcmVpZ2h0Q29sbGVjdGlvbhIKCgJpZBgDIAEoCRJRCgVpdGVtcxgBIAMoCzJCLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0Q29sbGVjdGlvbi5JdGVtc0VudHJ5ElMKE3ZlcmlmaWNhdGlvbkhpc3RvcnkYAiADKAsyNi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuVmVyaWZpY2F0aW9uSW5mbxpkCgpJdGVtc0VudHJ5EgsKA2tleRgBIAEoCRJFCgV2YWx1ZRgCIAEoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0UmVmZXJlbmNlOgI4ASItChdGcmVpZ2h0Q3JlYXRpb25Dcml0ZXJpYRISCgpleHByZXNzaW9uGAEgASgJIo0BCgtGcmVpZ2h0TGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI8CgVpdGVtcxgCIAMoCzItLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0IisKDUZyZWlnaHRPcmlnaW4SDAoEa2luZBgBIAEoCRIMCgRuYW1lGAIgASgJIu0CChBGcmVpZ2h0UmVmZXJlbmNlEgwKBG5hbWUYASABKAkSQwoGb3JpZ2luGAggASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SQAoHY29tbWl0cxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRDb21taXQSOwoGaW1hZ2VzGAMgAygLMisuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlEjsKBmNoYXJ0cxgEIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydBJKCglhcnRpZmFjdHMYCSADKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJ0aWZhY3RSZWZlcmVuY2UinAEKDkZyZWlnaHRSZXF1ZXN0EkMKBm9yaWdpbhgBIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0T3JpZ2luEkUKB3NvdXJjZXMYAiABKAsyNC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodFNvdXJjZXMi8gEKDkZyZWlnaHRTb3VyY2VzEg4KBmRpcmVjdBgBIAEoCBIOCgZzdGFnZXMYAiADKAkSSAoQcmVxdWlyZWRTb2FrVGltZRgDIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5EdXJhdGlvbhIcChRhdmFpbGFiaWxpdHlTdHJhdGVneRgEIAEoCRJYChRhdXRvUHJvbW90aW9uT3B0aW9ucxgFIAEoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BdXRvUHJvbW90aW9uT3B0aW9ucyKdBgoNRnJlaWdodFN0YXR1cxJZCgtjdXJyZW50bHlJbhgDIAMoCzJELmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U3RhdHVzLkN1cnJlbnRseUluRW50cnkSVwoKdmVyaWZpZWRJbhgBIAMoCzJDLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U3RhdHVzLlZlcmlmaWVkSW5FbnRyeRJZCgthcHByb3ZlZEZvchgCIAMoCzJELmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U3RhdHVzLkFwcHJvdmVkRm9yRW50cnkSUwoIbWV0YWRhdGEYBCADKAsyQS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodFN0YXR1cy5NZXRhZGF0YUVudHJ5GmYKEEN1cnJlbnRseUluRW50cnkSCwoDa2V5GAEgASgJEkEKBXZhbHVlGAIgASgLMjIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkN1cnJlbnRTdGFnZToCOAEaZgoPVmVyaWZpZWRJbkVudHJ5EgsKA2tleRgBIAEoCRJCCgV2YWx1ZRgCIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5WZXJpZmllZFN0YWdlOgI4ARpnChBBcHByb3ZlZEZvckVudHJ5EgsKA2tleRgBIAEoCRJCCgV2YWx1ZRgCIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BcHByb3ZlZFN0YWdlOgI4ARpvCg1NZXRhZGF0YUVudHJ5EgsKA2tleRgBIAEoCRJNCgV2YWx1ZRgCIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT046AjgBIq8CChRHZW5lcmljV2ViaG9va0FjdGlvbhIOCgZhY3Rpb24YASABKAkSFgoOd2hlbkV4cHJlc3Npb24YAiABKAkSXgoKcGFyYW1ldGVycxgDIAMoCzJKLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HZW5lcmljV2ViaG9va0FjdGlvbi5QYXJhbWV0ZXJzRW50cnkSXAoHdGFyZ2V0cxgEIAMoCzJLLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HZW5lcmljV2ViaG9va1RhcmdldFNlbGVjdGlvbkNyaXRlcmlhGjEKD1BhcmFtZXRlcnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIqgBChxHZW5lcmljV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZRJLCgdhY3Rpb25zGAIgAygLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdlbmVyaWNXZWJob29rQWN0aW9uItsBCiVHZW5lcmljV2ViaG9va1RhcmdldFNlbGVjdGlvbkNyaXRlcmlhEgwKBGtpbmQYASABKAkSDAoEbmFtZRgCIAEoCRJKCg1sYWJlbFNlbGVjdG9yGAMgASgLMjMuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxhYmVsU2VsZWN0b3ISSgoNaW5kZXhTZWxlY3RvchgEIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbmRleFNlbGVjdG9yInkKCUdpdENvbW1pdBIPCgdyZXBvVVJMGAEgASgJEgoKAmlkGAIgASgJEg4KBmJyYW5jaBgDIAEoCRILCgN0YWcYBCABKAkSDwoHbWVzc2FnZRgGIAEoCRIOCgZhdXRob3IYByABKAkSEQoJY29tbWl0dGVyGAggASgJIm4KEkdpdERpc2NvdmVyeVJlc3VsdBIPCgdyZXBvVVJMGAEgASgJEkcKB2NvbW1pdHMYAiADKAsyNi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRGlzY292ZXJlZENvbW1pdCJaChtHaXRIdWJXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlIloKG0dpdExhYldlYmhvb2tSZWNlaXZlckNvbmZpZxI7CglzZWNyZXRSZWYYASABKAsyKC5rOHMuaW8uYXBpLmNvcmUudjEuTG9jYWxPYmplY3RSZWZlcmVuY2Ui3QIKD0dpdFN1YnNjcmlwdGlvbhIRCglhbGxvd1RhZ3MYASABKAkSGAoQYWxsb3dUYWdzUmVnZXhlcxgCIAMoCRIOCgZicmFuY2gYAyABKAkSHwoXY29tbWl0U2VsZWN0aW9uU3RyYXRlZ3kYBCABKAkSFgoOZGlzY292ZXJ5TGltaXQYBSABKAMSFAoMZXhjbHVkZVBhdGhzGAYgAygJEhgKEGV4cHJlc3Npb25GaWx0ZXIYByABKAkSEgoKaWdub3JlVGFncxgIIAMoCRIZChFpZ25vcmVUYWdzUmVnZXhlcxgJIAMoCRIUCgxpbmNsdWRlUGF0aHMYCiADKAkSHQoVaW5zZWN1cmVTa2lwVExTVmVyaWZ5GAsgASgIEg8KB3JlcG9VUkwYDCABKAkSGAoQc2VtdmVyQ29uc3RyYWludBgNIAEoCRIVCg1zdHJpY3RTZW12ZXJzGA4gASgIIlkKGkdpdGVhV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZSJaChtIYXJib3JXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlIsgBCgZIZWFsdGgSDgoGc3RhdHVzGAEgASgJEg4KBmlzc3VlcxgCIAMoCRJOCgZjb25maWcYBCABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OEk4KBm91dHB1dBgFIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT04ibwoPSGVhbHRoQ2hlY2tTdGVwEgwKBHVzZXMYASABKAkSTgoGY29uZmlnGAIgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPTiIeCgtIZWFsdGhTdGF0cxIPCgdoZWFsdGh5GAEgASgDIrwBCgVJbWFnZRIPCgdyZXBvVVJMGAEgASgJEgsKA3RhZxgDIAEoCRIOCgZkaWdlc3QYBCABKAkSUQoLYW5ub3RhdGlvbnMYBSADKAsyPC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSW1hZ2UuQW5ub3RhdGlvbnNFbnRyeRoyChBBbm5vdGF0aW9uc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEijQEKFEltYWdlRGlzY292ZXJ5UmVzdWx0Eg8KB3JlcG9VUkwYASABKAkSEAoIcGxhdGZvcm0YAiABKAkSUgoKcmVmZXJlbmNlcxgDIAMoCzI+LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkSW1hZ2VSZWZlcmVuY2UiqAIKEUltYWdlU3Vic2NyaXB0aW9uEhEKCWFsbG93VGFncxgBIAEoCRIYChBhbGxvd1RhZ3NSZWdleGVzGAIgAygJEhIKCmNhY2hlQnlUYWcYAyABKAgSEgoKY29uc3RyYWludBgEIAEoCRIWCg5kaXNjb3ZlcnlMaW1pdBgFIAEoAxISCgppZ25vcmVUYWdzGAYgAygJEhkKEWlnbm9yZVRhZ3NSZWdleGVzGAcgAygJEh4KFmltYWdlU2VsZWN0aW9uU3RyYXRlZ3kYCCABKAkSHQoVaW5zZWN1cmVTa2lwVExTVmVyaWZ5GAkgASgIEhAKCHBsYXRmb3JtGAogASgJEg8KB3JlcG9VUkwYCyABKAkSFQoNc3RyaWN0U2VtdmVycxgMIAEoCCJlCg1JbmRleFNlbGVjdG9yElQKDG1hdGNoSW5kaWNlcxgBIAMoCzI+LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbmRleFNlbGVjdG9yUmVxdWlyZW1lbnQiSAoYSW5kZXhTZWxlY3RvclJlcXVpcmVtZW50EgsKA2tleRgBIAEoCRIQCghvcGVyYXRvchgCIAEoCRINCgV2YWx1ZRgDIAEoCSKSAQoHUHJvamVjdBJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkMKBnN0YXR1cxgDIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9qZWN0U3RhdHVzIuUBCg1Qcm9qZWN0Q29uZmlnEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESRQoEc3BlYxgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9qZWN0Q29uZmlnU3BlYxJJCgZzdGF0dXMYAyABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdENvbmZpZ1N0YXR1cyKZAQoRUHJvamVjdENvbmZpZ0xpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESQgoFaXRlbXMYAiADKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdENvbmZpZyK8AQoRUHJvamVjdENvbmZpZ1NwZWMSUAoRcHJvbW90aW9uUG9saWNpZXMYASADKAsyNS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uUG9saWN5ElUKEHdlYmhvb2tSZWNlaXZlcnMYAiADKAsyOy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2ViaG9va1JlY2VpdmVyQ29uZmlnIuoBChNQcm9qZWN0Q29uZmlnU3RhdHVzEkMKCmNvbmRpdGlvbnMYASADKAsyLy5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuQ29uZGl0aW9uEhoKEm9ic2VydmVkR2VuZXJhdGlvbhgDIAEoAxIaChJsYXN0SGFuZGxlZFJlZnJlc2gYBCABKAkSVgoQd2ViaG9va1JlY2VpdmVycxgCIAMoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XZWJob29rUmVjZWl2ZXJEZXRhaWxzIo0BCgtQcm9qZWN0TGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI8CgVpdGVtcxgCIAMoCzItLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9qZWN0IpoBCgxQcm9qZWN0U3RhdHMSSAoKd2FyZWhvdXNlcxgBIAEoCzI0LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XYXJlaG91c2VTdGF0cxJACgZzdGFnZXMYAiABKAsyMC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3RhZ2VTdGF0cyKXAQoNUHJvamVjdFN0YXR1cxJDCgpjb25kaXRpb25zGAMgAygLMi8uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkNvbmRpdGlvbhJBCgVzdGF0cxgEIAEoCzIyLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9qZWN0U3RhdHMi2QEKCVByb21vdGlvbhJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkEKBHNwZWMYAiABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uU3BlYxJFCgZzdGF0dXMYAyABKAsyNS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uU3RhdHVzIpEBCg1Qcm9tb3Rpb25MaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEj4KBWl0ZW1zGAIgAygLMi8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvbiKUAQoPUHJvbW90aW9uUG9saWN5Eg0KBXN0YWdlGAEgASgJElQKDXN0YWdlU2VsZWN0b3IYAyABKAsyPS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uUG9saWN5U2VsZWN0b3ISHAoUYXV0b1Byb21vdGlvbkVuYWJsZWQYAiABKAgicwoXUHJvbW90aW9uUG9saWN5U2VsZWN0b3ISDAoEbmFtZRgBIAEoCRJKCg1sYWJlbFNlbGVjdG9yGAIgASgLMjMuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxhYmVsU2VsZWN0b3Ii8gEKElByb21vdGlvblJlZmVyZW5jZRIMCgRuYW1lGAEgASgJEkcKB2ZyZWlnaHQYAiABKAsyNi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodFJlZmVyZW5jZRJFCgZzdGF0dXMYAyABKAsyNS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uU3RhdHVzEj4KCmZpbmlzaGVkQXQYBCABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSK7AQoNUHJvbW90aW9uU3BlYxINCgVzdGFnZRgBIAEoCRIPCgdmcmVpZ2h0GAIgASgJEkYKBHZhcnMYBCADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEkIKBXN0ZXBzGAMgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXAi9gQKD1Byb21vdGlvblN0YXR1cxIaChJsYXN0SGFuZGxlZFJlZnJlc2gYBCABKAkSDQoFcGhhc2UYASABKAkSDwoHbWVzc2FnZRgCIAEoCRJHCgdmcmVpZ2h0GAUgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2USUgoRZnJlaWdodENvbGxlY3Rpb24YByABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodENvbGxlY3Rpb24SSwoMaGVhbHRoQ2hlY2tzGAggAygLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkhlYWx0aENoZWNrU3RlcBI9CglzdGFydGVkQXQYDCABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZRI+CgpmaW5pc2hlZEF0GAYgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSEwoLY3VycmVudFN0ZXAYCSABKAMSWgoVc3RlcEV4ZWN1dGlvbk1ldGFkYXRhGAsgAygLMjsuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0ZXBFeGVjdXRpb25NZXRhZGF0YRJNCgVzdGF0ZRgKIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT04i+wIKDVByb21vdGlvblN0ZXASDAoEdXNlcxgBIAEoCRJKCgR0YXNrGAUgASgLMjwuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRhc2tSZWZlcmVuY2USCgoCYXMYAiABKAkSCgoCaWYYByABKAkSFwoPY29udGludWVPbkVycm9yGAggASgIEkcKBXJldHJ5GAQgASgLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXBSZXRyeRJGCgR2YXJzGAYgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJOCgZjb25maWcYAyABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIm0KElByb21vdGlvblN0ZXBSZXRyeRI/Cgd0aW1lb3V0GAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uEhYKDmVycm9yVGhyZXNob2xkGAIgASgNIpoBCg1Qcm9tb3Rpb25UYXNrEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESRQoEc3BlYxgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrU3BlYyKZAQoRUHJvbW90aW9uVGFza0xpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESQgoFaXRlbXMYAiADKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGFzayI0ChZQcm9tb3Rpb25UYXNrUmVmZXJlbmNlEgwKBG5hbWUYASABKAkSDAoEa2luZBgCIAEoCSKfAQoRUHJvbW90aW9uVGFza1NwZWMSRgoEdmFycxgBIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5FeHByZXNzaW9uVmFyaWFibGUSQgoFc3RlcHMYAiADKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uU3RlcCJeChFQcm9tb3Rpb25UZW1wbGF0ZRJJCgRzcGVjGAEgASgLMjsuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRlbXBsYXRlU3BlYyKjAQoVUHJvbW90aW9uVGVtcGxhdGVTcGVjEkYKBHZhcnMYAiADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEkIKBXN0ZXBzGAEgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXAiWAoZUXVheVdlYmhvb2tSZWNlaXZlckNvbmZpZxI7CglzZWNyZXRSZWYYASABKAsyKC5rOHMuaW8uYXBpLmNvcmUudjEuTG9jYWxPYmplY3RSZWZlcmVuY2UisAIKEFJlcG9TdWJzY3JpcHRpb24SQgoDZ2l0GAEgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdpdFN1YnNjcmlwdGlvbhJGCgVpbWFnZRgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZVN1YnNjcmlwdGlvbhJGCgVjaGFydBgDIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydFN1YnNjcmlwdGlvbhJICgxzdWJzY3JpcHRpb24YBCABKAsyMi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3Vic2NyaXB0aW9uIs0BCgVTdGFnZRJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEj0KBHNwZWMYAiABKAsyLy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3RhZ2VTcGVjEkEKBnN0YXR1cxgDIAEoCzIxLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGFnZVN0YXR1cyKJAQoJU3RhZ2VMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEjoKBWl0ZW1zGAIgAygLMisuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlItACCglTdGFnZVNwZWMSDQoFc2hhcmQYBCABKAkSRgoEdmFycxgHIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5FeHByZXNzaW9uVmFyaWFibGUSTgoQcmVxdWVzdGVkRnJlaWdodBgFIAMoCzI0LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0UmVxdWVzdBJSChFwcm9tb3Rpb25UZW1wbGF0ZRgGIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UZW1wbGF0ZRJICgx2ZXJpZmljYXRpb24YAyABKAsyMi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuVmVyaWZpY2F0aW9uIl4KClN0YWdlU3RhdHMSDQoFY291bnQYAiABKAMSQQoGaGVhbHRoGAEgASgLMjEuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkhlYWx0aFN0YXRzIrgFCgtTdGFnZVN0YXR1cxJDCgpjb25kaXRpb25zGA0gAygLMi8uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkNvbmRpdGlvbhIaChJsYXN0SGFuZGxlZFJlZnJlc2gYCyABKAkSTwoOZnJlaWdodEhpc3RvcnkYBCADKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodENvbGxlY3Rpb24SFgoOZnJlaWdodFN1bW1hcnkYDCABKAkSPAoGaGVhbHRoGAggASgLMiwuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkhlYWx0aBIaChJvYnNlcnZlZEdlbmVyYXRpb24YBiABKAMSUgoQY3VycmVudFByb21vdGlvbhgHIAEoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25SZWZlcmVuY2USTwoNbGFzdFByb21vdGlvbhgKIAEoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25SZWZlcmVuY2USHAoUYXV0b1Byb21vdGlvbkVuYWJsZWQYDiABKAgSUQoIbWV0YWRhdGEYDyADKAsyPy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3RhZ2VTdGF0dXMuTWV0YWRhdGFFbnRyeRpvCg1NZXRhZGF0YUVudHJ5EgsKA2tleRgBIAEoCRJNCgV2YWx1ZRgCIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT046AjgBIvMBChVTdGVwRXhlY3V0aW9uTWV0YWRhdGESDQoFYWxpYXMYASABKAkSPQoJc3RhcnRlZEF0GAIgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSPgoKZmluaXNoZWRBdBgDIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEhIKCmVycm9yQ291bnQYBCABKA0SDgoGc3RhdHVzGAUgASgJEg8KB21lc3NhZ2UYBiABKAkSFwoPY29udGludWVPbkVycm9yGAcgASgIIp4BCgxTdWJzY3JpcHRpb24SGAoQc3Vic2NyaXB0aW9uVHlwZRgBIAEoCRIMCgRuYW1lGAIgASgJEk4KBmNvbmZpZxgDIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT04SFgoOZGlzY292ZXJ5TGltaXQYBCABKAUiiwIKDFZlcmlmaWNhdGlvbhJaChFhbmFseXNpc1RlbXBsYXRlcxgBIAMoCzI/LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1RlbXBsYXRlUmVmZXJlbmNlElYKE2FuYWx5c2lzUnVuTWV0YWRhdGEYAiABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQW5hbHlzaXNSdW5NZXRhZGF0YRJHCgRhcmdzGAMgAygLMjkuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuQXJndW1lbnQinQIKEFZlcmlmaWNhdGlvbkluZm8SCgoCaWQYBCABKAkSDQoFYWN0b3IYByABKAkSPQoJc3RhcnRUaW1lGAUgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSDQoFcGhhc2UYASABKAkSDwoHbWVzc2FnZRgCIAEoCRJPCgthbmFseXNpc1J1bhgDIAEoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1blJlZmVyZW5jZRI+CgpmaW5pc2hUaW1lGAYgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUilAEKDVZlcmlmaWVkU3RhZ2USPgoKdmVyaWZpZWRBdBgBIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEkMKC2xvbmdlc3RTb2FrGAIgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uItkBCglXYXJlaG91c2USQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJBCgRzcGVjGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldhcmVob3VzZVNwZWMSRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldhcmVob3VzZVN0YXR1cyKRAQoNV2FyZWhvdXNlTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI+CgVpdGVtcxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XYXJlaG91c2UitgIKDVdhcmVob3VzZVNwZWMSDQoFc2hhcmQYAiABKAkSQAoIaW50ZXJ2YWwYBCABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuRHVyYXRpb24SHQoVZnJlaWdodENyZWF0aW9uUG9saWN5GAMgASgJElUKDXN1YnNjcmlwdGlvbnMYASADKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OEl4KF2ZyZWlnaHRDcmVhdGlvbkNyaXRlcmlhGAUgASgLMj0uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDcmVhdGlvbkNyaXRlcmlhImIKDldhcmVob3VzZVN0YXRzEg0KBWNvdW50GAIgASgDEkEKBmhlYWx0aBgBIAEoCzIxLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhTdGF0cyL9AQoPV2FyZWhvdXNlU3RhdHVzEkMKCmNvbmRpdGlvbnMYCSADKAsyLy5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuQ29uZGl0aW9uEhoKEmxhc3RIYW5kbGVkUmVmcmVzaBgGIAEoCRIaChJvYnNlcnZlZEdlbmVyYXRpb24YBCABKAMSFQoNbGFzdEZyZWlnaHRJRBgIIAEoCRJWChNkaXNjb3ZlcmVkQXJ0aWZhY3RzGAcgASgLMjkuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkRpc2NvdmVyZWRBcnRpZmFjdHMi8wYKFVdlYmhvb2tSZWNlaXZlckNvbmZpZxIMCgRuYW1lGAEgASgJElcKCWJpdGJ1Y2tldBgFIAEoCzJELmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5CaXRidWNrZXRXZWJob29rUmVjZWl2ZXJDb25maWcSVwoJZG9ja2VyaHViGAYgASgLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkRvY2tlckh1YldlYmhvb2tSZWNlaXZlckNvbmZpZxJRCgZnaXRodWIYAiABKAsyQS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0SHViV2ViaG9va1JlY2VpdmVyQ29uZmlnElEKBmdpdGxhYhgDIAEoCzJBLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRMYWJXZWJob29rUmVjZWl2ZXJDb25maWcSUQoGaGFyYm9yGAogASgLMkEuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkhhcmJvcldlYmhvb2tSZWNlaXZlckNvbmZpZxJNCgRxdWF5GAQgASgLMj8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlF1YXlXZWJob29rUmVjZWl2ZXJDb25maWcSWwoLYXJ0aWZhY3RvcnkYCSABKAsyRi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJ0aWZhY3RvcnlXZWJob29rUmVjZWl2ZXJDb25maWcSTwoFYXp1cmUYCCABKAsyQC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXp1cmVXZWJob29rUmVjZWl2ZXJDb25maWcSTwoFZ2l0ZWEYByABKAsyQC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0ZWFXZWJob29rUmVjZWl2ZXJDb25maWcSUwoHZ2VuZXJpYxgLIAEoCzJCLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HZW5lcmljV2ViaG9va1JlY2VpdmVyQ29uZmlnIkEKFldlYmhvb2tSZWNlaXZlckRldGFpbHMSDAoEbmFtZRgBIAEoCRIMCgRwYXRoGAMgASgJEgsKA3VybBgEIAEoCUKXAgooY29tLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMUIOR2VuZXJhdGVkUHJvdG9QAVokZ2l0aHViLmNvbS9ha3VpdHkva2FyZ28vYXBpL3YxYWxwaGExogIFR0NBS0GqAiRHaXRodWIuQ29tLkFrdWl0eS5LYXJnby5BcGkuVjFhbHBoYTHKAiRHaXRodWJcQ29tXEFrdWl0eVxLYXJnb1xBcGlcVjFhbHBoYTHiAjBHaXRodWJcQ29tXEFrdWl0eVxLYXJnb1xBcGlcVjFhbHBoYTFcR1BCTWV0YWRhdGHqAilHaXRodWI6OkNvbTo6QWt1aXR5OjpLYXJnbzo6QXBpOjpWMWFscGhhMQ", [file_k8s_io_api_core_v1_generated, file_k8s_io_apiextensions_apiserver_pkg_apis_apiextensions_v1_generated, file_k8s_io_apimachinery_pkg_apis_meta_v1_generated, file_k8s_io_apimachinery_pkg_runtime_generated, file_k8s_io_apimachinery_pkg_runtime_schema_generated]); + fileDesc("ChxhcGkvdjFhbHBoYTEvZ2VuZXJhdGVkLnByb3RvEiRnaXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEiMgoTQW5hbHlzaXNSdW5Bcmd1bWVudBIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIrACChNBbmFseXNpc1J1bk1ldGFkYXRhElUKBmxhYmVscxgBIAMoCzJFLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1bk1ldGFkYXRhLkxhYmVsc0VudHJ5El8KC2Fubm90YXRpb25zGAIgAygLMkouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuTWV0YWRhdGEuQW5ub3RhdGlvbnNFbnRyeRotCgtMYWJlbHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJGChRBbmFseXNpc1J1blJlZmVyZW5jZRIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRINCgVwaGFzZRgDIAEoCSI3ChlBbmFseXNpc1RlbXBsYXRlUmVmZXJlbmNlEgwKBG5hbWUYASABKAkSDAoEa2luZBgCIAEoCSJPCg1BcHByb3ZlZFN0YWdlEj4KCmFwcHJvdmVkQXQYASABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSI4ChVBcmdvQ0RBcHBIZWFsdGhTdGF0dXMSDgoGc3RhdHVzGAEgASgJEg8KB21lc3NhZ2UYAiABKAki1AEKD0FyZ29DREFwcFN0YXR1cxIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRJRCgxoZWFsdGhTdGF0dXMYAyABKAsyOy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwSGVhbHRoU3RhdHVzEk0KCnN5bmNTdGF0dXMYBCABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwU3luY1N0YXR1cyJKChNBcmdvQ0RBcHBTeW5jU3RhdHVzEg4KBnN0YXR1cxgBIAEoCRIQCghyZXZpc2lvbhgCIAEoCRIRCglyZXZpc2lvbnMYAyADKAkipgEKEUFydGlmYWN0UmVmZXJlbmNlEhQKDGFydGlmYWN0VHlwZRgBIAEoCRIYChBzdWJzY3JpcHRpb25OYW1lGAIgASgJEg8KB3ZlcnNpb24YAyABKAkSUAoIbWV0YWRhdGEYBCABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIngKIEFydGlmYWN0b3J5V2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZRIXCg92aXJ0dWFsUmVwb05hbWUYAiABKAkiLwoUQXV0b1Byb21vdGlvbk9wdGlvbnMSFwoPc2VsZWN0aW9uUG9saWN5GAEgASgJIlkKGkF6dXJlV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZSJdCh5CaXRidWNrZXRXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlIjcKBUNoYXJ0Eg8KB3JlcG9VUkwYASABKAkSDAoEbmFtZRgCIAEoCRIPCgd2ZXJzaW9uGAMgASgJImEKFENoYXJ0RGlzY292ZXJ5UmVzdWx0Eg8KB3JlcG9VUkwYASABKAkSDAoEbmFtZRgCIAEoCRIYChBzZW12ZXJDb25zdHJhaW50GAMgASgJEhAKCHZlcnNpb25zGAQgAygJIoMBChFDaGFydFN1YnNjcmlwdGlvbhIWCg5kaXNjb3ZlcnlMaW1pdBgBIAEoAxIdChVpbnNlY3VyZVNraXBUTFNWZXJpZnkYAiABKAgSDAoEbmFtZRgDIAEoCRIPCgdyZXBvVVJMGAQgASgJEhgKEHNlbXZlckNvbnN0cmFpbnQYBSABKAki5QEKDUNsdXN0ZXJDb25maWcSQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJFCgRzcGVjGAIgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkNsdXN0ZXJDb25maWdTcGVjEkkKBnN0YXR1cxgDIAEoCzI5LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DbHVzdGVyQ29uZmlnU3RhdHVzIpkBChFDbHVzdGVyQ29uZmlnTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRJCCgVpdGVtcxgCIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DbHVzdGVyQ29uZmlnImoKEUNsdXN0ZXJDb25maWdTcGVjElUKEHdlYmhvb2tSZWNlaXZlcnMYASADKAsyOy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2ViaG9va1JlY2VpdmVyQ29uZmlnIuoBChNDbHVzdGVyQ29uZmlnU3RhdHVzEkMKCmNvbmRpdGlvbnMYASADKAsyLy5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuQ29uZGl0aW9uEhoKEm9ic2VydmVkR2VuZXJhdGlvbhgDIAEoAxIaChJsYXN0SGFuZGxlZFJlZnJlc2gYBCABKAkSVgoQd2ViaG9va1JlY2VpdmVycxgCIAMoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XZWJob29rUmVjZWl2ZXJEZXRhaWxzIqEBChRDbHVzdGVyUHJvbW90aW9uVGFzaxJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkUKBHNwZWMYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGFza1NwZWMipwEKGENsdXN0ZXJQcm9tb3Rpb25UYXNrTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRJJCgVpdGVtcxgCIAMoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DbHVzdGVyUHJvbW90aW9uVGFzayJJCgxDdXJyZW50U3RhZ2USOQoFc2luY2UYASABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSL+AgoTRGlzY292ZXJlZEFydGlmYWN0cxJACgxkaXNjb3ZlcmVkQXQYBCABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZRJFCgNnaXQYASADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0RGlzY292ZXJ5UmVzdWx0EkoKBmltYWdlcxgCIAMoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZURpc2NvdmVyeVJlc3VsdBJKCgZjaGFydHMYAyADKAsyOi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2hhcnREaXNjb3ZlcnlSZXN1bHQSRgoHcmVzdWx0cxgFIAMoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcnlSZXN1bHQisAEKEERpc2NvdmVyZWRDb21taXQSCgoCaWQYASABKAkSDgoGYnJhbmNoGAIgASgJEgsKA3RhZxgDIAEoCRIPCgdzdWJqZWN0GAQgASgJEg4KBmF1dGhvchgFIAEoCRIRCgljb21taXR0ZXIYBiABKAkSPwoLY3JlYXRvckRhdGUYByABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSKQAgoYRGlzY292ZXJlZEltYWdlUmVmZXJlbmNlEgsKA3RhZxgBIAEoCRIOCgZkaWdlc3QYAiABKAkSZAoLYW5ub3RhdGlvbnMYBSADKAsyTy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRGlzY292ZXJlZEltYWdlUmVmZXJlbmNlLkFubm90YXRpb25zRW50cnkSPQoJY3JlYXRlZEF0GAQgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUaMgoQQW5ub3RhdGlvbnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBInQKD0Rpc2NvdmVyeVJlc3VsdBIMCgRuYW1lGAMgASgJElMKEmFydGlmYWN0UmVmZXJlbmNlcxgCIAMoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BcnRpZmFjdFJlZmVyZW5jZSJdCh5Eb2NrZXJIdWJXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlIjEKEkV4cHJlc3Npb25WYXJpYWJsZRIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIu4DCgdGcmVpZ2h0EkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESDQoFYWxpYXMYByABKAkSQwoGb3JpZ2luGAkgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SQAoHY29tbWl0cxgDIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRDb21taXQSOwoGaW1hZ2VzGAQgAygLMisuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlEjsKBmNoYXJ0cxgFIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydBJKCglhcnRpZmFjdHMYCiADKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJ0aWZhY3RSZWZlcmVuY2USQwoGc3RhdHVzGAYgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMirQIKEUZyZWlnaHRDb2xsZWN0aW9uEgoKAmlkGAMgASgJElEKBWl0ZW1zGAEgAygLMkIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uLkl0ZW1zRW50cnkSUwoTdmVyaWZpY2F0aW9uSGlzdG9yeRgCIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5WZXJpZmljYXRpb25JbmZvGmQKCkl0ZW1zRW50cnkSCwoDa2V5GAEgASgJEkUKBXZhbHVlGAIgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2U6AjgBIi0KF0ZyZWlnaHRDcmVhdGlvbkNyaXRlcmlhEhIKCmV4cHJlc3Npb24YASABKAkijQEKC0ZyZWlnaHRMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEjwKBWl0ZW1zGAIgAygLMi0uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHQiKwoNRnJlaWdodE9yaWdpbhIMCgRraW5kGAEgASgJEgwKBG5hbWUYAiABKAki7QIKEEZyZWlnaHRSZWZlcmVuY2USDAoEbmFtZRgBIAEoCRJDCgZvcmlnaW4YCCABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodE9yaWdpbhJACgdjb21taXRzGAIgAygLMi8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdpdENvbW1pdBI7CgZpbWFnZXMYAyADKAsyKy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSW1hZ2USOwoGY2hhcnRzGAQgAygLMisuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkNoYXJ0EkoKCWFydGlmYWN0cxgJIAMoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BcnRpZmFjdFJlZmVyZW5jZSKcAQoORnJlaWdodFJlcXVlc3QSQwoGb3JpZ2luGAEgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SRQoHc291cmNlcxgCIAEoCzI0LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U291cmNlcyLyAQoORnJlaWdodFNvdXJjZXMSDgoGZGlyZWN0GAEgASgIEg4KBnN0YWdlcxgCIAMoCRJIChByZXF1aXJlZFNvYWtUaW1lGAMgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uEhwKFGF2YWlsYWJpbGl0eVN0cmF0ZWd5GAQgASgJElgKFGF1dG9Qcm9tb3Rpb25PcHRpb25zGAUgASgLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkF1dG9Qcm9tb3Rpb25PcHRpb25zIp0GCg1GcmVpZ2h0U3RhdHVzElkKC2N1cnJlbnRseUluGAMgAygLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuQ3VycmVudGx5SW5FbnRyeRJXCgp2ZXJpZmllZEluGAEgAygLMkMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuVmVyaWZpZWRJbkVudHJ5ElkKC2FwcHJvdmVkRm9yGAIgAygLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuQXBwcm92ZWRGb3JFbnRyeRJTCghtZXRhZGF0YRgEIAMoCzJBLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U3RhdHVzLk1ldGFkYXRhRW50cnkaZgoQQ3VycmVudGx5SW5FbnRyeRILCgNrZXkYASABKAkSQQoFdmFsdWUYAiABKAsyMi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ3VycmVudFN0YWdlOgI4ARpmCg9WZXJpZmllZEluRW50cnkSCwoDa2V5GAEgASgJEkIKBXZhbHVlGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlZlcmlmaWVkU3RhZ2U6AjgBGmcKEEFwcHJvdmVkRm9yRW50cnkSCwoDa2V5GAEgASgJEkIKBXZhbHVlGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFwcHJvdmVkU3RhZ2U6AjgBGm8KDU1ldGFkYXRhRW50cnkSCwoDa2V5GAEgASgJEk0KBXZhbHVlGAIgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPTjoCOAEirwIKFEdlbmVyaWNXZWJob29rQWN0aW9uEg4KBmFjdGlvbhgBIAEoCRIWCg53aGVuRXhwcmVzc2lvbhgCIAEoCRJeCgpwYXJhbWV0ZXJzGAMgAygLMkouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdlbmVyaWNXZWJob29rQWN0aW9uLlBhcmFtZXRlcnNFbnRyeRJcCgd0YXJnZXRzGAQgAygLMksuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdlbmVyaWNXZWJob29rVGFyZ2V0U2VsZWN0aW9uQ3JpdGVyaWEaMQoPUGFyYW1ldGVyc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToCOAEiqAEKHEdlbmVyaWNXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlEksKB2FjdGlvbnMYAiADKAsyOi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2VuZXJpY1dlYmhvb2tBY3Rpb24i2wEKJUdlbmVyaWNXZWJob29rVGFyZ2V0U2VsZWN0aW9uQ3JpdGVyaWESDAoEa2luZBgBIAEoCRIMCgRuYW1lGAIgASgJEkoKDWxhYmVsU2VsZWN0b3IYAyABKAsyMy5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGFiZWxTZWxlY3RvchJKCg1pbmRleFNlbGVjdG9yGAQgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkluZGV4U2VsZWN0b3IieQoJR2l0Q29tbWl0Eg8KB3JlcG9VUkwYASABKAkSCgoCaWQYAiABKAkSDgoGYnJhbmNoGAMgASgJEgsKA3RhZxgEIAEoCRIPCgdtZXNzYWdlGAYgASgJEg4KBmF1dGhvchgHIAEoCRIRCgljb21taXR0ZXIYCCABKAkibgoSR2l0RGlzY292ZXJ5UmVzdWx0Eg8KB3JlcG9VUkwYASABKAkSRwoHY29tbWl0cxgCIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkQ29tbWl0IloKG0dpdEh1YldlYmhvb2tSZWNlaXZlckNvbmZpZxI7CglzZWNyZXRSZWYYASABKAsyKC5rOHMuaW8uYXBpLmNvcmUudjEuTG9jYWxPYmplY3RSZWZlcmVuY2UiWgobR2l0TGFiV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZSKYAwoPR2l0U3Vic2NyaXB0aW9uEhEKCWFsbG93VGFncxgBIAEoCRIYChBhbGxvd1RhZ3NSZWdleGVzGAIgAygJEg4KBmJyYW5jaBgDIAEoCRIfChdjb21taXRTZWxlY3Rpb25TdHJhdGVneRgEIAEoCRIWCg5kaXNjb3ZlcnlMaW1pdBgFIAEoAxIUCgxleGNsdWRlUGF0aHMYBiADKAkSGAoQZXhwcmVzc2lvbkZpbHRlchgHIAEoCRISCgppZ25vcmVUYWdzGAggAygJEhkKEWlnbm9yZVRhZ3NSZWdleGVzGAkgAygJEhQKDGluY2x1ZGVQYXRocxgKIAMoCRIdChVpbnNlY3VyZVNraXBUTFNWZXJpZnkYCyABKAgSDwoHcmVwb1VSTBgMIAEoCRIYChBzZW12ZXJDb25zdHJhaW50GA0gASgJEjkKBXNpbmNlGA4gASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSFQoNc3RyaWN0U2VtdmVycxgPIAEoCCJZChpHaXRlYVdlYmhvb2tSZWNlaXZlckNvbmZpZxI7CglzZWNyZXRSZWYYASABKAsyKC5rOHMuaW8uYXBpLmNvcmUudjEuTG9jYWxPYmplY3RSZWZlcmVuY2UiWgobSGFyYm9yV2ViaG9va1JlY2VpdmVyQ29uZmlnEjsKCXNlY3JldFJlZhgBIAEoCzIoLms4cy5pby5hcGkuY29yZS52MS5Mb2NhbE9iamVjdFJlZmVyZW5jZSLIAQoGSGVhbHRoEg4KBnN0YXR1cxgBIAEoCRIOCgZpc3N1ZXMYAiADKAkSTgoGY29uZmlnGAQgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPThJOCgZvdXRwdXQYBSABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIm8KD0hlYWx0aENoZWNrU3RlcBIMCgR1c2VzGAEgASgJEk4KBmNvbmZpZxgCIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT04iHgoLSGVhbHRoU3RhdHMSDwoHaGVhbHRoeRgBIAEoAyK8AQoFSW1hZ2USDwoHcmVwb1VSTBgBIAEoCRILCgN0YWcYAyABKAkSDgoGZGlnZXN0GAQgASgJElEKC2Fubm90YXRpb25zGAUgAygLMjwuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlLkFubm90YXRpb25zRW50cnkaMgoQQW5ub3RhdGlvbnNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBIo0BChRJbWFnZURpc2NvdmVyeVJlc3VsdBIPCgdyZXBvVVJMGAEgASgJEhAKCHBsYXRmb3JtGAIgASgJElIKCnJlZmVyZW5jZXMYAyADKAsyPi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRGlzY292ZXJlZEltYWdlUmVmZXJlbmNlIqgCChFJbWFnZVN1YnNjcmlwdGlvbhIRCglhbGxvd1RhZ3MYASABKAkSGAoQYWxsb3dUYWdzUmVnZXhlcxgCIAMoCRISCgpjYWNoZUJ5VGFnGAMgASgIEhIKCmNvbnN0cmFpbnQYBCABKAkSFgoOZGlzY292ZXJ5TGltaXQYBSABKAMSEgoKaWdub3JlVGFncxgGIAMoCRIZChFpZ25vcmVUYWdzUmVnZXhlcxgHIAMoCRIeChZpbWFnZVNlbGVjdGlvblN0cmF0ZWd5GAggASgJEh0KFWluc2VjdXJlU2tpcFRMU1ZlcmlmeRgJIAEoCBIQCghwbGF0Zm9ybRgKIAEoCRIPCgdyZXBvVVJMGAsgASgJEhUKDXN0cmljdFNlbXZlcnMYDCABKAgiZQoNSW5kZXhTZWxlY3RvchJUCgxtYXRjaEluZGljZXMYASADKAsyPi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSW5kZXhTZWxlY3RvclJlcXVpcmVtZW50IkgKGEluZGV4U2VsZWN0b3JSZXF1aXJlbWVudBILCgNrZXkYASABKAkSEAoIb3BlcmF0b3IYAiABKAkSDQoFdmFsdWUYAyABKAkikgEKB1Byb2plY3QSQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJDCgZzdGF0dXMYAyABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdFN0YXR1cyLlAQoNUHJvamVjdENvbmZpZxJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkUKBHNwZWMYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdENvbmZpZ1NwZWMSSQoGc3RhdHVzGAMgASgLMjkuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb2plY3RDb25maWdTdGF0dXMimQEKEVByb2plY3RDb25maWdMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEkIKBWl0ZW1zGAIgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb2plY3RDb25maWcivAEKEVByb2plY3RDb25maWdTcGVjElAKEXByb21vdGlvblBvbGljaWVzGAEgAygLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblBvbGljeRJVChB3ZWJob29rUmVjZWl2ZXJzGAIgAygLMjsuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldlYmhvb2tSZWNlaXZlckNvbmZpZyLqAQoTUHJvamVjdENvbmZpZ1N0YXR1cxJDCgpjb25kaXRpb25zGAEgAygLMi8uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkNvbmRpdGlvbhIaChJvYnNlcnZlZEdlbmVyYXRpb24YAyABKAMSGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAQgASgJElYKEHdlYmhvb2tSZWNlaXZlcnMYAiADKAsyPC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2ViaG9va1JlY2VpdmVyRGV0YWlscyKNAQoLUHJvamVjdExpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESPAoFaXRlbXMYAiADKAsyLS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdCKaAQoMUHJvamVjdFN0YXRzEkgKCndhcmVob3VzZXMYASABKAsyNC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2FyZWhvdXNlU3RhdHMSQAoGc3RhZ2VzGAIgASgLMjAuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3RhdHMilwEKDVByb2plY3RTdGF0dXMSQwoKY29uZGl0aW9ucxgDIAMoCzIvLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5Db25kaXRpb24SQQoFc3RhdHMYBCABKAsyMi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdFN0YXRzItkBCglQcm9tb3Rpb24SQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJBCgRzcGVjGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblNwZWMSRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0YXR1cyKRAQoNUHJvbW90aW9uTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI+CgVpdGVtcxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb24ilAEKD1Byb21vdGlvblBvbGljeRINCgVzdGFnZRgBIAEoCRJUCg1zdGFnZVNlbGVjdG9yGAMgASgLMj0uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblBvbGljeVNlbGVjdG9yEhwKFGF1dG9Qcm9tb3Rpb25FbmFibGVkGAIgASgIInMKF1Byb21vdGlvblBvbGljeVNlbGVjdG9yEgwKBG5hbWUYASABKAkSSgoNbGFiZWxTZWxlY3RvchgCIAEoCzIzLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MYWJlbFNlbGVjdG9yIvIBChJQcm9tb3Rpb25SZWZlcmVuY2USDAoEbmFtZRgBIAEoCRJHCgdmcmVpZ2h0GAIgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2USRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0YXR1cxI+CgpmaW5pc2hlZEF0GAQgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUiuwEKDVByb21vdGlvblNwZWMSDQoFc3RhZ2UYASABKAkSDwoHZnJlaWdodBgCIAEoCRJGCgR2YXJzGAQgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJCCgVzdGVwcxgDIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwIvYECg9Qcm9tb3Rpb25TdGF0dXMSGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAQgASgJEg0KBXBoYXNlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSRwoHZnJlaWdodBgFIAEoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0UmVmZXJlbmNlElIKEWZyZWlnaHRDb2xsZWN0aW9uGAcgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uEksKDGhlYWx0aENoZWNrcxgIIAMoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhDaGVja1N0ZXASPQoJc3RhcnRlZEF0GAwgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSPgoKZmluaXNoZWRBdBgGIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEhMKC2N1cnJlbnRTdGVwGAkgASgDEloKFXN0ZXBFeGVjdXRpb25NZXRhZGF0YRgLIAMoCzI7LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGVwRXhlY3V0aW9uTWV0YWRhdGESTQoFc3RhdGUYCiABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIvsCCg1Qcm9tb3Rpb25TdGVwEgwKBHVzZXMYASABKAkSSgoEdGFzaxgFIAEoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrUmVmZXJlbmNlEgoKAmFzGAIgASgJEgoKAmlmGAcgASgJEhcKD2NvbnRpbnVlT25FcnJvchgIIAEoCBJHCgVyZXRyeRgEIAEoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwUmV0cnkSRgoEdmFycxgGIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5FeHByZXNzaW9uVmFyaWFibGUSTgoGY29uZmlnGAMgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPTiJtChJQcm9tb3Rpb25TdGVwUmV0cnkSPwoHdGltZW91dBgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5EdXJhdGlvbhIWCg5lcnJvclRocmVzaG9sZBgCIAEoDSKaAQoNUHJvbW90aW9uVGFzaxJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkUKBHNwZWMYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGFza1NwZWMimQEKEVByb21vdGlvblRhc2tMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEkIKBWl0ZW1zGAIgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRhc2siNAoWUHJvbW90aW9uVGFza1JlZmVyZW5jZRIMCgRuYW1lGAEgASgJEgwKBGtpbmQYAiABKAkinwEKEVByb21vdGlvblRhc2tTcGVjEkYKBHZhcnMYASADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEkIKBXN0ZXBzGAIgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXAiXgoRUHJvbW90aW9uVGVtcGxhdGUSSQoEc3BlYxgBIAEoCzI7LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UZW1wbGF0ZVNwZWMiowEKFVByb21vdGlvblRlbXBsYXRlU3BlYxJGCgR2YXJzGAIgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJCCgVzdGVwcxgBIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwIlgKGVF1YXlXZWJob29rUmVjZWl2ZXJDb25maWcSOwoJc2VjcmV0UmVmGAEgASgLMiguazhzLmlvLmFwaS5jb3JlLnYxLkxvY2FsT2JqZWN0UmVmZXJlbmNlIrACChBSZXBvU3Vic2NyaXB0aW9uEkIKA2dpdBgBIAEoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRTdWJzY3JpcHRpb24SRgoFaW1hZ2UYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSW1hZ2VTdWJzY3JpcHRpb24SRgoFY2hhcnQYAyABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2hhcnRTdWJzY3JpcHRpb24SSAoMc3Vic2NyaXB0aW9uGAQgASgLMjIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN1YnNjcmlwdGlvbiLNAQoFU3RhZ2USQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRI9CgRzcGVjGAIgASgLMi8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3BlYxJBCgZzdGF0dXMYAyABKAsyMS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3RhZ2VTdGF0dXMiiQEKCVN0YWdlTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI6CgVpdGVtcxgCIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGFnZSLQAgoJU3RhZ2VTcGVjEg0KBXNoYXJkGAQgASgJEkYKBHZhcnMYByADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEk4KEHJlcXVlc3RlZEZyZWlnaHQYBSADKAsyNC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodFJlcXVlc3QSUgoRcHJvbW90aW9uVGVtcGxhdGUYBiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGVtcGxhdGUSSAoMdmVyaWZpY2F0aW9uGAMgASgLMjIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlZlcmlmaWNhdGlvbiJeCgpTdGFnZVN0YXRzEg0KBWNvdW50GAIgASgDEkEKBmhlYWx0aBgBIAEoCzIxLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhTdGF0cyK4BQoLU3RhZ2VTdGF0dXMSQwoKY29uZGl0aW9ucxgNIAMoCzIvLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5Db25kaXRpb24SGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAsgASgJEk8KDmZyZWlnaHRIaXN0b3J5GAQgAygLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uEhYKDmZyZWlnaHRTdW1tYXJ5GAwgASgJEjwKBmhlYWx0aBgIIAEoCzIsLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGgSGgoSb2JzZXJ2ZWRHZW5lcmF0aW9uGAYgASgDElIKEGN1cnJlbnRQcm9tb3Rpb24YByABKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uUmVmZXJlbmNlEk8KDWxhc3RQcm9tb3Rpb24YCiABKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uUmVmZXJlbmNlEhwKFGF1dG9Qcm9tb3Rpb25FbmFibGVkGA4gASgIElEKCG1ldGFkYXRhGA8gAygLMj8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3RhdHVzLk1ldGFkYXRhRW50cnkabwoNTWV0YWRhdGFFbnRyeRILCgNrZXkYASABKAkSTQoFdmFsdWUYAiABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OOgI4ASLzAQoVU3RlcEV4ZWN1dGlvbk1ldGFkYXRhEg0KBWFsaWFzGAEgASgJEj0KCXN0YXJ0ZWRBdBgCIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEj4KCmZpbmlzaGVkQXQYAyABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZRISCgplcnJvckNvdW50GAQgASgNEg4KBnN0YXR1cxgFIAEoCRIPCgdtZXNzYWdlGAYgASgJEhcKD2NvbnRpbnVlT25FcnJvchgHIAEoCCKeAQoMU3Vic2NyaXB0aW9uEhgKEHN1YnNjcmlwdGlvblR5cGUYASABKAkSDAoEbmFtZRgCIAEoCRJOCgZjb25maWcYAyABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OEhYKDmRpc2NvdmVyeUxpbWl0GAQgASgFIosCCgxWZXJpZmljYXRpb24SWgoRYW5hbHlzaXNUZW1wbGF0ZXMYASADKAsyPy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQW5hbHlzaXNUZW1wbGF0ZVJlZmVyZW5jZRJWChNhbmFseXNpc1J1bk1ldGFkYXRhGAIgASgLMjkuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuTWV0YWRhdGESRwoEYXJncxgDIAMoCzI5LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1bkFyZ3VtZW50Ip0CChBWZXJpZmljYXRpb25JbmZvEgoKAmlkGAQgASgJEg0KBWFjdG9yGAcgASgJEj0KCXN0YXJ0VGltZRgFIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEg0KBXBoYXNlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSTwoLYW5hbHlzaXNSdW4YAyABKAsyOi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQW5hbHlzaXNSdW5SZWZlcmVuY2USPgoKZmluaXNoVGltZRgGIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lIpQBCg1WZXJpZmllZFN0YWdlEj4KCnZlcmlmaWVkQXQYASABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZRJDCgtsb25nZXN0U29haxgCIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5EdXJhdGlvbiLZAQoJV2FyZWhvdXNlEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESQQoEc3BlYxgCIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XYXJlaG91c2VTcGVjEkUKBnN0YXR1cxgDIAEoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XYXJlaG91c2VTdGF0dXMikQEKDVdhcmVob3VzZUxpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESPgoFaXRlbXMYAiADKAsyLy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2FyZWhvdXNlIrYCCg1XYXJlaG91c2VTcGVjEg0KBXNoYXJkGAIgASgJEkAKCGludGVydmFsGAQgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uEh0KFWZyZWlnaHRDcmVhdGlvblBvbGljeRgDIAEoCRJVCg1zdWJzY3JpcHRpb25zGAEgAygLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPThJeChdmcmVpZ2h0Q3JlYXRpb25Dcml0ZXJpYRgFIAEoCzI9LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0Q3JlYXRpb25Dcml0ZXJpYSJiCg5XYXJlaG91c2VTdGF0cxINCgVjb3VudBgCIAEoAxJBCgZoZWFsdGgYASABKAsyMS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSGVhbHRoU3RhdHMi/QEKD1dhcmVob3VzZVN0YXR1cxJDCgpjb25kaXRpb25zGAkgAygLMi8uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkNvbmRpdGlvbhIaChJsYXN0SGFuZGxlZFJlZnJlc2gYBiABKAkSGgoSb2JzZXJ2ZWRHZW5lcmF0aW9uGAQgASgDEhUKDWxhc3RGcmVpZ2h0SUQYCCABKAkSVgoTZGlzY292ZXJlZEFydGlmYWN0cxgHIAEoCzI5LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkQXJ0aWZhY3RzIvMGChVXZWJob29rUmVjZWl2ZXJDb25maWcSDAoEbmFtZRgBIAEoCRJXCgliaXRidWNrZXQYBSABKAsyRC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQml0YnVja2V0V2ViaG9va1JlY2VpdmVyQ29uZmlnElcKCWRvY2tlcmh1YhgGIAEoCzJELmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Eb2NrZXJIdWJXZWJob29rUmVjZWl2ZXJDb25maWcSUQoGZ2l0aHViGAIgASgLMkEuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdpdEh1YldlYmhvb2tSZWNlaXZlckNvbmZpZxJRCgZnaXRsYWIYAyABKAsyQS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0TGFiV2ViaG9va1JlY2VpdmVyQ29uZmlnElEKBmhhcmJvchgKIAEoCzJBLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IYXJib3JXZWJob29rUmVjZWl2ZXJDb25maWcSTQoEcXVheRgEIAEoCzI/LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5RdWF5V2ViaG9va1JlY2VpdmVyQ29uZmlnElsKC2FydGlmYWN0b3J5GAkgASgLMkYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFydGlmYWN0b3J5V2ViaG9va1JlY2VpdmVyQ29uZmlnEk8KBWF6dXJlGAggASgLMkAuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkF6dXJlV2ViaG9va1JlY2VpdmVyQ29uZmlnEk8KBWdpdGVhGAcgASgLMkAuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdpdGVhV2ViaG9va1JlY2VpdmVyQ29uZmlnElMKB2dlbmVyaWMYCyABKAsyQi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2VuZXJpY1dlYmhvb2tSZWNlaXZlckNvbmZpZyJBChZXZWJob29rUmVjZWl2ZXJEZXRhaWxzEgwKBG5hbWUYASABKAkSDAoEcGF0aBgDIAEoCRILCgN1cmwYBCABKAlClwIKKGNvbS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTFCDkdlbmVyYXRlZFByb3RvUAFaJGdpdGh1Yi5jb20vYWt1aXR5L2thcmdvL2FwaS92MWFscGhhMaICBUdDQUtBqgIkR2l0aHViLkNvbS5Ba3VpdHkuS2FyZ28uQXBpLlYxYWxwaGExygIkR2l0aHViXENvbVxBa3VpdHlcS2FyZ29cQXBpXFYxYWxwaGEx4gIwR2l0aHViXENvbVxBa3VpdHlcS2FyZ29cQXBpXFYxYWxwaGExXEdQQk1ldGFkYXRh6gIpR2l0aHViOjpDb206OkFrdWl0eTo6S2FyZ286OkFwaTo6VjFhbHBoYTE", [file_k8s_io_api_core_v1_generated, file_k8s_io_apiextensions_apiserver_pkg_apis_apiextensions_v1_generated, file_k8s_io_apimachinery_pkg_apis_meta_v1_generated, file_k8s_io_apimachinery_pkg_runtime_generated, file_k8s_io_apimachinery_pkg_runtime_schema_generated]); /** * AnalysisRunArgument represents an argument to be added to an AnalysisRun. @@ -611,12 +611,20 @@ export type ChartSubscription = Message<"github.com.akuity.kargo.api.v1alpha1.Ch */ discoveryLimit: bigint; + /** + * InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored + * when connecting to the repository. This should be enabled only with great caution. + * + * @generated from field: optional bool insecureSkipTLSVerify = 2; + */ + insecureSkipTLSVerify: boolean; + /** * Name specifies the name of a Helm chart to subscribe to within a classic chart repository * specified by the repoURL field. This field is required when the repoURL field points to a * classic chart repository and MUST otherwise be empty. * - * @generated from field: optional string name = 2; + * @generated from field: optional string name = 3; */ name: string; @@ -629,7 +637,7 @@ export type ChartSubscription = Message<"github.com.akuity.kargo.api.v1alpha1.Ch * implicitly points to a specific chart and the name field MUST NOT be used. This field is * required. * - * @generated from field: optional string repoURL = 3; + * @generated from field: optional string repoURL = 4; */ repoURL: string; @@ -639,7 +647,7 @@ export type ChartSubscription = Message<"github.com.akuity.kargo.api.v1alpha1.Ch * chart will always be used. Care should be taken with leaving this field unspecified, as * it can lead to the unanticipated rollout of breaking changes. * - * @generated from field: optional string semverConstraint = 4; + * @generated from field: optional string semverConstraint = 5; */ semverConstraint: string; }; @@ -1810,6 +1818,8 @@ export type GitDiscoveryResult = Message<"github.com.akuity.kargo.api.v1alpha1.G /** * RepoURL is the repository URL of the GitSubscription. * + * TODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern. + * * +kubebuilder:validation:MinLength=1 * +kubebuilder:validation:Pattern=`(?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*))` * +akuity:test-kubebuilder-pattern=GitRepoURLPattern @@ -2006,7 +2016,9 @@ export type GitSubscription = Message<"github.com.akuity.kargo.api.v1alpha1.GitS insecureSkipTLSVerify: boolean; /** - * URL is the repository's URL. This is a required field. + * URL is the repository's URL. This is a required field. Deprecated: Support for SSH URLs + * (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in + * v1.13.0. Use HTTPS URLs instead. * * @generated from field: optional string repoURL = 12; */ @@ -2021,12 +2033,21 @@ export type GitSubscription = Message<"github.com.akuity.kargo.api.v1alpha1.GitS */ semverConstraint: string; + /** + * An optional date (RFC 3339) that limits commit discovery to commits at or after this + * date. When specified, discovery stops upon reaching a commit older than this date. When + * left unspecified, there is no cutoff. + * + * @generated from field: optional k8s.io.apimachinery.pkg.apis.meta.v1.Time since = 14; + */ + since?: Time; + /** * StrictSemvers specifies whether only "strict" semver tags should be considered. A * "strict" semver tag contains ALL of major, minor, and patch version components. Only has * effect when CommitSelectionStrategy is SemVer. * - * @generated from field: optional bool strictSemvers = 14; + * @generated from field: optional bool strictSemvers = 15; */ strictSemvers: boolean; }; diff --git a/ui/src/gen/api/v2/core/core.ts b/ui/src/gen/api/v2/core/core.ts index 2749208a07..b413884c4f 100644 --- a/ui/src/gen/api/v2/core/core.ts +++ b/ui/src/gen/api/v2/core/core.ts @@ -23,47 +23,33 @@ import type { import type { ApproveFreightParams, + ClusterPromotionTask, + ClusterPromotionTaskList, CreateConfigMapRequestBody, - CreateProjectConfigMap201, - CreateSharedConfigMap201, - CreateSystemConfigMap201, - GetClusterPromotionTask200, - GetFreight200, - GetProject200, - GetProjectConfig200, - GetProjectConfigMap200, - GetPromotion200, - GetPromotionTask200, - GetSharedConfigMap200, - GetStage200, - GetSystemConfigMap200, - GetWarehouse200, - ListClusterPromotionTasks200, + Freight, ListImages200, - ListProjectConfigMaps200, - ListProjects200, - ListPromotionTasks200, - ListPromotions200, ListPromotionsParams, - ListSharedConfigMaps200, - ListStages200, - ListSystemConfigMaps200, - ListWarehouses200, PatchConfigMapRequestBody, PatchFreightAliasParams, - PatchProjectConfigMap200, - PatchSharedConfigMap200, - PatchSystemConfigMap200, + Project, + ProjectConfig, + ProjectList, PromoteDownstream201, PromoteDownstreamRequest, - PromoteToStage201, PromoteToStageRequest, + Promotion, + PromotionList, + PromotionTask, + PromotionTaskList, QueryFreightsRest200, QueryFreightsRestParams, + Stage, + StageList, UpdateConfigMapRequestBody, - UpdateProjectConfigMap200, - UpdateSharedConfigMap200, - UpdateSystemConfigMap200 + V1ConfigMap, + V1ConfigMapList, + Warehouse, + WarehouseList } from '.././models'; import { customFetch } from '../../../../lib/api/custom-fetch'; @@ -75,7 +61,7 @@ type SecondParameter unknown> = Parameters[1]; * @summary List projects */ export type listProjectsResponse200 = { - data: ListProjects200; + data: ProjectList; status: 200; }; @@ -187,7 +173,7 @@ export function useListProjects> * @summary Retrieve a Project resource */ export type getProjectResponse200 = { - data: GetProject200; + data: Project; status: 200; }; @@ -399,7 +385,7 @@ namespace. * @summary Retrieve ProjectConfig */ export type getProjectConfigResponse200 = { - data: GetProjectConfig200; + data: ProjectConfig; status: 200; }; @@ -725,7 +711,7 @@ Kubernetes ConfigMapList resource. * @summary List project-level ConfigMaps */ export type listProjectConfigMapsResponse200 = { - data: ListProjectConfigMaps200; + data: V1ConfigMapList; status: 200; }; @@ -872,7 +858,7 @@ Kubernetes ConfigMap resource. * @summary Create a project-level ConfigMap */ export type createProjectConfigMapResponse201 = { - data: CreateProjectConfigMap201; + data: V1ConfigMap; status: 201; }; @@ -969,7 +955,7 @@ export const useCreateProjectConfigMap = ( * @summary Retrieve a project-level ConfigMap */ export type getProjectConfigMapResponse200 = { - data: GetProjectConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -1125,7 +1111,7 @@ is replaced. Returns the updated Kubernetes ConfigMap resource. * @summary Replace a project-level ConfigMap */ export type updateProjectConfigMapResponse200 = { - data: UpdateProjectConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -1326,7 +1312,7 @@ Returns the updated Kubernetes ConfigMap resource. * @summary Patch a project-level ConfigMap */ export type patchProjectConfigMapResponse200 = { - data: PatchProjectConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -1594,7 +1580,7 @@ or alias. * @summary Retrieve a Freight resource */ export type getFreightResponse200 = { - data: GetFreight200; + data: Freight; status: 200; }; @@ -2165,7 +2151,7 @@ a PromotionTaskList resource. * @summary List PromotionTasks */ export type listPromotionTasksResponse200 = { - data: ListPromotionTasks200; + data: PromotionTaskList; status: 200; }; @@ -2303,7 +2289,7 @@ export function useListPromotionTasks< * @summary Retrieve a PromotionTask */ export type getPromotionTaskResponse200 = { - data: GetPromotionTask200; + data: PromotionTask; status: 200; }; @@ -2447,7 +2433,7 @@ PromotionList resource. * @summary List Promotions */ export type listPromotionsResponse200 = { - data: ListPromotions200; + data: PromotionList; status: 200; }; @@ -2599,7 +2585,7 @@ export function useListPromotions< * @summary Retrieve a Promotion */ export type getPromotionResponse200 = { - data: GetPromotion200; + data: Promotion; status: 200; }; @@ -2915,7 +2901,7 @@ StageList resource. * @summary List Stages */ export type listStagesResponse200 = { - data: ListStages200; + data: StageList; status: 200; }; @@ -3037,7 +3023,7 @@ export function useListStages>, TE * @summary Retrieve a Stage */ export type getStageResponse200 = { - data: GetStage200; + data: Stage; status: 200; }; @@ -3256,7 +3242,7 @@ the state represented by the specified Freight. * @summary Promote to Stage */ export type promoteToStageResponse201 = { - data: PromoteToStage201; + data: Promotion; status: 201; }; @@ -3541,7 +3527,7 @@ WarehouseList resource. * @summary List Warehouses */ export type listWarehousesResponse200 = { - data: ListWarehouses200; + data: WarehouseList; status: 200; }; @@ -3675,7 +3661,7 @@ export function useListWarehouses< * @summary Retrieve a Warehouse */ export type getWarehouseResponse200 = { - data: GetWarehouse200; + data: Warehouse; status: 200; }; @@ -3993,7 +3979,7 @@ ClusterPromotionTaskList resource. * @summary List ClusterPromotionTasks */ export type listClusterPromotionTasksResponse200 = { - data: ListClusterPromotionTasks200; + data: ClusterPromotionTaskList; status: 200; }; @@ -4131,7 +4117,7 @@ export function useListClusterPromotionTasks< * @summary Retrieve a ClusterPromotionTask */ export type getClusterPromotionTaskResponse200 = { - data: GetClusterPromotionTask200; + data: ClusterPromotionTask; status: 200; }; @@ -4282,7 +4268,7 @@ Returns a Kubernetes ConfigMapList resource. * @summary List shared ConfigMaps */ export type listSharedConfigMapsResponse200 = { - data: ListSharedConfigMaps200; + data: V1ConfigMapList; status: 200; }; @@ -4419,7 +4405,7 @@ the created Kubernetes ConfigMap resource. * @summary Create a shared ConfigMap */ export type createSharedConfigMapResponse201 = { - data: CreateSharedConfigMap201; + data: V1ConfigMap; status: 201; }; @@ -4515,7 +4501,7 @@ export const useCreateSharedConfigMap = ( * @summary Retrieve a shared ConfigMap */ export type getSharedConfigMapResponse200 = { - data: GetSharedConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -4654,7 +4640,7 @@ Returns the updated Kubernetes ConfigMap resource. * @summary Replace a shared ConfigMap */ export type updateSharedConfigMapResponse200 = { - data: UpdateSharedConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -4847,7 +4833,7 @@ Returns the updated Kubernetes ConfigMap resource. * @summary Patch a shared ConfigMap */ export type patchSharedConfigMapResponse200 = { - data: PatchSharedConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -4945,7 +4931,7 @@ ConfigMapList resource. * @summary List system-level ConfigMaps */ export type listSystemConfigMapsResponse200 = { - data: ListSystemConfigMaps200; + data: V1ConfigMapList; status: 200; }; @@ -5082,7 +5068,7 @@ ConfigMap resource. * @summary Create a system-level ConfigMap */ export type createSystemConfigMapResponse201 = { - data: CreateSystemConfigMap201; + data: V1ConfigMap; status: 201; }; @@ -5178,7 +5164,7 @@ export const useCreateSystemConfigMap = ( * @summary Retrieve a system-level ConfigMap */ export type getSystemConfigMapResponse200 = { - data: GetSystemConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -5317,7 +5303,7 @@ Returns the updated Kubernetes ConfigMap resource. * @summary Replace a system-level ConfigMap */ export type updateSystemConfigMapResponse200 = { - data: UpdateSystemConfigMap200; + data: V1ConfigMap; status: 200; }; @@ -5510,7 +5496,7 @@ Returns the updated Kubernetes ConfigMap resource. * @summary Patch a system-level ConfigMap */ export type patchSystemConfigMapResponse200 = { - data: PatchSystemConfigMap200; + data: V1ConfigMap; status: 200; }; diff --git a/ui/src/gen/api/v2/credentials/credentials.ts b/ui/src/gen/api/v2/credentials/credentials.ts index 832635bf75..0278d055f0 100644 --- a/ui/src/gen/api/v2/credentials/credentials.ts +++ b/ui/src/gen/api/v2/credentials/credentials.ts @@ -23,36 +23,13 @@ import type { import type { CreateGenericCredentialsRequestBody, - CreateProjectGenericCredentials201, - CreateProjectRepoCredentials201, CreateRepoCredentialsRequestBody, - CreateSharedGenericCredentials201, - CreateSharedRepoCredentials201, - CreateSystemGenericCredentials201, - GetProjectGenericCredentials200, - GetProjectRepoCredentials200, - GetSharedGenericCredentials200, - GetSharedRepoCredentials200, - GetSystemGenericCredentials200, - ListProjectGenericCredentials200, - ListProjectRepoCredentials200, - ListSharedGenericCredentials200, - ListSharedRepoCredentials200, - ListSystemGenericCredentials200, PatchGenericCredentialsRequestBody, - PatchProjectGenericCredentials200, - PatchProjectRepoCredentials200, PatchRepoCredentialsRequestBody, - PatchSharedGenericCredentials200, - PatchSharedRepoCredentials200, - PatchSystemGenericCredentials200, UpdateGenericCredentialsRequestBody, - UpdateProjectGenericCredentials200, - UpdateProjectRepoCredentials200, UpdateRepoCredentialsRequestBody, - UpdateSharedGenericCredentials200, - UpdateSharedRepoCredentials200, - UpdateSystemGenericCredentials200 + V1Secret, + V1SecretList } from '.././models'; import { customFetch } from '../../../../lib/api/custom-fetch'; @@ -65,7 +42,7 @@ SecretList resource containing heavily redacted Secrets. * @summary List project-level generic credentials */ export type listProjectGenericCredentialsResponse200 = { - data: ListProjectGenericCredentials200; + data: V1SecretList; status: 200; }; @@ -216,7 +193,7 @@ redacted Kubernetes Secret resource. * @summary Create project-level generic credentials */ export type createProjectGenericCredentialsResponse201 = { - data: CreateProjectGenericCredentials201; + data: V1Secret; status: 201; }; @@ -319,7 +296,7 @@ heavily redacted Kubernetes Secret resource. * @summary Retrieve project-level generic credentials */ export type getProjectGenericCredentialsResponse200 = { - data: GetProjectGenericCredentials200; + data: V1Secret; status: 200; }; @@ -487,7 +464,7 @@ replaced. Returns a heavily redacted Kubernetes Secret resource. * @summary Replace project-level generic credentials */ export type updateProjectGenericCredentialsResponse200 = { - data: UpdateProjectGenericCredentials200; + data: V1Secret; status: 200; }; @@ -698,7 +675,7 @@ Returns a heavily redacted Kubernetes Secret resource. * @summary Patch project-level generic credentials */ export type patchProjectGenericCredentialsResponse200 = { - data: PatchProjectGenericCredentials200; + data: V1Secret; status: 200; }; @@ -804,7 +781,7 @@ resource containing heavily redacted Secrets. * @summary List project-level repository credentials */ export type listProjectRepoCredentialsResponse200 = { - data: ListProjectRepoCredentials200; + data: V1SecretList; status: 200; }; @@ -954,7 +931,7 @@ redacted Kubernetes Secret resource. * @summary Create project-level repository credentials */ export type createProjectRepoCredentialsResponse201 = { - data: CreateProjectRepoCredentials201; + data: V1Secret; status: 201; }; @@ -1056,7 +1033,7 @@ heavily redacted Kubernetes Secret resource. * @summary Retrieve project-level repository credentials */ export type getProjectRepoCredentialsResponse200 = { - data: GetProjectRepoCredentials200; + data: V1Secret; status: 200; }; @@ -1219,7 +1196,7 @@ Returns a heavily redacted Kubernetes Secret resource. * @summary Replace project-level repository credentials */ export type updateProjectRepoCredentialsResponse200 = { - data: UpdateProjectRepoCredentials200; + data: V1Secret; status: 200; }; @@ -1421,7 +1398,7 @@ are updated. Returns a heavily redacted Kubernetes Secret resource. * @summary Patch project-level repository credentials */ export type patchProjectRepoCredentialsResponse200 = { - data: PatchProjectRepoCredentials200; + data: V1Secret; status: 200; }; @@ -1523,7 +1500,7 @@ resource containing heavily redacted Secrets. * @summary List shared generic credentials */ export type listSharedGenericCredentialsResponse200 = { - data: ListSharedGenericCredentials200; + data: V1SecretList; status: 200; }; @@ -1663,7 +1640,7 @@ projects. Returns a heavily redacted Kubernetes Secret resource. * @summary Create shared generic credentials */ export type createSharedGenericCredentialsResponse201 = { - data: CreateSharedGenericCredentials201; + data: V1Secret; status: 201; }; @@ -1764,7 +1741,7 @@ heavily redacted Kubernetes Secret resource. * @summary Retrieve shared generic credentials */ export type getSharedGenericCredentialsResponse200 = { - data: GetSharedGenericCredentials200; + data: V1Secret; status: 200; }; @@ -1915,7 +1892,7 @@ Returns a heavily redacted Kubernetes Secret resource. * @summary Replace shared generic credentials */ export type updateSharedGenericCredentialsResponse200 = { - data: UpdateSharedGenericCredentials200; + data: V1Secret; status: 200; }; @@ -2116,7 +2093,7 @@ Returns a heavily redacted Kubernetes Secret resource. * @summary Patch shared generic credentials */ export type patchSharedGenericCredentialsResponse200 = { - data: PatchSharedGenericCredentials200; + data: V1Secret; status: 200; }; @@ -2218,7 +2195,7 @@ resource containing heavily redacted Secrets. * @summary List shared repository credentials */ export type listSharedRepoCredentialsResponse200 = { - data: ListSharedRepoCredentials200; + data: V1SecretList; status: 200; }; @@ -2357,7 +2334,7 @@ redacted Kubernetes Secret resource. * @summary Create shared repository credentials */ export type createSharedRepoCredentialsResponse201 = { - data: CreateSharedRepoCredentials201; + data: V1Secret; status: 201; }; @@ -2454,7 +2431,7 @@ heavily redacted Kubernetes Secret resource. * @summary Retrieve shared repository credentials */ export type getSharedRepoCredentialsResponse200 = { - data: GetSharedRepoCredentials200; + data: V1Secret; status: 200; }; @@ -2604,7 +2581,7 @@ Returns a heavily redacted Kubernetes Secret resource. * @summary Replace shared repository credentials */ export type updateSharedRepoCredentialsResponse200 = { - data: UpdateSharedRepoCredentials200; + data: V1Secret; status: 200; }; @@ -2802,7 +2779,7 @@ are updated. Returns a heavily redacted Kubernetes Secret resource. * @summary Patch shared repository credentials */ export type patchSharedRepoCredentialsResponse200 = { - data: PatchSharedRepoCredentials200; + data: V1Secret; status: 200; }; @@ -2903,7 +2880,7 @@ SecretList resource containing heavily redacted Secrets. * @summary List system-level generic credentials */ export type listSystemGenericCredentialsResponse200 = { - data: ListSystemGenericCredentials200; + data: V1SecretList; status: 200; }; @@ -3043,7 +3020,7 @@ redacted Kubernetes Secret resource. * @summary Create system-level generic credentials */ export type createSystemGenericCredentialsResponse201 = { - data: CreateSystemGenericCredentials201; + data: V1Secret; status: 201; }; @@ -3144,7 +3121,7 @@ heavily redacted Kubernetes Secret resource. * @summary Retrieve system-level generic credentials */ export type getSystemGenericCredentialsResponse200 = { - data: GetSystemGenericCredentials200; + data: V1Secret; status: 200; }; @@ -3295,7 +3272,7 @@ replaced. Returns a heavily redacted Kubernetes Secret resource. * @summary Replace system-level generic credentials */ export type updateSystemGenericCredentialsResponse200 = { - data: UpdateSystemGenericCredentials200; + data: V1Secret; status: 200; }; @@ -3496,7 +3473,7 @@ Returns a heavily redacted Kubernetes Secret resource. * @summary Patch system-level generic credentials */ export type patchSystemGenericCredentialsResponse200 = { - data: PatchSystemGenericCredentials200; + data: V1Secret; status: 200; }; diff --git a/ui/src/gen/api/v2/events/events.ts b/ui/src/gen/api/v2/events/events.ts index fa84a417dc..f6439983ba 100644 --- a/ui/src/gen/api/v2/events/events.ts +++ b/ui/src/gen/api/v2/events/events.ts @@ -18,7 +18,7 @@ import type { UseQueryResult } from '@tanstack/react-query'; -import type { ListProjectEvents200 } from '.././models'; +import type { V1EventList } from '.././models'; import { customFetch } from '../../../../lib/api/custom-fetch'; @@ -30,7 +30,7 @@ Kubernetes EventList resource. * @summary List project-level Kubernetes Events */ export type listProjectEventsResponse200 = { - data: ListProjectEvents200; + data: V1EventList; status: 200; }; diff --git a/ui/src/gen/api/v2/models/analysisRunArgument.ts b/ui/src/gen/api/v2/models/analysisRunArgument.ts new file mode 100644 index 0000000000..2e735f4a7a --- /dev/null +++ b/ui/src/gen/api/v2/models/analysisRunArgument.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface AnalysisRunArgument { + /** Name is the name of the argument. + ++kubebuilder:validation:Required */ + name: string; + /** Value is the value of the argument. + ++kubebuilder:validation:Required */ + value: string; +} diff --git a/ui/src/gen/api/v2/models/analysisRunMetadata.ts b/ui/src/gen/api/v2/models/analysisRunMetadata.ts new file mode 100644 index 0000000000..f90c7f4d9c --- /dev/null +++ b/ui/src/gen/api/v2/models/analysisRunMetadata.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { AnalysisRunMetadataAnnotations } from './analysisRunMetadataAnnotations'; +import type { AnalysisRunMetadataLabels } from './analysisRunMetadataLabels'; + +export interface AnalysisRunMetadata { + /** Additional annotations to apply to an AnalysisRun. */ + annotations?: AnalysisRunMetadataAnnotations; + /** Additional labels to apply to an AnalysisRun. */ + labels?: AnalysisRunMetadataLabels; +} diff --git a/ui/src/gen/api/v2/models/analysisRunMetadataAnnotations.ts b/ui/src/gen/api/v2/models/analysisRunMetadataAnnotations.ts new file mode 100644 index 0000000000..8343a479d2 --- /dev/null +++ b/ui/src/gen/api/v2/models/analysisRunMetadataAnnotations.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Additional annotations to apply to an AnalysisRun. + */ +export type AnalysisRunMetadataAnnotations = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/createSystemConfigMap201.ts b/ui/src/gen/api/v2/models/analysisRunMetadataLabels.ts similarity index 53% rename from ui/src/gen/api/v2/models/createSystemConfigMap201.ts rename to ui/src/gen/api/v2/models/analysisRunMetadataLabels.ts index 5526a1da7f..48a90fde0f 100644 --- a/ui/src/gen/api/v2/models/createSystemConfigMap201.ts +++ b/ui/src/gen/api/v2/models/analysisRunMetadataLabels.ts @@ -6,4 +6,7 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateSystemConfigMap201 = { [key: string]: unknown }; +/** + * Additional labels to apply to an AnalysisRun. + */ +export type AnalysisRunMetadataLabels = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/analysisRunReference.ts b/ui/src/gen/api/v2/models/analysisRunReference.ts new file mode 100644 index 0000000000..8c54c1fb9f --- /dev/null +++ b/ui/src/gen/api/v2/models/analysisRunReference.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface AnalysisRunReference { + /** Name is the name of the AnalysisRun. */ + name?: string; + /** Namespace is the namespace of the AnalysisRun. */ + namespace?: string; + /** Phase is the last observed phase of the AnalysisRun referenced by Name. */ + phase?: string; +} diff --git a/ui/src/gen/api/v2/models/analysisTemplateReference.ts b/ui/src/gen/api/v2/models/analysisTemplateReference.ts new file mode 100644 index 0000000000..67ae6d15fc --- /dev/null +++ b/ui/src/gen/api/v2/models/analysisTemplateReference.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface AnalysisTemplateReference { + /** Kind is the type of the AnalysisTemplate. Can be either AnalysisTemplate or +ClusterAnalysisTemplate, default is AnalysisTemplate. + ++kubebuilder:validation:Optional ++kubebuilder:validation:Enum=AnalysisTemplate;ClusterAnalysisTemplate */ + kind?: string; + /** Name is the name of the AnalysisTemplate in the same project/namespace as +the Stage. + ++kubebuilder:validation:Required */ + name: string; +} diff --git a/ui/src/gen/api/v2/models/approvedStage.ts b/ui/src/gen/api/v2/models/approvedStage.ts new file mode 100644 index 0000000000..6a79ce7fc1 --- /dev/null +++ b/ui/src/gen/api/v2/models/approvedStage.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface ApprovedStage { + /** ApprovedAt is the time at which the Freight was approved for the Stage. */ + approvedAt?: string; +} diff --git a/ui/src/gen/api/v2/models/artifactReference.ts b/ui/src/gen/api/v2/models/artifactReference.ts new file mode 100644 index 0000000000..0056c95d19 --- /dev/null +++ b/ui/src/gen/api/v2/models/artifactReference.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ArtifactReferenceMetadata } from './artifactReferenceMetadata'; + +export interface ArtifactReference { + /** ArtifactType specifies the type of artifact this is. Often, but not always, +it will be the media type (MIME type) of the artifact referenced by this +ArtifactReference. + ++kubebuilder:validation:MinLength=1 */ + artifactType?: string; + /** Metadata is a JSON object containing a mostly opaque collection of artifact +attributes. (It must be an object. It may not be a list or a scalar value.) +"Mostly" because Kargo may understand how to interpret some documented, +well-known, top-level keys. Those aside, this metadata is only understood +by a corresponding Subscriber implementation that created it. + ++optional */ + metadata?: ArtifactReferenceMetadata; + /** SubscriptionName is the name of the Subscription that discovered this +artifact. + ++kubebuilder:validation:MinLength=1 */ + subscriptionName?: string; + /** Version identifies a specific revision of this artifact. + ++kubebuilder:validation:MinLength=1 */ + version?: string; +} diff --git a/ui/src/gen/api/v2/models/artifactReferenceMetadata.ts b/ui/src/gen/api/v2/models/artifactReferenceMetadata.ts new file mode 100644 index 0000000000..9b836f9d5b --- /dev/null +++ b/ui/src/gen/api/v2/models/artifactReferenceMetadata.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Metadata is a JSON object containing a mostly opaque collection of artifact +attributes. (It must be an object. It may not be a list or a scalar value.) +"Mostly" because Kargo may understand how to interpret some documented, +well-known, top-level keys. Those aside, this metadata is only understood +by a corresponding Subscriber implementation that created it. + ++optional + */ +export type ArtifactReferenceMetadata = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/artifactoryWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/artifactoryWebhookReceiverConfig.ts new file mode 100644 index 0000000000..98f6bf5244 --- /dev/null +++ b/ui/src/gen/api/v2/models/artifactoryWebhookReceiverConfig.ts @@ -0,0 +1,53 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface ArtifactoryWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret-token` key whose +value is the shared secret used to authenticate the webhook requests sent +by JFrog Artifactory. For more information please refer to the JFrog +Artifactory documentation: + https://jfrog.com/help/r/jfrog-platform-administration-documentation/webhooks + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; + /** VirtualRepoName is the name of an Artifactory virtual repository. + +When unspecified, the Artifactory webhook receiver depends on the value of +the webhook payload's `data.repo_key` field when inferring the URL of the +repository from which the webhook originated, which will always be an +Artifactory "local repository." In cases where a Warehouse subscribes to +such a repository indirectly via a "virtual repository," there will be a +discrepancy between the inferred (local) repository URL and the URL +actually used by the subscription, which can prevent the receiver from +identifying such a Warehouse as one in need of refreshing. When specified, +the value of the VirtualRepoName field supersedes the value of the webhook +payload's `data.repo_key` field to compensate for that discrepancy. + +In practice, when using virtual repositories, a separate Artifactory +webhook receiver should be configured for each, but one such receiver can +handle inbound webhooks from any number of local repositories that are +aggregated by that virtual repository. For example, if a virtual repository +`proj-virtual` aggregates container images from all of the `proj` +Artifactory project's local image repositories, with a single webhook +configured to post to a single receiver configured for the `proj-virtual` +virtual repository, an image pushed to +`example.frog.io/proj-//image`, will cause that +receiver to refresh all Warehouses subscribed to +`example.frog.io/proj-virtual//image`. + ++optional */ + virtualRepoName?: string; +} diff --git a/ui/src/gen/api/v2/models/autoPromotionOptions.ts b/ui/src/gen/api/v2/models/autoPromotionOptions.ts new file mode 100644 index 0000000000..0548456f60 --- /dev/null +++ b/ui/src/gen/api/v2/models/autoPromotionOptions.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface AutoPromotionOptions { + /** SelectionPolicy specifies the rules for identifying new Freight that is +eligible for auto-promotion to this Stage. This field is optional. When +left unspecified, the field is implicitly treated as if its value were +"NewestFreight". + +Accepted Values: + +- "NewestFreight": The newest Freight that is available to the Stage is + eligible for auto-promotion. + +- "MatchUpstream": Only the Freight currently used immediately upstream + from this Stage is eligible for auto-promotion. This policy may only + be applied when the Stage has exactly one upstream Stage. */ + selectionPolicy?: string; +} diff --git a/ui/src/gen/api/v2/models/azureWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/azureWebhookReceiverConfig.ts new file mode 100644 index 0000000000..bf9b33bf40 --- /dev/null +++ b/ui/src/gen/api/v2/models/azureWebhookReceiverConfig.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface AzureWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret` key whose value +does NOT need to be shared directly with Azure when registering a webhook. +It is used only by Kargo to create a complex, hard-to-guess URL, +which implicitly serves as a shared secret. For more information about +Azure webhooks, please refer to the Azure documentation: + + Azure Container Registry: + https://learn.microsoft.com/en-us/azure/container-registry/container-registry-repositories + + Azure DevOps: + http://learn.microsoft.com/en-us/azure/devops/service-hooks/services/webhooks?view=azure-devops + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/bitbucketWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/bitbucketWebhookReceiverConfig.ts new file mode 100644 index 0000000000..6cae386bcd --- /dev/null +++ b/ui/src/gen/api/v2/models/bitbucketWebhookReceiverConfig.ts @@ -0,0 +1,26 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface BitbucketWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret` key whose +value is the shared secret used to authenticate the webhook requests sent +by Bitbucket. For more information please refer to the Bitbucket +documentation: + https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/ + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/chart.ts b/ui/src/gen/api/v2/models/chart.ts new file mode 100644 index 0000000000..1e0cc506af --- /dev/null +++ b/ui/src/gen/api/v2/models/chart.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface Chart { + /** Name specifies the name of the chart. */ + name?: string; + /** RepoURL specifies the URL of a Helm chart repository. Classic chart +repositories (using HTTP/S) can contain differently named charts. When this +field points to such a repository, the Name field will specify the name of +the chart within the repository. In the case of a repository within an OCI +registry, the URL implicitly points to a specific chart and the Name field +will be empty. */ + repoURL?: string; + /** Version specifies a particular version of the chart. */ + version?: string; +} diff --git a/ui/src/gen/api/v2/models/chartDiscoveryResult.ts b/ui/src/gen/api/v2/models/chartDiscoveryResult.ts new file mode 100644 index 0000000000..ae83557e09 --- /dev/null +++ b/ui/src/gen/api/v2/models/chartDiscoveryResult.ts @@ -0,0 +1,28 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface ChartDiscoveryResult { + /** Name is the name of the Helm chart, as specified in the ChartSubscription. */ + name?: string; + /** RepoURL is the repository URL of the Helm chart, as specified in the +ChartSubscription. + ++kubebuilder:validation:MinLength=1 */ + repoURL?: string; + /** SemverConstraint is the constraint for which versions were discovered. +This field is optional, and only populated if the ChartSubscription +specifies a SemverConstraint. */ + semverConstraint?: string; + /** Versions is a list of versions discovered by the Warehouse for the +ChartSubscription. An empty list indicates that the discovery operation was +successful, but no versions matching the ChartSubscription criteria were +found. + ++optional */ + versions?: string[]; +} diff --git a/ui/src/gen/api/v2/models/clusterConfig.ts b/ui/src/gen/api/v2/models/clusterConfig.ts new file mode 100644 index 0000000000..57148b6b0a --- /dev/null +++ b/ui/src/gen/api/v2/models/clusterConfig.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { ClusterConfigSpec } from './clusterConfigSpec'; +import type { ClusterConfigStatus } from './clusterConfigStatus'; + +export interface ClusterConfig { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes the configuration of a cluster. */ + spec?: ClusterConfigSpec; + /** Status describes the current status of a ClusterConfig. */ + status?: ClusterConfigStatus; +} diff --git a/ui/src/gen/api/v2/models/clusterConfigSpec.ts b/ui/src/gen/api/v2/models/clusterConfigSpec.ts new file mode 100644 index 0000000000..3fbb416f20 --- /dev/null +++ b/ui/src/gen/api/v2/models/clusterConfigSpec.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { WebhookReceiverConfig } from './webhookReceiverConfig'; + +export interface ClusterConfigSpec { + /** WebhookReceivers describes cluster-scoped webhook receivers used for +processing events from various external platforms */ + webhookReceivers?: WebhookReceiverConfig[]; +} diff --git a/ui/src/gen/api/v2/models/clusterConfigStatus.ts b/ui/src/gen/api/v2/models/clusterConfigStatus.ts new file mode 100644 index 0000000000..10e8c49016 --- /dev/null +++ b/ui/src/gen/api/v2/models/clusterConfigStatus.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Condition } from './v1Condition'; +import type { WebhookReceiverDetails } from './webhookReceiverDetails'; + +export interface ClusterConfigStatus { + /** Conditions contains the last observations of the ClusterConfig's current +state. + ++patchMergeKey=type ++patchStrategy=merge ++listType=map ++listMapKey=type */ + conditions?: V1Condition[]; + /** LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh +annotation that was handled by the controller. This field can be used to +determine whether the request to refresh the resource has been handled. ++optional */ + lastHandledRefresh?: string; + /** ObservedGeneration represents the .metadata.generation that this +ClusterConfig was reconciled against. */ + observedGeneration?: number; + /** WebhookReceivers describes the status of cluster-scoped webhook receivers. */ + webhookReceivers?: WebhookReceiverDetails[]; +} diff --git a/ui/src/gen/api/v2/models/clusterPromotionTask.ts b/ui/src/gen/api/v2/models/clusterPromotionTask.ts new file mode 100644 index 0000000000..35a5d448a2 --- /dev/null +++ b/ui/src/gen/api/v2/models/clusterPromotionTask.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { PromotionTaskSpec } from './promotionTaskSpec'; + +export interface ClusterPromotionTask { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes the desired transition of a specific Stage into a specific +Freight. + ++kubebuilder:validation:Required */ + spec: PromotionTaskSpec; +} diff --git a/ui/src/gen/api/v2/models/clusterPromotionTaskList.ts b/ui/src/gen/api/v2/models/clusterPromotionTaskList.ts new file mode 100644 index 0000000000..119f6ea567 --- /dev/null +++ b/ui/src/gen/api/v2/models/clusterPromotionTaskList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ClusterPromotionTask } from './clusterPromotionTask'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface ClusterPromotionTaskList { + /** 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 ++optional */ + apiVersion?: string; + items?: ClusterPromotionTask[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/createSharedGenericCredentials201.ts b/ui/src/gen/api/v2/models/createSharedGenericCredentials201.ts deleted file mode 100644 index 3d7e71950d..0000000000 --- a/ui/src/gen/api/v2/models/createSharedGenericCredentials201.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type CreateSharedGenericCredentials201 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/createSystemAPIToken201.ts b/ui/src/gen/api/v2/models/createSystemAPIToken201.ts deleted file mode 100644 index 21c8998e47..0000000000 --- a/ui/src/gen/api/v2/models/createSystemAPIToken201.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type CreateSystemAPIToken201 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/createSystemGenericCredentials201.ts b/ui/src/gen/api/v2/models/createSystemGenericCredentials201.ts deleted file mode 100644 index e078512776..0000000000 --- a/ui/src/gen/api/v2/models/createSystemGenericCredentials201.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type CreateSystemGenericCredentials201 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/currentStage.ts b/ui/src/gen/api/v2/models/currentStage.ts new file mode 100644 index 0000000000..7200f8c83f --- /dev/null +++ b/ui/src/gen/api/v2/models/currentStage.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface CurrentStage { + /** Since is the time at which the Stage most recently started using the +Freight. This can be used to calculate how long the Freight has been in use +by the Stage. */ + since?: string; +} diff --git a/ui/src/gen/api/v2/models/discoveredArtifacts.ts b/ui/src/gen/api/v2/models/discoveredArtifacts.ts new file mode 100644 index 0000000000..7c5e6197d0 --- /dev/null +++ b/ui/src/gen/api/v2/models/discoveredArtifacts.ts @@ -0,0 +1,37 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ChartDiscoveryResult } from './chartDiscoveryResult'; +import type { GitDiscoveryResult } from './gitDiscoveryResult'; +import type { ImageDiscoveryResult } from './imageDiscoveryResult'; +import type { DiscoveryResult } from './discoveryResult'; + +export interface DiscoveredArtifacts { + /** Charts holds the charts discovered by the Warehouse for the chart +subscriptions. + ++optional */ + charts?: ChartDiscoveryResult[]; + /** DiscoveredAt is the time at which the Warehouse discovered the artifacts. + ++optional */ + discoveredAt?: string; + /** Git holds the commits discovered by the Warehouse for the Git +subscriptions. + ++optional */ + git?: GitDiscoveryResult[]; + /** Images holds the image references discovered by the Warehouse for the +image subscriptions. + ++optional */ + images?: ImageDiscoveryResult[]; + /** Results holds the artifact references discovered by the Warehouse. + ++optional */ + results?: DiscoveryResult[]; +} diff --git a/ui/src/gen/api/v2/models/discoveredCommit.ts b/ui/src/gen/api/v2/models/discoveredCommit.ts new file mode 100644 index 0000000000..999675615d --- /dev/null +++ b/ui/src/gen/api/v2/models/discoveredCommit.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface DiscoveredCommit { + /** Author is the author of the commit. */ + author?: string; + /** Branch is the branch in which the commit was found. This field is +optional, and populated based on the CommitSelectionStrategy of the +GitSubscription. */ + branch?: string; + /** Committer is the person who committed the commit. */ + committer?: string; + /** CreatorDate is the commit creation date as specified by the commit, or +the tagger date if the commit belongs to an annotated tag. */ + creatorDate?: string; + /** ID is the identifier of the commit. This typically is a SHA-1 hash. + ++kubebuilder:validation:MinLength=1 */ + id?: string; + /** Subject is the subject of the commit (i.e. the first line of the commit +message). */ + subject?: string; + /** Tag is the tag that resolved to this commit. This field is optional, and +populated based on the CommitSelectionStrategy of the GitSubscription. */ + tag?: string; +} diff --git a/ui/src/gen/api/v2/models/discoveredImageReference.ts b/ui/src/gen/api/v2/models/discoveredImageReference.ts new file mode 100644 index 0000000000..8af898b4e0 --- /dev/null +++ b/ui/src/gen/api/v2/models/discoveredImageReference.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { DiscoveredImageReferenceAnnotations } from './discoveredImageReferenceAnnotations'; + +export interface DiscoveredImageReference { + /** Annotations is a map of key-value pairs that provide additional +information about the image. */ + annotations?: DiscoveredImageReferenceAnnotations; + /** CreatedAt is the time the image was created. This field is optional, and +not populated for every ImageSelectionStrategy. */ + createdAt?: string; + /** Digest is the digest of the image. + ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:Pattern=`^[a-z0-9]+:[a-f0-9]+$` ++akuity:test-kubebuilder-pattern=Digest */ + digest?: string; + /** Tag is the tag of the image. + ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:MaxLength=128 ++kubebuilder:validation:Pattern=`^[\w.\-\_]+$` ++akuity:test-kubebuilder-pattern=Tag */ + tag?: string; +} diff --git a/ui/src/gen/api/v2/models/discoveredImageReferenceAnnotations.ts b/ui/src/gen/api/v2/models/discoveredImageReferenceAnnotations.ts new file mode 100644 index 0000000000..d39bf2dac6 --- /dev/null +++ b/ui/src/gen/api/v2/models/discoveredImageReferenceAnnotations.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Annotations is a map of key-value pairs that provide additional +information about the image. + */ +export type DiscoveredImageReferenceAnnotations = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/discoveryResult.ts b/ui/src/gen/api/v2/models/discoveryResult.ts new file mode 100644 index 0000000000..64319bf2be --- /dev/null +++ b/ui/src/gen/api/v2/models/discoveryResult.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ArtifactReference } from './artifactReference'; + +export interface DiscoveryResult { + /** ArtifactReferences is a list of references to specific versions of an +artifact. + ++optional */ + artifactReferences?: ArtifactReference[]; + /** SubscriptionName is the name of the Subscription that discovered these +results. + ++kubebuilder:validation:MinLength=1 */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/dockerHubWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/dockerHubWebhookReceiverConfig.ts new file mode 100644 index 0000000000..03242cecd2 --- /dev/null +++ b/ui/src/gen/api/v2/models/dockerHubWebhookReceiverConfig.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface DockerHubWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +The Secret's data map is expected to contain a `secret` key whose value +does NOT need to be shared directly with Docker Hub when registering a +webhook. It is used only by Kargo to create a complex, hard-to-guess URL, +which implicitly serves as a shared secret. For more information about +Docker Hub webhooks, please refer to the Docker documentation: + https://docs.docker.com/docker-hub/webhooks/ + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/expressionVariable.ts b/ui/src/gen/api/v2/models/expressionVariable.ts new file mode 100644 index 0000000000..94d8ddd570 --- /dev/null +++ b/ui/src/gen/api/v2/models/expressionVariable.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface ExpressionVariable { + /** Name is the name of the variable. + ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:Pattern=^[a-zA-Z_]\w*$ */ + name?: string; + /** Value is the value of the variable. It is allowed to utilize expressions +in the value. +See https://docs.kargo.io/user-guide/reference-docs/expressions for details. */ + value?: string; +} diff --git a/ui/src/gen/api/v2/models/freight.ts b/ui/src/gen/api/v2/models/freight.ts new file mode 100644 index 0000000000..33465f3c27 --- /dev/null +++ b/ui/src/gen/api/v2/models/freight.ts @@ -0,0 +1,56 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ArtifactReference } from './artifactReference'; +import type { Chart } from './chart'; +import type { GitCommit } from './gitCommit'; +import type { Image } from './image'; +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { FreightOrigin } from './freightOrigin'; +import type { FreightStatus } from './freightStatus'; + +export interface Freight { + /** Alias is a human-friendly alias for a piece of Freight. This is an optional +field. A defaulting webhook will sync this field with the value of the +kargo.akuity.io/alias label. When the alias label is not present or differs +from the value of this field, the defaulting webhook will set the label to +the value of this field. If the alias label is present and this field is +empty, the defaulting webhook will set the value of this field to the value +of the alias label. If this field is empty and the alias label is not +present, the defaulting webhook will choose an available alias and assign +it to both the field and label. */ + alias?: string; + /** 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 ++optional */ + apiVersion?: string; + /** Artifacts describes specific versions of artifacts other +than Git repository commits, container images, and Helm charts. */ + artifacts?: ArtifactReference[]; + /** Charts describes specific versions of specific Helm charts. */ + charts?: Chart[]; + /** Commits describes specific Git repository commits. */ + commits?: GitCommit[]; + /** Images describes specific versions of specific container images. */ + images?: Image[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Origin describes a kind of Freight in terms of its origin. + ++kubebuilder:validation:Required */ + origin: FreightOrigin; + /** Status describes the current status of this Freight. */ + status?: FreightStatus; +} diff --git a/ui/src/gen/api/v2/models/freightCollection.ts b/ui/src/gen/api/v2/models/freightCollection.ts new file mode 100644 index 0000000000..9ab76f22f1 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightCollection.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightCollectionItems } from './freightCollectionItems'; +import type { VerificationInfo } from './verificationInfo'; + +export interface FreightCollection { + /** ID is a unique and deterministically calculated identifier for the +FreightCollection. It is updated on each use of the UpdateOrPush method. */ + id?: string; + /** Freight is a map of FreightReference objects, indexed by their Warehouse +origin. */ + items?: FreightCollectionItems; + /** VerificationHistory is a stack of recent VerificationInfo. By default, +the last ten VerificationInfo are stored. */ + verificationHistory?: VerificationInfo[]; +} diff --git a/ui/src/gen/api/v2/models/freightCollectionItems.ts b/ui/src/gen/api/v2/models/freightCollectionItems.ts new file mode 100644 index 0000000000..33b63f7e29 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightCollectionItems.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightReference } from './freightReference'; + +/** + * Freight is a map of FreightReference objects, indexed by their Warehouse +origin. + */ +export type FreightCollectionItems = { [key: string]: FreightReference }; diff --git a/ui/src/gen/api/v2/models/freightCreationCriteria.ts b/ui/src/gen/api/v2/models/freightCreationCriteria.ts new file mode 100644 index 0000000000..44e4f099a5 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightCreationCriteria.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface FreightCreationCriteria { + /** Expression is an expr-lang expression that must evaluate to true for +Freight to be created automatically from new artifacts following discovery. */ + expression?: string; +} diff --git a/ui/src/gen/api/v2/models/freightOrigin.ts b/ui/src/gen/api/v2/models/freightOrigin.ts new file mode 100644 index 0000000000..b04fa678b9 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightOrigin.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface FreightOrigin { + /** Kind is the kind of resource from which Freight may have originated. At +present, this can only be "Warehouse". + ++kubebuilder:validation:Required */ + kind: string; + /** Name is the name of the resource of the kind indicated by the Kind field +from which Freight may originate. + ++kubebuilder:validation:Required */ + name: string; +} diff --git a/ui/src/gen/api/v2/models/freightReference.ts b/ui/src/gen/api/v2/models/freightReference.ts new file mode 100644 index 0000000000..6b2ecfc618 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightReference.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ArtifactReference } from './artifactReference'; +import type { Chart } from './chart'; +import type { GitCommit } from './gitCommit'; +import type { Image } from './image'; +import type { FreightOrigin } from './freightOrigin'; + +export interface FreightReference { + /** Artifacts describes specific versions of artifacts other +than Git repository commits, container images, and Helm charts. */ + artifacts?: ArtifactReference[]; + /** Charts describes specific versions of specific Helm charts. */ + charts?: Chart[]; + /** Commits describes specific Git repository commits. */ + commits?: GitCommit[]; + /** Images describes specific versions of specific container images. */ + images?: Image[]; + /** Name is a system-assigned identifier derived deterministically from +the contents of the Freight. I.e., two pieces of Freight can be compared +for equality by comparing their Names. */ + name?: string; + /** Origin describes a kind of Freight in terms of its origin. */ + origin?: FreightOrigin; +} diff --git a/ui/src/gen/api/v2/models/freightRequest.ts b/ui/src/gen/api/v2/models/freightRequest.ts new file mode 100644 index 0000000000..df3a80940a --- /dev/null +++ b/ui/src/gen/api/v2/models/freightRequest.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightOrigin } from './freightOrigin'; +import type { FreightSources } from './freightSources'; + +export interface FreightRequest { + /** Origin specifies from where the requested Freight must have originated. +This is a required field. + ++kubebuilder:validation:Required */ + origin: FreightOrigin; + /** Sources describes where the requested Freight may be obtained from. This is +a required field. */ + sources?: FreightSources; +} diff --git a/ui/src/gen/api/v2/models/freightSources.ts b/ui/src/gen/api/v2/models/freightSources.ts new file mode 100644 index 0000000000..a660fa1c18 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightSources.ts @@ -0,0 +1,52 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { AutoPromotionOptions } from './autoPromotionOptions'; + +export interface FreightSources { + /** AutoPromotionOptions specifies options pertaining to auto-promotion. These +settings have no effect if auto-promotion is not enabled for this Stage at +the ProjectConfig level. */ + autoPromotionOptions?: AutoPromotionOptions; + /** AvailabilityStrategy specifies the semantics for how requested Freight is +made available to the Stage. This field is optional. When left unspecified, +the field is implicitly treated as if its value were "OneOf". + +Accepted Values: + +- "All": Freight must be verified and, if applicable, soaked in all + upstream Stages to be considered available for promotion. +- "OneOf": Freight must be verified and, if applicable, soaked in at least + one upstream Stage to be considered available for promotion. +- "": Treated the same as "OneOf". + ++kubebuilder:validation:Optional */ + availabilityStrategy?: string; + /** Direct indicates the requested Freight may be obtained directly from the +Warehouse from which it originated. If this field's value is false, then +the value of the Stages field must be non-empty. i.e. Between the two +fields, at least one source must be specified. */ + direct?: boolean; + /** RequiredSoakTime specifies a minimum duration for which the requested +Freight must have continuously occupied ("soaked in") in an upstream Stage +before becoming available for promotion to this Stage. This is an optional +field. If nil or zero, no soak time is required. Any soak time requirement +is in ADDITION to the requirement that Freight be verified in an upstream +Stage to become available for promotion to this Stage, although a manual +approval for promotion to this Stage will supersede any soak time +requirement. + ++kubebuilder:validation:Type=string ++kubebuilder:validation:Pattern=`^([0-9]+(\.[0-9]+)?(s|m|h))+$` ++akuity:test-kubebuilder-pattern=Duration */ + requiredSoakTime?: string; + /** Stages identifies other "upstream" Stages as potential sources of the +requested Freight. If this field's value is empty, then the value of the +Direct field must be true. i.e. Between the two fields, at least on source +must be specified. */ + stages?: string[]; +} diff --git a/ui/src/gen/api/v2/models/freightStatus.ts b/ui/src/gen/api/v2/models/freightStatus.ts new file mode 100644 index 0000000000..6acb207eab --- /dev/null +++ b/ui/src/gen/api/v2/models/freightStatus.ts @@ -0,0 +1,28 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightStatusApprovedFor } from './freightStatusApprovedFor'; +import type { FreightStatusCurrentlyIn } from './freightStatusCurrentlyIn'; +import type { FreightStatusMetadata } from './freightStatusMetadata'; +import type { FreightStatusVerifiedIn } from './freightStatusVerifiedIn'; + +export interface FreightStatus { + /** ApprovedFor describes the Stages for which this Freight has been approved +preemptively/manually by a user. This is useful for hotfixes, where one +might wish to promote a piece of Freight to a given Stage without +transiting the entire pipeline. */ + approvedFor?: FreightStatusApprovedFor; + /** CurrentlyIn describes the Stages in which this Freight is currently in use. */ + currentlyIn?: FreightStatusCurrentlyIn; + /** Metadata is a map of arbitrary metadata associated with the Freight. +This is useful for storing additional information about the Freight +or Promotion that can be shared across steps or stages. */ + metadata?: FreightStatusMetadata; + /** VerifiedIn describes the Stages in which this Freight has been verified +through promotion and subsequent health checks. */ + verifiedIn?: FreightStatusVerifiedIn; +} diff --git a/ui/src/gen/api/v2/models/freightStatusApprovedFor.ts b/ui/src/gen/api/v2/models/freightStatusApprovedFor.ts new file mode 100644 index 0000000000..84a1725eb4 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightStatusApprovedFor.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ApprovedStage } from './approvedStage'; + +/** + * ApprovedFor describes the Stages for which this Freight has been approved +preemptively/manually by a user. This is useful for hotfixes, where one +might wish to promote a piece of Freight to a given Stage without +transiting the entire pipeline. + */ +export type FreightStatusApprovedFor = { [key: string]: ApprovedStage }; diff --git a/ui/src/gen/api/v2/models/freightStatusCurrentlyIn.ts b/ui/src/gen/api/v2/models/freightStatusCurrentlyIn.ts new file mode 100644 index 0000000000..e34fb78aa7 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightStatusCurrentlyIn.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { CurrentStage } from './currentStage'; + +/** + * CurrentlyIn describes the Stages in which this Freight is currently in use. + */ +export type FreightStatusCurrentlyIn = { [key: string]: CurrentStage }; diff --git a/ui/src/gen/api/v2/models/freightStatusMetadata.ts b/ui/src/gen/api/v2/models/freightStatusMetadata.ts new file mode 100644 index 0000000000..e9a621301c --- /dev/null +++ b/ui/src/gen/api/v2/models/freightStatusMetadata.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Metadata is a map of arbitrary metadata associated with the Freight. +This is useful for storing additional information about the Freight +or Promotion that can be shared across steps or stages. + */ +export type FreightStatusMetadata = { [key: string]: { [key: string]: unknown } }; diff --git a/ui/src/gen/api/v2/models/freightStatusVerifiedIn.ts b/ui/src/gen/api/v2/models/freightStatusVerifiedIn.ts new file mode 100644 index 0000000000..0c5a85bf70 --- /dev/null +++ b/ui/src/gen/api/v2/models/freightStatusVerifiedIn.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { VerifiedStage } from './verifiedStage'; + +/** + * VerifiedIn describes the Stages in which this Freight has been verified +through promotion and subsequent health checks. + */ +export type FreightStatusVerifiedIn = { [key: string]: VerifiedStage }; diff --git a/ui/src/gen/api/v2/models/genericWebhookAction.ts b/ui/src/gen/api/v2/models/genericWebhookAction.ts new file mode 100644 index 0000000000..1338342591 --- /dev/null +++ b/ui/src/gen/api/v2/models/genericWebhookAction.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { GenericWebhookActionParameters } from './genericWebhookActionParameters'; +import type { GenericWebhookTargetSelectionCriteria } from './genericWebhookTargetSelectionCriteria'; + +export interface GenericWebhookAction { + /** ActionType indicates the type of action to be performed. `Refresh` is the +only currently supported action. + ++kubebuilder:validation:Enum=Refresh; */ + action?: string; + /** Parameters contains additional, action-specific parameters. Values may be +static or extracted from the request using expressions. + ++optional */ + parameters?: GenericWebhookActionParameters; + /** TargetSelectionCriteria is a list of selection criteria for the resources on which the +action should be performed. + ++kubebuilder:validation:MinItems=1 */ + targetSelectionCriteria?: GenericWebhookTargetSelectionCriteria[]; + /** WhenExpression defines criteria that a request must meet to run this +action. + ++optional */ + whenExpression?: string; +} diff --git a/ui/src/gen/api/v2/models/genericWebhookActionParameters.ts b/ui/src/gen/api/v2/models/genericWebhookActionParameters.ts new file mode 100644 index 0000000000..5ac8335f3e --- /dev/null +++ b/ui/src/gen/api/v2/models/genericWebhookActionParameters.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Parameters contains additional, action-specific parameters. Values may be +static or extracted from the request using expressions. + ++optional + */ +export type GenericWebhookActionParameters = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/genericWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/genericWebhookReceiverConfig.ts new file mode 100644 index 0000000000..7f14097e95 --- /dev/null +++ b/ui/src/gen/api/v2/models/genericWebhookReceiverConfig.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { GenericWebhookAction } from './genericWebhookAction'; +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface GenericWebhookReceiverConfig { + /** Actions is a list of actions to be performed when a webhook event is received. + ++kubebuilder:validation:MinItems=1 */ + actions?: GenericWebhookAction[]; + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret` key whose value +does NOT need to be shared directly with the sender. It is used only by +Kargo to create a complex, hard-to-guess URL, which implicitly serves as a +shared secret. + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/genericWebhookTargetSelectionCriteria.ts b/ui/src/gen/api/v2/models/genericWebhookTargetSelectionCriteria.ts new file mode 100644 index 0000000000..0b56e83af6 --- /dev/null +++ b/ui/src/gen/api/v2/models/genericWebhookTargetSelectionCriteria.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { IndexSelector } from './indexSelector'; +import type { V1LabelSelector } from './v1LabelSelector'; + +export interface GenericWebhookTargetSelectionCriteria { + /** IndexSelector is a selector used to identify cached target resources by cache key. +If used with LabelSelector and/or Name, the results are the combined (logical AND) of all the criteria. + ++optional */ + indexSelector?: IndexSelector; + /** Kind is the kind of the target resource. + ++kubebuilder:validation:Enum=Warehouse; */ + kind?: string; + /** LabelSelector is a label selector to identify the target resources. +If used with IndexSelector and/or Name, the results are the combined (logical AND) of all the criteria. + ++optional */ + labelSelector?: V1LabelSelector; + /** Name is the name of the target resource. If LabelSelector and/or IndexSelectors +are also specified, the results are the combined (logical AND) of the criteria. + ++optional */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/getAnalysisRun200.ts b/ui/src/gen/api/v2/models/getAnalysisRun200.ts deleted file mode 100644 index 0cfef3b017..0000000000 --- a/ui/src/gen/api/v2/models/getAnalysisRun200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetAnalysisRun200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getAnalysisTemplate200.ts b/ui/src/gen/api/v2/models/getAnalysisTemplate200.ts deleted file mode 100644 index 6362f99245..0000000000 --- a/ui/src/gen/api/v2/models/getAnalysisTemplate200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetAnalysisTemplate200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getClusterAnalysisTemplate200.ts b/ui/src/gen/api/v2/models/getClusterAnalysisTemplate200.ts deleted file mode 100644 index a16cb2c04e..0000000000 --- a/ui/src/gen/api/v2/models/getClusterAnalysisTemplate200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetClusterAnalysisTemplate200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getClusterConfig200.ts b/ui/src/gen/api/v2/models/getClusterConfig200.ts deleted file mode 100644 index a240ad636f..0000000000 --- a/ui/src/gen/api/v2/models/getClusterConfig200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetClusterConfig200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getClusterPromotionTask200.ts b/ui/src/gen/api/v2/models/getClusterPromotionTask200.ts deleted file mode 100644 index 4ad437ad4f..0000000000 --- a/ui/src/gen/api/v2/models/getClusterPromotionTask200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetClusterPromotionTask200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getFreight200.ts b/ui/src/gen/api/v2/models/getFreight200.ts deleted file mode 100644 index 304abcd0e9..0000000000 --- a/ui/src/gen/api/v2/models/getFreight200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetFreight200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getProjectAPIToken200.ts b/ui/src/gen/api/v2/models/getProjectAPIToken200.ts deleted file mode 100644 index 92f53ba9ea..0000000000 --- a/ui/src/gen/api/v2/models/getProjectAPIToken200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetProjectAPIToken200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getProjectConfig200.ts b/ui/src/gen/api/v2/models/getProjectConfig200.ts deleted file mode 100644 index c991f6e232..0000000000 --- a/ui/src/gen/api/v2/models/getProjectConfig200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetProjectConfig200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getProjectConfigMap200.ts b/ui/src/gen/api/v2/models/getProjectConfigMap200.ts deleted file mode 100644 index 529bf6cbf0..0000000000 --- a/ui/src/gen/api/v2/models/getProjectConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetProjectConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getProjectGenericCredentials200.ts b/ui/src/gen/api/v2/models/getProjectGenericCredentials200.ts deleted file mode 100644 index 74b25906b6..0000000000 --- a/ui/src/gen/api/v2/models/getProjectGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetProjectGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getProjectRepoCredentials200.ts b/ui/src/gen/api/v2/models/getProjectRepoCredentials200.ts deleted file mode 100644 index f4442e490e..0000000000 --- a/ui/src/gen/api/v2/models/getProjectRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetProjectRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getPromotionTask200.ts b/ui/src/gen/api/v2/models/getPromotionTask200.ts deleted file mode 100644 index 5a7c34d71f..0000000000 --- a/ui/src/gen/api/v2/models/getPromotionTask200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetPromotionTask200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getSharedConfigMap200.ts b/ui/src/gen/api/v2/models/getSharedConfigMap200.ts deleted file mode 100644 index 28f0c86ae1..0000000000 --- a/ui/src/gen/api/v2/models/getSharedConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetSharedConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getSharedGenericCredentials200.ts b/ui/src/gen/api/v2/models/getSharedGenericCredentials200.ts deleted file mode 100644 index 7c21d45c97..0000000000 --- a/ui/src/gen/api/v2/models/getSharedGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetSharedGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getSharedRepoCredentials200.ts b/ui/src/gen/api/v2/models/getSharedRepoCredentials200.ts deleted file mode 100644 index 6a573d9e56..0000000000 --- a/ui/src/gen/api/v2/models/getSharedRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetSharedRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getSystemAPIToken200.ts b/ui/src/gen/api/v2/models/getSystemAPIToken200.ts deleted file mode 100644 index be80356312..0000000000 --- a/ui/src/gen/api/v2/models/getSystemAPIToken200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetSystemAPIToken200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getSystemGenericCredentials200.ts b/ui/src/gen/api/v2/models/getSystemGenericCredentials200.ts deleted file mode 100644 index fb235b1e5a..0000000000 --- a/ui/src/gen/api/v2/models/getSystemGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetSystemGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/getWarehouse200.ts b/ui/src/gen/api/v2/models/getWarehouse200.ts deleted file mode 100644 index 89d4a72717..0000000000 --- a/ui/src/gen/api/v2/models/getWarehouse200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type GetWarehouse200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/gitCommit.ts b/ui/src/gen/api/v2/models/gitCommit.ts new file mode 100644 index 0000000000..7ccea8d2db --- /dev/null +++ b/ui/src/gen/api/v2/models/gitCommit.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface GitCommit { + /** Author is the author of the commit. */ + author?: string; + /** Branch denotes the branch of the repository where this commit was found. */ + branch?: string; + /** Committer is the person who committed the commit. */ + committer?: string; + /** ID is the ID of a specific commit in the Git repository specified by +RepoURL. */ + id?: string; + /** Message is the message associated with the commit. At present, this only +contains the first line (subject) of the commit message. */ + message?: string; + /** RepoURL is the URL of a Git repository. */ + repoURL?: string; + /** Tag denotes a tag in the repository that matched selection criteria and +resolved to this commit. */ + tag?: string; +} diff --git a/ui/src/gen/api/v2/models/gitDiscoveryResult.ts b/ui/src/gen/api/v2/models/gitDiscoveryResult.ts new file mode 100644 index 0000000000..a6895462d7 --- /dev/null +++ b/ui/src/gen/api/v2/models/gitDiscoveryResult.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { DiscoveredCommit } from './discoveredCommit'; + +export interface GitDiscoveryResult { + /** Commits is a list of commits discovered by the Warehouse for the +GitSubscription. An empty list indicates that the discovery operation was +successful, but no commits matching the GitSubscription criteria were found. + ++optional */ + commits?: DiscoveredCommit[]; + /** RepoURL is the repository URL of the GitSubscription. + +TODO(v1.13.0): Remove SSH/SCP-style URL support from this pattern. + ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:Pattern=`(?:^(ssh|https?)://(?:([\w-]+)(:(.+))?@)?([\w-]+(?:\.[\w-]+)*)(?::(\d{1,5}))?(/.*)$)|(?:^([\w-]+)@([\w+]+(?:\.[\w-]+)*):(/?.*))` ++akuity:test-kubebuilder-pattern=GitRepoURLPattern */ + repoURL?: string; +} diff --git a/ui/src/gen/api/v2/models/gitHubWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/gitHubWebhookReceiverConfig.ts new file mode 100644 index 0000000000..0960f5bd48 --- /dev/null +++ b/ui/src/gen/api/v2/models/gitHubWebhookReceiverConfig.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface GitHubWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret` key whose value is +the shared secret used to authenticate the webhook requests sent by GitHub. +For more information please refer to GitHub documentation: + https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/gitLabWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/gitLabWebhookReceiverConfig.ts new file mode 100644 index 0000000000..a2e38620d9 --- /dev/null +++ b/ui/src/gen/api/v2/models/gitLabWebhookReceiverConfig.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface GitLabWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The secret is expected to contain a `secret-token` key containing the +shared secret specified when registering the webhook in GitLab. For more +information about this token, please refer to the GitLab documentation: + https://docs.gitlab.com/user/project/integrations/webhooks/ + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/giteaWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/giteaWebhookReceiverConfig.ts new file mode 100644 index 0000000000..848c90f971 --- /dev/null +++ b/ui/src/gen/api/v2/models/giteaWebhookReceiverConfig.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface GiteaWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret` key whose value is +the shared secret used to authenticate the webhook requests sent by Gitea. +For more information please refer to the Gitea documentation: + https://docs.gitea.io/en-us/webhooks/ + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/grant200.ts b/ui/src/gen/api/v2/models/grant200.ts deleted file mode 100644 index 95cd2364a2..0000000000 --- a/ui/src/gen/api/v2/models/grant200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type Grant200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/harborWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/harborWebhookReceiverConfig.ts new file mode 100644 index 0000000000..a2156f845f --- /dev/null +++ b/ui/src/gen/api/v2/models/harborWebhookReceiverConfig.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface HarborWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The secret is expected to contain an `auth-header` key containing the "auth +header" specified when registering the webhook in Harbor. For more +information, please refer to the Harbor documentation: + https://goharbor.io/docs/main/working-with-projects/project-configuration/configure-webhooks/ + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/health.ts b/ui/src/gen/api/v2/models/health.ts new file mode 100644 index 0000000000..dcd91ce2bb --- /dev/null +++ b/ui/src/gen/api/v2/models/health.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { HealthConfig } from './healthConfig'; +import type { HealthOutput } from './healthOutput'; + +export interface Health { + /** Config is the opaque configuration of all health checks performed on this +Stage. */ + config?: HealthConfig; + /** Issues clarifies why a Stage in any state other than Healthy is in that +state. This field will always be the empty when a Stage is Healthy. */ + issues?: string[]; + /** Output is the opaque output of all health checks performed on this Stage. */ + output?: HealthOutput; + /** Status describes the health of the Stage. */ + status?: string; +} diff --git a/ui/src/gen/api/v2/models/healthCheckStep.ts b/ui/src/gen/api/v2/models/healthCheckStep.ts new file mode 100644 index 0000000000..c9de0c9b6f --- /dev/null +++ b/ui/src/gen/api/v2/models/healthCheckStep.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { HealthCheckStepConfig } from './healthCheckStepConfig'; + +export interface HealthCheckStep { + /** Config is the configuration for the directive. */ + config?: HealthCheckStepConfig; + /** Uses identifies a runner that can execute this step. + ++kubebuilder:validation:MinLength=1 */ + uses?: string; +} diff --git a/ui/src/gen/api/v2/models/healthCheckStepConfig.ts b/ui/src/gen/api/v2/models/healthCheckStepConfig.ts new file mode 100644 index 0000000000..60f41cfc73 --- /dev/null +++ b/ui/src/gen/api/v2/models/healthCheckStepConfig.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Config is the configuration for the directive. + */ +export type HealthCheckStepConfig = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/healthConfig.ts b/ui/src/gen/api/v2/models/healthConfig.ts new file mode 100644 index 0000000000..b70a4026cc --- /dev/null +++ b/ui/src/gen/api/v2/models/healthConfig.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Config is the opaque configuration of all health checks performed on this +Stage. + */ +export type HealthConfig = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/healthOutput.ts b/ui/src/gen/api/v2/models/healthOutput.ts new file mode 100644 index 0000000000..9547a15a2e --- /dev/null +++ b/ui/src/gen/api/v2/models/healthOutput.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Output is the opaque output of all health checks performed on this Stage. + */ +export type HealthOutput = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/healthStats.ts b/ui/src/gen/api/v2/models/healthStats.ts new file mode 100644 index 0000000000..c0a9d97bfe --- /dev/null +++ b/ui/src/gen/api/v2/models/healthStats.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface HealthStats { + /** Healthy contains the number of resources that are explicitly healthy. */ + healthy?: number; +} diff --git a/ui/src/gen/api/v2/models/image.ts b/ui/src/gen/api/v2/models/image.ts new file mode 100644 index 0000000000..59e03bd070 --- /dev/null +++ b/ui/src/gen/api/v2/models/image.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ImageAnnotations } from './imageAnnotations'; + +export interface Image { + /** Annotations is a map of arbitrary metadata for the image. */ + annotations?: ImageAnnotations; + /** Digest identifies a specific version of the image in the repository +specified by RepoURL. This is a more precise identifier than Tag. */ + digest?: string; + /** RepoURL describes the repository in which the image can be found. */ + repoURL?: string; + /** Tag identifies a specific version of the image in the repository specified +by RepoURL. */ + tag?: string; +} diff --git a/ui/src/gen/api/v2/models/imageAnnotations.ts b/ui/src/gen/api/v2/models/imageAnnotations.ts new file mode 100644 index 0000000000..0b86854eb9 --- /dev/null +++ b/ui/src/gen/api/v2/models/imageAnnotations.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Annotations is a map of arbitrary metadata for the image. + */ +export type ImageAnnotations = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/imageDiscoveryResult.ts b/ui/src/gen/api/v2/models/imageDiscoveryResult.ts new file mode 100644 index 0000000000..03c7d514a7 --- /dev/null +++ b/ui/src/gen/api/v2/models/imageDiscoveryResult.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { DiscoveredImageReference } from './discoveredImageReference'; + +export interface ImageDiscoveryResult { + /** Platform is the target platform constraint of the ImageSubscription +for which references were discovered. This field is optional, and +only populated if the ImageSubscription specifies a Platform. */ + platform?: string; + /** References is a list of image references discovered by the Warehouse for +the ImageSubscription. An empty list indicates that the discovery +operation was successful, but no images matching the ImageSubscription +criteria were found. + ++optional */ + references?: DiscoveredImageReference[]; + /** RepoURL is the repository URL of the image, as specified in the +ImageSubscription. + ++kubebuilder:validation:MinLength=1 */ + repoURL?: string; +} diff --git a/ui/src/gen/api/v2/models/index.ts b/ui/src/gen/api/v2/models/index.ts index 038f8f6ddb..9f6c0f9ea2 100644 --- a/ui/src/gen/api/v2/models/index.ts +++ b/ui/src/gen/api/v2/models/index.ts @@ -7,9 +7,29 @@ */ export * from './adminLoginResponse'; +export * from './analysisRunArgument'; +export * from './analysisRunMetadata'; +export * from './analysisRunMetadataAnnotations'; +export * from './analysisRunMetadataLabels'; +export * from './analysisRunReference'; +export * from './analysisTemplateReference'; export * from './approveFreightParams'; +export * from './approvedStage'; export * from './argoCDShard'; +export * from './artifactReference'; +export * from './artifactReferenceMetadata'; +export * from './artifactoryWebhookReceiverConfig'; +export * from './autoPromotionOptions'; +export * from './azureWebhookReceiverConfig'; +export * from './bitbucketWebhookReceiverConfig'; +export * from './chart'; +export * from './chartDiscoveryResult'; export * from './claim'; +export * from './clusterConfig'; +export * from './clusterConfigSpec'; +export * from './clusterConfigStatus'; +export * from './clusterPromotionTask'; +export * from './clusterPromotionTaskList'; export * from './createAPITokenRequest'; export * from './createAPITokenRequestBody'; export * from './createConfigMapRequest'; @@ -22,82 +42,72 @@ export * from './createOrUpdateResourceResponse'; export * from './createOrUpdateResourceResult'; export * from './createOrUpdateResourceResultCreatedResourceManifest'; export * from './createOrUpdateResourceResultUpdatedResourceManifest'; -export * from './createProjectAPIToken201'; -export * from './createProjectConfigMap201'; -export * from './createProjectGenericCredentials201'; -export * from './createProjectRepoCredentials201'; -export * from './createProjectRole201'; export * from './createProjectRoleBodyBody'; export * from './createRepoCredentialsRequest'; export * from './createRepoCredentialsRequestBody'; export * from './createResourceResponse'; export * from './createResourceResult'; export * from './createResourceResultCreatedResourceManifest'; -export * from './createSharedConfigMap201'; -export * from './createSharedGenericCredentials201'; -export * from './createSharedRepoCredentials201'; -export * from './createSystemAPIToken201'; -export * from './createSystemConfigMap201'; -export * from './createSystemGenericCredentials201'; +export * from './currentStage'; export * from './deleteResourceResponse'; export * from './deleteResourceResult'; export * from './deleteResourceResultDeletedResourceManifest'; -export * from './getAnalysisRun200'; +export * from './discoveredArtifacts'; +export * from './discoveredCommit'; +export * from './discoveredImageReference'; +export * from './discoveredImageReferenceAnnotations'; +export * from './discoveryResult'; +export * from './dockerHubWebhookReceiverConfig'; +export * from './expressionVariable'; +export * from './freight'; +export * from './freightCollection'; +export * from './freightCollectionItems'; +export * from './freightCreationCriteria'; +export * from './freightOrigin'; +export * from './freightReference'; +export * from './freightRequest'; +export * from './freightSources'; +export * from './freightStatus'; +export * from './freightStatusApprovedFor'; +export * from './freightStatusCurrentlyIn'; +export * from './freightStatusMetadata'; +export * from './freightStatusVerifiedIn'; +export * from './genericWebhookAction'; +export * from './genericWebhookActionParameters'; +export * from './genericWebhookReceiverConfig'; +export * from './genericWebhookTargetSelectionCriteria'; export * from './getAnalysisRunLogsParams'; -export * from './getAnalysisTemplate200'; -export * from './getClusterAnalysisTemplate200'; -export * from './getClusterConfig200'; -export * from './getClusterPromotionTask200'; export * from './getConfigResponse'; export * from './getConfigResponseArgocdShards'; -export * from './getFreight200'; -export * from './getProject200'; -export * from './getProjectAPIToken200'; -export * from './getProjectConfig200'; -export * from './getProjectConfigMap200'; -export * from './getProjectGenericCredentials200'; -export * from './getProjectRepoCredentials200'; export * from './getProjectRole200'; -export * from './getPromotion200'; -export * from './getPromotionTask200'; -export * from './getSharedConfigMap200'; -export * from './getSharedGenericCredentials200'; -export * from './getSharedRepoCredentials200'; -export * from './getStage200'; -export * from './getSystemAPIToken200'; -export * from './getSystemConfigMap200'; -export * from './getSystemGenericCredentials200'; export * from './getSystemRole200'; -export * from './getWarehouse200'; -export * from './grant200'; +export * from './gitCommit'; +export * from './gitDiscoveryResult'; +export * from './gitHubWebhookReceiverConfig'; +export * from './gitLabWebhookReceiverConfig'; +export * from './giteaWebhookReceiverConfig'; export * from './grantRequest'; +export * from './harborWebhookReceiverConfig'; +export * from './health'; +export * from './healthCheckStep'; +export * from './healthCheckStepConfig'; +export * from './healthConfig'; +export * from './healthOutput'; +export * from './healthStats'; +export * from './image'; +export * from './imageAnnotations'; +export * from './imageDiscoveryResult'; export * from './imageStageMap'; export * from './imageStageMapStages'; -export * from './listAnalysisTemplates200'; -export * from './listClusterAnalysisTemplates200'; -export * from './listClusterPromotionTasks200'; +export * from './indexSelector'; +export * from './indexSelectorRequirement'; +export * from './intOrString'; export * from './listImages200'; -export * from './listProjectAPITokens200'; export * from './listProjectAPITokensParams'; -export * from './listProjectConfigMaps200'; -export * from './listProjectEvents200'; -export * from './listProjectGenericCredentials200'; -export * from './listProjectRepoCredentials200'; export * from './listProjectRoles200'; -export * from './listProjects200'; -export * from './listPromotionTasks200'; -export * from './listPromotions200'; export * from './listPromotionsParams'; -export * from './listSharedConfigMaps200'; -export * from './listSharedGenericCredentials200'; -export * from './listSharedRepoCredentials200'; -export * from './listStages200'; -export * from './listSystemAPITokens200'; export * from './listSystemAPITokensParams'; -export * from './listSystemConfigMaps200'; -export * from './listSystemGenericCredentials200'; export * from './listSystemRoles200'; -export * from './listWarehouses200'; export * from './oIDCConfig'; export * from './patchConfigMapRequest'; export * from './patchConfigMapRequestBody'; @@ -106,26 +116,97 @@ export * from './patchFreightAliasParams'; export * from './patchGenericCredentialsRequest'; export * from './patchGenericCredentialsRequestBody'; export * from './patchGenericCredentialsRequestData'; -export * from './patchProjectConfigMap200'; -export * from './patchProjectGenericCredentials200'; -export * from './patchProjectRepoCredentials200'; export * from './patchRepoCredentialsRequest'; export * from './patchRepoCredentialsRequestBody'; -export * from './patchSharedConfigMap200'; -export * from './patchSharedGenericCredentials200'; -export * from './patchSharedRepoCredentials200'; -export * from './patchSystemConfigMap200'; -export * from './patchSystemGenericCredentials200'; +export * from './project'; +export * from './projectConfig'; +export * from './projectConfigSpec'; +export * from './projectConfigStatus'; +export * from './projectList'; +export * from './projectStats'; +export * from './projectStatus'; export * from './promoteDownstream201'; export * from './promoteDownstreamRequest'; -export * from './promoteToStage201'; export * from './promoteToStageRequest'; +export * from './promotion'; +export * from './promotionList'; +export * from './promotionPolicy'; +export * from './promotionPolicySelector'; +export * from './promotionPolicySelectorMatchLabels'; +export * from './promotionReference'; +export * from './promotionSpec'; +export * from './promotionStatus'; +export * from './promotionStatusState'; +export * from './promotionStep'; +export * from './promotionStepConfig'; +export * from './promotionStepRetry'; +export * from './promotionTask'; +export * from './promotionTaskList'; +export * from './promotionTaskReference'; +export * from './promotionTaskSpec'; +export * from './promotionTemplate'; +export * from './promotionTemplateSpec'; export * from './publicConfig'; +export * from './quantity'; +export * from './quantityFormat'; +export * from './quayWebhookReceiverConfig'; export * from './queryFreightsRest200'; export * from './queryFreightsRestParams'; +export * from './rbacRole'; export * from './resourceDetails'; -export * from './revoke200'; export * from './revokeRequest'; +export * from './rolloutsAnalysisRun'; +export * from './rolloutsAnalysisRunSpec'; +export * from './rolloutsAnalysisRunStatus'; +export * from './rolloutsAnalysisTemplate'; +export * from './rolloutsAnalysisTemplateList'; +export * from './rolloutsAnalysisTemplateSpec'; +export * from './rolloutsArgument'; +export * from './rolloutsAuthentication'; +export * from './rolloutsCloudWatchMetric'; +export * from './rolloutsCloudWatchMetricDataQuery'; +export * from './rolloutsCloudWatchMetricStat'; +export * from './rolloutsCloudWatchMetricStatMetric'; +export * from './rolloutsCloudWatchMetricStatMetricDimension'; +export * from './rolloutsClusterAnalysisTemplate'; +export * from './rolloutsClusterAnalysisTemplateList'; +export * from './rolloutsDatadogMetric'; +export * from './rolloutsDatadogMetricQueries'; +export * from './rolloutsDryRun'; +export * from './rolloutsFieldRef'; +export * from './rolloutsGraphiteMetric'; +export * from './rolloutsInfluxdbMetric'; +export * from './rolloutsJobMetric'; +export * from './rolloutsKayentaMetric'; +export * from './rolloutsKayentaScope'; +export * from './rolloutsKayentaThreshold'; +export * from './rolloutsMeasurement'; +export * from './rolloutsMeasurementMetadata'; +export * from './rolloutsMeasurementRetention'; +export * from './rolloutsMetric'; +export * from './rolloutsMetricProvider'; +export * from './rolloutsMetricProviderPlugin'; +export * from './rolloutsMetricResult'; +export * from './rolloutsMetricResultMetadata'; +export * from './rolloutsNewRelicMetric'; +export * from './rolloutsOAuth2Config'; +export * from './rolloutsPrometheusMetric'; +export * from './rolloutsRunSummary'; +export * from './rolloutsScopeDetail'; +export * from './rolloutsSecretKeyRef'; +export * from './rolloutsSigv4Config'; +export * from './rolloutsSkyWalkingMetric'; +export * from './rolloutsValueFrom'; +export * from './rolloutsWavefrontMetric'; +export * from './rolloutsWebMetric'; +export * from './rolloutsWebMetricHeader'; +export * from './stage'; +export * from './stageList'; +export * from './stageSpec'; +export * from './stageStats'; +export * from './stageStatus'; +export * from './stageStatusMetadata'; +export * from './stepExecutionMetadata'; export * from './tagMap'; export * from './tagMapTags'; export * from './updateConfigMapRequest'; @@ -134,18 +215,165 @@ export * from './updateConfigMapRequestData'; export * from './updateGenericCredentialsRequest'; export * from './updateGenericCredentialsRequestBody'; export * from './updateGenericCredentialsRequestData'; -export * from './updateProjectConfigMap200'; -export * from './updateProjectGenericCredentials200'; -export * from './updateProjectRepoCredentials200'; export * from './updateRepoCredentialsRequest'; export * from './updateRepoCredentialsRequestBody'; export * from './updateResourceManifestBody'; export * from './updateResourceParams'; -export * from './updateRole200'; -export * from './updateSharedConfigMap200'; -export * from './updateSharedGenericCredentials200'; -export * from './updateSharedRepoCredentials200'; -export * from './updateSystemConfigMap200'; -export * from './updateSystemGenericCredentials200'; export * from './userClaims'; +export * from './v1AWSElasticBlockStoreVolumeSource'; +export * from './v1Affinity'; +export * from './v1AppArmorProfile'; +export * from './v1AzureDiskVolumeSource'; +export * from './v1AzureFileVolumeSource'; +export * from './v1CSIVolumeSource'; +export * from './v1CSIVolumeSourceVolumeAttributes'; +export * from './v1Capabilities'; +export * from './v1CephFSVolumeSource'; +export * from './v1CinderVolumeSource'; +export * from './v1ClusterTrustBundleProjection'; +export * from './v1CompletionMode'; +export * from './v1Condition'; +export * from './v1ConfigMap'; +export * from './v1ConfigMapBinaryData'; +export * from './v1ConfigMapData'; +export * from './v1ConfigMapEnvSource'; +export * from './v1ConfigMapKeySelector'; +export * from './v1ConfigMapList'; +export * from './v1ConfigMapProjection'; +export * from './v1ConfigMapVolumeSource'; +export * from './v1Container'; +export * from './v1ContainerPort'; +export * from './v1ContainerResizePolicy'; +export * from './v1ContainerRestartRule'; +export * from './v1ContainerRestartRuleOnExitCodes'; +export * from './v1DownwardAPIProjection'; +export * from './v1DownwardAPIVolumeFile'; +export * from './v1DownwardAPIVolumeSource'; +export * from './v1EmptyDirVolumeSource'; +export * from './v1EnvFromSource'; +export * from './v1EnvVar'; +export * from './v1EnvVarSource'; +export * from './v1EphemeralContainer'; +export * from './v1EphemeralVolumeSource'; +export * from './v1Event'; +export * from './v1EventList'; +export * from './v1EventSeries'; +export * from './v1EventSource'; +export * from './v1ExecAction'; +export * from './v1FCVolumeSource'; +export * from './v1FieldsV1'; +export * from './v1FileKeySelector'; +export * from './v1FlexVolumeSource'; +export * from './v1FlexVolumeSourceOptions'; +export * from './v1FlockerVolumeSource'; +export * from './v1GCEPersistentDiskVolumeSource'; +export * from './v1GRPCAction'; +export * from './v1GitRepoVolumeSource'; +export * from './v1GlusterfsVolumeSource'; +export * from './v1HTTPGetAction'; +export * from './v1HTTPHeader'; +export * from './v1HostAlias'; +export * from './v1HostPathVolumeSource'; +export * from './v1ISCSIVolumeSource'; +export * from './v1ImageVolumeSource'; +export * from './v1JobSpec'; +export * from './v1KeyToPath'; +export * from './v1LabelSelector'; +export * from './v1LabelSelectorMatchLabels'; +export * from './v1LabelSelectorRequirement'; +export * from './v1Lifecycle'; +export * from './v1LifecycleHandler'; +export * from './v1ListMeta'; +export * from './v1LocalObjectReference'; +export * from './v1ManagedFieldsEntry'; +export * from './v1MicroTime'; +export * from './v1NFSVolumeSource'; +export * from './v1NodeAffinity'; +export * from './v1NodeSelector'; +export * from './v1NodeSelectorRequirement'; +export * from './v1NodeSelectorTerm'; +export * from './v1ObjectFieldSelector'; +export * from './v1ObjectMeta'; +export * from './v1ObjectMetaAnnotations'; +export * from './v1ObjectMetaLabels'; +export * from './v1ObjectReference'; +export * from './v1OwnerReference'; +export * from './v1PersistentVolumeClaimSpec'; +export * from './v1PersistentVolumeClaimTemplate'; +export * from './v1PersistentVolumeClaimVolumeSource'; +export * from './v1PhotonPersistentDiskVolumeSource'; +export * from './v1PodAffinity'; +export * from './v1PodAffinityTerm'; +export * from './v1PodAntiAffinity'; +export * from './v1PodCertificateProjection'; +export * from './v1PodDNSConfig'; +export * from './v1PodDNSConfigOption'; +export * from './v1PodFailurePolicy'; +export * from './v1PodFailurePolicyAction'; +export * from './v1PodFailurePolicyOnExitCodesOperator'; +export * from './v1PodFailurePolicyOnExitCodesRequirement'; +export * from './v1PodFailurePolicyOnPodConditionsPattern'; +export * from './v1PodFailurePolicyRule'; +export * from './v1PodOS'; +export * from './v1PodReadinessGate'; +export * from './v1PodReplacementPolicy'; +export * from './v1PodResourceClaim'; +export * from './v1PodSchedulingGate'; +export * from './v1PodSecurityContext'; +export * from './v1PodSpec'; +export * from './v1PodSpecNodeSelector'; +export * from './v1PodTemplateSpec'; +export * from './v1PolicyRule'; +export * from './v1PortworxVolumeSource'; +export * from './v1PreferredSchedulingTerm'; +export * from './v1Probe'; +export * from './v1ProjectedVolumeSource'; +export * from './v1QuobyteVolumeSource'; +export * from './v1RBDVolumeSource'; +export * from './v1ResourceClaim'; +export * from './v1ResourceFieldSelector'; +export * from './v1ResourceList'; +export * from './v1ResourceRequirements'; +export * from './v1SELinuxOptions'; +export * from './v1ScaleIOVolumeSource'; +export * from './v1SeccompProfile'; +export * from './v1Secret'; +export * from './v1SecretData'; +export * from './v1SecretEnvSource'; +export * from './v1SecretKeySelector'; +export * from './v1SecretList'; +export * from './v1SecretProjection'; +export * from './v1SecretStringData'; +export * from './v1SecretVolumeSource'; +export * from './v1SecurityContext'; +export * from './v1ServiceAccountTokenProjection'; +export * from './v1SleepAction'; +export * from './v1StorageOSVolumeSource'; +export * from './v1SuccessPolicy'; +export * from './v1SuccessPolicyRule'; +export * from './v1Sysctl'; +export * from './v1TCPSocketAction'; +export * from './v1Toleration'; +export * from './v1TopologySpreadConstraint'; +export * from './v1TypedLocalObjectReference'; +export * from './v1TypedObjectReference'; +export * from './v1Volume'; +export * from './v1VolumeDevice'; +export * from './v1VolumeMount'; +export * from './v1VolumeProjection'; +export * from './v1VolumeResourceRequirements'; +export * from './v1VsphereVirtualDiskVolumeSource'; +export * from './v1WeightedPodAffinityTerm'; +export * from './v1WindowsSecurityContextOptions'; +export * from './verification'; +export * from './verificationInfo'; +export * from './verifiedStage'; export * from './versionInfo'; +export * from './warehouse'; +export * from './warehouseList'; +export * from './warehouseSpec'; +export * from './warehouseSpecSubscriptionsItem'; +export * from './warehouseStats'; +export * from './warehouseStatus'; +export * from './webhookReceiverConfig'; +export * from './webhookReceiverDetails'; diff --git a/ui/src/gen/api/v2/models/indexSelector.ts b/ui/src/gen/api/v2/models/indexSelector.ts new file mode 100644 index 0000000000..684d405976 --- /dev/null +++ b/ui/src/gen/api/v2/models/indexSelector.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { IndexSelectorRequirement } from './indexSelectorRequirement'; + +export interface IndexSelector { + /** MatchIndices is a list of index selector requirements. + ++kubebuilder:validation:MinItems=1 */ + matchIndices?: IndexSelectorRequirement[]; +} diff --git a/ui/src/gen/api/v2/models/indexSelectorRequirement.ts b/ui/src/gen/api/v2/models/indexSelectorRequirement.ts new file mode 100644 index 0000000000..1952c5d63e --- /dev/null +++ b/ui/src/gen/api/v2/models/indexSelectorRequirement.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface IndexSelectorRequirement { + /** Key is the key of the index. + ++kubebuilder:validation:Enum=subscribedURLs;receiverPaths */ + key?: string; + /** Operator indicates the operation that should be used to evaluate +whether the selection requirement is satisfied. + +kubebuilder:validation:Enum=Equal;NotEqual; */ + operator?: string; + /** Value can be a static string or an expression that will be evaluated. + +kubebuilder:validation:Required */ + value?: string; +} diff --git a/ui/src/gen/api/v2/models/intOrString.ts b/ui/src/gen/api/v2/models/intOrString.ts new file mode 100644 index 0000000000..06b7e3397b --- /dev/null +++ b/ui/src/gen/api/v2/models/intOrString.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface IntOrString { + intVal?: number; + strVal?: string; + type?: number; +} diff --git a/ui/src/gen/api/v2/models/listAnalysisTemplates200.ts b/ui/src/gen/api/v2/models/listAnalysisTemplates200.ts deleted file mode 100644 index 401fde4783..0000000000 --- a/ui/src/gen/api/v2/models/listAnalysisTemplates200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListAnalysisTemplates200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listClusterAnalysisTemplates200.ts b/ui/src/gen/api/v2/models/listClusterAnalysisTemplates200.ts deleted file mode 100644 index dcc783b776..0000000000 --- a/ui/src/gen/api/v2/models/listClusterAnalysisTemplates200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListClusterAnalysisTemplates200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listClusterPromotionTasks200.ts b/ui/src/gen/api/v2/models/listClusterPromotionTasks200.ts deleted file mode 100644 index baf667a81e..0000000000 --- a/ui/src/gen/api/v2/models/listClusterPromotionTasks200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListClusterPromotionTasks200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listProjectAPITokens200.ts b/ui/src/gen/api/v2/models/listProjectAPITokens200.ts deleted file mode 100644 index f4cb6ad056..0000000000 --- a/ui/src/gen/api/v2/models/listProjectAPITokens200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListProjectAPITokens200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listProjectConfigMaps200.ts b/ui/src/gen/api/v2/models/listProjectConfigMaps200.ts deleted file mode 100644 index 90e5080409..0000000000 --- a/ui/src/gen/api/v2/models/listProjectConfigMaps200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListProjectConfigMaps200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listProjectEvents200.ts b/ui/src/gen/api/v2/models/listProjectEvents200.ts deleted file mode 100644 index a0d38e136e..0000000000 --- a/ui/src/gen/api/v2/models/listProjectEvents200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListProjectEvents200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listProjectGenericCredentials200.ts b/ui/src/gen/api/v2/models/listProjectGenericCredentials200.ts deleted file mode 100644 index 1d310f2243..0000000000 --- a/ui/src/gen/api/v2/models/listProjectGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListProjectGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listProjectRepoCredentials200.ts b/ui/src/gen/api/v2/models/listProjectRepoCredentials200.ts deleted file mode 100644 index 75486dd0b2..0000000000 --- a/ui/src/gen/api/v2/models/listProjectRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListProjectRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listProjects200.ts b/ui/src/gen/api/v2/models/listProjects200.ts deleted file mode 100644 index 6efeaf796c..0000000000 --- a/ui/src/gen/api/v2/models/listProjects200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListProjects200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listPromotionTasks200.ts b/ui/src/gen/api/v2/models/listPromotionTasks200.ts deleted file mode 100644 index d0539add95..0000000000 --- a/ui/src/gen/api/v2/models/listPromotionTasks200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListPromotionTasks200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listPromotions200.ts b/ui/src/gen/api/v2/models/listPromotions200.ts deleted file mode 100644 index 56e20696c8..0000000000 --- a/ui/src/gen/api/v2/models/listPromotions200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListPromotions200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listSharedConfigMaps200.ts b/ui/src/gen/api/v2/models/listSharedConfigMaps200.ts deleted file mode 100644 index 2a11ec0256..0000000000 --- a/ui/src/gen/api/v2/models/listSharedConfigMaps200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListSharedConfigMaps200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listSharedGenericCredentials200.ts b/ui/src/gen/api/v2/models/listSharedGenericCredentials200.ts deleted file mode 100644 index d1832ad742..0000000000 --- a/ui/src/gen/api/v2/models/listSharedGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListSharedGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listSharedRepoCredentials200.ts b/ui/src/gen/api/v2/models/listSharedRepoCredentials200.ts deleted file mode 100644 index 66a95a2e92..0000000000 --- a/ui/src/gen/api/v2/models/listSharedRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListSharedRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listStages200.ts b/ui/src/gen/api/v2/models/listStages200.ts deleted file mode 100644 index e35dde3113..0000000000 --- a/ui/src/gen/api/v2/models/listStages200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListStages200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listSystemAPITokens200.ts b/ui/src/gen/api/v2/models/listSystemAPITokens200.ts deleted file mode 100644 index 1185cf8fb2..0000000000 --- a/ui/src/gen/api/v2/models/listSystemAPITokens200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListSystemAPITokens200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listSystemConfigMaps200.ts b/ui/src/gen/api/v2/models/listSystemConfigMaps200.ts deleted file mode 100644 index 2b6f69139d..0000000000 --- a/ui/src/gen/api/v2/models/listSystemConfigMaps200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListSystemConfigMaps200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listSystemGenericCredentials200.ts b/ui/src/gen/api/v2/models/listSystemGenericCredentials200.ts deleted file mode 100644 index b09484552d..0000000000 --- a/ui/src/gen/api/v2/models/listSystemGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListSystemGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/listWarehouses200.ts b/ui/src/gen/api/v2/models/listWarehouses200.ts deleted file mode 100644 index 4084703815..0000000000 --- a/ui/src/gen/api/v2/models/listWarehouses200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type ListWarehouses200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchProjectConfigMap200.ts b/ui/src/gen/api/v2/models/patchProjectConfigMap200.ts deleted file mode 100644 index dba5197a97..0000000000 --- a/ui/src/gen/api/v2/models/patchProjectConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchProjectConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchProjectGenericCredentials200.ts b/ui/src/gen/api/v2/models/patchProjectGenericCredentials200.ts deleted file mode 100644 index 9a04cc5cf6..0000000000 --- a/ui/src/gen/api/v2/models/patchProjectGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchProjectGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchProjectRepoCredentials200.ts b/ui/src/gen/api/v2/models/patchProjectRepoCredentials200.ts deleted file mode 100644 index 774e417d75..0000000000 --- a/ui/src/gen/api/v2/models/patchProjectRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchProjectRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchSharedConfigMap200.ts b/ui/src/gen/api/v2/models/patchSharedConfigMap200.ts deleted file mode 100644 index 158723b0f3..0000000000 --- a/ui/src/gen/api/v2/models/patchSharedConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchSharedConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchSharedGenericCredentials200.ts b/ui/src/gen/api/v2/models/patchSharedGenericCredentials200.ts deleted file mode 100644 index 005effa6b0..0000000000 --- a/ui/src/gen/api/v2/models/patchSharedGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchSharedGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchSharedRepoCredentials200.ts b/ui/src/gen/api/v2/models/patchSharedRepoCredentials200.ts deleted file mode 100644 index 0040db53aa..0000000000 --- a/ui/src/gen/api/v2/models/patchSharedRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchSharedRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchSystemConfigMap200.ts b/ui/src/gen/api/v2/models/patchSystemConfigMap200.ts deleted file mode 100644 index a09ee2ca09..0000000000 --- a/ui/src/gen/api/v2/models/patchSystemConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchSystemConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/patchSystemGenericCredentials200.ts b/ui/src/gen/api/v2/models/patchSystemGenericCredentials200.ts deleted file mode 100644 index 99c64741ed..0000000000 --- a/ui/src/gen/api/v2/models/patchSystemGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PatchSystemGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/project.ts b/ui/src/gen/api/v2/models/project.ts new file mode 100644 index 0000000000..e858625520 --- /dev/null +++ b/ui/src/gen/api/v2/models/project.ts @@ -0,0 +1,28 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { ProjectStatus } from './projectStatus'; + +export interface Project { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Status describes the Project's current status. */ + status?: ProjectStatus; +} diff --git a/ui/src/gen/api/v2/models/projectConfig.ts b/ui/src/gen/api/v2/models/projectConfig.ts new file mode 100644 index 0000000000..f91a89047d --- /dev/null +++ b/ui/src/gen/api/v2/models/projectConfig.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { ProjectConfigSpec } from './projectConfigSpec'; +import type { ProjectConfigStatus } from './projectConfigStatus'; + +export interface ProjectConfig { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes the configuration of a Project. */ + spec?: ProjectConfigSpec; + /** Status describes the current status of a ProjectConfig. */ + status?: ProjectConfigStatus; +} diff --git a/ui/src/gen/api/v2/models/projectConfigSpec.ts b/ui/src/gen/api/v2/models/projectConfigSpec.ts new file mode 100644 index 0000000000..54a8799023 --- /dev/null +++ b/ui/src/gen/api/v2/models/projectConfigSpec.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionPolicy } from './promotionPolicy'; +import type { WebhookReceiverConfig } from './webhookReceiverConfig'; + +export interface ProjectConfigSpec { + /** PromotionPolicies defines policies governing the promotion of Freight to +specific Stages within the Project. */ + promotionPolicies?: PromotionPolicy[]; + /** WebhookReceivers describes Project-specific webhook receivers used for +processing events from various external platforms */ + webhookReceivers?: WebhookReceiverConfig[]; +} diff --git a/ui/src/gen/api/v2/models/projectConfigStatus.ts b/ui/src/gen/api/v2/models/projectConfigStatus.ts new file mode 100644 index 0000000000..fd268607f7 --- /dev/null +++ b/ui/src/gen/api/v2/models/projectConfigStatus.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Condition } from './v1Condition'; +import type { WebhookReceiverDetails } from './webhookReceiverDetails'; + +export interface ProjectConfigStatus { + /** Conditions contains the last observations of the Project Config's current +state. + ++patchMergeKey=type ++patchStrategy=merge ++listType=map ++listMapKey=type */ + conditions?: V1Condition[]; + /** LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh +annotation that was handled by the controller. This field can be used to +determine whether the request to refresh the resource has been handled. ++optional */ + lastHandledRefresh?: string; + /** ObservedGeneration represents the .metadata.generation that this +ProjectConfig was reconciled against. */ + observedGeneration?: number; + /** WebhookReceivers describes the status of Project-specific webhook +receivers. */ + webhookReceivers?: WebhookReceiverDetails[]; +} diff --git a/ui/src/gen/api/v2/models/projectList.ts b/ui/src/gen/api/v2/models/projectList.ts new file mode 100644 index 0000000000..301d334371 --- /dev/null +++ b/ui/src/gen/api/v2/models/projectList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Project } from './project'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface ProjectList { + /** 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 ++optional */ + apiVersion?: string; + items?: Project[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/projectStats.ts b/ui/src/gen/api/v2/models/projectStats.ts new file mode 100644 index 0000000000..10efdb1a8b --- /dev/null +++ b/ui/src/gen/api/v2/models/projectStats.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { StageStats } from './stageStats'; +import type { WarehouseStats } from './warehouseStats'; + +export interface ProjectStats { + /** Stages contains a summary of the collective state of the Project's Stages. */ + stages?: StageStats; + /** Warehouses contains a summary of the collective state of the Project's +Warehouses. */ + warehouses?: WarehouseStats; +} diff --git a/ui/src/gen/api/v2/models/projectStatus.ts b/ui/src/gen/api/v2/models/projectStatus.ts new file mode 100644 index 0000000000..a932c0f1fd --- /dev/null +++ b/ui/src/gen/api/v2/models/projectStatus.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Condition } from './v1Condition'; +import type { ProjectStats } from './projectStats'; + +export interface ProjectStatus { + /** Conditions contains the last observations of the Project's current +state. ++patchMergeKey=type ++patchStrategy=merge ++listType=map ++listMapKey=type */ + conditions?: V1Condition[]; + /** Stats contains a summary of the collective state of a Project's +constituent resources. */ + stats?: ProjectStats; +} diff --git a/ui/src/gen/api/v2/models/promoteToStage201.ts b/ui/src/gen/api/v2/models/promoteToStage201.ts deleted file mode 100644 index f4b09ea73a..0000000000 --- a/ui/src/gen/api/v2/models/promoteToStage201.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type PromoteToStage201 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/promotion.ts b/ui/src/gen/api/v2/models/promotion.ts new file mode 100644 index 0000000000..2a50a7ff0c --- /dev/null +++ b/ui/src/gen/api/v2/models/promotion.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { PromotionSpec } from './promotionSpec'; +import type { PromotionStatus } from './promotionStatus'; + +export interface Promotion { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes the desired transition of a specific Stage into a specific +Freight. + ++kubebuilder:validation:Required */ + spec: PromotionSpec; + /** Status describes the current state of the transition represented by this +Promotion. */ + status?: PromotionStatus; +} diff --git a/ui/src/gen/api/v2/models/promotionList.ts b/ui/src/gen/api/v2/models/promotionList.ts new file mode 100644 index 0000000000..a84ca66407 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Promotion } from './promotion'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface PromotionList { + /** 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 ++optional */ + apiVersion?: string; + items?: Promotion[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/promotionPolicy.ts b/ui/src/gen/api/v2/models/promotionPolicy.ts new file mode 100644 index 0000000000..16e06b221c --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionPolicy.ts @@ -0,0 +1,28 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionPolicySelector } from './promotionPolicySelector'; + +export interface PromotionPolicy { + /** AutoPromotionEnabled indicates whether new Freight can automatically be +promoted into the Stage referenced by the Stage field. Note: There are may +be other conditions also required for an auto-promotion to occur. This +field defaults to false, but is commonly set to true for Stages that +subscribe to Warehouses instead of other, upstream Stages. This allows +users to define Stages that are automatically updated as soon as new +artifacts are detected. */ + autoPromotionEnabled?: boolean; + /** Stage is the name of the Stage to which this policy applies. + +Deprecated: Use StageSelector instead. + ++kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ */ + stage?: string; + /** StageSelector is a selector that matches the Stage resource to which +this policy applies. */ + stageSelector?: PromotionPolicySelector; +} diff --git a/ui/src/gen/api/v2/models/promotionPolicySelector.ts b/ui/src/gen/api/v2/models/promotionPolicySelector.ts new file mode 100644 index 0000000000..ff0dae4b3b --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionPolicySelector.ts @@ -0,0 +1,39 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LabelSelectorRequirement } from './v1LabelSelectorRequirement'; +import type { PromotionPolicySelectorMatchLabels } from './promotionPolicySelectorMatchLabels'; + +export interface PromotionPolicySelector { + /** matchExpressions is a list of label selector requirements. The requirements are ANDed. ++optional ++listType=atomic */ + matchExpressions?: V1LabelSelectorRequirement[]; + /** matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is "key", the +operator is "In", and the values array contains only "value". The requirements are ANDed. ++optional */ + matchLabels?: PromotionPolicySelectorMatchLabels; + /** Name is the name of the resource to which this policy applies. + +It can be an exact name, a regex pattern (with prefix "regex:"), or a +glob pattern (with prefix "glob:"). + +When both Name and LabelSelector are specified, the Name is ANDed with +the LabelSelector. I.e., the resource must match both the Name and +LabelSelector to be selected by this policy. + +NOTE: Using a specific exact name is the most secure option. Pattern +matching via regex or glob can be exploited by users with permissions to +match promotion policies that weren't intended to apply to their +resources. For example, a user could create a resource with a name +deliberately crafted to match the pattern, potentially bypassing intended +promotion controls. + ++optional */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/promotionPolicySelectorMatchLabels.ts b/ui/src/gen/api/v2/models/promotionPolicySelectorMatchLabels.ts new file mode 100644 index 0000000000..5756b7bdc7 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionPolicySelectorMatchLabels.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is "key", the +operator is "In", and the values array contains only "value". The requirements are ANDed. ++optional + */ +export type PromotionPolicySelectorMatchLabels = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/promotionReference.ts b/ui/src/gen/api/v2/models/promotionReference.ts new file mode 100644 index 0000000000..9b7d0bb0d4 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionReference.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightReference } from './freightReference'; +import type { PromotionStatus } from './promotionStatus'; + +export interface PromotionReference { + /** FinishedAt is the time at which the Promotion was completed. */ + finishedAt?: string; + /** Freight is the freight being promoted. */ + freight?: FreightReference; + /** Name is the name of the Promotion. */ + name?: string; + /** Status is the (optional) status of the Promotion. */ + status?: PromotionStatus; +} diff --git a/ui/src/gen/api/v2/models/promotionSpec.ts b/ui/src/gen/api/v2/models/promotionSpec.ts new file mode 100644 index 0000000000..61bf7023fc --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionSpec.ts @@ -0,0 +1,42 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionStep } from './promotionStep'; +import type { ExpressionVariable } from './expressionVariable'; + +export interface PromotionSpec { + /** Freight specifies the piece of Freight to be promoted into the Stage +referenced by the Stage field. + ++kubebuilder:validation:Required ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:MaxLength=253 ++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` ++akuity:test-kubebuilder-pattern=KubernetesName */ + freight: string; + /** Stage specifies the name of the Stage to which this Promotion +applies. The Stage referenced by this field MUST be in the same +namespace as the Promotion. + ++kubebuilder:validation:Required ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:MaxLength=253 ++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` ++akuity:test-kubebuilder-pattern=KubernetesName */ + stage: string; + /** Steps specifies the directives to be executed as part of this Promotion. +The order in which the directives are executed is the order in which they +are listed in this field. + ++kubebuilder:validation:Required ++kubebuilder:validation:MinItems=1 ++kubebuilder:validation:items:XValidation:message="Promotion step must have uses set and must not reference a task",rule="has(self.uses) && !has(self.task)" */ + steps: PromotionStep[]; + /** Vars is a list of variables that can be referenced by expressions in +promotion steps. */ + vars?: ExpressionVariable[]; +} diff --git a/ui/src/gen/api/v2/models/promotionStatus.ts b/ui/src/gen/api/v2/models/promotionStatus.ts new file mode 100644 index 0000000000..bb5fa787fa --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionStatus.ts @@ -0,0 +1,50 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightReference } from './freightReference'; +import type { FreightCollection } from './freightCollection'; +import type { HealthCheckStep } from './healthCheckStep'; +import type { PromotionStatusState } from './promotionStatusState'; +import type { StepExecutionMetadata } from './stepExecutionMetadata'; + +export interface PromotionStatus { + /** CurrentStep is the index of the current promotion step being executed. This +permits steps that have already run successfully to be skipped on +subsequent reconciliations attempts. */ + currentStep?: number; + /** FinishedAt is the time when the promotion was completed. */ + finishedAt?: string; + /** Freight is the detail of the piece of freight that was referenced by this promotion. */ + freight?: FreightReference; + /** FreightCollection contains the details of the piece of Freight referenced +by this Promotion as well as any additional Freight that is carried over +from the target Stage's current state. */ + freightCollection?: FreightCollection; + /** HealthChecks contains the health check directives to be executed after +the Promotion has completed. */ + healthChecks?: HealthCheckStep[]; + /** LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh +annotation that was handled by the controller. This field can be used to +determine whether the request to refresh the resource has been handled. ++optional */ + lastHandledRefresh?: string; + /** Message is a display message about the promotion, including any errors +preventing the Promotion controller from executing this Promotion. +i.e. If the Phase field has a value of Failed, this field can be expected +to explain why. */ + message?: string; + /** Phase describes where the Promotion currently is in its lifecycle. */ + phase?: string; + /** StartedAt is the time when the promotion started. */ + startedAt?: string; + /** State stores the state of the promotion process between reconciliation +attempts. */ + state?: PromotionStatusState; + /** StepExecutionMetadata tracks metadata pertaining to the execution +of individual promotion steps. */ + stepExecutionMetadata?: StepExecutionMetadata[]; +} diff --git a/ui/src/gen/api/v2/models/promotionStatusState.ts b/ui/src/gen/api/v2/models/promotionStatusState.ts new file mode 100644 index 0000000000..1e9db1bd1e --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionStatusState.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * State stores the state of the promotion process between reconciliation +attempts. + */ +export type PromotionStatusState = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/promotionStep.ts b/ui/src/gen/api/v2/models/promotionStep.ts new file mode 100644 index 0000000000..42ea80d0a7 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionStep.ts @@ -0,0 +1,45 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionStepConfig } from './promotionStepConfig'; +import type { PromotionStepRetry } from './promotionStepRetry'; +import type { PromotionTaskReference } from './promotionTaskReference'; +import type { ExpressionVariable } from './expressionVariable'; + +export interface PromotionStep { + /** As is the alias this step can be referred to as. */ + as?: string; + /** Config is opaque configuration for the PromotionStep that is understood +only by each PromotionStep's implementation. It is legal to utilize +expressions in defining values at any level of this block. +See https://docs.kargo.io/user-guide/reference-docs/expressions for details. */ + config?: PromotionStepConfig; + /** ContinueOnError is a boolean value that, if set to true, will cause the +Promotion to continue executing the next step even if this step fails. It +also will not permit this failure to impact the overall status of the +Promotion. */ + continueOnError?: boolean; + /** If is an optional expression that, if present, must evaluate to a boolean +value. If the expression evaluates to false, the step will be skipped. +If the expression does not evaluate to a boolean value, the step will be +considered to have failed. */ + if?: string; + /** Retry is the retry policy for this step. */ + retry?: PromotionStepRetry; + /** Task is a reference to a PromotionTask that should be inflated into a +Promotion when it is built from a PromotionTemplate. */ + task?: PromotionTaskReference; + /** Uses identifies a runner that can execute this step. + ++kubebuilder:validation:Optional ++kubebuilder:validation:MinLength=1 */ + uses?: string; + /** Vars is a list of variables that can be referenced by expressions in +the step's Config. The values override the values specified in the +PromotionSpec. */ + vars?: ExpressionVariable[]; +} diff --git a/ui/src/gen/api/v2/models/promotionStepConfig.ts b/ui/src/gen/api/v2/models/promotionStepConfig.ts new file mode 100644 index 0000000000..187bdcca71 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionStepConfig.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Config is opaque configuration for the PromotionStep that is understood +only by each PromotionStep's implementation. It is legal to utilize +expressions in defining values at any level of this block. +See https://docs.kargo.io/user-guide/reference-docs/expressions for details. + */ +export type PromotionStepConfig = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/promotionStepRetry.ts b/ui/src/gen/api/v2/models/promotionStepRetry.ts new file mode 100644 index 0000000000..d82c79468e --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionStepRetry.ts @@ -0,0 +1,45 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface PromotionStepRetry { + /** ErrorThreshold is the number of consecutive times the step must fail (for +any reason) before retries are abandoned and the entire Promotion is marked +as failed. + +If this field is set to 0, the effective default will be a step-specific +one. If no step-specific default exists (i.e. is also 0), the effective +default will be the system-wide default of 1. + +A value of 1 will cause the Promotion to be marked as failed after just +a single failure; i.e. no retries will be attempted. + +There is no option to specify an infinite number of retries using a value +such as -1. + +In a future release, Kargo is likely to become capable of distinguishing +between recoverable and non-recoverable step failures. At that time, it is +planned that unrecoverable failures will not be subject to this threshold +and will immediately cause the Promotion to be marked as failed without +further condition. */ + errorThreshold?: number; + /** Timeout is the soft maximum interval in which a step that returns a Running +status (which typically indicates it's waiting for something to happen) +may be retried. + +The maximum is a soft one because the check for whether the interval has +elapsed occurs AFTER the step has run. This effectively means a step may +run ONCE beyond the close of the interval. + +If this field is set to nil, the effective default will be a step-specific +one. If no step-specific default exists (i.e. is also nil), the effective +default will be the system-wide default of 0. + +A value of 0 will cause the step to be retried indefinitely unless the +ErrorThreshold is reached. */ + timeout?: string; +} diff --git a/ui/src/gen/api/v2/models/promotionTask.ts b/ui/src/gen/api/v2/models/promotionTask.ts new file mode 100644 index 0000000000..9a30135335 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionTask.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { PromotionTaskSpec } from './promotionTaskSpec'; + +export interface PromotionTask { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes the composition of a PromotionTask, including the +variables available to the task and the steps. + ++kubebuilder:validation:Required */ + spec: PromotionTaskSpec; +} diff --git a/ui/src/gen/api/v2/models/promotionTaskList.ts b/ui/src/gen/api/v2/models/promotionTaskList.ts new file mode 100644 index 0000000000..8fc7820446 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionTaskList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionTask } from './promotionTask'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface PromotionTaskList { + /** 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 ++optional */ + apiVersion?: string; + items?: PromotionTask[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/promotionTaskReference.ts b/ui/src/gen/api/v2/models/promotionTaskReference.ts new file mode 100644 index 0000000000..29a0021c74 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionTaskReference.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface PromotionTaskReference { + /** Kind is the type of the PromotionTask. Can be either PromotionTask or +ClusterPromotionTask, default is PromotionTask. + ++kubebuilder:validation:Optional ++kubebuilder:validation:Enum=PromotionTask;ClusterPromotionTask */ + kind?: string; + /** Name is the name of the (Cluster)PromotionTask. + ++kubebuilder:validation:Required ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:MaxLength=253 ++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` ++akuity:test-kubebuilder-pattern=KubernetesName */ + name: string; +} diff --git a/ui/src/gen/api/v2/models/promotionTaskSpec.ts b/ui/src/gen/api/v2/models/promotionTaskSpec.ts new file mode 100644 index 0000000000..5a508658e1 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionTaskSpec.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionStep } from './promotionStep'; +import type { ExpressionVariable } from './expressionVariable'; + +export interface PromotionTaskSpec { + /** Steps specifies the directives to be executed as part of this +PromotionTask. The steps as defined here are inflated into a +Promotion when it is built from a PromotionTemplate. + ++kubebuilder:validation:Required ++kubebuilder:validation:MinItems=1 ++kubebuilder:validation:items:XValidation:message="PromotionTask step must have uses set and must not reference another task",rule="has(self.uses) && !has(self.task)" */ + steps: PromotionStep[]; + /** Vars specifies the variables available to the PromotionTask. The +values of these variables are the default values that can be +overridden by the step referencing the task. */ + vars?: ExpressionVariable[]; +} diff --git a/ui/src/gen/api/v2/models/promotionTemplate.ts b/ui/src/gen/api/v2/models/promotionTemplate.ts new file mode 100644 index 0000000000..99da3877f5 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionTemplate.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionTemplateSpec } from './promotionTemplateSpec'; + +export interface PromotionTemplate { + spec?: PromotionTemplateSpec; +} diff --git a/ui/src/gen/api/v2/models/promotionTemplateSpec.ts b/ui/src/gen/api/v2/models/promotionTemplateSpec.ts new file mode 100644 index 0000000000..ce3c76a133 --- /dev/null +++ b/ui/src/gen/api/v2/models/promotionTemplateSpec.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionStep } from './promotionStep'; +import type { ExpressionVariable } from './expressionVariable'; + +export interface PromotionTemplateSpec { + /** Steps specifies the directives to be executed as part of a Promotion. +The order in which the directives are executed is the order in which they +are listed in this field. + ++kubebuilder:validation:MinItems=1 ++kubebuilder:validation:items:XValidation:message="PromotionTemplate step must have exactly one of uses or task set",rule="(has(self.uses) ? !has(self.task) : has(self.task))" ++kubebuilder:validation:items:XValidation:message="PromotionTemplate step referencing a task cannot set continueOnError",rule="!has(self.task) || !has(self.continueOnError)" ++kubebuilder:validation:items:XValidation:message="PromotionTemplate step referencing a task cannot set retry",rule="!has(self.task) || !has(self.retry)" */ + steps?: PromotionStep[]; + /** Vars is a list of variables that can be referenced by expressions in +promotion steps. */ + vars?: ExpressionVariable[]; +} diff --git a/ui/src/gen/api/v2/models/quantity.ts b/ui/src/gen/api/v2/models/quantity.ts new file mode 100644 index 0000000000..18990dff6d --- /dev/null +++ b/ui/src/gen/api/v2/models/quantity.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { QuantityFormat } from './quantityFormat'; + +export interface Quantity { + Format?: QuantityFormat; +} diff --git a/ui/src/gen/api/v2/models/quantityFormat.ts b/ui/src/gen/api/v2/models/quantityFormat.ts new file mode 100644 index 0000000000..6e653a80d8 --- /dev/null +++ b/ui/src/gen/api/v2/models/quantityFormat.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export type QuantityFormat = (typeof QuantityFormat)[keyof typeof QuantityFormat]; + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const QuantityFormat = { + /** e.g., 12e6 */ + DecimalExponent: 'DecimalExponent', + /** e.g., 12Mi (12 * 2^20) */ + BinarySI: 'BinarySI', + /** e.g., 12M (12 * 10^6) */ + DecimalSI: 'DecimalSI' +} as const; diff --git a/ui/src/gen/api/v2/models/quayWebhookReceiverConfig.ts b/ui/src/gen/api/v2/models/quayWebhookReceiverConfig.ts new file mode 100644 index 0000000000..b52787e33b --- /dev/null +++ b/ui/src/gen/api/v2/models/quayWebhookReceiverConfig.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface QuayWebhookReceiverConfig { + /** SecretRef contains a reference to a Secret. For Project-scoped webhook +receivers, the referenced Secret must be in the same namespace as the +ProjectConfig. + +For cluster-scoped webhook receivers, the referenced Secret must be in the +designated "system resources" namespace. + +The Secret's data map is expected to contain a `secret` key whose value +does NOT need to be shared directly with Quay when registering a +webhook. It is used only by Kargo to create a complex, hard-to-guess URL, +which implicitly serves as a shared secret. For more information about +Quay webhooks, please refer to the Quay documentation: + https://docs.quay.io/guides/notifications.html + ++kubebuilder:validation:Required */ + secretRef: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/rbacRole.ts b/ui/src/gen/api/v2/models/rbacRole.ts new file mode 100644 index 0000000000..f17e042dc8 --- /dev/null +++ b/ui/src/gen/api/v2/models/rbacRole.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Claim } from './claim'; +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { V1PolicyRule } from './v1PolicyRule'; + +export interface RbacRole { + /** 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 ++optional */ + apiVersion?: string; + claims?: Claim[]; + kargoManaged?: boolean; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + rules?: V1PolicyRule[]; +} diff --git a/ui/src/gen/api/v2/models/revoke200.ts b/ui/src/gen/api/v2/models/revoke200.ts deleted file mode 100644 index e43c8bbb82..0000000000 --- a/ui/src/gen/api/v2/models/revoke200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type Revoke200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/rolloutsAnalysisRun.ts b/ui/src/gen/api/v2/models/rolloutsAnalysisRun.ts new file mode 100644 index 0000000000..ff5f8558f5 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAnalysisRun.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { RolloutsAnalysisRunSpec } from './rolloutsAnalysisRunSpec'; +import type { RolloutsAnalysisRunStatus } from './rolloutsAnalysisRunStatus'; + +export interface RolloutsAnalysisRun { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + spec?: RolloutsAnalysisRunSpec; + status?: RolloutsAnalysisRunStatus; +} diff --git a/ui/src/gen/api/v2/models/rolloutsAnalysisRunSpec.ts b/ui/src/gen/api/v2/models/rolloutsAnalysisRunSpec.ts new file mode 100644 index 0000000000..76f0397709 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAnalysisRunSpec.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsArgument } from './rolloutsArgument'; +import type { RolloutsDryRun } from './rolloutsDryRun'; +import type { RolloutsMeasurementRetention } from './rolloutsMeasurementRetention'; +import type { RolloutsMetric } from './rolloutsMetric'; + +export interface RolloutsAnalysisRunSpec { + args?: RolloutsArgument[]; + dryRun?: RolloutsDryRun[]; + measurementRetention?: RolloutsMeasurementRetention[]; + metrics?: RolloutsMetric[]; + terminate?: boolean; +} diff --git a/ui/src/gen/api/v2/models/rolloutsAnalysisRunStatus.ts b/ui/src/gen/api/v2/models/rolloutsAnalysisRunStatus.ts new file mode 100644 index 0000000000..a0622fdd2e --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAnalysisRunStatus.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsRunSummary } from './rolloutsRunSummary'; +import type { RolloutsMetricResult } from './rolloutsMetricResult'; + +export interface RolloutsAnalysisRunStatus { + dryRunSummary?: RolloutsRunSummary; + message?: string; + metricResults?: RolloutsMetricResult[]; + phase?: string; + runSummary?: RolloutsRunSummary; + startedAt?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsAnalysisTemplate.ts b/ui/src/gen/api/v2/models/rolloutsAnalysisTemplate.ts new file mode 100644 index 0000000000..5003d95012 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAnalysisTemplate.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { RolloutsAnalysisTemplateSpec } from './rolloutsAnalysisTemplateSpec'; + +export interface RolloutsAnalysisTemplate { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + spec?: RolloutsAnalysisTemplateSpec; +} diff --git a/ui/src/gen/api/v2/models/rolloutsAnalysisTemplateList.ts b/ui/src/gen/api/v2/models/rolloutsAnalysisTemplateList.ts new file mode 100644 index 0000000000..53a1e47ca3 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAnalysisTemplateList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsAnalysisTemplate } from './rolloutsAnalysisTemplate'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface RolloutsAnalysisTemplateList { + /** 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 ++optional */ + apiVersion?: string; + items?: RolloutsAnalysisTemplate[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/rolloutsAnalysisTemplateSpec.ts b/ui/src/gen/api/v2/models/rolloutsAnalysisTemplateSpec.ts new file mode 100644 index 0000000000..09025d490d --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAnalysisTemplateSpec.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsArgument } from './rolloutsArgument'; +import type { RolloutsDryRun } from './rolloutsDryRun'; +import type { RolloutsMeasurementRetention } from './rolloutsMeasurementRetention'; +import type { RolloutsMetric } from './rolloutsMetric'; + +export interface RolloutsAnalysisTemplateSpec { + args?: RolloutsArgument[]; + dryRun?: RolloutsDryRun[]; + measurementRetention?: RolloutsMeasurementRetention[]; + metrics?: RolloutsMetric[]; +} diff --git a/ui/src/gen/api/v2/models/rolloutsArgument.ts b/ui/src/gen/api/v2/models/rolloutsArgument.ts new file mode 100644 index 0000000000..bb978d9b1e --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsArgument.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsValueFrom } from './rolloutsValueFrom'; + +export interface RolloutsArgument { + name?: string; + value?: string; + valueFrom?: RolloutsValueFrom; +} diff --git a/ui/src/gen/api/v2/models/rolloutsAuthentication.ts b/ui/src/gen/api/v2/models/rolloutsAuthentication.ts new file mode 100644 index 0000000000..cb2d4cc2f9 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsAuthentication.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsOAuth2Config } from './rolloutsOAuth2Config'; +import type { RolloutsSigv4Config } from './rolloutsSigv4Config'; + +export interface RolloutsAuthentication { + oauth2?: RolloutsOAuth2Config; + sigv4?: RolloutsSigv4Config; +} diff --git a/ui/src/gen/api/v2/models/rolloutsCloudWatchMetric.ts b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetric.ts new file mode 100644 index 0000000000..080c4b7b2e --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetric.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsCloudWatchMetricDataQuery } from './rolloutsCloudWatchMetricDataQuery'; + +export interface RolloutsCloudWatchMetric { + interval?: string; + metricDataQueries?: RolloutsCloudWatchMetricDataQuery[]; +} diff --git a/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricDataQuery.ts b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricDataQuery.ts new file mode 100644 index 0000000000..2bdfda4354 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricDataQuery.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsCloudWatchMetricStat } from './rolloutsCloudWatchMetricStat'; +import type { IntOrString } from './intOrString'; + +export interface RolloutsCloudWatchMetricDataQuery { + expression?: string; + id?: string; + label?: string; + metricStat?: RolloutsCloudWatchMetricStat; + period?: IntOrString; + returnData?: boolean; +} diff --git a/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStat.ts b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStat.ts new file mode 100644 index 0000000000..e7b052f920 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStat.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsCloudWatchMetricStatMetric } from './rolloutsCloudWatchMetricStatMetric'; +import type { IntOrString } from './intOrString'; + +export interface RolloutsCloudWatchMetricStat { + metric?: RolloutsCloudWatchMetricStatMetric; + period?: IntOrString; + stat?: string; + unit?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStatMetric.ts b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStatMetric.ts new file mode 100644 index 0000000000..11c0b5c74f --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStatMetric.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsCloudWatchMetricStatMetricDimension } from './rolloutsCloudWatchMetricStatMetricDimension'; + +export interface RolloutsCloudWatchMetricStatMetric { + dimensions?: RolloutsCloudWatchMetricStatMetricDimension[]; + metricName?: string; + namespace?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStatMetricDimension.ts b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStatMetricDimension.ts new file mode 100644 index 0000000000..6341c80256 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsCloudWatchMetricStatMetricDimension.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsCloudWatchMetricStatMetricDimension { + name?: string; + value?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsClusterAnalysisTemplate.ts b/ui/src/gen/api/v2/models/rolloutsClusterAnalysisTemplate.ts new file mode 100644 index 0000000000..cdeea2203b --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsClusterAnalysisTemplate.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { RolloutsAnalysisTemplateSpec } from './rolloutsAnalysisTemplateSpec'; + +export interface RolloutsClusterAnalysisTemplate { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + spec?: RolloutsAnalysisTemplateSpec; +} diff --git a/ui/src/gen/api/v2/models/rolloutsClusterAnalysisTemplateList.ts b/ui/src/gen/api/v2/models/rolloutsClusterAnalysisTemplateList.ts new file mode 100644 index 0000000000..6cff4cd37b --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsClusterAnalysisTemplateList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsClusterAnalysisTemplate } from './rolloutsClusterAnalysisTemplate'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface RolloutsClusterAnalysisTemplateList { + /** 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 ++optional */ + apiVersion?: string; + items?: RolloutsClusterAnalysisTemplate[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/rolloutsDatadogMetric.ts b/ui/src/gen/api/v2/models/rolloutsDatadogMetric.ts new file mode 100644 index 0000000000..c6d0bb5a5f --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsDatadogMetric.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsDatadogMetricQueries } from './rolloutsDatadogMetricQueries'; + +export interface RolloutsDatadogMetric { + aggregator?: string; + apiVersion?: string; + formula?: string; + interval?: string; + queries?: RolloutsDatadogMetricQueries; + query?: string; +} diff --git a/ui/src/gen/api/v2/models/createProjectConfigMap201.ts b/ui/src/gen/api/v2/models/rolloutsDatadogMetricQueries.ts similarity index 66% rename from ui/src/gen/api/v2/models/createProjectConfigMap201.ts rename to ui/src/gen/api/v2/models/rolloutsDatadogMetricQueries.ts index ba13dc0e95..a80ea5332b 100644 --- a/ui/src/gen/api/v2/models/createProjectConfigMap201.ts +++ b/ui/src/gen/api/v2/models/rolloutsDatadogMetricQueries.ts @@ -6,4 +6,4 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateProjectConfigMap201 = { [key: string]: unknown }; +export type RolloutsDatadogMetricQueries = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/getProject200.ts b/ui/src/gen/api/v2/models/rolloutsDryRun.ts similarity index 70% rename from ui/src/gen/api/v2/models/getProject200.ts rename to ui/src/gen/api/v2/models/rolloutsDryRun.ts index 2a570cbf87..472a0935e0 100644 --- a/ui/src/gen/api/v2/models/getProject200.ts +++ b/ui/src/gen/api/v2/models/rolloutsDryRun.ts @@ -6,4 +6,6 @@ * OpenAPI spec version: v1alpha1 */ -export type GetProject200 = { [key: string]: unknown }; +export interface RolloutsDryRun { + metricName?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsFieldRef.ts b/ui/src/gen/api/v2/models/rolloutsFieldRef.ts new file mode 100644 index 0000000000..186a781875 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsFieldRef.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsFieldRef { + /** Required: Path of the field to select in the specified API version */ + fieldPath?: string; +} diff --git a/ui/src/gen/api/v2/models/createProjectRepoCredentials201.ts b/ui/src/gen/api/v2/models/rolloutsGraphiteMetric.ts similarity index 62% rename from ui/src/gen/api/v2/models/createProjectRepoCredentials201.ts rename to ui/src/gen/api/v2/models/rolloutsGraphiteMetric.ts index 1794a497db..8510f94388 100644 --- a/ui/src/gen/api/v2/models/createProjectRepoCredentials201.ts +++ b/ui/src/gen/api/v2/models/rolloutsGraphiteMetric.ts @@ -6,4 +6,7 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateProjectRepoCredentials201 = { [key: string]: unknown }; +export interface RolloutsGraphiteMetric { + address?: string; + query?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsInfluxdbMetric.ts b/ui/src/gen/api/v2/models/rolloutsInfluxdbMetric.ts new file mode 100644 index 0000000000..e6dee6f394 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsInfluxdbMetric.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsInfluxdbMetric { + profile?: string; + query?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsJobMetric.ts b/ui/src/gen/api/v2/models/rolloutsJobMetric.ts new file mode 100644 index 0000000000..3b6ea12cec --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsJobMetric.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { V1JobSpec } from './v1JobSpec'; + +export interface RolloutsJobMetric { + metadata?: V1ObjectMeta; + spec?: V1JobSpec; +} diff --git a/ui/src/gen/api/v2/models/rolloutsKayentaMetric.ts b/ui/src/gen/api/v2/models/rolloutsKayentaMetric.ts new file mode 100644 index 0000000000..da60063ece --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsKayentaMetric.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsKayentaScope } from './rolloutsKayentaScope'; +import type { RolloutsKayentaThreshold } from './rolloutsKayentaThreshold'; + +export interface RolloutsKayentaMetric { + address?: string; + application?: string; + canaryConfigName?: string; + configurationAccountName?: string; + metricsAccountName?: string; + scopes?: RolloutsKayentaScope[]; + storageAccountName?: string; + threshold?: RolloutsKayentaThreshold; +} diff --git a/ui/src/gen/api/v2/models/rolloutsKayentaScope.ts b/ui/src/gen/api/v2/models/rolloutsKayentaScope.ts new file mode 100644 index 0000000000..47d0bdd761 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsKayentaScope.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsScopeDetail } from './rolloutsScopeDetail'; + +export interface RolloutsKayentaScope { + controlScope?: RolloutsScopeDetail; + experimentScope?: RolloutsScopeDetail; + name?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsKayentaThreshold.ts b/ui/src/gen/api/v2/models/rolloutsKayentaThreshold.ts new file mode 100644 index 0000000000..0fadf80a31 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsKayentaThreshold.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsKayentaThreshold { + marginal?: number; + pass?: number; +} diff --git a/ui/src/gen/api/v2/models/rolloutsMeasurement.ts b/ui/src/gen/api/v2/models/rolloutsMeasurement.ts new file mode 100644 index 0000000000..77384d6762 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsMeasurement.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsMeasurementMetadata } from './rolloutsMeasurementMetadata'; + +export interface RolloutsMeasurement { + finishedAt?: string; + message?: string; + metadata?: RolloutsMeasurementMetadata; + phase?: string; + resumeAt?: string; + startedAt?: string; + value?: string; +} diff --git a/ui/src/gen/api/v2/models/createProjectAPIToken201.ts b/ui/src/gen/api/v2/models/rolloutsMeasurementMetadata.ts similarity index 66% rename from ui/src/gen/api/v2/models/createProjectAPIToken201.ts rename to ui/src/gen/api/v2/models/rolloutsMeasurementMetadata.ts index 8ca0d9f3fb..e3a2306fd2 100644 --- a/ui/src/gen/api/v2/models/createProjectAPIToken201.ts +++ b/ui/src/gen/api/v2/models/rolloutsMeasurementMetadata.ts @@ -6,4 +6,4 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateProjectAPIToken201 = { [key: string]: unknown }; +export type RolloutsMeasurementMetadata = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/rolloutsMeasurementRetention.ts b/ui/src/gen/api/v2/models/rolloutsMeasurementRetention.ts new file mode 100644 index 0000000000..c855e43e97 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsMeasurementRetention.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsMeasurementRetention { + limit?: number; + metricName?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsMetric.ts b/ui/src/gen/api/v2/models/rolloutsMetric.ts new file mode 100644 index 0000000000..cdda8b187f --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsMetric.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { IntOrString } from './intOrString'; +import type { RolloutsMetricProvider } from './rolloutsMetricProvider'; + +export interface RolloutsMetric { + consecutiveErrorLimit?: IntOrString; + consecutiveSuccessLimit?: IntOrString; + count?: IntOrString; + failureCondition?: string; + failureLimit?: IntOrString; + inconclusiveLimit?: IntOrString; + initialDelay?: string; + interval?: string; + name?: string; + provider?: RolloutsMetricProvider; + successCondition?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsMetricProvider.ts b/ui/src/gen/api/v2/models/rolloutsMetricProvider.ts new file mode 100644 index 0000000000..ac9bf8cbbc --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsMetricProvider.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsCloudWatchMetric } from './rolloutsCloudWatchMetric'; +import type { RolloutsDatadogMetric } from './rolloutsDatadogMetric'; +import type { RolloutsGraphiteMetric } from './rolloutsGraphiteMetric'; +import type { RolloutsInfluxdbMetric } from './rolloutsInfluxdbMetric'; +import type { RolloutsJobMetric } from './rolloutsJobMetric'; +import type { RolloutsKayentaMetric } from './rolloutsKayentaMetric'; +import type { RolloutsNewRelicMetric } from './rolloutsNewRelicMetric'; +import type { RolloutsMetricProviderPlugin } from './rolloutsMetricProviderPlugin'; +import type { RolloutsPrometheusMetric } from './rolloutsPrometheusMetric'; +import type { RolloutsSkyWalkingMetric } from './rolloutsSkyWalkingMetric'; +import type { RolloutsWavefrontMetric } from './rolloutsWavefrontMetric'; +import type { RolloutsWebMetric } from './rolloutsWebMetric'; + +export interface RolloutsMetricProvider { + cloudWatch?: RolloutsCloudWatchMetric; + datadog?: RolloutsDatadogMetric; + graphite?: RolloutsGraphiteMetric; + influxdb?: RolloutsInfluxdbMetric; + job?: RolloutsJobMetric; + kayenta?: RolloutsKayentaMetric; + newRelic?: RolloutsNewRelicMetric; + plugin?: RolloutsMetricProviderPlugin; + prometheus?: RolloutsPrometheusMetric; + skywalking?: RolloutsSkyWalkingMetric; + wavefront?: RolloutsWavefrontMetric; + web?: RolloutsWebMetric; +} diff --git a/ui/src/gen/api/v2/models/createProjectRole201.ts b/ui/src/gen/api/v2/models/rolloutsMetricProviderPlugin.ts similarity index 66% rename from ui/src/gen/api/v2/models/createProjectRole201.ts rename to ui/src/gen/api/v2/models/rolloutsMetricProviderPlugin.ts index cb296b7a0e..2fc754703d 100644 --- a/ui/src/gen/api/v2/models/createProjectRole201.ts +++ b/ui/src/gen/api/v2/models/rolloutsMetricProviderPlugin.ts @@ -6,4 +6,4 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateProjectRole201 = { [key: string]: unknown }; +export type RolloutsMetricProviderPlugin = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/rolloutsMetricResult.ts b/ui/src/gen/api/v2/models/rolloutsMetricResult.ts new file mode 100644 index 0000000000..15bc56db6a --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsMetricResult.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsMeasurement } from './rolloutsMeasurement'; +import type { RolloutsMetricResultMetadata } from './rolloutsMetricResultMetadata'; + +export interface RolloutsMetricResult { + consecutiveError?: number; + count?: number; + dryRun?: boolean; + error?: number; + failed?: number; + inconclusive?: number; + measurements?: RolloutsMeasurement[]; + message?: string; + metadata?: RolloutsMetricResultMetadata; + name?: string; + phase?: string; + successful?: number; +} diff --git a/ui/src/gen/api/v2/models/createSharedConfigMap201.ts b/ui/src/gen/api/v2/models/rolloutsMetricResultMetadata.ts similarity index 66% rename from ui/src/gen/api/v2/models/createSharedConfigMap201.ts rename to ui/src/gen/api/v2/models/rolloutsMetricResultMetadata.ts index ddd8f41a04..a0bf1e957f 100644 --- a/ui/src/gen/api/v2/models/createSharedConfigMap201.ts +++ b/ui/src/gen/api/v2/models/rolloutsMetricResultMetadata.ts @@ -6,4 +6,4 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateSharedConfigMap201 = { [key: string]: unknown }; +export type RolloutsMetricResultMetadata = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/rolloutsNewRelicMetric.ts b/ui/src/gen/api/v2/models/rolloutsNewRelicMetric.ts new file mode 100644 index 0000000000..7d42750ea5 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsNewRelicMetric.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsNewRelicMetric { + profile?: string; + query?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsOAuth2Config.ts b/ui/src/gen/api/v2/models/rolloutsOAuth2Config.ts new file mode 100644 index 0000000000..5156eb6c33 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsOAuth2Config.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsOAuth2Config { + clientId?: string; + clientSecret?: string; + scopes?: string[]; + tokenUrl?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsPrometheusMetric.ts b/ui/src/gen/api/v2/models/rolloutsPrometheusMetric.ts new file mode 100644 index 0000000000..5e7ca216cc --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsPrometheusMetric.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsAuthentication } from './rolloutsAuthentication'; +import type { RolloutsWebMetricHeader } from './rolloutsWebMetricHeader'; + +export interface RolloutsPrometheusMetric { + address?: string; + authentication?: RolloutsAuthentication; + headers?: RolloutsWebMetricHeader[]; + insecure?: boolean; + query?: string; + timeout?: number; +} diff --git a/ui/src/gen/api/v2/models/rolloutsRunSummary.ts b/ui/src/gen/api/v2/models/rolloutsRunSummary.ts new file mode 100644 index 0000000000..9ac6b02269 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsRunSummary.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsRunSummary { + count?: number; + error?: number; + failed?: number; + inconclusive?: number; + successful?: number; +} diff --git a/ui/src/gen/api/v2/models/rolloutsScopeDetail.ts b/ui/src/gen/api/v2/models/rolloutsScopeDetail.ts new file mode 100644 index 0000000000..b03b318d11 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsScopeDetail.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsScopeDetail { + end?: string; + region?: string; + scope?: string; + start?: string; + step?: number; +} diff --git a/ui/src/gen/api/v2/models/getSystemConfigMap200.ts b/ui/src/gen/api/v2/models/rolloutsSecretKeyRef.ts similarity index 72% rename from ui/src/gen/api/v2/models/getSystemConfigMap200.ts rename to ui/src/gen/api/v2/models/rolloutsSecretKeyRef.ts index 0a84d7b61e..e0ce70553b 100644 --- a/ui/src/gen/api/v2/models/getSystemConfigMap200.ts +++ b/ui/src/gen/api/v2/models/rolloutsSecretKeyRef.ts @@ -6,4 +6,7 @@ * OpenAPI spec version: v1alpha1 */ -export type GetSystemConfigMap200 = { [key: string]: unknown }; +export interface RolloutsSecretKeyRef { + key?: string; + name?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsSigv4Config.ts b/ui/src/gen/api/v2/models/rolloutsSigv4Config.ts new file mode 100644 index 0000000000..1b37db7c62 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsSigv4Config.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsSigv4Config { + profile?: string; + region?: string; + roleArn?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsSkyWalkingMetric.ts b/ui/src/gen/api/v2/models/rolloutsSkyWalkingMetric.ts new file mode 100644 index 0000000000..48e8b3f5bc --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsSkyWalkingMetric.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsSkyWalkingMetric { + address?: string; + interval?: string; + query?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsValueFrom.ts b/ui/src/gen/api/v2/models/rolloutsValueFrom.ts new file mode 100644 index 0000000000..c1ec7d9397 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsValueFrom.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsFieldRef } from './rolloutsFieldRef'; +import type { RolloutsSecretKeyRef } from './rolloutsSecretKeyRef'; + +export interface RolloutsValueFrom { + fieldRef?: RolloutsFieldRef; + secretKeyRef?: RolloutsSecretKeyRef; +} diff --git a/ui/src/gen/api/v2/models/rolloutsWavefrontMetric.ts b/ui/src/gen/api/v2/models/rolloutsWavefrontMetric.ts new file mode 100644 index 0000000000..c09e68a335 --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsWavefrontMetric.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface RolloutsWavefrontMetric { + address?: string; + query?: string; +} diff --git a/ui/src/gen/api/v2/models/rolloutsWebMetric.ts b/ui/src/gen/api/v2/models/rolloutsWebMetric.ts new file mode 100644 index 0000000000..434877006a --- /dev/null +++ b/ui/src/gen/api/v2/models/rolloutsWebMetric.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { RolloutsAuthentication } from './rolloutsAuthentication'; +import type { RolloutsWebMetricHeader } from './rolloutsWebMetricHeader'; + +export interface RolloutsWebMetric { + authentication?: RolloutsAuthentication; + body?: string; + headers?: RolloutsWebMetricHeader[]; + insecure?: boolean; + jsonBody?: number[]; + jsonPath?: string; + method?: string; + timeoutSeconds?: number; + /** URL is the address of the web metric */ + url?: string; +} diff --git a/ui/src/gen/api/v2/models/createProjectGenericCredentials201.ts b/ui/src/gen/api/v2/models/rolloutsWebMetricHeader.ts similarity index 63% rename from ui/src/gen/api/v2/models/createProjectGenericCredentials201.ts rename to ui/src/gen/api/v2/models/rolloutsWebMetricHeader.ts index 60661349bd..7b47a48af5 100644 --- a/ui/src/gen/api/v2/models/createProjectGenericCredentials201.ts +++ b/ui/src/gen/api/v2/models/rolloutsWebMetricHeader.ts @@ -6,4 +6,7 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateProjectGenericCredentials201 = { [key: string]: unknown }; +export interface RolloutsWebMetricHeader { + key?: string; + value?: string; +} diff --git a/ui/src/gen/api/v2/models/stage.ts b/ui/src/gen/api/v2/models/stage.ts new file mode 100644 index 0000000000..c2f9a09a7c --- /dev/null +++ b/ui/src/gen/api/v2/models/stage.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { StageSpec } from './stageSpec'; +import type { StageStatus } from './stageStatus'; + +export interface Stage { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes sources of Freight used by the Stage and how to incorporate +Freight into the Stage. + ++kubebuilder:validation:Required */ + spec: StageSpec; + /** Status describes the Stage's current and recent Freight, health, and more. */ + status?: StageStatus; +} diff --git a/ui/src/gen/api/v2/models/stageList.ts b/ui/src/gen/api/v2/models/stageList.ts new file mode 100644 index 0000000000..596f917239 --- /dev/null +++ b/ui/src/gen/api/v2/models/stageList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Stage } from './stage'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface StageList { + /** 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 ++optional */ + apiVersion?: string; + items?: Stage[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/stageSpec.ts b/ui/src/gen/api/v2/models/stageSpec.ts new file mode 100644 index 0000000000..3d677d9423 --- /dev/null +++ b/ui/src/gen/api/v2/models/stageSpec.ts @@ -0,0 +1,41 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { PromotionTemplate } from './promotionTemplate'; +import type { FreightRequest } from './freightRequest'; +import type { ExpressionVariable } from './expressionVariable'; +import type { Verification } from './verification'; + +export interface StageSpec { + /** PromotionTemplate describes how to incorporate Freight into the Stage +using a Promotion. */ + promotionTemplate?: PromotionTemplate; + /** RequestedFreight expresses the Stage's need for certain pieces of Freight, +each having originated from a particular Warehouse. This list must be +non-empty. In the common case, a Stage will request Freight having +originated from just one specific Warehouse. In advanced cases, requesting +Freight from multiple Warehouses provides a method of advancing new +artifacts of different types through parallel pipelines at different +speeds. This can be useful, for instance, if a Stage is home to multiple +microservices that are independently versioned. + ++kubebuilder:validation:MinItems=1 */ + requestedFreight?: FreightRequest[]; + /** Shard is the name of the shard that this Stage belongs to. This is an +optional field. If not specified, the Stage will belong to the default +shard. A defaulting webhook will sync the value of the +kargo.akuity.io/shard label with the value of this field. When this field +is empty, the webhook will ensure that label is absent. */ + shard?: string; + /** Vars is a list of variables that can be referenced anywhere in the +StageSpec that supports expressions. For example, the PromotionTemplate +and arguments of the Verification. */ + vars?: ExpressionVariable[]; + /** Verification describes how to verify a Stage's current Freight is fit for +promotion downstream. */ + verification?: Verification; +} diff --git a/ui/src/gen/api/v2/models/stageStats.ts b/ui/src/gen/api/v2/models/stageStats.ts new file mode 100644 index 0000000000..7ca06e6045 --- /dev/null +++ b/ui/src/gen/api/v2/models/stageStats.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { HealthStats } from './healthStats'; + +export interface StageStats { + /** Count contains the total number of Stages in the Project. */ + count?: number; + /** Health contains a summary of the collective health of a Project's Stages. */ + health?: HealthStats; +} diff --git a/ui/src/gen/api/v2/models/stageStatus.ts b/ui/src/gen/api/v2/models/stageStatus.ts new file mode 100644 index 0000000000..06bf31acc9 --- /dev/null +++ b/ui/src/gen/api/v2/models/stageStatus.ts @@ -0,0 +1,59 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Condition } from './v1Condition'; +import type { PromotionReference } from './promotionReference'; +import type { FreightCollection } from './freightCollection'; +import type { Health } from './health'; +import type { StageStatusMetadata } from './stageStatusMetadata'; + +export interface StageStatus { + /** AutoPromotionEnabled indicates whether automatic promotion is enabled +for the Stage based on the ProjectConfig. */ + autoPromotionEnabled?: boolean; + /** Conditions contains the last observations of the Stage's current +state. ++patchMergeKey=type ++patchStrategy=merge ++listType=map ++listMapKey=type */ + conditions?: V1Condition[]; + /** CurrentPromotion is a reference to the currently Running promotion. */ + currentPromotion?: PromotionReference; + /** FreightHistory is a list of recent Freight selections that were deployed +to the Stage. By default, the last ten Freight selections are stored. +The first item in the list is the most recent Freight selection and +currently deployed to the Stage, subsequent items are older selections. */ + freightHistory?: FreightCollection[]; + /** FreightSummary is human-readable text maintained by the controller that +summarizes what Freight is currently deployed to the Stage. For Stages that +request a single piece of Freight AND the request has been fulfilled, this +field will simply contain the name of the Freight. For Stages that request +a single piece of Freight AND the request has NOT been fulfilled, or for +Stages that request multiple pieces of Freight, this field will contain a +summary of fulfilled/requested Freight. The existence of this field is a +workaround for kubectl limitations so that this complex but valuable +information can be displayed in a column in response to `kubectl get +stages`. */ + freightSummary?: string; + /** Health is the Stage's last observed health. */ + health?: Health; + /** LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh +annotation that was handled by the controller. This field can be used to +determine whether the request to refresh the resource has been handled. ++optional */ + lastHandledRefresh?: string; + /** LastPromotion is a reference to the last completed promotion. */ + lastPromotion?: PromotionReference; + /** Metadata is a map of arbitrary metadata associated with the Stage. +This is useful for storing additional information about the Stage +that can be shared across promotions, verifications, or other processes. */ + metadata?: StageStatusMetadata; + /** ObservedGeneration represents the .metadata.generation that this Stage +status was reconciled against. */ + observedGeneration?: number; +} diff --git a/ui/src/gen/api/v2/models/stageStatusMetadata.ts b/ui/src/gen/api/v2/models/stageStatusMetadata.ts new file mode 100644 index 0000000000..94ccf61de3 --- /dev/null +++ b/ui/src/gen/api/v2/models/stageStatusMetadata.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Metadata is a map of arbitrary metadata associated with the Stage. +This is useful for storing additional information about the Stage +that can be shared across promotions, verifications, or other processes. + */ +export type StageStatusMetadata = { [key: string]: { [key: string]: unknown } }; diff --git a/ui/src/gen/api/v2/models/stepExecutionMetadata.ts b/ui/src/gen/api/v2/models/stepExecutionMetadata.ts new file mode 100644 index 0000000000..9c139ba546 --- /dev/null +++ b/ui/src/gen/api/v2/models/stepExecutionMetadata.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface StepExecutionMetadata { + /** Alias is the alias of the step. */ + alias?: string; + /** ContinueOnError is a boolean value that, if set to true, will cause the +Promotion to continue executing the next step even if this step fails. It +also will not permit this failure to impact the overall status of the +Promotion. */ + continueOnError?: boolean; + /** ErrorCount tracks consecutive failed attempts to execute the step. */ + errorCount?: number; + /** FinishedAt is the time at which the final attempt to execute the step +completed. */ + finishedAt?: string; + /** Message is a display message about the step, including any errors. */ + message?: string; + /** StartedAt is the time at which the first attempt to execute the step +began. */ + startedAt?: string; + /** Status is the high-level outcome of the step. */ + status?: string; +} diff --git a/ui/src/gen/api/v2/models/updateProjectConfigMap200.ts b/ui/src/gen/api/v2/models/updateProjectConfigMap200.ts deleted file mode 100644 index 317db28bc1..0000000000 --- a/ui/src/gen/api/v2/models/updateProjectConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateProjectConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateProjectGenericCredentials200.ts b/ui/src/gen/api/v2/models/updateProjectGenericCredentials200.ts deleted file mode 100644 index 146f7ae834..0000000000 --- a/ui/src/gen/api/v2/models/updateProjectGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateProjectGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateProjectRepoCredentials200.ts b/ui/src/gen/api/v2/models/updateProjectRepoCredentials200.ts deleted file mode 100644 index 7f322ac072..0000000000 --- a/ui/src/gen/api/v2/models/updateProjectRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateProjectRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateRole200.ts b/ui/src/gen/api/v2/models/updateRole200.ts deleted file mode 100644 index 0cf0eb12ff..0000000000 --- a/ui/src/gen/api/v2/models/updateRole200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateRole200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateSharedConfigMap200.ts b/ui/src/gen/api/v2/models/updateSharedConfigMap200.ts deleted file mode 100644 index 396286c310..0000000000 --- a/ui/src/gen/api/v2/models/updateSharedConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateSharedConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateSharedGenericCredentials200.ts b/ui/src/gen/api/v2/models/updateSharedGenericCredentials200.ts deleted file mode 100644 index 261dfb0b2f..0000000000 --- a/ui/src/gen/api/v2/models/updateSharedGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateSharedGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateSharedRepoCredentials200.ts b/ui/src/gen/api/v2/models/updateSharedRepoCredentials200.ts deleted file mode 100644 index 5fac222a3d..0000000000 --- a/ui/src/gen/api/v2/models/updateSharedRepoCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateSharedRepoCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateSystemConfigMap200.ts b/ui/src/gen/api/v2/models/updateSystemConfigMap200.ts deleted file mode 100644 index 78353aa5b5..0000000000 --- a/ui/src/gen/api/v2/models/updateSystemConfigMap200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateSystemConfigMap200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/updateSystemGenericCredentials200.ts b/ui/src/gen/api/v2/models/updateSystemGenericCredentials200.ts deleted file mode 100644 index 3eaf24d329..0000000000 --- a/ui/src/gen/api/v2/models/updateSystemGenericCredentials200.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Generated by orval v7.19.0 🍺 - * Do not edit manually. - * Kargo API - * REST API for Kargo - * OpenAPI spec version: v1alpha1 - */ - -export type UpdateSystemGenericCredentials200 = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/v1AWSElasticBlockStoreVolumeSource.ts b/ui/src/gen/api/v2/models/v1AWSElasticBlockStoreVolumeSource.ts new file mode 100644 index 0000000000..41f3e49922 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1AWSElasticBlockStoreVolumeSource.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1AWSElasticBlockStoreVolumeSource { + /** fsType is the filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string; + /** partition is the partition in the volume that you want to mount. +If omitted, the default is to mount by volume name. +Examples: For volume /dev/sda1, you specify the partition as "1". +Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). ++optional */ + partition?: number; + /** readOnly value true will force the readOnly setting in VolumeMounts. +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore ++optional */ + readOnly?: boolean; + /** volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore */ + volumeID?: string; +} diff --git a/ui/src/gen/api/v2/models/v1Affinity.ts b/ui/src/gen/api/v2/models/v1Affinity.ts new file mode 100644 index 0000000000..4a3cece7e4 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Affinity.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1NodeAffinity } from './v1NodeAffinity'; +import type { V1PodAffinity } from './v1PodAffinity'; +import type { V1PodAntiAffinity } from './v1PodAntiAffinity'; + +export interface V1Affinity { + /** Describes node affinity scheduling rules for the pod. ++optional */ + nodeAffinity?: V1NodeAffinity; + /** Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). ++optional */ + podAffinity?: V1PodAffinity; + /** Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). ++optional */ + podAntiAffinity?: V1PodAntiAffinity; +} diff --git a/ui/src/gen/api/v2/models/v1AppArmorProfile.ts b/ui/src/gen/api/v2/models/v1AppArmorProfile.ts new file mode 100644 index 0000000000..8e1853b5a1 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1AppArmorProfile.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1AppArmorProfile { + /** localhostProfile indicates a profile loaded on the node that should be used. +The profile must be preconfigured on the node to work. +Must match the loaded name of the profile. +Must be set if and only if type is "Localhost". ++optional */ + localhostProfile?: string; + /** type indicates which kind of AppArmor profile will be applied. +Valid options are: + Localhost - a profile pre-loaded on the node. + RuntimeDefault - the container runtime's default profile. + Unconfined - no AppArmor enforcement. ++unionDiscriminator */ + type?: string; +} diff --git a/ui/src/gen/api/v2/models/v1AzureDiskVolumeSource.ts b/ui/src/gen/api/v2/models/v1AzureDiskVolumeSource.ts new file mode 100644 index 0000000000..853882b09b --- /dev/null +++ b/ui/src/gen/api/v2/models/v1AzureDiskVolumeSource.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1AzureDiskVolumeSource { + /** cachingMode is the Host Caching mode: None, Read Only, Read Write. ++optional ++default=ref(AzureDataDiskCachingReadWrite) */ + cachingMode?: string; + /** diskName is the Name of the data disk in the blob storage */ + diskName?: string; + /** diskURI is the URI of data disk in the blob storage */ + diskURI?: string; + /** fsType is Filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. ++optional ++default="ext4" */ + fsType?: string; + /** kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared ++default=ref(AzureSharedBlobDisk) */ + kind?: string; + /** readOnly Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional ++default=false */ + readOnly?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1AzureFileVolumeSource.ts b/ui/src/gen/api/v2/models/v1AzureFileVolumeSource.ts new file mode 100644 index 0000000000..cf92601d57 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1AzureFileVolumeSource.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1AzureFileVolumeSource { + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean; + /** secretName is the name of secret that contains Azure Storage Account Name and Key */ + secretName?: string; + /** shareName is the azure share Name */ + shareName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1CSIVolumeSource.ts b/ui/src/gen/api/v2/models/v1CSIVolumeSource.ts new file mode 100644 index 0000000000..fcdf070998 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1CSIVolumeSource.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; +import type { V1CSIVolumeSourceVolumeAttributes } from './v1CSIVolumeSourceVolumeAttributes'; + +export interface V1CSIVolumeSource { + /** driver is the name of the CSI driver that handles this volume. +Consult with your admin for the correct name as registered in the cluster. */ + driver?: string; + /** fsType to mount. Ex. "ext4", "xfs", "ntfs". +If not provided, the empty value is passed to the associated CSI driver +which will determine the default filesystem to apply. ++optional */ + fsType?: string; + /** nodePublishSecretRef is a reference to the secret object containing +sensitive information to pass to the CSI driver to complete the CSI +NodePublishVolume and NodeUnpublishVolume calls. +This field is optional, and may be empty if no secret is required. If the +secret object contains more than one secret, all secret references are passed. ++optional */ + nodePublishSecretRef?: V1LocalObjectReference; + /** readOnly specifies a read-only configuration for the volume. +Defaults to false (read/write). ++optional */ + readOnly?: boolean; + /** volumeAttributes stores driver-specific properties that are passed to the CSI +driver. Consult your driver's documentation for supported values. ++optional */ + volumeAttributes?: V1CSIVolumeSourceVolumeAttributes; +} diff --git a/ui/src/gen/api/v2/models/v1CSIVolumeSourceVolumeAttributes.ts b/ui/src/gen/api/v2/models/v1CSIVolumeSourceVolumeAttributes.ts new file mode 100644 index 0000000000..1f6ff65b20 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1CSIVolumeSourceVolumeAttributes.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * volumeAttributes stores driver-specific properties that are passed to the CSI +driver. Consult your driver's documentation for supported values. ++optional + */ +export type V1CSIVolumeSourceVolumeAttributes = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1Capabilities.ts b/ui/src/gen/api/v2/models/v1Capabilities.ts new file mode 100644 index 0000000000..cb0cece417 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Capabilities.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1Capabilities { + /** Added capabilities ++optional ++listType=atomic */ + add?: string[]; + /** Removed capabilities ++optional ++listType=atomic */ + drop?: string[]; +} diff --git a/ui/src/gen/api/v2/models/v1CephFSVolumeSource.ts b/ui/src/gen/api/v2/models/v1CephFSVolumeSource.ts new file mode 100644 index 0000000000..ead88582e2 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1CephFSVolumeSource.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1CephFSVolumeSource { + /** monitors is Required: Monitors is a collection of Ceph monitors +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++listType=atomic */ + monitors?: string[]; + /** path is Optional: Used as the mounted root, rather than the full Ceph tree, default is / ++optional */ + path?: string; + /** readOnly is Optional: Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + readOnly?: boolean; + /** secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + secretFile?: string; + /** secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + secretRef?: V1LocalObjectReference; + /** user is optional: User is the rados user name, default is admin +More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it ++optional */ + user?: string; +} diff --git a/ui/src/gen/api/v2/models/v1CinderVolumeSource.ts b/ui/src/gen/api/v2/models/v1CinderVolumeSource.ts new file mode 100644 index 0000000000..96f8d0f1dc --- /dev/null +++ b/ui/src/gen/api/v2/models/v1CinderVolumeSource.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1CinderVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md ++optional */ + fsType?: string; + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md ++optional */ + readOnly?: boolean; + /** secretRef is optional: points to a secret object containing parameters used to connect +to OpenStack. ++optional */ + secretRef?: V1LocalObjectReference; + /** volumeID used to identify the volume in cinder. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md */ + volumeID?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ClusterTrustBundleProjection.ts b/ui/src/gen/api/v2/models/v1ClusterTrustBundleProjection.ts new file mode 100644 index 0000000000..296c20cfac --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ClusterTrustBundleProjection.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LabelSelector } from './v1LabelSelector'; + +export interface V1ClusterTrustBundleProjection { + /** Select all ClusterTrustBundles that match this label selector. Only has +effect if signerName is set. Mutually-exclusive with name. If unset, +interpreted as "match nothing". If set but empty, interpreted as "match +everything". ++optional */ + labelSelector?: V1LabelSelector; + /** Select a single ClusterTrustBundle by object name. Mutually-exclusive +with signerName and labelSelector. ++optional */ + name?: string; + /** If true, don't block pod startup if the referenced ClusterTrustBundle(s) +aren't available. If using name, then the named ClusterTrustBundle is +allowed not to exist. If using signerName, then the combination of +signerName and labelSelector is allowed to match zero +ClusterTrustBundles. ++optional */ + optional?: boolean; + /** Relative path from the volume root to write the bundle. */ + path?: string; + /** Select all ClusterTrustBundles that match this signer name. +Mutually-exclusive with name. The contents of all selected +ClusterTrustBundles will be unified and deduplicated. ++optional */ + signerName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1CompletionMode.ts b/ui/src/gen/api/v2/models/v1CompletionMode.ts new file mode 100644 index 0000000000..11ae9421ca --- /dev/null +++ b/ui/src/gen/api/v2/models/v1CompletionMode.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export type V1CompletionMode = (typeof V1CompletionMode)[keyof typeof V1CompletionMode]; + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const V1CompletionMode = { + NonIndexedCompletion: 'NonIndexed', + IndexedCompletion: 'Indexed' +} as const; diff --git a/ui/src/gen/api/v2/models/v1Condition.ts b/ui/src/gen/api/v2/models/v1Condition.ts new file mode 100644 index 0000000000..b5a0219b60 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Condition.ts @@ -0,0 +1,55 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1Condition { + /** lastTransitionTime is the 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. ++required ++kubebuilder:validation:Required ++kubebuilder:validation:Type=string ++kubebuilder:validation:Format=date-time */ + lastTransitionTime: string; + /** message is a human readable message indicating details about the transition. +This may be an empty string. ++required ++kubebuilder:validation:Required ++kubebuilder:validation:MaxLength=32768 */ + message: string; + /** observedGeneration represents the .metadata.generation that the condition was set based upon. +For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date +with respect to the current state of the instance. ++optional ++kubebuilder:validation:Minimum=0 */ + observedGeneration?: number; + /** reason contains a programmatic identifier indicating the reason for the condition's last transition. +Producers of specific condition types may define expected values and meanings for this field, +and whether the values are considered a guaranteed API. +The value should be a CamelCase string. +This field may not be empty. ++required ++kubebuilder:validation:Required ++kubebuilder:validation:MaxLength=1024 ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:Pattern=`^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$` */ + reason: string; + /** status of the condition, one of True, False, Unknown. ++required ++kubebuilder:validation:Required ++kubebuilder:validation:Enum=True;False;Unknown */ + status: string; + /** 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. +The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) ++required ++kubebuilder:validation:Required ++kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$` ++kubebuilder:validation:MaxLength=316 */ + type: string; +} diff --git a/ui/src/gen/api/v2/models/v1ConfigMap.ts b/ui/src/gen/api/v2/models/v1ConfigMap.ts new file mode 100644 index 0000000000..3240864d0b --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMap.ts @@ -0,0 +1,52 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ConfigMapBinaryData } from './v1ConfigMapBinaryData'; +import type { V1ConfigMapData } from './v1ConfigMapData'; +import type { V1ObjectMeta } from './v1ObjectMeta'; + +export interface V1ConfigMap { + /** 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 ++optional */ + apiVersion?: string; + /** BinaryData contains the binary data. +Each key must consist of alphanumeric characters, '-', '_' or '.'. +BinaryData can contain byte sequences that are not in the UTF-8 range. +The keys stored in BinaryData must not overlap with the ones in +the Data field, this is enforced during validation process. +Using this field will require 1.10+ apiserver and +kubelet. ++optional */ + binaryData?: V1ConfigMapBinaryData; + /** Data contains the configuration data. +Each key must consist of alphanumeric characters, '-', '_' or '.'. +Values with non-UTF-8 byte sequences must use the BinaryData field. +The keys stored in Data must not overlap with the keys in +the BinaryData field, this is enforced during validation process. ++optional */ + data?: V1ConfigMapData; + /** Immutable, if set to true, ensures that data stored in the ConfigMap cannot +be updated (only object metadata can be modified). +If not set to true, the field can be modified at any time. +Defaulted to nil. ++optional */ + immutable?: boolean; + /** 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 ++optional */ + kind?: string; + /** Standard object's metadata. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + metadata?: V1ObjectMeta; +} diff --git a/ui/src/gen/api/v2/models/v1ConfigMapBinaryData.ts b/ui/src/gen/api/v2/models/v1ConfigMapBinaryData.ts new file mode 100644 index 0000000000..9271926b5f --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapBinaryData.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * BinaryData contains the binary data. +Each key must consist of alphanumeric characters, '-', '_' or '.'. +BinaryData can contain byte sequences that are not in the UTF-8 range. +The keys stored in BinaryData must not overlap with the ones in +the Data field, this is enforced during validation process. +Using this field will require 1.10+ apiserver and +kubelet. ++optional + */ +export type V1ConfigMapBinaryData = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1ConfigMapData.ts b/ui/src/gen/api/v2/models/v1ConfigMapData.ts new file mode 100644 index 0000000000..64911a0a5e --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapData.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Data contains the configuration data. +Each key must consist of alphanumeric characters, '-', '_' or '.'. +Values with non-UTF-8 byte sequences must use the BinaryData field. +The keys stored in Data must not overlap with the keys in +the BinaryData field, this is enforced during validation process. ++optional + */ +export type V1ConfigMapData = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1ConfigMapEnvSource.ts b/ui/src/gen/api/v2/models/v1ConfigMapEnvSource.ts new file mode 100644 index 0000000000..b9b62d1a37 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapEnvSource.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ConfigMapEnvSource { + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** Specify whether the ConfigMap must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1ConfigMapKeySelector.ts b/ui/src/gen/api/v2/models/v1ConfigMapKeySelector.ts new file mode 100644 index 0000000000..f33660a29d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapKeySelector.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ConfigMapKeySelector { + /** The key to select. */ + key?: string; + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** Specify whether the ConfigMap or its key must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1ConfigMapList.ts b/ui/src/gen/api/v2/models/v1ConfigMapList.ts new file mode 100644 index 0000000000..de96a067fe --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapList.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ConfigMap } from './v1ConfigMap'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface V1ConfigMapList { + /** 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 ++optional */ + apiVersion?: string; + /** Items is the list of ConfigMaps. */ + items?: V1ConfigMap[]; + /** 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 ++optional */ + kind?: string; + /** More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/v1ConfigMapProjection.ts b/ui/src/gen/api/v2/models/v1ConfigMapProjection.ts new file mode 100644 index 0000000000..47cb91e98a --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapProjection.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1KeyToPath } from './v1KeyToPath'; + +export interface V1ConfigMapProjection { + /** items if unspecified, each key-value pair in the Data field of the referenced +ConfigMap will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the ConfigMap, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional ++listType=atomic */ + items?: V1KeyToPath[]; + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** optional specify whether the ConfigMap or its keys must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1ConfigMapVolumeSource.ts b/ui/src/gen/api/v2/models/v1ConfigMapVolumeSource.ts new file mode 100644 index 0000000000..402dd6ada9 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ConfigMapVolumeSource.ts @@ -0,0 +1,43 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1KeyToPath } from './v1KeyToPath'; + +export interface V1ConfigMapVolumeSource { + /** defaultMode is optional: mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +Defaults to 0644. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number; + /** items if unspecified, each key-value pair in the Data field of the referenced +ConfigMap will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the ConfigMap, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional ++listType=atomic */ + items?: V1KeyToPath[]; + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** optional specify whether the ConfigMap or its keys must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1Container.ts b/ui/src/gen/api/v2/models/v1Container.ts new file mode 100644 index 0000000000..a26e8c573c --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Container.ts @@ -0,0 +1,221 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1EnvVar } from './v1EnvVar'; +import type { V1EnvFromSource } from './v1EnvFromSource'; +import type { V1Lifecycle } from './v1Lifecycle'; +import type { V1Probe } from './v1Probe'; +import type { V1ContainerPort } from './v1ContainerPort'; +import type { V1ContainerResizePolicy } from './v1ContainerResizePolicy'; +import type { V1ResourceRequirements } from './v1ResourceRequirements'; +import type { V1ContainerRestartRule } from './v1ContainerRestartRule'; +import type { V1SecurityContext } from './v1SecurityContext'; +import type { V1VolumeDevice } from './v1VolumeDevice'; +import type { V1VolumeMount } from './v1VolumeMount'; + +export interface V1Container { + /** Arguments to the entrypoint. +The container image's CMD is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. +More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell ++optional ++listType=atomic */ + args?: string[]; + /** Entrypoint array. Not executed within a shell. +The container image's ENTRYPOINT is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. +More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell ++optional ++listType=atomic */ + command?: string[]; + /** List of environment variables to set in the container. +Cannot be updated. ++optional ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name */ + env?: V1EnvVar[]; + /** List of sources to populate environment variables in the container. +The keys defined within a source may consist of any printable ASCII characters except '='. +When a key exists in multiple +sources, the value associated with the last source will take precedence. +Values defined by an Env with a duplicate key will take precedence. +Cannot be updated. ++optional ++listType=atomic */ + envFrom?: V1EnvFromSource[]; + /** Container image name. +More info: https://kubernetes.io/docs/concepts/containers/images +This field is optional to allow higher level config management to default or override +container images in workload controllers like Deployments and StatefulSets. ++optional */ + image?: string; + /** Image pull policy. +One of Always, Never, IfNotPresent. +Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/containers/images#updating-images ++optional */ + imagePullPolicy?: string; + /** Actions that the management system should take in response to container lifecycle events. +Cannot be updated. ++optional */ + lifecycle?: V1Lifecycle; + /** Periodic probe of container liveness. +Container will be restarted if the probe fails. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + livenessProbe?: V1Probe; + /** Name of the container specified as a DNS_LABEL. +Each container in a pod must have a unique name (DNS_LABEL). +Cannot be updated. */ + name?: string; + /** List of ports to expose from the container. Not specifying a port here +DOES NOT prevent that port from being exposed. Any port which is +listening on the default "0.0.0.0" address inside a container will be +accessible from the network. +Modifying this array with strategic merge patch may corrupt the data. +For more information See https://github.com/kubernetes/kubernetes/issues/108255. +Cannot be updated. ++optional ++patchMergeKey=containerPort ++patchStrategy=merge ++listType=map ++listMapKey=containerPort ++listMapKey=protocol */ + ports?: V1ContainerPort[]; + /** Periodic probe of container service readiness. +Container will be removed from service endpoints if the probe fails. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + readinessProbe?: V1Probe; + /** Resources resize policy for the container. ++featureGate=InPlacePodVerticalScaling ++optional ++listType=atomic */ + resizePolicy?: V1ContainerResizePolicy[]; + /** Compute Resources required by this container. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ ++optional */ + resources?: V1ResourceRequirements; + /** RestartPolicy defines the restart behavior of individual containers in a pod. +This overrides the pod-level restart policy. When this field is not specified, +the restart behavior is defined by the Pod's restart policy and the container type. +Additionally, setting the RestartPolicy as "Always" for the init container will +have the following effect: +this init container will be continually restarted on +exit until all regular containers have terminated. Once all regular +containers have completed, all init containers with restartPolicy "Always" +will be shut down. This lifecycle differs from normal init containers and +is often referred to as a "sidecar" container. Although this init +container still starts in the init container sequence, it does not wait +for the container to complete before proceeding to the next init +container. Instead, the next init container starts immediately after this +init container is started, or after any startupProbe has successfully +completed. ++featureGate=SidecarContainers ++optional */ + restartPolicy?: string; + /** Represents a list of rules to be checked to determine if the +container should be restarted on exit. The rules are evaluated in +order. Once a rule matches a container exit condition, the remaining +rules are ignored. If no rule matches the container exit condition, +the Container-level restart policy determines the whether the container +is restarted or not. Constraints on the rules: +- At most 20 rules are allowed. +- Rules can have the same action. +- Identical rules are not forbidden in validations. +When rules are specified, container MUST set RestartPolicy explicitly +even it if matches the Pod's RestartPolicy. ++featureGate=ContainerRestartRules ++optional ++listType=atomic */ + restartPolicyRules?: V1ContainerRestartRule[]; + /** SecurityContext defines the security options the container should be run with. +If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. +More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ ++optional */ + securityContext?: V1SecurityContext; + /** StartupProbe indicates that the Pod has successfully initialized. +If specified, no other probes are executed until this completes successfully. +If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. +This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, +when it might take a long time to load data or warm a cache, than during steady-state operation. +This cannot be updated. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + startupProbe?: V1Probe; + /** Whether this container should allocate a buffer for stdin in the container runtime. If this +is not set, reads from stdin in the container will always result in EOF. +Default is false. ++optional */ + stdin?: boolean; + /** Whether the container runtime should close the stdin channel after it has been opened by +a single attach. When stdin is true the stdin stream will remain open across multiple attach +sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the +first client attaches to stdin, and then remains open and accepts data until the client disconnects, +at which time stdin is closed and remains closed until the container is restarted. If this +flag is false, a container processes that reads from stdin will never receive an EOF. +Default is false ++optional */ + stdinOnce?: boolean; + /** Optional: Path at which the file to which the container's termination message +will be written is mounted into the container's filesystem. +Message written is intended to be brief final status, such as an assertion failure message. +Will be truncated by the node if greater than 4096 bytes. The total message length across +all containers will be limited to 12kb. +Defaults to /dev/termination-log. +Cannot be updated. ++optional */ + terminationMessagePath?: string; + /** Indicate how the termination message should be populated. File will use the contents of +terminationMessagePath to populate the container status message on both success and failure. +FallbackToLogsOnError will use the last chunk of container log output if the termination +message file is empty and the container exited with an error. +The log output is limited to 2048 bytes or 80 lines, whichever is smaller. +Defaults to File. +Cannot be updated. ++optional */ + terminationMessagePolicy?: string; + /** Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. +Default is false. ++optional */ + tty?: boolean; + /** volumeDevices is the list of block devices to be used by the container. ++patchMergeKey=devicePath ++patchStrategy=merge ++listType=map ++listMapKey=devicePath ++optional */ + volumeDevices?: V1VolumeDevice[]; + /** Pod volumes to mount into the container's filesystem. +Cannot be updated. ++optional ++patchMergeKey=mountPath ++patchStrategy=merge ++listType=map ++listMapKey=mountPath */ + volumeMounts?: V1VolumeMount[]; + /** Container's working directory. +If not specified, the container runtime's default will be used, which +might be configured in the container image. +Cannot be updated. ++optional */ + workingDir?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ContainerPort.ts b/ui/src/gen/api/v2/models/v1ContainerPort.ts new file mode 100644 index 0000000000..65d9322070 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ContainerPort.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ContainerPort { + /** Number of port to expose on the pod's IP address. +This must be a valid port number, 0 < x < 65536. */ + containerPort?: number; + /** What host IP to bind the external port to. ++optional */ + hostIP?: string; + /** Number of port to expose on the host. +If specified, this must be a valid port number, 0 < x < 65536. +If HostNetwork is specified, this must match ContainerPort. +Most containers do not need this. ++optional */ + hostPort?: number; + /** If specified, this must be an IANA_SVC_NAME and unique within the pod. Each +named port in a pod must have a unique name. Name for the port that can be +referred to by services. ++optional */ + name?: string; + /** Protocol for port. Must be UDP, TCP, or SCTP. +Defaults to "TCP". ++optional ++default="TCP" */ + protocol?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ContainerResizePolicy.ts b/ui/src/gen/api/v2/models/v1ContainerResizePolicy.ts new file mode 100644 index 0000000000..1829bd7e9c --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ContainerResizePolicy.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ContainerResizePolicy { + /** Name of the resource to which this resource resize policy applies. +Supported values: cpu, memory. */ + resourceName?: string; + /** Restart policy to apply when specified resource is resized. +If not specified, it defaults to NotRequired. */ + restartPolicy?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ContainerRestartRule.ts b/ui/src/gen/api/v2/models/v1ContainerRestartRule.ts new file mode 100644 index 0000000000..667a541157 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ContainerRestartRule.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ContainerRestartRuleOnExitCodes } from './v1ContainerRestartRuleOnExitCodes'; + +export interface V1ContainerRestartRule { + /** Specifies the action taken on a container exit if the requirements +are satisfied. The only possible value is "Restart" to restart the +container. ++required */ + action?: string; + /** Represents the exit codes to check on container exits. ++optional ++oneOf=when */ + exitCodes?: V1ContainerRestartRuleOnExitCodes; +} diff --git a/ui/src/gen/api/v2/models/v1ContainerRestartRuleOnExitCodes.ts b/ui/src/gen/api/v2/models/v1ContainerRestartRuleOnExitCodes.ts new file mode 100644 index 0000000000..93e781f28d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ContainerRestartRuleOnExitCodes.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ContainerRestartRuleOnExitCodes { + /** Represents the relationship between the container exit code(s) and the +specified values. Possible values are: +- In: the requirement is satisfied if the container exit code is in the + set of specified values. +- NotIn: the requirement is satisfied if the container exit code is + not in the set of specified values. ++required */ + operator?: string; + /** Specifies the set of values to check for container exit codes. +At most 255 elements are allowed. ++optional ++listType=set */ + values?: number[]; +} diff --git a/ui/src/gen/api/v2/models/v1DownwardAPIProjection.ts b/ui/src/gen/api/v2/models/v1DownwardAPIProjection.ts new file mode 100644 index 0000000000..b9f64321c6 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1DownwardAPIProjection.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1DownwardAPIVolumeFile } from './v1DownwardAPIVolumeFile'; + +export interface V1DownwardAPIProjection { + /** Items is a list of DownwardAPIVolume file ++optional ++listType=atomic */ + items?: V1DownwardAPIVolumeFile[]; +} diff --git a/ui/src/gen/api/v2/models/v1DownwardAPIVolumeFile.ts b/ui/src/gen/api/v2/models/v1DownwardAPIVolumeFile.ts new file mode 100644 index 0000000000..d65ccef9af --- /dev/null +++ b/ui/src/gen/api/v2/models/v1DownwardAPIVolumeFile.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectFieldSelector } from './v1ObjectFieldSelector'; +import type { V1ResourceFieldSelector } from './v1ResourceFieldSelector'; + +export interface V1DownwardAPIVolumeFile { + /** Required: Selects a field of the pod: only annotations, labels, name, namespace and uid are supported. ++optional */ + fieldRef?: V1ObjectFieldSelector; + /** Optional: mode bits used to set permissions on this file, must be an octal value +between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +If not specified, the volume defaultMode will be used. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + mode?: number; + /** Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..' */ + path?: string; + /** Selects a resource of the container: only resources limits and requests +(limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. ++optional */ + resourceFieldRef?: V1ResourceFieldSelector; +} diff --git a/ui/src/gen/api/v2/models/v1DownwardAPIVolumeSource.ts b/ui/src/gen/api/v2/models/v1DownwardAPIVolumeSource.ts new file mode 100644 index 0000000000..3bad6655e2 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1DownwardAPIVolumeSource.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1DownwardAPIVolumeFile } from './v1DownwardAPIVolumeFile'; + +export interface V1DownwardAPIVolumeSource { + /** Optional: mode bits to use on created files by default. Must be a +Optional: mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +Defaults to 0644. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number; + /** Items is a list of downward API volume file ++optional ++listType=atomic */ + items?: V1DownwardAPIVolumeFile[]; +} diff --git a/ui/src/gen/api/v2/models/v1EmptyDirVolumeSource.ts b/ui/src/gen/api/v2/models/v1EmptyDirVolumeSource.ts new file mode 100644 index 0000000000..a1e7878f86 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EmptyDirVolumeSource.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Quantity } from './quantity'; + +export interface V1EmptyDirVolumeSource { + /** medium represents what type of storage medium should back this directory. +The default is "" which means to use the node's default medium. +Must be an empty string (default) or Memory. +More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir ++optional */ + medium?: string; + /** sizeLimit is the total amount of local storage required for this EmptyDir volume. +The size limit is also applicable for memory medium. +The maximum usage on memory medium EmptyDir would be the minimum value between +the SizeLimit specified here and the sum of memory limits of all containers in a pod. +The default is nil which means that the limit is undefined. +More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir ++optional */ + sizeLimit?: Quantity; +} diff --git a/ui/src/gen/api/v2/models/v1EnvFromSource.ts b/ui/src/gen/api/v2/models/v1EnvFromSource.ts new file mode 100644 index 0000000000..229390bd7f --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EnvFromSource.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ConfigMapEnvSource } from './v1ConfigMapEnvSource'; +import type { V1SecretEnvSource } from './v1SecretEnvSource'; + +export interface V1EnvFromSource { + /** The ConfigMap to select from ++optional */ + configMapRef?: V1ConfigMapEnvSource; + /** Optional text to prepend to the name of each environment variable. +May consist of any printable ASCII characters except '='. ++optional */ + prefix?: string; + /** The Secret to select from ++optional */ + secretRef?: V1SecretEnvSource; +} diff --git a/ui/src/gen/api/v2/models/v1EnvVar.ts b/ui/src/gen/api/v2/models/v1EnvVar.ts new file mode 100644 index 0000000000..d0784260d2 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EnvVar.ts @@ -0,0 +1,28 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1EnvVarSource } from './v1EnvVarSource'; + +export interface V1EnvVar { + /** Name of the environment variable. +May consist of any printable ASCII characters except '='. */ + name?: string; + /** Variable references $(VAR_NAME) are expanded +using the previously defined environment variables in the container and +any service environment variables. If a variable cannot be resolved, +the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. +"$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". +Escaped references will never be expanded, regardless of whether the variable +exists or not. +Defaults to "". ++optional */ + value?: string; + /** Source for the environment variable's value. Cannot be used if value is not empty. ++optional */ + valueFrom?: V1EnvVarSource; +} diff --git a/ui/src/gen/api/v2/models/v1EnvVarSource.ts b/ui/src/gen/api/v2/models/v1EnvVarSource.ts new file mode 100644 index 0000000000..629854e8a4 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EnvVarSource.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ConfigMapKeySelector } from './v1ConfigMapKeySelector'; +import type { V1ObjectFieldSelector } from './v1ObjectFieldSelector'; +import type { V1FileKeySelector } from './v1FileKeySelector'; +import type { V1ResourceFieldSelector } from './v1ResourceFieldSelector'; +import type { V1SecretKeySelector } from './v1SecretKeySelector'; + +export interface V1EnvVarSource { + /** Selects a key of a ConfigMap. ++optional */ + configMapKeyRef?: V1ConfigMapKeySelector; + /** Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, +spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. ++optional */ + fieldRef?: V1ObjectFieldSelector; + /** FileKeyRef selects a key of the env file. +Requires the EnvFiles feature gate to be enabled. + ++featureGate=EnvFiles ++optional */ + fileKeyRef?: V1FileKeySelector; + /** Selects a resource of the container: only resources limits and requests +(limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. ++optional */ + resourceFieldRef?: V1ResourceFieldSelector; + /** Selects a key of a secret in the pod's namespace ++optional */ + secretKeyRef?: V1SecretKeySelector; +} diff --git a/ui/src/gen/api/v2/models/v1EphemeralContainer.ts b/ui/src/gen/api/v2/models/v1EphemeralContainer.ts new file mode 100644 index 0000000000..8296f55ecc --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EphemeralContainer.ts @@ -0,0 +1,184 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1EnvVar } from './v1EnvVar'; +import type { V1EnvFromSource } from './v1EnvFromSource'; +import type { V1Lifecycle } from './v1Lifecycle'; +import type { V1Probe } from './v1Probe'; +import type { V1ContainerPort } from './v1ContainerPort'; +import type { V1ContainerResizePolicy } from './v1ContainerResizePolicy'; +import type { V1ResourceRequirements } from './v1ResourceRequirements'; +import type { V1ContainerRestartRule } from './v1ContainerRestartRule'; +import type { V1SecurityContext } from './v1SecurityContext'; +import type { V1VolumeDevice } from './v1VolumeDevice'; +import type { V1VolumeMount } from './v1VolumeMount'; + +export interface V1EphemeralContainer { + /** Arguments to the entrypoint. +The image's CMD is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. +More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell ++optional ++listType=atomic */ + args?: string[]; + /** Entrypoint array. Not executed within a shell. +The image's ENTRYPOINT is used if this is not provided. +Variable references $(VAR_NAME) are expanded using the container's environment. If a variable +cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced +to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will +produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless +of whether the variable exists or not. Cannot be updated. +More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell ++optional ++listType=atomic */ + command?: string[]; + /** List of environment variables to set in the container. +Cannot be updated. ++optional ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name */ + env?: V1EnvVar[]; + /** List of sources to populate environment variables in the container. +The keys defined within a source may consist of any printable ASCII characters except '='. +When a key exists in multiple +sources, the value associated with the last source will take precedence. +Values defined by an Env with a duplicate key will take precedence. +Cannot be updated. ++optional ++listType=atomic */ + envFrom?: V1EnvFromSource[]; + /** Container image name. +More info: https://kubernetes.io/docs/concepts/containers/images */ + image?: string; + /** Image pull policy. +One of Always, Never, IfNotPresent. +Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/containers/images#updating-images ++optional */ + imagePullPolicy?: string; + /** Lifecycle is not allowed for ephemeral containers. ++optional */ + lifecycle?: V1Lifecycle; + /** Probes are not allowed for ephemeral containers. ++optional */ + livenessProbe?: V1Probe; + /** Name of the ephemeral container specified as a DNS_LABEL. +This name must be unique among all containers, init containers and ephemeral containers. */ + name?: string; + /** Ports are not allowed for ephemeral containers. ++optional ++patchMergeKey=containerPort ++patchStrategy=merge ++listType=map ++listMapKey=containerPort ++listMapKey=protocol */ + ports?: V1ContainerPort[]; + /** Probes are not allowed for ephemeral containers. ++optional */ + readinessProbe?: V1Probe; + /** Resources resize policy for the container. ++featureGate=InPlacePodVerticalScaling ++optional ++listType=atomic */ + resizePolicy?: V1ContainerResizePolicy[]; + /** Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources +already allocated to the pod. ++optional */ + resources?: V1ResourceRequirements; + /** Restart policy for the container to manage the restart behavior of each +container within a pod. +You cannot set this field on ephemeral containers. ++featureGate=SidecarContainers ++optional */ + restartPolicy?: string; + /** Represents a list of rules to be checked to determine if the +container should be restarted on exit. You cannot set this field on +ephemeral containers. ++featureGate=ContainerRestartRules ++optional ++listType=atomic */ + restartPolicyRules?: V1ContainerRestartRule[]; + /** Optional: SecurityContext defines the security options the ephemeral container should be run with. +If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. ++optional */ + securityContext?: V1SecurityContext; + /** Probes are not allowed for ephemeral containers. ++optional */ + startupProbe?: V1Probe; + /** Whether this container should allocate a buffer for stdin in the container runtime. If this +is not set, reads from stdin in the container will always result in EOF. +Default is false. ++optional */ + stdin?: boolean; + /** Whether the container runtime should close the stdin channel after it has been opened by +a single attach. When stdin is true the stdin stream will remain open across multiple attach +sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the +first client attaches to stdin, and then remains open and accepts data until the client disconnects, +at which time stdin is closed and remains closed until the container is restarted. If this +flag is false, a container processes that reads from stdin will never receive an EOF. +Default is false ++optional */ + stdinOnce?: boolean; + /** If set, the name of the container from PodSpec that this ephemeral container targets. +The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. +If not set then the ephemeral container uses the namespaces configured in the Pod spec. + +The container runtime must implement support for this feature. If the runtime does not +support namespace targeting then the result of setting this field is undefined. ++optional */ + targetContainerName?: string; + /** Optional: Path at which the file to which the container's termination message +will be written is mounted into the container's filesystem. +Message written is intended to be brief final status, such as an assertion failure message. +Will be truncated by the node if greater than 4096 bytes. The total message length across +all containers will be limited to 12kb. +Defaults to /dev/termination-log. +Cannot be updated. ++optional */ + terminationMessagePath?: string; + /** Indicate how the termination message should be populated. File will use the contents of +terminationMessagePath to populate the container status message on both success and failure. +FallbackToLogsOnError will use the last chunk of container log output if the termination +message file is empty and the container exited with an error. +The log output is limited to 2048 bytes or 80 lines, whichever is smaller. +Defaults to File. +Cannot be updated. ++optional */ + terminationMessagePolicy?: string; + /** Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. +Default is false. ++optional */ + tty?: boolean; + /** volumeDevices is the list of block devices to be used by the container. ++patchMergeKey=devicePath ++patchStrategy=merge ++listType=map ++listMapKey=devicePath ++optional */ + volumeDevices?: V1VolumeDevice[]; + /** Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. +Cannot be updated. ++optional ++patchMergeKey=mountPath ++patchStrategy=merge ++listType=map ++listMapKey=mountPath */ + volumeMounts?: V1VolumeMount[]; + /** Container's working directory. +If not specified, the container runtime's default will be used, which +might be configured in the container image. +Cannot be updated. ++optional */ + workingDir?: string; +} diff --git a/ui/src/gen/api/v2/models/v1EphemeralVolumeSource.ts b/ui/src/gen/api/v2/models/v1EphemeralVolumeSource.ts new file mode 100644 index 0000000000..b497b12d86 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EphemeralVolumeSource.ts @@ -0,0 +1,33 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PersistentVolumeClaimTemplate } from './v1PersistentVolumeClaimTemplate'; + +export interface V1EphemeralVolumeSource { + /** Will be used to create a stand-alone PVC to provision the volume. +The pod in which this EphemeralVolumeSource is embedded will be the +owner of the PVC, i.e. the PVC will be deleted together with the +pod. The name of the PVC will be `-` where +`` is the name from the `PodSpec.Volumes` array +entry. Pod validation will reject the pod if the concatenated name +is not valid for a PVC (for example, too long). + +An existing PVC with that name that is not owned by the pod +will *not* be used for the pod to avoid using an unrelated +volume by mistake. Starting the pod is then blocked until +the unrelated PVC is removed. If such a pre-created PVC is +meant to be used by the pod, the PVC has to updated with an +owner reference to the pod once the pod exists. Normally +this should not be necessary, but it may be useful when +manually reconstructing a broken cluster. + +This field is read-only and no changes will be made by Kubernetes +to the PVC after it has been created. + +Required, must not be nil. */ + volumeClaimTemplate?: V1PersistentVolumeClaimTemplate; +} diff --git a/ui/src/gen/api/v2/models/v1Event.ts b/ui/src/gen/api/v2/models/v1Event.ts new file mode 100644 index 0000000000..a5935d47e9 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Event.ts @@ -0,0 +1,75 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1MicroTime } from './v1MicroTime'; +import type { V1ObjectReference } from './v1ObjectReference'; +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { V1EventSeries } from './v1EventSeries'; +import type { V1EventSource } from './v1EventSource'; + +export interface V1Event { + /** What action was taken/failed regarding to the Regarding object. ++optional */ + action?: string; + /** 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 ++optional */ + apiVersion?: string; + /** The number of times this event has occurred. ++optional */ + count?: number; + /** Time when this Event was first observed. ++optional */ + eventTime?: V1MicroTime; + /** The time at which the event was first recorded. (Time of server receipt is in TypeMeta.) ++optional */ + firstTimestamp?: string; + /** The object that this event is about. */ + involvedObject?: V1ObjectReference; + /** 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 ++optional */ + kind?: string; + /** The time at which the most recent occurrence of this event was recorded. ++optional */ + lastTimestamp?: string; + /** A human-readable description of the status of this operation. +TODO: decide on maximum length. ++optional */ + message?: string; + /** Standard object's metadata. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + metadata?: V1ObjectMeta; + /** This should be a short, machine understandable string that gives the reason +for the transition into the object's current status. +TODO: provide exact specification for format. ++optional */ + reason?: string; + /** Optional secondary object for more complex actions. ++optional */ + related?: V1ObjectReference; + /** Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`. ++optional */ + reportingComponent?: string; + /** ID of the controller instance, e.g. `kubelet-xyzf`. ++optional */ + reportingInstance?: string; + /** Data about the Event series this event represents or nil if it's a singleton Event. ++optional */ + series?: V1EventSeries; + /** The component reporting this event. Should be a short machine understandable string. ++optional */ + source?: V1EventSource; + /** Type of this event (Normal, Warning), new types could be added in the future ++optional */ + type?: string; +} diff --git a/ui/src/gen/api/v2/models/v1EventList.ts b/ui/src/gen/api/v2/models/v1EventList.ts new file mode 100644 index 0000000000..549ab39299 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EventList.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Event } from './v1Event'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface V1EventList { + /** 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 ++optional */ + apiVersion?: string; + /** List of events */ + items?: V1Event[]; + /** 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 ++optional */ + kind?: string; + /** Standard list metadata. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/v1EventSeries.ts b/ui/src/gen/api/v2/models/v1EventSeries.ts new file mode 100644 index 0000000000..5e4baeb629 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EventSeries.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1MicroTime } from './v1MicroTime'; + +export interface V1EventSeries { + /** Number of occurrences in this series up to the last heartbeat time */ + count?: number; + /** Time of the last occurrence observed */ + lastObservedTime?: V1MicroTime; +} diff --git a/ui/src/gen/api/v2/models/v1EventSource.ts b/ui/src/gen/api/v2/models/v1EventSource.ts new file mode 100644 index 0000000000..9263cac2e0 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1EventSource.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1EventSource { + /** Component from which the event is generated. ++optional */ + component?: string; + /** Node name on which the event is generated. ++optional */ + host?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ExecAction.ts b/ui/src/gen/api/v2/models/v1ExecAction.ts new file mode 100644 index 0000000000..25e62c8ead --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ExecAction.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ExecAction { + /** Command is the command line to execute inside the container, the working directory for the +command is root ('/') in the container's filesystem. The command is simply exec'd, it is +not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use +a shell, you need to explicitly call out to that shell. +Exit status of 0 is treated as live/healthy and non-zero is unhealthy. ++optional ++listType=atomic */ + command?: string[]; +} diff --git a/ui/src/gen/api/v2/models/v1FCVolumeSource.ts b/ui/src/gen/api/v2/models/v1FCVolumeSource.ts new file mode 100644 index 0000000000..632ef7a475 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1FCVolumeSource.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1FCVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string; + /** lun is Optional: FC target lun number ++optional */ + lun?: number; + /** readOnly is Optional: Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean; + /** targetWWNs is Optional: FC target worldwide names (WWNs) ++optional ++listType=atomic */ + targetWWNs?: string[]; + /** wwids Optional: FC volume world wide identifiers (wwids) +Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. ++optional ++listType=atomic */ + wwids?: string[]; +} diff --git a/ui/src/gen/api/v2/models/getPromotion200.ts b/ui/src/gen/api/v2/models/v1FieldsV1.ts similarity index 70% rename from ui/src/gen/api/v2/models/getPromotion200.ts rename to ui/src/gen/api/v2/models/v1FieldsV1.ts index e7b6ebea5b..6a157e95f9 100644 --- a/ui/src/gen/api/v2/models/getPromotion200.ts +++ b/ui/src/gen/api/v2/models/v1FieldsV1.ts @@ -6,4 +6,6 @@ * OpenAPI spec version: v1alpha1 */ -export type GetPromotion200 = { [key: string]: unknown }; +export interface V1FieldsV1 { + [key: string]: unknown; +} diff --git a/ui/src/gen/api/v2/models/v1FileKeySelector.ts b/ui/src/gen/api/v2/models/v1FileKeySelector.ts new file mode 100644 index 0000000000..425c89c529 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1FileKeySelector.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1FileKeySelector { + /** The key within the env file. An invalid key will prevent the pod from starting. +The keys defined within a source may consist of any printable ASCII characters except '='. +During Alpha stage of the EnvFiles feature gate, the key size is limited to 128 characters. ++required */ + key?: string; + /** Specify whether the file or its key must be defined. If the file or key +does not exist, then the env var is not published. +If optional is set to true and the specified key does not exist, +the environment variable will not be set in the Pod's containers. + +If optional is set to false and the specified key does not exist, +an error will be returned during Pod creation. ++optional ++default=false */ + optional?: boolean; + /** The path within the volume from which to select the file. +Must be relative and may not contain the '..' path or start with '..'. ++required */ + path?: string; + /** The name of the volume mount containing the env file. ++required */ + volumeName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1FlexVolumeSource.ts b/ui/src/gen/api/v2/models/v1FlexVolumeSource.ts new file mode 100644 index 0000000000..83f22c158b --- /dev/null +++ b/ui/src/gen/api/v2/models/v1FlexVolumeSource.ts @@ -0,0 +1,33 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1FlexVolumeSourceOptions } from './v1FlexVolumeSourceOptions'; +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1FlexVolumeSource { + /** driver is the name of the driver to use for this volume. */ + driver?: string; + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. ++optional */ + fsType?: string; + /** options is Optional: this field holds extra command options if any. ++optional */ + options?: V1FlexVolumeSourceOptions; + /** readOnly is Optional: defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean; + /** secretRef is Optional: secretRef is reference to the secret object containing +sensitive information to pass to the plugin scripts. This may be +empty if no secret object is specified. If the secret object +contains more than one secret, all secrets are passed to the plugin +scripts. ++optional */ + secretRef?: V1LocalObjectReference; +} diff --git a/ui/src/gen/api/v2/models/v1FlexVolumeSourceOptions.ts b/ui/src/gen/api/v2/models/v1FlexVolumeSourceOptions.ts new file mode 100644 index 0000000000..5ff6ce5e16 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1FlexVolumeSourceOptions.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * options is Optional: this field holds extra command options if any. ++optional + */ +export type V1FlexVolumeSourceOptions = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1FlockerVolumeSource.ts b/ui/src/gen/api/v2/models/v1FlockerVolumeSource.ts new file mode 100644 index 0000000000..14e182895d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1FlockerVolumeSource.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1FlockerVolumeSource { + /** datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker +should be considered as deprecated ++optional */ + datasetName?: string; + /** datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset ++optional */ + datasetUUID?: string; +} diff --git a/ui/src/gen/api/v2/models/v1GCEPersistentDiskVolumeSource.ts b/ui/src/gen/api/v2/models/v1GCEPersistentDiskVolumeSource.ts new file mode 100644 index 0000000000..2d7caa56e2 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1GCEPersistentDiskVolumeSource.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1GCEPersistentDiskVolumeSource { + /** fsType is filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string; + /** partition is the partition in the volume that you want to mount. +If omitted, the default is to mount by volume name. +Examples: For volume /dev/sda1, you specify the partition as "1". +Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk ++optional */ + partition?: number; + /** pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk */ + pdName?: string; + /** readOnly here will force the ReadOnly setting in VolumeMounts. +Defaults to false. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk ++optional */ + readOnly?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1GRPCAction.ts b/ui/src/gen/api/v2/models/v1GRPCAction.ts new file mode 100644 index 0000000000..81ea6b6450 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1GRPCAction.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1GRPCAction { + /** Port number of the gRPC service. Number must be in the range 1 to 65535. */ + port?: number; + /** Service is the name of the service to place in the gRPC HealthCheckRequest +(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + +If this is not specified, the default behavior is defined by gRPC. ++optional ++default="" */ + service?: string; +} diff --git a/ui/src/gen/api/v2/models/v1GitRepoVolumeSource.ts b/ui/src/gen/api/v2/models/v1GitRepoVolumeSource.ts new file mode 100644 index 0000000000..74c3f4a985 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1GitRepoVolumeSource.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1GitRepoVolumeSource { + /** directory is the target directory name. +Must not contain or start with '..'. If '.' is supplied, the volume directory will be the +git repository. Otherwise, if specified, the volume will contain the git repository in +the subdirectory with the given name. ++optional */ + directory?: string; + /** repository is the URL */ + repository?: string; + /** revision is the commit hash for the specified revision. ++optional */ + revision?: string; +} diff --git a/ui/src/gen/api/v2/models/v1GlusterfsVolumeSource.ts b/ui/src/gen/api/v2/models/v1GlusterfsVolumeSource.ts new file mode 100644 index 0000000000..b17011d791 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1GlusterfsVolumeSource.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1GlusterfsVolumeSource { + /** endpoints is the endpoint name that details Glusterfs topology. */ + endpoints?: string; + /** path is the Glusterfs volume path. +More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod */ + path?: string; + /** readOnly here will force the Glusterfs volume to be mounted with read-only permissions. +Defaults to false. +More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod ++optional */ + readOnly?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1HTTPGetAction.ts b/ui/src/gen/api/v2/models/v1HTTPGetAction.ts new file mode 100644 index 0000000000..0e0eaa5e34 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1HTTPGetAction.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1HTTPHeader } from './v1HTTPHeader'; +import type { IntOrString } from './intOrString'; + +export interface V1HTTPGetAction { + /** Host name to connect to, defaults to the pod IP. You probably want to set +"Host" in httpHeaders instead. ++optional */ + host?: string; + /** Custom headers to set in the request. HTTP allows repeated headers. ++optional ++listType=atomic */ + httpHeaders?: V1HTTPHeader[]; + /** Path to access on the HTTP server. ++optional */ + path?: string; + /** Name or number of the port to access on the container. +Number must be in the range 1 to 65535. +Name must be an IANA_SVC_NAME. */ + port?: IntOrString; + /** Scheme to use for connecting to the host. +Defaults to HTTP. ++optional */ + scheme?: string; +} diff --git a/ui/src/gen/api/v2/models/v1HTTPHeader.ts b/ui/src/gen/api/v2/models/v1HTTPHeader.ts new file mode 100644 index 0000000000..ca2b530faa --- /dev/null +++ b/ui/src/gen/api/v2/models/v1HTTPHeader.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1HTTPHeader { + /** The header field name. +This will be canonicalized upon output, so case-variant names will be understood as the same header. */ + name?: string; + /** The header field value */ + value?: string; +} diff --git a/ui/src/gen/api/v2/models/v1HostAlias.ts b/ui/src/gen/api/v2/models/v1HostAlias.ts new file mode 100644 index 0000000000..f851ecdb51 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1HostAlias.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1HostAlias { + /** Hostnames for the above IP address. ++listType=atomic */ + hostnames?: string[]; + /** IP address of the host file entry. ++required */ + ip?: string; +} diff --git a/ui/src/gen/api/v2/models/v1HostPathVolumeSource.ts b/ui/src/gen/api/v2/models/v1HostPathVolumeSource.ts new file mode 100644 index 0000000000..52e2f58937 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1HostPathVolumeSource.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1HostPathVolumeSource { + /** path of the directory on the host. +If the path is a symlink, it will follow the link to the real path. +More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath */ + path?: string; + /** type for HostPath Volume +Defaults to "" +More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath ++optional */ + type?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ISCSIVolumeSource.ts b/ui/src/gen/api/v2/models/v1ISCSIVolumeSource.ts new file mode 100644 index 0000000000..38af46619c --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ISCSIVolumeSource.ts @@ -0,0 +1,53 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1ISCSIVolumeSource { + /** chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication ++optional */ + chapAuthDiscovery?: boolean; + /** chapAuthSession defines whether support iSCSI Session CHAP authentication ++optional */ + chapAuthSession?: boolean; + /** fsType is the filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string; + /** initiatorName is the custom iSCSI Initiator Name. +If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface +: will be created for the connection. ++optional */ + initiatorName?: string; + /** iqn is the target iSCSI Qualified Name. */ + iqn?: string; + /** iscsiInterface is the interface Name that uses an iSCSI transport. +Defaults to 'default' (tcp). ++optional ++default="default" */ + iscsiInterface?: string; + /** lun represents iSCSI Target Lun number. */ + lun?: number; + /** portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port +is other than default (typically TCP ports 860 and 3260). ++optional ++listType=atomic */ + portals?: string[]; + /** readOnly here will force the ReadOnly setting in VolumeMounts. +Defaults to false. ++optional */ + readOnly?: boolean; + /** secretRef is the CHAP Secret for iSCSI target and initiator authentication ++optional */ + secretRef?: V1LocalObjectReference; + /** targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port +is other than default (typically TCP ports 860 and 3260). */ + targetPortal?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ImageVolumeSource.ts b/ui/src/gen/api/v2/models/v1ImageVolumeSource.ts new file mode 100644 index 0000000000..45f352e4c6 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ImageVolumeSource.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ImageVolumeSource { + /** Policy for pulling OCI objects. Possible values are: +Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. +Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. +IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. +Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. ++optional */ + pullPolicy?: string; + /** Required: Image or artifact reference to be used. +Behaves in the same way as pod.spec.containers[*].image. +Pull secrets will be assembled in the same way as for the container image by looking up node credentials, SA image pull secrets, and pod spec image pull secrets. +More info: https://kubernetes.io/docs/concepts/containers/images +This field is optional to allow higher level config management to default or override +container images in workload controllers like Deployments and StatefulSets. ++optional */ + reference?: string; +} diff --git a/ui/src/gen/api/v2/models/v1JobSpec.ts b/ui/src/gen/api/v2/models/v1JobSpec.ts new file mode 100644 index 0000000000..a0bf236210 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1JobSpec.ts @@ -0,0 +1,168 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1CompletionMode } from './v1CompletionMode'; +import type { V1PodFailurePolicy } from './v1PodFailurePolicy'; +import type { V1PodReplacementPolicy } from './v1PodReplacementPolicy'; +import type { V1LabelSelector } from './v1LabelSelector'; +import type { V1SuccessPolicy } from './v1SuccessPolicy'; +import type { V1PodTemplateSpec } from './v1PodTemplateSpec'; + +export interface V1JobSpec { + /** Specifies the duration in seconds relative to the startTime that the job +may be continuously active before the system tries to terminate it; value +must be positive integer. If a Job is suspended (at creation or through an +update), this timer will effectively be stopped and reset when the Job is +resumed again. ++optional */ + activeDeadlineSeconds?: number; + /** Specifies the number of retries before marking this job failed. +Defaults to 6, unless backoffLimitPerIndex (only Indexed Job) is specified. +When backoffLimitPerIndex is specified, backoffLimit defaults to 2147483647. ++optional */ + backoffLimit?: number; + /** Specifies the limit for the number of retries within an +index before marking this index as failed. When enabled the number of +failures per index is kept in the pod's +batch.kubernetes.io/job-index-failure-count annotation. It can only +be set when Job's completionMode=Indexed, and the Pod's restart +policy is Never. The field is immutable. ++optional */ + backoffLimitPerIndex?: number; + /** completionMode specifies how Pod completions are tracked. It can be +`NonIndexed` (default) or `Indexed`. + +`NonIndexed` means that the Job is considered complete when there have +been .spec.completions successfully completed Pods. Each Pod completion is +homologous to each other. + +`Indexed` means that the Pods of a +Job get an associated completion index from 0 to (.spec.completions - 1), +available in the annotation batch.kubernetes.io/job-completion-index. +The Job is considered complete when there is one successfully completed Pod +for each index. +When value is `Indexed`, .spec.completions must be specified and +`.spec.parallelism` must be less than or equal to 10^5. +In addition, The Pod name takes the form +`$(job-name)-$(index)-$(random-string)`, +the Pod hostname takes the form `$(job-name)-$(index)`. + +More completion modes can be added in the future. +If the Job controller observes a mode that it doesn't recognize, which +is possible during upgrades due to version skew, the controller +skips updates for the Job. ++optional */ + completionMode?: V1CompletionMode; + /** Specifies the desired number of successfully finished pods the +job should be run with. Setting to null means that the success of any +pod signals the success of all pods, and allows parallelism to have any positive +value. Setting to 1 means that parallelism is limited to 1 and the success of that +pod signals the success of the job. +More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ ++optional */ + completions?: number; + /** ManagedBy field indicates the controller that manages a Job. The k8s Job +controller reconciles jobs which don't have this field at all or the field +value is the reserved string `kubernetes.io/job-controller`, but skips +reconciling Jobs with a custom value for this field. +The value must be a valid domain-prefixed path (e.g. acme.io/foo) - +all characters before the first "/" must be a valid subdomain as defined +by RFC 1123. All characters trailing the first "/" must be valid HTTP Path +characters as defined by RFC 3986. The value cannot exceed 63 characters. +This field is immutable. + +This field is beta-level. The job controller accepts setting the field +when the feature gate JobManagedBy is enabled (enabled by default). ++optional */ + managedBy?: string; + /** manualSelector controls generation of pod labels and pod selectors. +Leave `manualSelector` unset unless you are certain what you are doing. +When false or unset, the system pick labels unique to this job +and appends those labels to the pod template. When true, +the user is responsible for picking unique labels and specifying +the selector. Failure to pick a unique label may cause this +and other jobs to not function correctly. However, You may see +`manualSelector=true` in jobs that were created with the old `extensions/v1beta1` +API. +More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector ++optional */ + manualSelector?: boolean; + /** Specifies the maximal number of failed indexes before marking the Job as +failed, when backoffLimitPerIndex is set. Once the number of failed +indexes exceeds this number the entire Job is marked as Failed and its +execution is terminated. When left as null the job continues execution of +all of its indexes and is marked with the `Complete` Job condition. +It can only be specified when backoffLimitPerIndex is set. +It can be null or up to completions. It is required and must be +less than or equal to 10^4 when is completions greater than 10^5. ++optional */ + maxFailedIndexes?: number; + /** Specifies the maximum desired number of pods the job should +run at any given time. The actual number of pods running in steady state will +be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), +i.e. when the work left to do is less than max parallelism. +More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ ++optional */ + parallelism?: number; + /** Specifies the policy of handling failed pods. In particular, it allows to +specify the set of actions and conditions which need to be +satisfied to take the associated action. +If empty, the default behaviour applies - the counter of failed pods, +represented by the jobs's .status.failed field, is incremented and it is +checked against the backoffLimit. This field cannot be used in combination +with restartPolicy=OnFailure. + ++optional */ + podFailurePolicy?: V1PodFailurePolicy; + /** podReplacementPolicy specifies when to create replacement Pods. +Possible values are: +- TerminatingOrFailed means that we recreate pods + when they are terminating (has a metadata.deletionTimestamp) or failed. +- Failed means to wait until a previously created Pod is fully terminated (has phase + Failed or Succeeded) before creating a replacement Pod. + +When using podFailurePolicy, Failed is the the only allowed value. +TerminatingOrFailed and Failed are allowed values when podFailurePolicy is not in use. ++optional */ + podReplacementPolicy?: V1PodReplacementPolicy; + /** A label query over pods that should match the pod count. +Normally, the system sets this field for you. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors ++optional */ + selector?: V1LabelSelector; + /** successPolicy specifies the policy when the Job can be declared as succeeded. +If empty, the default behavior applies - the Job is declared as succeeded +only when the number of succeeded pods equals to the completions. +When the field is specified, it must be immutable and works only for the Indexed Jobs. +Once the Job meets the SuccessPolicy, the lingering pods are terminated. + ++optional */ + successPolicy?: V1SuccessPolicy; + /** suspend specifies whether the Job controller should create Pods or not. If +a Job is created with suspend set to true, no Pods are created by the Job +controller. If a Job is suspended after creation (i.e. the flag goes from +false to true), the Job controller will delete all active Pods associated +with this Job. Users must design their workload to gracefully handle this. +Suspending a Job will reset the StartTime field of the Job, effectively +resetting the ActiveDeadlineSeconds timer too. Defaults to false. + ++optional */ + suspend?: boolean; + /** Describes the pod that will be created when executing a job. +The only allowed template.spec.restartPolicy values are "Never" or "OnFailure". +More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ */ + template?: V1PodTemplateSpec; + /** ttlSecondsAfterFinished limits the lifetime of a Job that has finished +execution (either Complete or Failed). If this field is set, +ttlSecondsAfterFinished after the Job finishes, it is eligible to be +automatically deleted. When the Job is being deleted, its lifecycle +guarantees (e.g. finalizers) will be honored. If this field is unset, +the Job won't be automatically deleted. If this field is set to zero, +the Job becomes eligible to be deleted immediately after it finishes. ++optional */ + ttlSecondsAfterFinished?: number; +} diff --git a/ui/src/gen/api/v2/models/v1KeyToPath.ts b/ui/src/gen/api/v2/models/v1KeyToPath.ts new file mode 100644 index 0000000000..1082daca41 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1KeyToPath.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1KeyToPath { + /** key is the key to project. */ + key?: string; + /** mode is Optional: mode bits used to set permissions on this file. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +If not specified, the volume defaultMode will be used. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + mode?: number; + /** path is the relative path of the file to map the key to. +May not be an absolute path. +May not contain the path element '..'. +May not start with the string '..'. */ + path?: string; +} diff --git a/ui/src/gen/api/v2/models/v1LabelSelector.ts b/ui/src/gen/api/v2/models/v1LabelSelector.ts new file mode 100644 index 0000000000..b19e202e70 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1LabelSelector.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LabelSelectorRequirement } from './v1LabelSelectorRequirement'; +import type { V1LabelSelectorMatchLabels } from './v1LabelSelectorMatchLabels'; + +export interface V1LabelSelector { + /** matchExpressions is a list of label selector requirements. The requirements are ANDed. ++optional ++listType=atomic */ + matchExpressions?: V1LabelSelectorRequirement[]; + /** matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is "key", the +operator is "In", and the values array contains only "value". The requirements are ANDed. ++optional */ + matchLabels?: V1LabelSelectorMatchLabels; +} diff --git a/ui/src/gen/api/v2/models/v1LabelSelectorMatchLabels.ts b/ui/src/gen/api/v2/models/v1LabelSelectorMatchLabels.ts new file mode 100644 index 0000000000..e24845298e --- /dev/null +++ b/ui/src/gen/api/v2/models/v1LabelSelectorMatchLabels.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels +map is equivalent to an element of matchExpressions, whose key field is "key", the +operator is "In", and the values array contains only "value". The requirements are ANDed. ++optional + */ +export type V1LabelSelectorMatchLabels = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1LabelSelectorRequirement.ts b/ui/src/gen/api/v2/models/v1LabelSelectorRequirement.ts new file mode 100644 index 0000000000..4afee058a3 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1LabelSelectorRequirement.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1LabelSelectorRequirement { + /** key is the label key that the selector applies to. */ + key?: string; + /** operator represents a key's relationship to a set of values. +Valid operators are In, NotIn, Exists and DoesNotExist. */ + operator?: string; + /** values is an array of string values. If the operator is In or NotIn, +the values array must be non-empty. If the operator is Exists or DoesNotExist, +the values array must be empty. This array is replaced during a strategic +merge patch. ++optional ++listType=atomic */ + values?: string[]; +} diff --git a/ui/src/gen/api/v2/models/v1Lifecycle.ts b/ui/src/gen/api/v2/models/v1Lifecycle.ts new file mode 100644 index 0000000000..633f8ada4a --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Lifecycle.ts @@ -0,0 +1,33 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LifecycleHandler } from './v1LifecycleHandler'; + +export interface V1Lifecycle { + /** PostStart is called immediately after a container is created. If the handler fails, +the container is terminated and restarted according to its restart policy. +Other management of the container blocks until the hook completes. +More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks ++optional */ + postStart?: V1LifecycleHandler; + /** PreStop is called immediately before a container is terminated due to an +API request or management event such as liveness/startup probe failure, +preemption, resource contention, etc. The handler is not called if the +container crashes or exits. The Pod's termination grace period countdown begins before the +PreStop hook is executed. Regardless of the outcome of the handler, the +container will eventually terminate within the Pod's termination grace +period (unless delayed by finalizers). Other management of the container blocks until the hook completes +or until the termination grace period is reached. +More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks ++optional */ + preStop?: V1LifecycleHandler; + /** StopSignal defines which signal will be sent to a container when it is being stopped. +If not specified, the default is defined by the container runtime in use. +StopSignal can only be set for Pods with a non-empty .spec.os.name ++optional */ + stopSignal?: string; +} diff --git a/ui/src/gen/api/v2/models/v1LifecycleHandler.ts b/ui/src/gen/api/v2/models/v1LifecycleHandler.ts new file mode 100644 index 0000000000..809800321a --- /dev/null +++ b/ui/src/gen/api/v2/models/v1LifecycleHandler.ts @@ -0,0 +1,29 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ExecAction } from './v1ExecAction'; +import type { V1HTTPGetAction } from './v1HTTPGetAction'; +import type { V1SleepAction } from './v1SleepAction'; +import type { V1TCPSocketAction } from './v1TCPSocketAction'; + +export interface V1LifecycleHandler { + /** Exec specifies a command to execute in the container. ++optional */ + exec?: V1ExecAction; + /** HTTPGet specifies an HTTP GET request to perform. ++optional */ + httpGet?: V1HTTPGetAction; + /** Sleep represents a duration that the container should sleep. ++featureGate=PodLifecycleSleepAction ++optional */ + sleep?: V1SleepAction; + /** Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept +for backward compatibility. There is no validation of this field and +lifecycle hooks will fail at runtime when it is specified. ++optional */ + tcpSocket?: V1TCPSocketAction; +} diff --git a/ui/src/gen/api/v2/models/v1ListMeta.ts b/ui/src/gen/api/v2/models/v1ListMeta.ts new file mode 100644 index 0000000000..58e280c484 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ListMeta.ts @@ -0,0 +1,40 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ListMeta { + /** continue may be set if the user set a limit on the number of items returned, and indicates that +the server has more data available. The value is opaque and may be used to issue another request +to the endpoint that served this list to retrieve the next set of available objects. Continuing a +consistent list may not be possible if the server configuration has changed or more than a few +minutes have passed. The resourceVersion field returned when using this continue value will be +identical to the value in the first response, unless you have received this token from an error +message. */ + continue?: string; + /** remainingItemCount is the number of subsequent items in the list which are not included in this +list response. If the list request contained label or field selectors, then the number of +remaining items is unknown and the field will be left unset and omitted during serialization. +If the list is complete (either because it is not chunking or because this is the last chunk), +then there are no more remaining items and this field will be left unset and omitted during +serialization. +Servers older than v1.15 do not set this field. +The intended use of the remainingItemCount is *estimating* the size of a collection. Clients +should not rely on the remainingItemCount to be set or to be exact. ++optional */ + remainingItemCount?: number; + /** String that identifies the server's internal version of this object that +can be used by clients to determine when objects have changed. +Value must be treated as opaque by clients and passed unmodified back to the server. +Populated by the system. +Read-only. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency ++optional */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. ++optional */ + selfLink?: string; +} diff --git a/ui/src/gen/api/v2/models/v1LocalObjectReference.ts b/ui/src/gen/api/v2/models/v1LocalObjectReference.ts new file mode 100644 index 0000000000..3d41eebaac --- /dev/null +++ b/ui/src/gen/api/v2/models/v1LocalObjectReference.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1LocalObjectReference { + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ManagedFieldsEntry.ts b/ui/src/gen/api/v2/models/v1ManagedFieldsEntry.ts new file mode 100644 index 0000000000..4020edc692 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ManagedFieldsEntry.ts @@ -0,0 +1,42 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1FieldsV1 } from './v1FieldsV1'; + +export interface V1ManagedFieldsEntry { + /** APIVersion defines the version of this resource that this field set +applies to. The format is "group/version" just like the top-level +APIVersion field. It is necessary to track the version of a field +set because it cannot be automatically converted. */ + apiVersion?: string; + /** FieldsType is the discriminator for the different fields format and version. +There is currently only one possible value: "FieldsV1" */ + fieldsType?: string; + /** FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. ++optional */ + fieldsV1?: V1FieldsV1; + /** Manager is an identifier of the workflow managing these fields. */ + manager?: string; + /** Operation is the type of operation which lead to this ManagedFieldsEntry being created. +The only valid values for this field are 'Apply' and 'Update'. */ + operation?: string; + /** Subresource is the name of the subresource used to update that object, or +empty string if the object was updated through the main resource. The +value of this field is used to distinguish between managers, even if they +share the same name. For example, a status update will be distinct from a +regular update using the same manager name. +Note that the APIVersion field is not related to the Subresource field and +it always corresponds to the version of the main resource. */ + subresource?: string; + /** Time is the timestamp of when the ManagedFields entry was added. The +timestamp will also be updated if a field is added, the manager +changes any of the owned fields value or removes a field. The +timestamp does not update when a field is removed from the entry +because another manager took it over. ++optional */ + time?: string; +} diff --git a/ui/src/gen/api/v2/models/getStage200.ts b/ui/src/gen/api/v2/models/v1MicroTime.ts similarity index 70% rename from ui/src/gen/api/v2/models/getStage200.ts rename to ui/src/gen/api/v2/models/v1MicroTime.ts index eb05d8dbcd..0607bc60d6 100644 --- a/ui/src/gen/api/v2/models/getStage200.ts +++ b/ui/src/gen/api/v2/models/v1MicroTime.ts @@ -6,4 +6,6 @@ * OpenAPI spec version: v1alpha1 */ -export type GetStage200 = { [key: string]: unknown }; +export interface V1MicroTime { + 'time.Time'?: string; +} diff --git a/ui/src/gen/api/v2/models/v1NFSVolumeSource.ts b/ui/src/gen/api/v2/models/v1NFSVolumeSource.ts new file mode 100644 index 0000000000..cc6d5601ff --- /dev/null +++ b/ui/src/gen/api/v2/models/v1NFSVolumeSource.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1NFSVolumeSource { + /** path that is exported by the NFS server. +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs */ + path?: string; + /** readOnly here will force the NFS export to be mounted with read-only permissions. +Defaults to false. +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs ++optional */ + readOnly?: boolean; + /** server is the hostname or IP address of the NFS server. +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs */ + server?: string; +} diff --git a/ui/src/gen/api/v2/models/v1NodeAffinity.ts b/ui/src/gen/api/v2/models/v1NodeAffinity.ts new file mode 100644 index 0000000000..da9f95b7b0 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1NodeAffinity.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PreferredSchedulingTerm } from './v1PreferredSchedulingTerm'; +import type { V1NodeSelector } from './v1NodeSelector'; + +export interface V1NodeAffinity { + /** The scheduler will prefer to schedule pods to nodes that satisfy +the affinity expressions specified by this field, but it may choose +a node that violates one or more of the expressions. The node that is +most preferred is the one with the greatest sum of weights, i.e. +for each node that meets all of the scheduling requirements (resource +request, requiredDuringScheduling affinity expressions, etc.), +compute a sum by iterating through the elements of this field and adding +"weight" to the sum if the node matches the corresponding matchExpressions; the +node(s) with the highest sum are the most preferred. ++optional ++listType=atomic */ + preferredDuringSchedulingIgnoredDuringExecution?: V1PreferredSchedulingTerm[]; + /** If the affinity requirements specified by this field are not met at +scheduling time, the pod will not be scheduled onto the node. +If the affinity requirements specified by this field cease to be met +at some point during pod execution (e.g. due to an update), the system +may or may not try to eventually evict the pod from its node. ++optional */ + requiredDuringSchedulingIgnoredDuringExecution?: V1NodeSelector; +} diff --git a/ui/src/gen/api/v2/models/v1NodeSelector.ts b/ui/src/gen/api/v2/models/v1NodeSelector.ts new file mode 100644 index 0000000000..c780c582aa --- /dev/null +++ b/ui/src/gen/api/v2/models/v1NodeSelector.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1NodeSelectorTerm } from './v1NodeSelectorTerm'; + +export interface V1NodeSelector { + /** Required. A list of node selector terms. The terms are ORed. ++listType=atomic */ + nodeSelectorTerms?: V1NodeSelectorTerm[]; +} diff --git a/ui/src/gen/api/v2/models/v1NodeSelectorRequirement.ts b/ui/src/gen/api/v2/models/v1NodeSelectorRequirement.ts new file mode 100644 index 0000000000..d8e1f3162d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1NodeSelectorRequirement.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1NodeSelectorRequirement { + /** The label key that the selector applies to. */ + key?: string; + /** Represents a key's relationship to a set of values. +Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. */ + operator?: string; + /** An array of string values. If the operator is In or NotIn, +the values array must be non-empty. If the operator is Exists or DoesNotExist, +the values array must be empty. If the operator is Gt or Lt, the values +array must have a single element, which will be interpreted as an integer. +This array is replaced during a strategic merge patch. ++optional ++listType=atomic */ + values?: string[]; +} diff --git a/ui/src/gen/api/v2/models/v1NodeSelectorTerm.ts b/ui/src/gen/api/v2/models/v1NodeSelectorTerm.ts new file mode 100644 index 0000000000..25dfab5594 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1NodeSelectorTerm.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1NodeSelectorRequirement } from './v1NodeSelectorRequirement'; + +export interface V1NodeSelectorTerm { + /** A list of node selector requirements by node's labels. ++optional ++listType=atomic */ + matchExpressions?: V1NodeSelectorRequirement[]; + /** A list of node selector requirements by node's fields. ++optional ++listType=atomic */ + matchFields?: V1NodeSelectorRequirement[]; +} diff --git a/ui/src/gen/api/v2/models/v1ObjectFieldSelector.ts b/ui/src/gen/api/v2/models/v1ObjectFieldSelector.ts new file mode 100644 index 0000000000..5bb4578d67 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ObjectFieldSelector.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ObjectFieldSelector { + /** Version of the schema the FieldPath is written in terms of, defaults to "v1". ++optional */ + apiVersion?: string; + /** Path of the field to select in the specified API version. */ + fieldPath?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ObjectMeta.ts b/ui/src/gen/api/v2/models/v1ObjectMeta.ts new file mode 100644 index 0000000000..6614805bd0 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ObjectMeta.ts @@ -0,0 +1,160 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMetaAnnotations } from './v1ObjectMetaAnnotations'; +import type { V1ObjectMetaLabels } from './v1ObjectMetaLabels'; +import type { V1ManagedFieldsEntry } from './v1ManagedFieldsEntry'; +import type { V1OwnerReference } from './v1OwnerReference'; + +export interface V1ObjectMeta { + /** Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations ++optional */ + annotations?: V1ObjectMetaAnnotations; + /** CreationTimestamp is a timestamp representing the server time when this object was +created. It is not guaranteed to be set in happens-before order across separate operations. +Clients may not set this value. It is represented in RFC3339 form and is in UTC. + +Populated by the system. +Read-only. +Null for lists. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + creationTimestamp?: string; + /** Number of seconds allowed for this object to gracefully terminate before +it will be removed from the system. Only set when deletionTimestamp is also set. +May only be shortened. +Read-only. ++optional */ + deletionGracePeriodSeconds?: number; + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This +field is set by the server when a graceful deletion is requested by the user, and is not +directly settable by a client. The resource is expected to be deleted (no longer visible +from resource lists, and not reachable by name) after the time in this field, once the +finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. +Once the deletionTimestamp is set, this value may not be unset or be set further into the +future, although it may be shortened or the resource may be deleted prior to this time. +For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react +by sending a graceful termination signal to the containers in the pod. After that 30 seconds, +the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, +remove the pod from the API. In the presence of network partitions, this object may still +exist after this timestamp, until an administrator or automated process can determine the +resource is fully terminated. +If not set, graceful deletion of the object has not been requested. + +Populated by the system when a graceful deletion is requested. +Read-only. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + deletionTimestamp?: string; + /** Must be empty before the object is deleted from the registry. Each entry +is an identifier for the responsible component that will remove the entry +from the list. If the deletionTimestamp of the object is non-nil, entries +in this list can only be removed. +Finalizers may be processed and removed in any order. Order is NOT enforced +because it introduces significant risk of stuck finalizers. +finalizers is a shared field, any actor with permission can reorder it. +If the finalizer list is processed in order, then this can lead to a situation +in which the component responsible for the first finalizer in the list is +waiting for a signal (field value, external system, or other) produced by a +component responsible for a finalizer later in the list, resulting in a deadlock. +Without enforced ordering finalizers are free to order amongst themselves and +are not vulnerable to ordering changes in the list. ++optional ++patchStrategy=merge ++listType=set */ + finalizers?: string[]; + /** GenerateName is an optional prefix, used by the server, to generate a unique +name ONLY IF the Name field has not been provided. +If this field is used, the name returned to the client will be different +than the name passed. This value will also be combined with a unique suffix. +The provided value has the same validation rules as the Name field, +and may be truncated by the length of the suffix required to make the value +unique on the server. + +If this field is specified and the generated name exists, the server will return a 409. + +Applied only if Name is not specified. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency ++optional */ + generateName?: string; + /** A sequence number representing a specific generation of the desired state. +Populated by the system. Read-only. ++optional */ + generation?: number; + /** Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels ++optional */ + labels?: V1ObjectMetaLabels; + /** ManagedFields maps workflow-id and version to the set of fields +that are managed by that workflow. This is mostly for internal +housekeeping, and users typically shouldn't need to set or +understand this field. A workflow can be the user's name, a +controller's name, or the name of a specific apply path like +"ci-cd". The set of fields is always in the version that the +workflow used when modifying the object. + ++optional ++listType=atomic */ + managedFields?: V1ManagedFieldsEntry[]; + /** Name must be unique within a namespace. Is required when creating resources, although +some resources may allow a client to request the generation of an appropriate name +automatically. Name is primarily intended for creation idempotence and configuration +definition. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names ++optional */ + name?: string; + /** Namespace defines the space within which each name must be unique. An empty namespace is +equivalent to the "default" namespace, but "default" is the canonical representation. +Not all objects are required to be scoped to a namespace - the value of this field for +those objects will be empty. + +Must be a DNS_LABEL. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces ++optional */ + namespace?: string; + /** List of objects depended by this object. If ALL objects in the list have +been deleted, this object will be garbage collected. If this object is managed by a controller, +then an entry in this list will point to this controller, with the controller field set to true. +There cannot be more than one managing controller. ++optional ++patchMergeKey=uid ++patchStrategy=merge ++listType=map ++listMapKey=uid */ + ownerReferences?: V1OwnerReference[]; + /** An opaque value that represents the internal version of this object that can +be used by clients to determine when objects have changed. May be used for optimistic +concurrency, change detection, and the watch operation on a resource or set of resources. +Clients must treat these values as opaque and passed unmodified back to the server. +They may only be valid for a particular resource or set of resources. + +Populated by the system. +Read-only. +Value must be treated as opaque by clients and . +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency ++optional */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. ++optional */ + selfLink?: string; + /** UID is the unique in time and space value for this object. It is typically generated by +the server on successful creation of a resource and is not allowed to change on PUT +operations. + +Populated by the system. +Read-only. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids ++optional */ + uid?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ObjectMetaAnnotations.ts b/ui/src/gen/api/v2/models/v1ObjectMetaAnnotations.ts new file mode 100644 index 0000000000..c97171150d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ObjectMetaAnnotations.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Annotations is an unstructured key value map stored with a resource that may be +set by external tools to store and retrieve arbitrary metadata. They are not +queryable and should be preserved when modifying objects. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations ++optional + */ +export type V1ObjectMetaAnnotations = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1ObjectMetaLabels.ts b/ui/src/gen/api/v2/models/v1ObjectMetaLabels.ts new file mode 100644 index 0000000000..b3af3949d4 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ObjectMetaLabels.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Map of string keys and values that can be used to organize and categorize +(scope and select) objects. May match selectors of replication controllers +and services. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels ++optional + */ +export type V1ObjectMetaLabels = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1ObjectReference.ts b/ui/src/gen/api/v2/models/v1ObjectReference.ts new file mode 100644 index 0000000000..2105e84aa3 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ObjectReference.ts @@ -0,0 +1,43 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ObjectReference { + /** API version of the referent. ++optional */ + apiVersion?: string; + /** 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. ++optional */ + fieldPath?: string; + /** Kind of the referent. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + kind?: string; + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional */ + name?: string; + /** Namespace of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ ++optional */ + namespace?: string; + /** 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 ++optional */ + resourceVersion?: string; + /** UID of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids ++optional */ + uid?: string; +} diff --git a/ui/src/gen/api/v2/models/v1OwnerReference.ts b/ui/src/gen/api/v2/models/v1OwnerReference.ts new file mode 100644 index 0000000000..ef1e8bb876 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1OwnerReference.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1OwnerReference { + /** API version of the referent. */ + apiVersion?: string; + /** If true, AND if the owner has the "foregroundDeletion" finalizer, then +the owner cannot be deleted from the key-value store until this +reference is removed. +See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion +for how the garbage collector interacts with this field and enforces the foreground deletion. +Defaults to false. +To set this field, a user needs "delete" permission of the owner, +otherwise 422 (Unprocessable Entity) will be returned. ++optional */ + blockOwnerDeletion?: boolean; + /** If true, this reference points to the managing controller. ++optional */ + controller?: boolean; + /** Kind of the referent. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** Name of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name?: string; + /** UID of the referent. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PersistentVolumeClaimSpec.ts b/ui/src/gen/api/v2/models/v1PersistentVolumeClaimSpec.ts new file mode 100644 index 0000000000..1d4848a3e6 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PersistentVolumeClaimSpec.ts @@ -0,0 +1,88 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1TypedLocalObjectReference } from './v1TypedLocalObjectReference'; +import type { V1TypedObjectReference } from './v1TypedObjectReference'; +import type { V1VolumeResourceRequirements } from './v1VolumeResourceRequirements'; +import type { V1LabelSelector } from './v1LabelSelector'; + +export interface V1PersistentVolumeClaimSpec { + /** accessModes contains the desired access modes the volume should have. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 ++optional ++listType=atomic */ + accessModes?: string[]; + /** dataSource field can be used to specify either: +* An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) +* An existing PVC (PersistentVolumeClaim) +If the provisioner or an external controller can support the specified data source, +it will create a new volume based on the contents of the specified data source. +When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, +and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. +If the namespace is specified, then dataSourceRef will not be copied to dataSource. ++optional */ + dataSource?: V1TypedLocalObjectReference; + /** dataSourceRef specifies the object from which to populate the volume with data, if a non-empty +volume is desired. This may be any object from a non-empty API group (non +core object) or a PersistentVolumeClaim object. +When this field is specified, volume binding will only succeed if the type of +the specified object matches some installed volume populator or dynamic +provisioner. +This field will replace the functionality of the dataSource field and as such +if both fields are non-empty, they must have the same value. For backwards +compatibility, when namespace isn't specified in dataSourceRef, +both fields (dataSource and dataSourceRef) will be set to the same +value automatically if one of them is empty and the other is non-empty. +When namespace is specified in dataSourceRef, +dataSource isn't set to the same value and must be empty. +There are three important differences between dataSource and dataSourceRef: +* While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. +* While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. +* While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. +(Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. +(Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. ++optional */ + dataSourceRef?: V1TypedObjectReference; + /** resources represents the minimum resources the volume should have. +If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements +that are lower than previous value but must still be higher than capacity recorded in the +status field of the claim. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources ++optional */ + resources?: V1VolumeResourceRequirements; + /** selector is a label query over volumes to consider for binding. ++optional */ + selector?: V1LabelSelector; + /** storageClassName is the name of the StorageClass required by the claim. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 ++optional */ + storageClassName?: string; + /** volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. +If specified, the CSI driver will create or update the volume with the attributes defined +in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, +it can be changed after the claim is created. An empty string or nil value indicates that no +VolumeAttributesClass will be applied to the claim. If the claim enters an Infeasible error state, +this field can be reset to its previous value (including nil) to cancel the modification. +If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be +set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource +exists. +More info: https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/ ++featureGate=VolumeAttributesClass ++optional */ + volumeAttributesClassName?: string; + /** volumeMode defines what type of volume is required by the claim. +Value of Filesystem is implied when not included in claim spec. ++optional */ + volumeMode?: string; + /** volumeName is the binding reference to the PersistentVolume backing this claim. ++optional */ + volumeName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PersistentVolumeClaimTemplate.ts b/ui/src/gen/api/v2/models/v1PersistentVolumeClaimTemplate.ts new file mode 100644 index 0000000000..aacefe361e --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PersistentVolumeClaimTemplate.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { V1PersistentVolumeClaimSpec } from './v1PersistentVolumeClaimSpec'; + +export interface V1PersistentVolumeClaimTemplate { + /** May contain labels and annotations that will be copied into the PVC +when creating it. No other fields are allowed and will be rejected during +validation. + ++optional */ + metadata?: V1ObjectMeta; + /** The specification for the PersistentVolumeClaim. The entire content is +copied unchanged into the PVC that gets created from this +template. The same fields as in a PersistentVolumeClaim +are also valid here. */ + spec?: V1PersistentVolumeClaimSpec; +} diff --git a/ui/src/gen/api/v2/models/v1PersistentVolumeClaimVolumeSource.ts b/ui/src/gen/api/v2/models/v1PersistentVolumeClaimVolumeSource.ts new file mode 100644 index 0000000000..d15a0bc43a --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PersistentVolumeClaimVolumeSource.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PersistentVolumeClaimVolumeSource { + /** claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims */ + claimName?: string; + /** readOnly Will force the ReadOnly setting in VolumeMounts. +Default false. ++optional */ + readOnly?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1PhotonPersistentDiskVolumeSource.ts b/ui/src/gen/api/v2/models/v1PhotonPersistentDiskVolumeSource.ts new file mode 100644 index 0000000000..5975d4e0eb --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PhotonPersistentDiskVolumeSource.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PhotonPersistentDiskVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. */ + fsType?: string; + /** pdID is the ID that identifies Photon Controller persistent disk */ + pdID?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodAffinity.ts b/ui/src/gen/api/v2/models/v1PodAffinity.ts new file mode 100644 index 0000000000..b9dadb6761 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodAffinity.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1WeightedPodAffinityTerm } from './v1WeightedPodAffinityTerm'; +import type { V1PodAffinityTerm } from './v1PodAffinityTerm'; + +export interface V1PodAffinity { + /** The scheduler will prefer to schedule pods to nodes that satisfy +the affinity expressions specified by this field, but it may choose +a node that violates one or more of the expressions. The node that is +most preferred is the one with the greatest sum of weights, i.e. +for each node that meets all of the scheduling requirements (resource +request, requiredDuringScheduling affinity expressions, etc.), +compute a sum by iterating through the elements of this field and adding +"weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the +node(s) with the highest sum are the most preferred. ++optional ++listType=atomic */ + preferredDuringSchedulingIgnoredDuringExecution?: V1WeightedPodAffinityTerm[]; + /** If the affinity requirements specified by this field are not met at +scheduling time, the pod will not be scheduled onto the node. +If the affinity requirements specified by this field cease to be met +at some point during pod execution (e.g. due to a pod label update), the +system may or may not try to eventually evict the pod from its node. +When there are multiple elements, the lists of nodes corresponding to each +podAffinityTerm are intersected, i.e. all terms must be satisfied. ++optional ++listType=atomic */ + requiredDuringSchedulingIgnoredDuringExecution?: V1PodAffinityTerm[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodAffinityTerm.ts b/ui/src/gen/api/v2/models/v1PodAffinityTerm.ts new file mode 100644 index 0000000000..7beba10ba6 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodAffinityTerm.ts @@ -0,0 +1,59 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LabelSelector } from './v1LabelSelector'; + +export interface V1PodAffinityTerm { + /** A label query over a set of resources, in this case pods. +If it's null, this PodAffinityTerm matches with no Pods. ++optional */ + labelSelector?: V1LabelSelector; + /** MatchLabelKeys is a set of pod label keys to select which pods will +be taken into consideration. The keys are used to lookup values from the +incoming pod labels, those key-value labels are merged with `labelSelector` as `key in (value)` +to select the group of existing pods which pods will be taken into consideration +for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming +pod labels will be ignored. The default value is empty. +The same key is forbidden to exist in both matchLabelKeys and labelSelector. +Also, matchLabelKeys cannot be set when labelSelector isn't set. + ++listType=atomic ++optional */ + matchLabelKeys?: string[]; + /** MismatchLabelKeys is a set of pod label keys to select which pods will +be taken into consideration. The keys are used to lookup values from the +incoming pod labels, those key-value labels are merged with `labelSelector` as `key notin (value)` +to select the group of existing pods which pods will be taken into consideration +for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming +pod labels will be ignored. The default value is empty. +The same key is forbidden to exist in both mismatchLabelKeys and labelSelector. +Also, mismatchLabelKeys cannot be set when labelSelector isn't set. + ++listType=atomic ++optional */ + mismatchLabelKeys?: string[]; + /** A label query over the set of namespaces that the term applies to. +The term is applied to the union of the namespaces selected by this field +and the ones listed in the namespaces field. +null selector and null or empty namespaces list means "this pod's namespace". +An empty selector ({}) matches all namespaces. ++optional */ + namespaceSelector?: V1LabelSelector; + /** namespaces specifies a static list of namespace names that the term applies to. +The term is applied to the union of the namespaces listed in this field +and the ones selected by namespaceSelector. +null or empty namespaces list and null namespaceSelector means "this pod's namespace". ++optional ++listType=atomic */ + namespaces?: string[]; + /** This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching +the labelSelector in the specified namespaces, where co-located is defined as running on a node +whose value of the label with key topologyKey matches that of any node on which any of the +selected pods is running. +Empty topologyKey is not allowed. */ + topologyKey?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodAntiAffinity.ts b/ui/src/gen/api/v2/models/v1PodAntiAffinity.ts new file mode 100644 index 0000000000..f9413fd828 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodAntiAffinity.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1WeightedPodAffinityTerm } from './v1WeightedPodAffinityTerm'; +import type { V1PodAffinityTerm } from './v1PodAffinityTerm'; + +export interface V1PodAntiAffinity { + /** The scheduler will prefer to schedule pods to nodes that satisfy +the anti-affinity expressions specified by this field, but it may choose +a node that violates one or more of the expressions. The node that is +most preferred is the one with the greatest sum of weights, i.e. +for each node that meets all of the scheduling requirements (resource +request, requiredDuringScheduling anti-affinity expressions, etc.), +compute a sum by iterating through the elements of this field and subtracting +"weight" from the sum if the node has pods which matches the corresponding podAffinityTerm; the +node(s) with the highest sum are the most preferred. ++optional ++listType=atomic */ + preferredDuringSchedulingIgnoredDuringExecution?: V1WeightedPodAffinityTerm[]; + /** If the anti-affinity requirements specified by this field are not met at +scheduling time, the pod will not be scheduled onto the node. +If the anti-affinity requirements specified by this field cease to be met +at some point during pod execution (e.g. due to a pod label update), the +system may or may not try to eventually evict the pod from its node. +When there are multiple elements, the lists of nodes corresponding to each +podAffinityTerm are intersected, i.e. all terms must be satisfied. ++optional ++listType=atomic */ + requiredDuringSchedulingIgnoredDuringExecution?: V1PodAffinityTerm[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodCertificateProjection.ts b/ui/src/gen/api/v2/models/v1PodCertificateProjection.ts new file mode 100644 index 0000000000..414dda65df --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodCertificateProjection.ts @@ -0,0 +1,73 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodCertificateProjection { + /** Write the certificate chain at this path in the projected volume. + +Most applications should use credentialBundlePath. When using keyPath +and certificateChainPath, your application needs to check that the key +and leaf certificate are consistent, because it is possible to read the +files mid-rotation. + ++optional */ + certificateChainPath?: string; + /** Write the credential bundle at this path in the projected volume. + +The credential bundle is a single file that contains multiple PEM blocks. +The first PEM block is a PRIVATE KEY block, containing a PKCS#8 private +key. + +The remaining blocks are CERTIFICATE blocks, containing the issued +certificate chain from the signer (leaf and any intermediates). + +Using credentialBundlePath lets your Pod's application code make a single +atomic read that retrieves a consistent key and certificate chain. If you +project them to separate files, your application code will need to +additionally check that the leaf certificate was issued to the key. + ++optional */ + credentialBundlePath?: string; + /** Write the key at this path in the projected volume. + +Most applications should use credentialBundlePath. When using keyPath +and certificateChainPath, your application needs to check that the key +and leaf certificate are consistent, because it is possible to read the +files mid-rotation. + ++optional */ + keyPath?: string; + /** The type of keypair Kubelet will generate for the pod. + +Valid values are "RSA3072", "RSA4096", "ECDSAP256", "ECDSAP384", +"ECDSAP521", and "ED25519". + ++required */ + keyType?: string; + /** maxExpirationSeconds is the maximum lifetime permitted for the +certificate. + +Kubelet copies this value verbatim into the PodCertificateRequests it +generates for this projection. + +If omitted, kube-apiserver will set it to 86400(24 hours). kube-apiserver +will reject values shorter than 3600 (1 hour). The maximum allowable +value is 7862400 (91 days). + +The signer implementation is then free to issue a certificate with any +lifetime *shorter* than MaxExpirationSeconds, but no shorter than 3600 +seconds (1 hour). This constraint is enforced by kube-apiserver. +`kubernetes.io` signers will never issue certificates with a lifetime +longer than 24 hours. + ++optional */ + maxExpirationSeconds?: number; + /** Kubelet's generated CSRs will be addressed to this signer. + ++required */ + signerName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodDNSConfig.ts b/ui/src/gen/api/v2/models/v1PodDNSConfig.ts new file mode 100644 index 0000000000..635c74d176 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodDNSConfig.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PodDNSConfigOption } from './v1PodDNSConfigOption'; + +export interface V1PodDNSConfig { + /** A list of DNS name server IP addresses. +This will be appended to the base nameservers generated from DNSPolicy. +Duplicated nameservers will be removed. ++optional ++listType=atomic */ + nameservers?: string[]; + /** A list of DNS resolver options. +This will be merged with the base options generated from DNSPolicy. +Duplicated entries will be removed. Resolution options given in Options +will override those that appear in the base DNSPolicy. ++optional ++listType=atomic */ + options?: V1PodDNSConfigOption[]; + /** A list of DNS search domains for host-name lookup. +This will be appended to the base search paths generated from DNSPolicy. +Duplicated search paths will be removed. ++optional ++listType=atomic */ + searches?: string[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodDNSConfigOption.ts b/ui/src/gen/api/v2/models/v1PodDNSConfigOption.ts new file mode 100644 index 0000000000..1dcd4634bf --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodDNSConfigOption.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodDNSConfigOption { + /** Name is this DNS resolver option's name. +Required. */ + name?: string; + /** Value is this DNS resolver option's value. ++optional */ + value?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodFailurePolicy.ts b/ui/src/gen/api/v2/models/v1PodFailurePolicy.ts new file mode 100644 index 0000000000..2f73a52c7e --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodFailurePolicy.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PodFailurePolicyRule } from './v1PodFailurePolicyRule'; + +export interface V1PodFailurePolicy { + /** A list of pod failure policy rules. The rules are evaluated in order. +Once a rule matches a Pod failure, the remaining of the rules are ignored. +When no rule matches the Pod failure, the default handling applies - the +counter of pod failures is incremented and it is checked against +the backoffLimit. At most 20 elements are allowed. ++listType=atomic */ + rules?: V1PodFailurePolicyRule[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodFailurePolicyAction.ts b/ui/src/gen/api/v2/models/v1PodFailurePolicyAction.ts new file mode 100644 index 0000000000..ef9cca38db --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodFailurePolicyAction.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export type V1PodFailurePolicyAction = + (typeof V1PodFailurePolicyAction)[keyof typeof V1PodFailurePolicyAction]; + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const V1PodFailurePolicyAction = { + PodFailurePolicyActionFailJob: 'FailJob', + PodFailurePolicyActionFailIndex: 'FailIndex', + PodFailurePolicyActionIgnore: 'Ignore', + PodFailurePolicyActionCount: 'Count' +} as const; diff --git a/ui/src/gen/api/v2/models/v1PodFailurePolicyOnExitCodesOperator.ts b/ui/src/gen/api/v2/models/v1PodFailurePolicyOnExitCodesOperator.ts new file mode 100644 index 0000000000..2ada56a580 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodFailurePolicyOnExitCodesOperator.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export type V1PodFailurePolicyOnExitCodesOperator = + (typeof V1PodFailurePolicyOnExitCodesOperator)[keyof typeof V1PodFailurePolicyOnExitCodesOperator]; + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const V1PodFailurePolicyOnExitCodesOperator = { + PodFailurePolicyOnExitCodesOpIn: 'In', + PodFailurePolicyOnExitCodesOpNotIn: 'NotIn' +} as const; diff --git a/ui/src/gen/api/v2/models/v1PodFailurePolicyOnExitCodesRequirement.ts b/ui/src/gen/api/v2/models/v1PodFailurePolicyOnExitCodesRequirement.ts new file mode 100644 index 0000000000..d390a55163 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodFailurePolicyOnExitCodesRequirement.ts @@ -0,0 +1,37 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PodFailurePolicyOnExitCodesOperator } from './v1PodFailurePolicyOnExitCodesOperator'; + +export interface V1PodFailurePolicyOnExitCodesRequirement { + /** Restricts the check for exit codes to the container with the +specified name. When null, the rule applies to all containers. +When specified, it should match one the container or initContainer +names in the pod template. ++optional */ + containerName?: string; + /** Represents the relationship between the container exit code(s) and the +specified values. Containers completed with success (exit code 0) are +excluded from the requirement check. Possible values are: + +- In: the requirement is satisfied if at least one container exit code + (might be multiple if there are multiple containers not restricted + by the 'containerName' field) is in the set of specified values. +- NotIn: the requirement is satisfied if at least one container exit code + (might be multiple if there are multiple containers not restricted + by the 'containerName' field) is not in the set of specified values. +Additional values are considered to be added in the future. Clients should +react to an unknown operator by assuming the requirement is not satisfied. */ + operator?: V1PodFailurePolicyOnExitCodesOperator; + /** Specifies the set of values. Each returned container exit code (might be +multiple in case of multiple containers) is checked against this set of +values with respect to the operator. The list of values must be ordered +and must not contain duplicates. Value '0' cannot be used for the In operator. +At least one element is required. At most 255 elements are allowed. ++listType=set */ + values?: number[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodFailurePolicyOnPodConditionsPattern.ts b/ui/src/gen/api/v2/models/v1PodFailurePolicyOnPodConditionsPattern.ts new file mode 100644 index 0000000000..b51c21e6b3 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodFailurePolicyOnPodConditionsPattern.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodFailurePolicyOnPodConditionsPattern { + /** Specifies the required Pod condition status. To match a pod condition +it is required that the specified status equals the pod condition status. +Defaults to True. */ + status?: string; + /** Specifies the required Pod condition type. To match a pod condition +it is required that specified type equals the pod condition type. */ + type?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodFailurePolicyRule.ts b/ui/src/gen/api/v2/models/v1PodFailurePolicyRule.ts new file mode 100644 index 0000000000..3ebdaec995 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodFailurePolicyRule.ts @@ -0,0 +1,36 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PodFailurePolicyAction } from './v1PodFailurePolicyAction'; +import type { V1PodFailurePolicyOnExitCodesRequirement } from './v1PodFailurePolicyOnExitCodesRequirement'; +import type { V1PodFailurePolicyOnPodConditionsPattern } from './v1PodFailurePolicyOnPodConditionsPattern'; + +export interface V1PodFailurePolicyRule { + /** Specifies the action taken on a pod failure when the requirements are satisfied. +Possible values are: + +- FailJob: indicates that the pod's job is marked as Failed and all + running pods are terminated. +- FailIndex: indicates that the pod's index is marked as Failed and will + not be restarted. +- Ignore: indicates that the counter towards the .backoffLimit is not + incremented and a replacement pod is created. +- Count: indicates that the pod is handled in the default way - the + counter towards the .backoffLimit is incremented. +Additional values are considered to be added in the future. Clients should +react to an unknown action by skipping the rule. */ + action?: V1PodFailurePolicyAction; + /** Represents the requirement on the container exit codes. ++optional */ + onExitCodes?: V1PodFailurePolicyOnExitCodesRequirement; + /** Represents the requirement on the pod conditions. The requirement is represented +as a list of pod condition patterns. The requirement is satisfied if at +least one pattern matches an actual pod condition. At most 20 elements are allowed. ++listType=atomic ++optional */ + onPodConditions?: V1PodFailurePolicyOnPodConditionsPattern[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodOS.ts b/ui/src/gen/api/v2/models/v1PodOS.ts new file mode 100644 index 0000000000..824e208187 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodOS.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodOS { + /** Name is the name of the operating system. The currently supported values are linux and windows. +Additional value may be defined in future and can be one of: +https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration +Clients should expect to handle additional values and treat unrecognized values in this field as os: null */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodReadinessGate.ts b/ui/src/gen/api/v2/models/v1PodReadinessGate.ts new file mode 100644 index 0000000000..382309aeee --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodReadinessGate.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodReadinessGate { + /** ConditionType refers to a condition in the pod's condition list with matching type. */ + conditionType?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodReplacementPolicy.ts b/ui/src/gen/api/v2/models/v1PodReplacementPolicy.ts new file mode 100644 index 0000000000..a3f72b86e3 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodReplacementPolicy.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export type V1PodReplacementPolicy = + (typeof V1PodReplacementPolicy)[keyof typeof V1PodReplacementPolicy]; + +// eslint-disable-next-line @typescript-eslint/no-redeclare +export const V1PodReplacementPolicy = { + TerminatingOrFailed: 'TerminatingOrFailed', + Failed: 'Failed' +} as const; diff --git a/ui/src/gen/api/v2/models/v1PodResourceClaim.ts b/ui/src/gen/api/v2/models/v1PodResourceClaim.ts new file mode 100644 index 0000000000..a944a94dbc --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodResourceClaim.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodResourceClaim { + /** Name uniquely identifies this resource claim inside the pod. +This must be a DNS_LABEL. */ + name?: string; + /** ResourceClaimName is the name of a ResourceClaim object in the same +namespace as this pod. + +Exactly one of ResourceClaimName and ResourceClaimTemplateName must +be set. */ + resourceClaimName?: string; + /** ResourceClaimTemplateName is the name of a ResourceClaimTemplate +object in the same namespace as this pod. + +The template will be used to create a new ResourceClaim, which will +be bound to this pod. When this pod is deleted, the ResourceClaim +will also be deleted. The pod name and resource name, along with a +generated component, will be used to form a unique name for the +ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + +This field is immutable and no changes will be made to the +corresponding ResourceClaim by the control plane after creating the +ResourceClaim. + +Exactly one of ResourceClaimName and ResourceClaimTemplateName must +be set. */ + resourceClaimTemplateName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodSchedulingGate.ts b/ui/src/gen/api/v2/models/v1PodSchedulingGate.ts new file mode 100644 index 0000000000..7ab545e7ad --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodSchedulingGate.ts @@ -0,0 +1,13 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PodSchedulingGate { + /** Name of the scheduling gate. +Each scheduling gate must have a unique name field. */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PodSecurityContext.ts b/ui/src/gen/api/v2/models/v1PodSecurityContext.ts new file mode 100644 index 0000000000..2cdae2f345 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodSecurityContext.ts @@ -0,0 +1,135 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1AppArmorProfile } from './v1AppArmorProfile'; +import type { V1SELinuxOptions } from './v1SELinuxOptions'; +import type { V1SeccompProfile } from './v1SeccompProfile'; +import type { V1Sysctl } from './v1Sysctl'; +import type { V1WindowsSecurityContextOptions } from './v1WindowsSecurityContextOptions'; + +export interface V1PodSecurityContext { + /** appArmorProfile is the AppArmor options to use by the containers in this pod. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + appArmorProfile?: V1AppArmorProfile; + /** A special supplemental group that applies to all containers in a pod. +Some volume types allow the Kubelet to change the ownership of that volume +to be owned by the pod: + +1. The owning GID will be the FSGroup +2. The setgid bit is set (new files created in the volume will be owned by FSGroup) +3. The permission bits are OR'd with rw-rw---- + +If unset, the Kubelet will not modify the ownership and permissions of any volume. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + fsGroup?: number; + /** fsGroupChangePolicy defines behavior of changing ownership and permission of the volume +before being exposed inside Pod. This field will only apply to +volume types which support fsGroup based ownership(and permissions). +It will have no effect on ephemeral volume types such as: secret, configmaps +and emptydir. +Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + fsGroupChangePolicy?: string; + /** The GID to run the entrypoint of the container process. +Uses runtime default if unset. +May also be set in SecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence +for that container. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + runAsGroup?: number; + /** Indicates that the container must run as a non-root user. +If true, the Kubelet will validate the image at runtime to ensure that it +does not run as UID 0 (root) and fail to start the container if it does. +If unset or false, no such validation will be performed. +May also be set in SecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. ++optional */ + runAsNonRoot?: boolean; + /** The UID to run the entrypoint of the container process. +Defaults to user specified in image metadata if unspecified. +May also be set in SecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence +for that container. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + runAsUser?: number; + /** seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod. +It has no effect on nodes that do not support SELinux or to volumes does not support SELinux. +Valid values are "MountOption" and "Recursive". + +"Recursive" means relabeling of all files on all Pod volumes by the container runtime. +This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node. + +"MountOption" mounts all eligible Pod volumes with `-o context` mount option. +This requires all Pods that share the same volume to use the same SELinux label. +It is not possible to share the same volume among privileged and unprivileged Pods. +Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes +whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their +CSIDriver instance. Other volumes are always re-labelled recursively. +"MountOption" value is allowed only when SELinuxMount feature gate is enabled. + +If not specified and SELinuxMount feature gate is enabled, "MountOption" is used. +If not specified and SELinuxMount feature gate is disabled, "MountOption" is used for ReadWriteOncePod volumes +and "Recursive" for all other volumes. + +This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers. + +All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state. +Note that this field cannot be set when spec.os.name is windows. ++featureGate=SELinuxChangePolicy ++optional */ + seLinuxChangePolicy?: string; + /** The SELinux context to be applied to all containers. +If unspecified, the container runtime will allocate a random SELinux context for each +container. May also be set in SecurityContext. If set in +both SecurityContext and PodSecurityContext, the value specified in SecurityContext +takes precedence for that container. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + seLinuxOptions?: V1SELinuxOptions; + /** The seccomp options to use by the containers in this pod. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + seccompProfile?: V1SeccompProfile; + /** A list of groups applied to the first process run in each container, in +addition to the container's primary GID and fsGroup (if specified). If +the SupplementalGroupsPolicy feature is enabled, the +supplementalGroupsPolicy field determines whether these are in addition +to or instead of any group memberships defined in the container image. +If unspecified, no additional groups are added, though group memberships +defined in the container image may still be used, depending on the +supplementalGroupsPolicy field. +Note that this field cannot be set when spec.os.name is windows. ++optional ++listType=atomic */ + supplementalGroups?: number[]; + /** Defines how supplemental groups of the first container processes are calculated. +Valid values are "Merge" and "Strict". If not specified, "Merge" is used. +(Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled +and the container runtime must implement support for this feature. +Note that this field cannot be set when spec.os.name is windows. +TODO: update the default value to "Merge" when spec.os.name is not windows in v1.34 ++featureGate=SupplementalGroupsPolicy ++optional */ + supplementalGroupsPolicy?: string; + /** Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported +sysctls (by the container runtime) might fail to launch. +Note that this field cannot be set when spec.os.name is windows. ++optional ++listType=atomic */ + sysctls?: V1Sysctl[]; + /** The Windows specific settings applied to all containers. +If unspecified, the options within a container's SecurityContext will be used. +If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is linux. ++optional */ + windowsOptions?: V1WindowsSecurityContextOptions; +} diff --git a/ui/src/gen/api/v2/models/v1PodSpec.ts b/ui/src/gen/api/v2/models/v1PodSpec.ts new file mode 100644 index 0000000000..e539f5adae --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodSpec.ts @@ -0,0 +1,365 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Affinity } from './v1Affinity'; +import type { V1Container } from './v1Container'; +import type { V1PodDNSConfig } from './v1PodDNSConfig'; +import type { V1EphemeralContainer } from './v1EphemeralContainer'; +import type { V1HostAlias } from './v1HostAlias'; +import type { V1LocalObjectReference } from './v1LocalObjectReference'; +import type { V1PodSpecNodeSelector } from './v1PodSpecNodeSelector'; +import type { V1PodOS } from './v1PodOS'; +import type { V1ResourceList } from './v1ResourceList'; +import type { V1PodReadinessGate } from './v1PodReadinessGate'; +import type { V1PodResourceClaim } from './v1PodResourceClaim'; +import type { V1ResourceRequirements } from './v1ResourceRequirements'; +import type { V1PodSchedulingGate } from './v1PodSchedulingGate'; +import type { V1PodSecurityContext } from './v1PodSecurityContext'; +import type { V1Toleration } from './v1Toleration'; +import type { V1TopologySpreadConstraint } from './v1TopologySpreadConstraint'; +import type { V1Volume } from './v1Volume'; + +export interface V1PodSpec { + /** Optional duration in seconds the pod may be active on the node relative to +StartTime before the system will actively try to mark it failed and kill associated containers. +Value must be a positive integer. ++optional */ + activeDeadlineSeconds?: number; + /** If specified, the pod's scheduling constraints ++optional */ + affinity?: V1Affinity; + /** AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. ++optional */ + automountServiceAccountToken?: boolean; + /** List of containers belonging to the pod. +Containers cannot currently be added or removed. +There must be at least one container in a Pod. +Cannot be updated. ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name */ + containers?: V1Container[]; + /** Specifies the DNS parameters of a pod. +Parameters specified here will be merged to the generated DNS +configuration based on DNSPolicy. ++optional */ + dnsConfig?: V1PodDNSConfig; + /** Set DNS policy for the pod. +Defaults to "ClusterFirst". +Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. +DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. +To have DNS options set along with hostNetwork, you have to specify DNS policy +explicitly to 'ClusterFirstWithHostNet'. ++optional */ + dnsPolicy?: string; + /** EnableServiceLinks indicates whether information about services should be injected into pod's +environment variables, matching the syntax of Docker links. +Optional: Defaults to true. ++optional */ + enableServiceLinks?: boolean; + /** List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing +pod to perform user-initiated actions such as debugging. This list cannot be specified when +creating a pod, and it cannot be modified by updating the pod spec. In order to add an +ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. ++optional ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name */ + ephemeralContainers?: V1EphemeralContainer[]; + /** HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts +file if specified. ++optional ++patchMergeKey=ip ++patchStrategy=merge ++listType=map ++listMapKey=ip */ + hostAliases?: V1HostAlias[]; + /** Use the host's ipc namespace. +Optional: Default to false. ++k8s:conversion-gen=false ++optional */ + hostIPC?: boolean; + /** Host networking requested for this pod. Use the host's network namespace. +When using HostNetwork you should specify ports so the scheduler is aware. +When `hostNetwork` is true, specified `hostPort` fields in port definitions must match `containerPort`, +and unspecified `hostPort` fields in port definitions are defaulted to match `containerPort`. +Default to false. ++k8s:conversion-gen=false ++optional */ + hostNetwork?: boolean; + /** Use the host's pid namespace. +Optional: Default to false. ++k8s:conversion-gen=false ++optional */ + hostPID?: boolean; + /** Use the host's user namespace. +Optional: Default to true. +If set to true or not present, the pod will be run in the host user namespace, useful +for when the pod needs a feature only available to the host user namespace, such as +loading a kernel module with CAP_SYS_MODULE. +When set to false, a new userns is created for the pod. Setting false is useful for +mitigating container breakout vulnerabilities even allowing users to run their +containers as root without actually having root privileges on the host. +This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. ++k8s:conversion-gen=false ++optional */ + hostUsers?: boolean; + /** Specifies the hostname of the Pod +If not specified, the pod's hostname will be set to a system-defined value. ++optional */ + hostname?: string; + /** HostnameOverride specifies an explicit override for the pod's hostname as perceived by the pod. +This field only specifies the pod's hostname and does not affect its DNS records. +When this field is set to a non-empty string: +- It takes precedence over the values set in `hostname` and `subdomain`. +- The Pod's hostname will be set to this value. +- `setHostnameAsFQDN` must be nil or set to false. +- `hostNetwork` must be set to false. + +This field must be a valid DNS subdomain as defined in RFC 1123 and contain at most 64 characters. +Requires the HostnameOverride feature gate to be enabled. + ++featureGate=HostnameOverride ++optional */ + hostnameOverride?: string; + /** ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. +If specified, these secrets will be passed to individual puller implementations for them to use. +More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod ++optional ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name */ + imagePullSecrets?: V1LocalObjectReference[]; + /** List of initialization containers belonging to the pod. +Init containers are executed in order prior to containers being started. If any +init container fails, the pod is considered to have failed and is handled according +to its restartPolicy. The name for an init container or normal container must be +unique among all containers. +Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. +The resourceRequirements of an init container are taken into account during scheduling +by finding the highest request/limit for each resource type, and then using the max of +that value or the sum of the normal containers. Limits are applied to init containers +in a similar fashion. +Init containers cannot currently be added or removed. +Cannot be updated. +More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name */ + initContainers?: V1Container[]; + /** NodeName indicates in which node this pod is scheduled. +If empty, this pod is a candidate for scheduling by the scheduler defined in schedulerName. +Once this field is set, the kubelet for this node becomes responsible for the lifecycle of this pod. +This field should not be used to express a desire for the pod to be scheduled on a specific node. +https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodename ++optional */ + nodeName?: string; + /** NodeSelector is a selector which must be true for the pod to fit on a node. +Selector which must match a node's labels for the pod to be scheduled on that node. +More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ ++optional ++mapType=atomic */ + nodeSelector?: V1PodSpecNodeSelector; + /** Specifies the OS of the containers in the pod. +Some pod and container fields are restricted if this is set. + +If the OS field is set to linux, the following fields must be unset: +-securityContext.windowsOptions + +If the OS field is set to windows, following fields must be unset: +- spec.hostPID +- spec.hostIPC +- spec.hostUsers +- spec.resources +- spec.securityContext.appArmorProfile +- spec.securityContext.seLinuxOptions +- spec.securityContext.seccompProfile +- spec.securityContext.fsGroup +- spec.securityContext.fsGroupChangePolicy +- spec.securityContext.sysctls +- spec.shareProcessNamespace +- spec.securityContext.runAsUser +- spec.securityContext.runAsGroup +- spec.securityContext.supplementalGroups +- spec.securityContext.supplementalGroupsPolicy +- spec.containers[*].securityContext.appArmorProfile +- spec.containers[*].securityContext.seLinuxOptions +- spec.containers[*].securityContext.seccompProfile +- spec.containers[*].securityContext.capabilities +- spec.containers[*].securityContext.readOnlyRootFilesystem +- spec.containers[*].securityContext.privileged +- spec.containers[*].securityContext.allowPrivilegeEscalation +- spec.containers[*].securityContext.procMount +- spec.containers[*].securityContext.runAsUser +- spec.containers[*].securityContext.runAsGroup ++optional */ + os?: V1PodOS; + /** Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. +This field will be autopopulated at admission time by the RuntimeClass admission controller. If +the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. +The RuntimeClass admission controller will reject Pod create requests which have the overhead already +set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value +defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. +More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md ++optional */ + overhead?: V1ResourceList; + /** PreemptionPolicy is the Policy for preempting pods with lower priority. +One of Never, PreemptLowerPriority. +Defaults to PreemptLowerPriority if unset. ++optional */ + preemptionPolicy?: string; + /** The priority value. Various system components use this field to find the +priority of the pod. When Priority Admission Controller is enabled, it +prevents users from setting this field. The admission controller populates +this field from PriorityClassName. +The higher the value, the higher the priority. ++optional */ + priority?: number; + /** If specified, indicates the pod's priority. "system-node-critical" and +"system-cluster-critical" are two special keywords which indicate the +highest priorities with the former being the highest priority. Any other +name must be defined by creating a PriorityClass object with that name. +If not specified, the pod priority will be default or zero if there is no +default. ++optional */ + priorityClassName?: string; + /** If specified, all readiness gates will be evaluated for pod readiness. +A pod is ready when all its containers are ready AND +all conditions specified in the readiness gates have status equal to "True" +More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates ++optional ++listType=atomic */ + readinessGates?: V1PodReadinessGate[]; + /** ResourceClaims defines which ResourceClaims must be allocated +and reserved before the Pod is allowed to start. The resources +will be made available to those containers which consume them +by name. + +This is an alpha field and requires enabling the +DynamicResourceAllocation feature gate. + +This field is immutable. + ++patchMergeKey=name ++patchStrategy=merge,retainKeys ++listType=map ++listMapKey=name ++featureGate=DynamicResourceAllocation ++optional */ + resourceClaims?: V1PodResourceClaim[]; + /** Resources is the total amount of CPU and Memory resources required by all +containers in the pod. It supports specifying Requests and Limits for +"cpu", "memory" and "hugepages-" resource names only. ResourceClaims are not supported. + +This field enables fine-grained control over resource allocation for the +entire pod, allowing resource sharing among containers in a pod. +TODO: For beta graduation, expand this comment with a detailed explanation. + +This is an alpha field and requires enabling the PodLevelResources feature +gate. + ++featureGate=PodLevelResources ++optional */ + resources?: V1ResourceRequirements; + /** Restart policy for all containers within the pod. +One of Always, OnFailure, Never. In some contexts, only a subset of those values may be permitted. +Default to Always. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy ++optional */ + restartPolicy?: string; + /** RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used +to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. +If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an +empty definition that uses the default runtime handler. +More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class ++optional */ + runtimeClassName?: string; + /** If specified, the pod will be dispatched by specified scheduler. +If not specified, the pod will be dispatched by default scheduler. ++optional */ + schedulerName?: string; + /** SchedulingGates is an opaque list of values that if specified will block scheduling the pod. +If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the +scheduler will not attempt to schedule the pod. + +SchedulingGates can only be set at pod creation time, and be removed only afterwards. + ++patchMergeKey=name ++patchStrategy=merge ++listType=map ++listMapKey=name ++optional */ + schedulingGates?: V1PodSchedulingGate[]; + /** SecurityContext holds pod-level security attributes and common container settings. +Optional: Defaults to empty. See type description for default values of each field. ++optional */ + securityContext?: V1PodSecurityContext; + /** DeprecatedServiceAccount is a deprecated alias for ServiceAccountName. +Deprecated: Use serviceAccountName instead. ++k8s:conversion-gen=false ++optional */ + serviceAccount?: string; + /** ServiceAccountName is the name of the ServiceAccount to use to run this pod. +More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ ++optional */ + serviceAccountName?: string; + /** If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). +In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). +In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. +If a pod does not have FQDN, this has no effect. +Default to false. ++optional */ + setHostnameAsFQDN?: boolean; + /** Share a single process namespace between all of the containers in a pod. +When this is set containers will be able to view and signal processes from other containers +in the same pod, and the first process in each container will not be assigned PID 1. +HostPID and ShareProcessNamespace cannot both be set. +Optional: Default to false. ++k8s:conversion-gen=false ++optional */ + shareProcessNamespace?: boolean; + /** If specified, the fully qualified Pod hostname will be "...svc.". +If not specified, the pod will not have a domainname at all. ++optional */ + subdomain?: string; + /** Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. +Value must be non-negative integer. The value zero indicates stop immediately via +the kill signal (no opportunity to shut down). +If this value is nil, the default grace period will be used instead. +The grace period is the duration in seconds after the processes running in the pod are sent +a termination signal and the time when the processes are forcibly halted with a kill signal. +Set this value longer than the expected cleanup time for your process. +Defaults to 30 seconds. ++optional */ + terminationGracePeriodSeconds?: number; + /** If specified, the pod's tolerations. ++optional ++listType=atomic */ + tolerations?: V1Toleration[]; + /** TopologySpreadConstraints describes how a group of pods ought to spread across topology +domains. Scheduler will schedule pods in a way which abides by the constraints. +All topologySpreadConstraints are ANDed. ++optional ++patchMergeKey=topologyKey ++patchStrategy=merge ++listType=map ++listMapKey=topologyKey ++listMapKey=whenUnsatisfiable */ + topologySpreadConstraints?: V1TopologySpreadConstraint[]; + /** List of volumes that can be mounted by containers belonging to the pod. +More info: https://kubernetes.io/docs/concepts/storage/volumes ++optional ++patchMergeKey=name ++patchStrategy=merge,retainKeys ++listType=map ++listMapKey=name */ + volumes?: V1Volume[]; +} diff --git a/ui/src/gen/api/v2/models/v1PodSpecNodeSelector.ts b/ui/src/gen/api/v2/models/v1PodSpecNodeSelector.ts new file mode 100644 index 0000000000..7da8f5750e --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodSpecNodeSelector.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * NodeSelector is a selector which must be true for the pod to fit on a node. +Selector which must match a node's labels for the pod to be scheduled on that node. +More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ ++optional ++mapType=atomic + */ +export type V1PodSpecNodeSelector = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1PodTemplateSpec.ts b/ui/src/gen/api/v2/models/v1PodTemplateSpec.ts new file mode 100644 index 0000000000..aa955a0924 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PodTemplateSpec.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { V1PodSpec } from './v1PodSpec'; + +export interface V1PodTemplateSpec { + /** Standard object's metadata. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + metadata?: V1ObjectMeta; + /** Specification of the desired behavior of the pod. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status ++optional */ + spec?: V1PodSpec; +} diff --git a/ui/src/gen/api/v2/models/v1PolicyRule.ts b/ui/src/gen/api/v2/models/v1PolicyRule.ts new file mode 100644 index 0000000000..51ed31c0b0 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PolicyRule.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PolicyRule { + /** APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of +the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. ++optional ++listType=atomic */ + apiGroups?: string[]; + /** NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path +Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. +Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. ++optional ++listType=atomic */ + nonResourceURLs?: string[]; + /** ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. ++optional ++listType=atomic */ + resourceNames?: string[]; + /** Resources is a list of resources this rule applies to. '*' represents all resources. ++optional ++listType=atomic */ + resources?: string[]; + /** Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs. ++listType=atomic */ + verbs?: string[]; +} diff --git a/ui/src/gen/api/v2/models/v1PortworxVolumeSource.ts b/ui/src/gen/api/v2/models/v1PortworxVolumeSource.ts new file mode 100644 index 0000000000..81108e9c69 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PortworxVolumeSource.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1PortworxVolumeSource { + /** fSType represents the filesystem type to mount +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. */ + fsType?: string; + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean; + /** volumeID uniquely identifies a Portworx volume */ + volumeID?: string; +} diff --git a/ui/src/gen/api/v2/models/v1PreferredSchedulingTerm.ts b/ui/src/gen/api/v2/models/v1PreferredSchedulingTerm.ts new file mode 100644 index 0000000000..5c19546149 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1PreferredSchedulingTerm.ts @@ -0,0 +1,15 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1NodeSelectorTerm } from './v1NodeSelectorTerm'; + +export interface V1PreferredSchedulingTerm { + /** A node selector term, associated with the corresponding weight. */ + preference?: V1NodeSelectorTerm; + /** Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. */ + weight?: number; +} diff --git a/ui/src/gen/api/v2/models/v1Probe.ts b/ui/src/gen/api/v2/models/v1Probe.ts new file mode 100644 index 0000000000..a5dc24de0f --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Probe.ts @@ -0,0 +1,59 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ExecAction } from './v1ExecAction'; +import type { V1GRPCAction } from './v1GRPCAction'; +import type { V1HTTPGetAction } from './v1HTTPGetAction'; +import type { V1TCPSocketAction } from './v1TCPSocketAction'; + +export interface V1Probe { + /** Exec specifies a command to execute in the container. ++optional */ + exec?: V1ExecAction; + /** Minimum consecutive failures for the probe to be considered failed after having succeeded. +Defaults to 3. Minimum value is 1. ++optional */ + failureThreshold?: number; + /** GRPC specifies a GRPC HealthCheckRequest. ++optional */ + grpc?: V1GRPCAction; + /** HTTPGet specifies an HTTP GET request to perform. ++optional */ + httpGet?: V1HTTPGetAction; + /** Number of seconds after the container has started before liveness probes are initiated. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + initialDelaySeconds?: number; + /** How often (in seconds) to perform the probe. +Default to 10 seconds. Minimum value is 1. ++optional */ + periodSeconds?: number; + /** Minimum consecutive successes for the probe to be considered successful after having failed. +Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. ++optional */ + successThreshold?: number; + /** TCPSocket specifies a connection to a TCP port. ++optional */ + tcpSocket?: V1TCPSocketAction; + /** Optional duration in seconds the pod needs to terminate gracefully upon probe failure. +The grace period is the duration in seconds after the processes running in the pod are sent +a termination signal and the time when the processes are forcibly halted with a kill signal. +Set this value longer than the expected cleanup time for your process. +If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this +value overrides the value provided by the pod spec. +Value must be non-negative integer. The value zero indicates stop immediately via +the kill signal (no opportunity to shut down). +This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. +Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. ++optional */ + terminationGracePeriodSeconds?: number; + /** Number of seconds after which the probe times out. +Defaults to 1 second. Minimum value is 1. +More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes ++optional */ + timeoutSeconds?: number; +} diff --git a/ui/src/gen/api/v2/models/v1ProjectedVolumeSource.ts b/ui/src/gen/api/v2/models/v1ProjectedVolumeSource.ts new file mode 100644 index 0000000000..28d47234ac --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ProjectedVolumeSource.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1VolumeProjection } from './v1VolumeProjection'; + +export interface V1ProjectedVolumeSource { + /** defaultMode are the mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number; + /** sources is the list of volume projections. Each entry in this list +handles one source. ++optional ++listType=atomic */ + sources?: V1VolumeProjection[]; +} diff --git a/ui/src/gen/api/v2/models/v1QuobyteVolumeSource.ts b/ui/src/gen/api/v2/models/v1QuobyteVolumeSource.ts new file mode 100644 index 0000000000..50b3767dc3 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1QuobyteVolumeSource.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1QuobyteVolumeSource { + /** group to map volume access to +Default is no group ++optional */ + group?: string; + /** readOnly here will force the Quobyte volume to be mounted with read-only permissions. +Defaults to false. ++optional */ + readOnly?: boolean; + /** registry represents a single or multiple Quobyte Registry services +specified as a string as host:port pair (multiple entries are separated with commas) +which acts as the central registry for volumes */ + registry?: string; + /** tenant owning the given Quobyte volume in the Backend +Used with dynamically provisioned Quobyte volumes, value is set by the plugin ++optional */ + tenant?: string; + /** user to map volume access to +Defaults to serivceaccount user ++optional */ + user?: string; + /** volume is a string that references an already created Quobyte volume by name. */ + volume?: string; +} diff --git a/ui/src/gen/api/v2/models/v1RBDVolumeSource.ts b/ui/src/gen/api/v2/models/v1RBDVolumeSource.ts new file mode 100644 index 0000000000..5ea7419c4c --- /dev/null +++ b/ui/src/gen/api/v2/models/v1RBDVolumeSource.ts @@ -0,0 +1,54 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1RBDVolumeSource { + /** fsType is the filesystem type of the volume that you want to mount. +Tip: Ensure that the filesystem type is supported by the host operating system. +Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. +More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd +TODO: how do we prevent errors in the filesystem from compromising the machine ++optional */ + fsType?: string; + /** image is the rados image name. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it */ + image?: string; + /** keyring is the path to key ring for RBDUser. +Default is /etc/ceph/keyring. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional ++default="/etc/ceph/keyring" */ + keyring?: string; + /** monitors is a collection of Ceph monitors. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++listType=atomic */ + monitors?: string[]; + /** pool is the rados pool name. +Default is rbd. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional ++default="rbd" */ + pool?: string; + /** readOnly here will force the ReadOnly setting in VolumeMounts. +Defaults to false. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional */ + readOnly?: boolean; + /** secretRef is name of the authentication secret for RBDUser. If provided +overrides keyring. +Default is nil. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional */ + secretRef?: V1LocalObjectReference; + /** user is the rados user name. +Default is admin. +More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it ++optional ++default="admin" */ + user?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ResourceClaim.ts b/ui/src/gen/api/v2/models/v1ResourceClaim.ts new file mode 100644 index 0000000000..d677ecd70e --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ResourceClaim.ts @@ -0,0 +1,20 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ResourceClaim { + /** Name must match the name of one entry in pod.spec.resourceClaims of +the Pod where this field is used. It makes that resource available +inside a container. */ + name?: string; + /** Request is the name chosen for a request in the referenced claim. +If empty, everything from the claim is made available, otherwise +only the result of this request. + ++optional */ + request?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ResourceFieldSelector.ts b/ui/src/gen/api/v2/models/v1ResourceFieldSelector.ts new file mode 100644 index 0000000000..36c4dccf13 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ResourceFieldSelector.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Quantity } from './quantity'; + +export interface V1ResourceFieldSelector { + /** Container name: required for volumes, optional for env vars ++optional */ + containerName?: string; + /** Specifies the output format of the exposed resources, defaults to "1" ++optional */ + divisor?: Quantity; + /** Required: resource to select */ + resource?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ResourceList.ts b/ui/src/gen/api/v2/models/v1ResourceList.ts new file mode 100644 index 0000000000..9781ed008d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ResourceList.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Quantity } from './quantity'; + +export interface V1ResourceList { + [key: string]: Quantity; +} diff --git a/ui/src/gen/api/v2/models/v1ResourceRequirements.ts b/ui/src/gen/api/v2/models/v1ResourceRequirements.ts new file mode 100644 index 0000000000..db79ae751a --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ResourceRequirements.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ResourceClaim } from './v1ResourceClaim'; +import type { V1ResourceList } from './v1ResourceList'; + +export interface V1ResourceRequirements { + /** Claims lists the names of resources, defined in spec.resourceClaims, +that are used by this container. + +This field depends on the +DynamicResourceAllocation feature gate. + +This field is immutable. It can only be set for containers. + ++listType=map ++listMapKey=name ++featureGate=DynamicResourceAllocation ++optional */ + claims?: V1ResourceClaim[]; + /** Limits describes the maximum amount of compute resources allowed. +More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ ++optional */ + limits?: V1ResourceList; + /** Requests describes the minimum amount of compute resources required. +If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, +otherwise to an implementation-defined value. Requests cannot exceed Limits. +More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ ++optional */ + requests?: V1ResourceList; +} diff --git a/ui/src/gen/api/v2/models/v1SELinuxOptions.ts b/ui/src/gen/api/v2/models/v1SELinuxOptions.ts new file mode 100644 index 0000000000..78a19488df --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SELinuxOptions.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1SELinuxOptions { + /** Level is SELinux level label that applies to the container. ++optional */ + level?: string; + /** Role is a SELinux role label that applies to the container. ++optional */ + role?: string; + /** Type is a SELinux type label that applies to the container. ++optional */ + type?: string; + /** User is a SELinux user label that applies to the container. ++optional */ + user?: string; +} diff --git a/ui/src/gen/api/v2/models/v1ScaleIOVolumeSource.ts b/ui/src/gen/api/v2/models/v1ScaleIOVolumeSource.ts new file mode 100644 index 0000000000..a6feb6c4a4 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ScaleIOVolumeSource.ts @@ -0,0 +1,46 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1ScaleIOVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". +Default is "xfs". ++optional ++default="xfs" */ + fsType?: string; + /** gateway is the host address of the ScaleIO API Gateway. */ + gateway?: string; + /** protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. ++optional */ + protectionDomain?: string; + /** readOnly Defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean; + /** secretRef references to the secret for ScaleIO user and other +sensitive information. If this is not provided, Login operation will fail. */ + secretRef?: V1LocalObjectReference; + /** sslEnabled Flag enable/disable SSL communication with Gateway, default false ++optional */ + sslEnabled?: boolean; + /** storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. +Default is ThinProvisioned. ++optional ++default="ThinProvisioned" */ + storageMode?: string; + /** storagePool is the ScaleIO Storage Pool associated with the protection domain. ++optional */ + storagePool?: string; + /** system is the name of the storage system as configured in ScaleIO. */ + system?: string; + /** volumeName is the name of a volume already created in the ScaleIO system +that is associated with this volume source. */ + volumeName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1SeccompProfile.ts b/ui/src/gen/api/v2/models/v1SeccompProfile.ts new file mode 100644 index 0000000000..83e32cb4cd --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SeccompProfile.ts @@ -0,0 +1,24 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1SeccompProfile { + /** localhostProfile indicates a profile defined in a file on the node should be used. +The profile must be preconfigured on the node to work. +Must be a descending path, relative to the kubelet's configured seccomp profile location. +Must be set if type is "Localhost". Must NOT be set for any other type. ++optional */ + localhostProfile?: string; + /** type indicates which kind of seccomp profile will be applied. +Valid options are: + +Localhost - a profile defined in a file on the node should be used. +RuntimeDefault - the container runtime default profile should be used. +Unconfined - no profile should be applied. ++unionDiscriminator */ + type?: string; +} diff --git a/ui/src/gen/api/v2/models/v1Secret.ts b/ui/src/gen/api/v2/models/v1Secret.ts new file mode 100644 index 0000000000..16ee365c55 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Secret.ts @@ -0,0 +1,53 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1SecretData } from './v1SecretData'; +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { V1SecretStringData } from './v1SecretStringData'; + +export interface V1Secret { + /** 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 ++optional */ + apiVersion?: string; + /** Data contains the secret data. Each key must consist of alphanumeric +characters, '-', '_' or '.'. The serialized form of the secret data is a +base64 encoded string, representing the arbitrary (possibly non-string) +data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 ++optional */ + data?: V1SecretData; + /** Immutable, if set to true, ensures that data stored in the Secret cannot +be updated (only object metadata can be modified). +If not set to true, the field can be modified at any time. +Defaulted to nil. ++optional */ + immutable?: boolean; + /** 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 ++optional */ + kind?: string; + /** Standard object's metadata. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata ++optional */ + metadata?: V1ObjectMeta; + /** stringData allows specifying non-binary secret data in string form. +It is provided as a write-only input field for convenience. +All keys and values are merged into the data field on write, overwriting any existing values. +The stringData field is never output when reading from the API. ++k8s:conversion-gen=false ++optional */ + stringData?: V1SecretStringData; + /** Used to facilitate programmatic handling of secret data. +More info: https://kubernetes.io/docs/concepts/configuration/secret/#secret-types ++optional */ + type?: string; +} diff --git a/ui/src/gen/api/v2/models/v1SecretData.ts b/ui/src/gen/api/v2/models/v1SecretData.ts new file mode 100644 index 0000000000..b7b253dbc1 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretData.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * Data contains the secret data. Each key must consist of alphanumeric +characters, '-', '_' or '.'. The serialized form of the secret data is a +base64 encoded string, representing the arbitrary (possibly non-string) +data value here. Described in https://tools.ietf.org/html/rfc4648#section-4 ++optional + */ +export type V1SecretData = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1SecretEnvSource.ts b/ui/src/gen/api/v2/models/v1SecretEnvSource.ts new file mode 100644 index 0000000000..1e2f55f2f8 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretEnvSource.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1SecretEnvSource { + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** Specify whether the Secret must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1SecretKeySelector.ts b/ui/src/gen/api/v2/models/v1SecretKeySelector.ts new file mode 100644 index 0000000000..e1599054d0 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretKeySelector.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1SecretKeySelector { + /** The key of the secret to select from. Must be a valid secret key. */ + key?: string; + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** Specify whether the Secret or its key must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1SecretList.ts b/ui/src/gen/api/v2/models/v1SecretList.ts new file mode 100644 index 0000000000..6c04bd8414 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretList.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Secret } from './v1Secret'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface V1SecretList { + /** 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 ++optional */ + apiVersion?: string; + /** Items is a list of secret objects. +More info: https://kubernetes.io/docs/concepts/configuration/secret */ + items?: V1Secret[]; + /** 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 ++optional */ + kind?: string; + /** Standard list metadata. +More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds ++optional */ + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/v1SecretProjection.ts b/ui/src/gen/api/v2/models/v1SecretProjection.ts new file mode 100644 index 0000000000..d32f9c6272 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretProjection.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1KeyToPath } from './v1KeyToPath'; + +export interface V1SecretProjection { + /** items if unspecified, each key-value pair in the Data field of the referenced +Secret will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the Secret, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional ++listType=atomic */ + items?: V1KeyToPath[]; + /** Name of the referent. +This field is effectively required, but due to backwards compatibility is +allowed to be empty. Instances of this type with an empty value here are +almost certainly wrong. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names ++optional ++default="" ++kubebuilder:default="" +TODO: Drop `kubebuilder:default` when controller-gen doesn't need it https://github.com/kubernetes-sigs/kubebuilder/issues/3896. */ + name?: string; + /** optional field specify whether the Secret or its key must be defined ++optional */ + optional?: boolean; +} diff --git a/ui/src/gen/api/v2/models/v1SecretStringData.ts b/ui/src/gen/api/v2/models/v1SecretStringData.ts new file mode 100644 index 0000000000..6f36123242 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretStringData.ts @@ -0,0 +1,17 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +/** + * stringData allows specifying non-binary secret data in string form. +It is provided as a write-only input field for convenience. +All keys and values are merged into the data field on write, overwriting any existing values. +The stringData field is never output when reading from the API. ++k8s:conversion-gen=false ++optional + */ +export type V1SecretStringData = { [key: string]: string }; diff --git a/ui/src/gen/api/v2/models/v1SecretVolumeSource.ts b/ui/src/gen/api/v2/models/v1SecretVolumeSource.ts new file mode 100644 index 0000000000..b3e93f023d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecretVolumeSource.ts @@ -0,0 +1,37 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1KeyToPath } from './v1KeyToPath'; + +export interface V1SecretVolumeSource { + /** defaultMode is Optional: mode bits used to set permissions on created files by default. +Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. +YAML accepts both octal and decimal values, JSON requires decimal values +for mode bits. Defaults to 0644. +Directories within the path are not affected by this setting. +This might be in conflict with other options that affect the file +mode, like fsGroup, and the result can be other mode bits set. ++optional */ + defaultMode?: number; + /** items If unspecified, each key-value pair in the Data field of the referenced +Secret will be projected into the volume as a file whose name is the +key and content is the value. If specified, the listed keys will be +projected into the specified paths, and unlisted keys will not be +present. If a key is specified which is not present in the Secret, +the volume setup will error unless it is marked optional. Paths must be +relative and may not contain the '..' path or start with '..'. ++optional ++listType=atomic */ + items?: V1KeyToPath[]; + /** optional field specify whether the Secret or its keys must be defined ++optional */ + optional?: boolean; + /** secretName is the name of the secret in the pod's namespace to use. +More info: https://kubernetes.io/docs/concepts/storage/volumes#secret ++optional */ + secretName?: string; +} diff --git a/ui/src/gen/api/v2/models/v1SecurityContext.ts b/ui/src/gen/api/v2/models/v1SecurityContext.ts new file mode 100644 index 0000000000..11c64249b6 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SecurityContext.ts @@ -0,0 +1,93 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1AppArmorProfile } from './v1AppArmorProfile'; +import type { V1Capabilities } from './v1Capabilities'; +import type { V1SELinuxOptions } from './v1SELinuxOptions'; +import type { V1SeccompProfile } from './v1SeccompProfile'; +import type { V1WindowsSecurityContextOptions } from './v1WindowsSecurityContextOptions'; + +export interface V1SecurityContext { + /** AllowPrivilegeEscalation controls whether a process can gain more +privileges than its parent process. This bool directly controls if +the no_new_privs flag will be set on the container process. +AllowPrivilegeEscalation is true always when the container is: +1) run as Privileged +2) has CAP_SYS_ADMIN +Note that this field cannot be set when spec.os.name is windows. ++optional */ + allowPrivilegeEscalation?: boolean; + /** appArmorProfile is the AppArmor options to use by this container. If set, this profile +overrides the pod's appArmorProfile. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + appArmorProfile?: V1AppArmorProfile; + /** The capabilities to add/drop when running containers. +Defaults to the default set of capabilities granted by the container runtime. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + capabilities?: V1Capabilities; + /** Run container in privileged mode. +Processes in privileged containers are essentially equivalent to root on the host. +Defaults to false. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + privileged?: boolean; + /** procMount denotes the type of proc mount to use for the containers. +The default value is Default which uses the container runtime defaults for +readonly paths and masked paths. +This requires the ProcMountType feature flag to be enabled. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + procMount?: string; + /** Whether this container has a read-only root filesystem. +Default is false. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + readOnlyRootFilesystem?: boolean; + /** The GID to run the entrypoint of the container process. +Uses runtime default if unset. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + runAsGroup?: number; + /** Indicates that the container must run as a non-root user. +If true, the Kubelet will validate the image at runtime to ensure that it +does not run as UID 0 (root) and fail to start the container if it does. +If unset or false, no such validation will be performed. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. ++optional */ + runAsNonRoot?: boolean; + /** The UID to run the entrypoint of the container process. +Defaults to user specified in image metadata if unspecified. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + runAsUser?: number; + /** The SELinux context to be applied to the container. +If unspecified, the container runtime will allocate a random SELinux context for each +container. May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + seLinuxOptions?: V1SELinuxOptions; + /** The seccomp options to use by this container. If seccomp options are +provided at both the pod & container level, the container options +override the pod options. +Note that this field cannot be set when spec.os.name is windows. ++optional */ + seccompProfile?: V1SeccompProfile; + /** The Windows specific settings applied to all containers. +If unspecified, the options from the PodSecurityContext will be used. +If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. +Note that this field cannot be set when spec.os.name is linux. ++optional */ + windowsOptions?: V1WindowsSecurityContextOptions; +} diff --git a/ui/src/gen/api/v2/models/v1ServiceAccountTokenProjection.ts b/ui/src/gen/api/v2/models/v1ServiceAccountTokenProjection.ts new file mode 100644 index 0000000000..223272f0f4 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1ServiceAccountTokenProjection.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1ServiceAccountTokenProjection { + /** audience is the intended audience of the token. A recipient of a token +must identify itself with an identifier specified in the audience of the +token, and otherwise should reject the token. The audience defaults to the +identifier of the apiserver. ++optional */ + audience?: string; + /** expirationSeconds is the requested duration of validity of the service +account token. As the token approaches expiration, the kubelet volume +plugin will proactively rotate the service account token. The kubelet will +start trying to rotate the token if the token is older than 80 percent of +its time to live or if the token is older than 24 hours.Defaults to 1 hour +and must be at least 10 minutes. ++optional */ + expirationSeconds?: number; + /** path is the path relative to the mount point of the file to project the +token into. */ + path?: string; +} diff --git a/ui/src/gen/api/v2/models/v1SleepAction.ts b/ui/src/gen/api/v2/models/v1SleepAction.ts new file mode 100644 index 0000000000..a260869797 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SleepAction.ts @@ -0,0 +1,12 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1SleepAction { + /** Seconds is the number of seconds to sleep. */ + seconds?: number; +} diff --git a/ui/src/gen/api/v2/models/v1StorageOSVolumeSource.ts b/ui/src/gen/api/v2/models/v1StorageOSVolumeSource.ts new file mode 100644 index 0000000000..654615c3f4 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1StorageOSVolumeSource.ts @@ -0,0 +1,35 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LocalObjectReference } from './v1LocalObjectReference'; + +export interface V1StorageOSVolumeSource { + /** fsType is the filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. ++optional */ + fsType?: string; + /** readOnly defaults to false (read/write). ReadOnly here will force +the ReadOnly setting in VolumeMounts. ++optional */ + readOnly?: boolean; + /** secretRef specifies the secret to use for obtaining the StorageOS API +credentials. If not specified, default values will be attempted. ++optional */ + secretRef?: V1LocalObjectReference; + /** volumeName is the human-readable name of the StorageOS volume. Volume +names are only unique within a namespace. */ + volumeName?: string; + /** volumeNamespace specifies the scope of the volume within StorageOS. If no +namespace is specified then the Pod's namespace will be used. This allows the +Kubernetes name scoping to be mirrored within StorageOS for tighter integration. +Set VolumeName to any name to override the default behaviour. +Set to "default" if you are not using namespaces within StorageOS. +Namespaces that do not pre-exist within StorageOS will be created. ++optional */ + volumeNamespace?: string; +} diff --git a/ui/src/gen/api/v2/models/v1SuccessPolicy.ts b/ui/src/gen/api/v2/models/v1SuccessPolicy.ts new file mode 100644 index 0000000000..795f484b44 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SuccessPolicy.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1SuccessPolicyRule } from './v1SuccessPolicyRule'; + +export interface V1SuccessPolicy { + /** rules represents the list of alternative rules for the declaring the Jobs +as successful before `.status.succeeded >= .spec.completions`. Once any of the rules are met, +the "SuccessCriteriaMet" condition is added, and the lingering pods are removed. +The terminal state for such a Job has the "Complete" condition. +Additionally, these rules are evaluated in order; Once the Job meets one of the rules, +other rules are ignored. At most 20 elements are allowed. ++listType=atomic */ + rules?: V1SuccessPolicyRule[]; +} diff --git a/ui/src/gen/api/v2/models/v1SuccessPolicyRule.ts b/ui/src/gen/api/v2/models/v1SuccessPolicyRule.ts new file mode 100644 index 0000000000..729c4cf282 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1SuccessPolicyRule.ts @@ -0,0 +1,37 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1SuccessPolicyRule { + /** succeededCount specifies the minimal required size of the actual set of the succeeded indexes +for the Job. When succeededCount is used along with succeededIndexes, the check is +constrained only to the set of indexes specified by succeededIndexes. +For example, given that succeededIndexes is "1-4", succeededCount is "3", +and completed indexes are "1", "3", and "5", the Job isn't declared as succeeded +because only "1" and "3" indexes are considered in that rules. +When this field is null, this doesn't default to any value and +is never evaluated at any time. +When specified it needs to be a positive integer. + ++optional */ + succeededCount?: number; + /** succeededIndexes specifies the set of indexes +which need to be contained in the actual set of the succeeded indexes for the Job. +The list of indexes must be within 0 to ".spec.completions-1" and +must not contain duplicates. At least one element is required. +The indexes are represented as intervals separated by commas. +The intervals can be a decimal integer or a pair of decimal integers separated by a hyphen. +The number are listed in represented by the first and last element of the series, +separated by a hyphen. +For example, if the completed indexes are 1, 3, 4, 5 and 7, they are +represented as "1,3-5,7". +When this field is null, this field doesn't default to any value +and is never evaluated at any time. + ++optional */ + succeededIndexes?: string; +} diff --git a/ui/src/gen/api/v2/models/v1Sysctl.ts b/ui/src/gen/api/v2/models/v1Sysctl.ts new file mode 100644 index 0000000000..3b05bbfa88 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Sysctl.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1Sysctl { + /** Name of a property to set */ + name?: string; + /** Value of a property to set */ + value?: string; +} diff --git a/ui/src/gen/api/v2/models/v1TCPSocketAction.ts b/ui/src/gen/api/v2/models/v1TCPSocketAction.ts new file mode 100644 index 0000000000..2af0b516ec --- /dev/null +++ b/ui/src/gen/api/v2/models/v1TCPSocketAction.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { IntOrString } from './intOrString'; + +export interface V1TCPSocketAction { + /** Optional: Host name to connect to, defaults to the pod IP. ++optional */ + host?: string; + /** Number or name of the port to access on the container. +Number must be in the range 1 to 65535. +Name must be an IANA_SVC_NAME. */ + port?: IntOrString; +} diff --git a/ui/src/gen/api/v2/models/v1Toleration.ts b/ui/src/gen/api/v2/models/v1Toleration.ts new file mode 100644 index 0000000000..0a94502252 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Toleration.ts @@ -0,0 +1,34 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1Toleration { + /** Effect indicates the taint effect to match. Empty means match all taint effects. +When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. ++optional */ + effect?: string; + /** Key is the taint key that the toleration applies to. Empty means match all taint keys. +If the key is empty, operator must be Exists; this combination means to match all values and all keys. ++optional */ + key?: string; + /** Operator represents a key's relationship to the value. +Valid operators are Exists and Equal. Defaults to Equal. +Exists is equivalent to wildcard for value, so that a pod can +tolerate all taints of a particular category. ++optional */ + operator?: string; + /** TolerationSeconds represents the period of time the toleration (which must be +of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, +it is not set, which means tolerate the taint forever (do not evict). Zero and +negative values will be treated as 0 (evict immediately) by the system. ++optional */ + tolerationSeconds?: number; + /** Value is the taint value the toleration matches to. +If the operator is Exists, the value should be empty, otherwise just a regular string. ++optional */ + value?: string; +} diff --git a/ui/src/gen/api/v2/models/v1TopologySpreadConstraint.ts b/ui/src/gen/api/v2/models/v1TopologySpreadConstraint.ts new file mode 100644 index 0000000000..23bb333223 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1TopologySpreadConstraint.ts @@ -0,0 +1,124 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1LabelSelector } from './v1LabelSelector'; + +export interface V1TopologySpreadConstraint { + /** LabelSelector is used to find matching pods. +Pods that match this label selector are counted to determine the number of pods +in their corresponding topology domain. ++optional */ + labelSelector?: V1LabelSelector; + /** MatchLabelKeys is a set of pod label keys to select the pods over which +spreading will be calculated. The keys are used to lookup values from the +incoming pod labels, those key-value labels are ANDed with labelSelector +to select the group of existing pods over which spreading will be calculated +for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. +MatchLabelKeys cannot be set when LabelSelector isn't set. +Keys that don't exist in the incoming pod labels will +be ignored. A null or empty list means only match against labelSelector. + +This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). ++listType=atomic ++optional */ + matchLabelKeys?: string[]; + /** MaxSkew describes the degree to which pods may be unevenly distributed. +When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference +between the number of matching pods in the target topology and the global minimum. +The global minimum is the minimum number of matching pods in an eligible domain +or zero if the number of eligible domains is less than MinDomains. +For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same +labelSelector spread as 2/2/1: +In this case, the global minimum is 1. ++-------+-------+-------+ +| zone1 | zone2 | zone3 | ++-------+-------+-------+ +| P P | P P | P | ++-------+-------+-------+ +- if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; +scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) +violate MaxSkew(1). +- if MaxSkew is 2, incoming pod can be scheduled onto any zone. +When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence +to topologies that satisfy it. +It's a required field. Default value is 1 and 0 is not allowed. */ + maxSkew?: number; + /** MinDomains indicates a minimum number of eligible domains. +When the number of eligible domains with matching topology keys is less than minDomains, +Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. +And when the number of eligible domains with matching topology keys equals or greater than minDomains, +this value has no effect on scheduling. +As a result, when the number of eligible domains is less than minDomains, +scheduler won't schedule more than maxSkew Pods to those domains. +If value is nil, the constraint behaves as if MinDomains is equal to 1. +Valid values are integers greater than 0. +When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + +For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same +labelSelector spread as 2/2/2: ++-------+-------+-------+ +| zone1 | zone2 | zone3 | ++-------+-------+-------+ +| P P | P P | P P | ++-------+-------+-------+ +The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. +In this situation, new pod with the same labelSelector cannot be scheduled, +because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, +it will violate MaxSkew. ++optional */ + minDomains?: number; + /** NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector +when calculating pod topology spread skew. Options are: +- Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. +- Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. + +If this value is nil, the behavior is equivalent to the Honor policy. ++optional */ + nodeAffinityPolicy?: string; + /** NodeTaintsPolicy indicates how we will treat node taints when calculating +pod topology spread skew. Options are: +- Honor: nodes without taints, along with tainted nodes for which the incoming pod +has a toleration, are included. +- Ignore: node taints are ignored. All nodes are included. + +If this value is nil, the behavior is equivalent to the Ignore policy. ++optional */ + nodeTaintsPolicy?: string; + /** TopologyKey is the key of node labels. Nodes that have a label with this key +and identical values are considered to be in the same topology. +We consider each as a "bucket", and try to put balanced number +of pods into each bucket. +We define a domain as a particular instance of a topology. +Also, we define an eligible domain as a domain whose nodes meet the requirements of +nodeAffinityPolicy and nodeTaintsPolicy. +e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. +And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. +It's a required field. */ + topologyKey?: string; + /** WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy +the spread constraint. +- DoNotSchedule (default) tells the scheduler not to schedule it. +- ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. +A constraint is considered "Unsatisfiable" for an incoming pod +if and only if every possible node assignment for that pod would violate +"MaxSkew" on some topology. +For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same +labelSelector spread as 3/1/1: ++-------+-------+-------+ +| zone1 | zone2 | zone3 | ++-------+-------+-------+ +| P P P | P | P | ++-------+-------+-------+ +If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled +to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies +MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler +won't make it *more* imbalanced. +It's a required field. */ + whenUnsatisfiable?: string; +} diff --git a/ui/src/gen/api/v2/models/v1TypedLocalObjectReference.ts b/ui/src/gen/api/v2/models/v1TypedLocalObjectReference.ts new file mode 100644 index 0000000000..c9994bf9be --- /dev/null +++ b/ui/src/gen/api/v2/models/v1TypedLocalObjectReference.ts @@ -0,0 +1,19 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1TypedLocalObjectReference { + /** APIGroup is the group for the resource being referenced. +If APIGroup is not specified, the specified Kind must be in the core API group. +For any other third-party types, APIGroup is required. ++optional */ + apiGroup?: string; + /** Kind is the type of resource being referenced */ + kind?: string; + /** Name is the name of resource being referenced */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/v1TypedObjectReference.ts b/ui/src/gen/api/v2/models/v1TypedObjectReference.ts new file mode 100644 index 0000000000..dc4a9d8f25 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1TypedObjectReference.ts @@ -0,0 +1,25 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1TypedObjectReference { + /** APIGroup is the group for the resource being referenced. +If APIGroup is not specified, the specified Kind must be in the core API group. +For any other third-party types, APIGroup is required. ++optional */ + apiGroup?: string; + /** Kind is the type of resource being referenced */ + kind?: string; + /** Name is the name of resource being referenced */ + name?: string; + /** Namespace is the namespace of resource being referenced +Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. +(Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. ++featureGate=CrossNamespaceVolumeDataSource ++optional */ + namespace?: string; +} diff --git a/ui/src/gen/api/v2/models/v1Volume.ts b/ui/src/gen/api/v2/models/v1Volume.ts new file mode 100644 index 0000000000..124b96452d --- /dev/null +++ b/ui/src/gen/api/v2/models/v1Volume.ts @@ -0,0 +1,217 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1AWSElasticBlockStoreVolumeSource } from './v1AWSElasticBlockStoreVolumeSource'; +import type { V1AzureDiskVolumeSource } from './v1AzureDiskVolumeSource'; +import type { V1AzureFileVolumeSource } from './v1AzureFileVolumeSource'; +import type { V1CephFSVolumeSource } from './v1CephFSVolumeSource'; +import type { V1CinderVolumeSource } from './v1CinderVolumeSource'; +import type { V1ConfigMapVolumeSource } from './v1ConfigMapVolumeSource'; +import type { V1CSIVolumeSource } from './v1CSIVolumeSource'; +import type { V1DownwardAPIVolumeSource } from './v1DownwardAPIVolumeSource'; +import type { V1EmptyDirVolumeSource } from './v1EmptyDirVolumeSource'; +import type { V1EphemeralVolumeSource } from './v1EphemeralVolumeSource'; +import type { V1FCVolumeSource } from './v1FCVolumeSource'; +import type { V1FlexVolumeSource } from './v1FlexVolumeSource'; +import type { V1FlockerVolumeSource } from './v1FlockerVolumeSource'; +import type { V1GCEPersistentDiskVolumeSource } from './v1GCEPersistentDiskVolumeSource'; +import type { V1GitRepoVolumeSource } from './v1GitRepoVolumeSource'; +import type { V1GlusterfsVolumeSource } from './v1GlusterfsVolumeSource'; +import type { V1HostPathVolumeSource } from './v1HostPathVolumeSource'; +import type { V1ImageVolumeSource } from './v1ImageVolumeSource'; +import type { V1ISCSIVolumeSource } from './v1ISCSIVolumeSource'; +import type { V1NFSVolumeSource } from './v1NFSVolumeSource'; +import type { V1PersistentVolumeClaimVolumeSource } from './v1PersistentVolumeClaimVolumeSource'; +import type { V1PhotonPersistentDiskVolumeSource } from './v1PhotonPersistentDiskVolumeSource'; +import type { V1PortworxVolumeSource } from './v1PortworxVolumeSource'; +import type { V1ProjectedVolumeSource } from './v1ProjectedVolumeSource'; +import type { V1QuobyteVolumeSource } from './v1QuobyteVolumeSource'; +import type { V1RBDVolumeSource } from './v1RBDVolumeSource'; +import type { V1ScaleIOVolumeSource } from './v1ScaleIOVolumeSource'; +import type { V1SecretVolumeSource } from './v1SecretVolumeSource'; +import type { V1StorageOSVolumeSource } from './v1StorageOSVolumeSource'; +import type { V1VsphereVirtualDiskVolumeSource } from './v1VsphereVirtualDiskVolumeSource'; + +export interface V1Volume { + /** awsElasticBlockStore represents an AWS Disk resource that is attached to a +kubelet's host machine and then exposed to the pod. +Deprecated: AWSElasticBlockStore is deprecated. All operations for the in-tree +awsElasticBlockStore type are redirected to the ebs.csi.aws.com CSI driver. +More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore ++optional */ + awsElasticBlockStore?: V1AWSElasticBlockStoreVolumeSource; + /** azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. +Deprecated: AzureDisk is deprecated. All operations for the in-tree azureDisk type +are redirected to the disk.csi.azure.com CSI driver. ++optional */ + azureDisk?: V1AzureDiskVolumeSource; + /** azureFile represents an Azure File Service mount on the host and bind mount to the pod. +Deprecated: AzureFile is deprecated. All operations for the in-tree azureFile type +are redirected to the file.csi.azure.com CSI driver. ++optional */ + azureFile?: V1AzureFileVolumeSource; + /** cephFS represents a Ceph FS mount on the host that shares a pod's lifetime. +Deprecated: CephFS is deprecated and the in-tree cephfs type is no longer supported. ++optional */ + cephfs?: V1CephFSVolumeSource; + /** cinder represents a cinder volume attached and mounted on kubelets host machine. +Deprecated: Cinder is deprecated. All operations for the in-tree cinder type +are redirected to the cinder.csi.openstack.org CSI driver. +More info: https://examples.k8s.io/mysql-cinder-pd/README.md ++optional */ + cinder?: V1CinderVolumeSource; + /** configMap represents a configMap that should populate this volume ++optional */ + configMap?: V1ConfigMapVolumeSource; + /** csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers. ++optional */ + csi?: V1CSIVolumeSource; + /** downwardAPI represents downward API about the pod that should populate this volume ++optional */ + downwardAPI?: V1DownwardAPIVolumeSource; + /** emptyDir represents a temporary directory that shares a pod's lifetime. +More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir ++optional */ + emptyDir?: V1EmptyDirVolumeSource; + /** ephemeral represents a volume that is handled by a cluster storage driver. +The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, +and deleted when the pod is removed. + +Use this if: +a) the volume is only needed while the pod runs, +b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, +c) the storage driver is specified through a storage class, and +d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + +Use PersistentVolumeClaim or one of the vendor-specific +APIs for volumes that persist for longer than the lifecycle +of an individual pod. + +Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to +be used that way - see the documentation of the driver for +more information. + +A pod can use both types of ephemeral volumes and +persistent volumes at the same time. + ++optional */ + ephemeral?: V1EphemeralVolumeSource; + /** fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. ++optional */ + fc?: V1FCVolumeSource; + /** flexVolume represents a generic volume resource that is +provisioned/attached using an exec based plugin. +Deprecated: FlexVolume is deprecated. Consider using a CSIDriver instead. ++optional */ + flexVolume?: V1FlexVolumeSource; + /** flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running. +Deprecated: Flocker is deprecated and the in-tree flocker type is no longer supported. ++optional */ + flocker?: V1FlockerVolumeSource; + /** gcePersistentDisk represents a GCE Disk resource that is attached to a +kubelet's host machine and then exposed to the pod. +Deprecated: GCEPersistentDisk is deprecated. All operations for the in-tree +gcePersistentDisk type are redirected to the pd.csi.storage.gke.io CSI driver. +More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk ++optional */ + gcePersistentDisk?: V1GCEPersistentDiskVolumeSource; + /** gitRepo represents a git repository at a particular revision. +Deprecated: GitRepo is deprecated. To provision a container with a git repo, mount an +EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir +into the Pod's container. ++optional */ + gitRepo?: V1GitRepoVolumeSource; + /** glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. +Deprecated: Glusterfs is deprecated and the in-tree glusterfs type is no longer supported. ++optional */ + glusterfs?: V1GlusterfsVolumeSource; + /** hostPath represents a pre-existing file or directory on the host +machine that is directly exposed to the container. This is generally +used for system agents or other privileged things that are allowed +to see the host machine. Most containers will NOT need this. +More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath +--- +TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not +mount host directories as read/write. ++optional */ + hostPath?: V1HostPathVolumeSource; + /** image represents an OCI object (a container image or artifact) pulled and mounted on the kubelet's host machine. +The volume is resolved at pod startup depending on which PullPolicy value is provided: + +- Always: the kubelet always attempts to pull the reference. Container creation will fail If the pull fails. +- Never: the kubelet never pulls the reference and only uses a local image or artifact. Container creation will fail if the reference isn't present. +- IfNotPresent: the kubelet pulls if the reference isn't already present on disk. Container creation will fail if the reference isn't present and the pull fails. + +The volume gets re-resolved if the pod gets deleted and recreated, which means that new remote content will become available on pod recreation. +A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. +The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. +The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. +The volume will be mounted read-only (ro) and non-executable files (noexec). +Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. +The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. ++featureGate=ImageVolume ++optional */ + image?: V1ImageVolumeSource; + /** iscsi represents an ISCSI Disk resource that is attached to a +kubelet's host machine and then exposed to the pod. +More info: https://kubernetes.io/docs/concepts/storage/volumes/#iscsi ++optional */ + iscsi?: V1ISCSIVolumeSource; + /** name of the volume. +Must be a DNS_LABEL and unique within the pod. +More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names */ + name?: string; + /** nfs represents an NFS mount on the host that shares a pod's lifetime +More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs ++optional */ + nfs?: V1NFSVolumeSource; + /** persistentVolumeClaimVolumeSource represents a reference to a +PersistentVolumeClaim in the same namespace. +More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims ++optional */ + persistentVolumeClaim?: V1PersistentVolumeClaimVolumeSource; + /** photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine. +Deprecated: PhotonPersistentDisk is deprecated and the in-tree photonPersistentDisk type is no longer supported. */ + photonPersistentDisk?: V1PhotonPersistentDiskVolumeSource; + /** portworxVolume represents a portworx volume attached and mounted on kubelets host machine. +Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type +are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate +is on. ++optional */ + portworxVolume?: V1PortworxVolumeSource; + /** projected items for all in one resources secrets, configmaps, and downward API */ + projected?: V1ProjectedVolumeSource; + /** quobyte represents a Quobyte mount on the host that shares a pod's lifetime. +Deprecated: Quobyte is deprecated and the in-tree quobyte type is no longer supported. ++optional */ + quobyte?: V1QuobyteVolumeSource; + /** rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. +Deprecated: RBD is deprecated and the in-tree rbd type is no longer supported. ++optional */ + rbd?: V1RBDVolumeSource; + /** scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. +Deprecated: ScaleIO is deprecated and the in-tree scaleIO type is no longer supported. ++optional */ + scaleIO?: V1ScaleIOVolumeSource; + /** secret represents a secret that should populate this volume. +More info: https://kubernetes.io/docs/concepts/storage/volumes#secret ++optional */ + secret?: V1SecretVolumeSource; + /** storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. +Deprecated: StorageOS is deprecated and the in-tree storageos type is no longer supported. ++optional */ + storageos?: V1StorageOSVolumeSource; + /** vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine. +Deprecated: VsphereVolume is deprecated. All operations for the in-tree vsphereVolume type +are redirected to the csi.vsphere.vmware.com CSI driver. ++optional */ + vsphereVolume?: V1VsphereVirtualDiskVolumeSource; +} diff --git a/ui/src/gen/api/v2/models/v1VolumeDevice.ts b/ui/src/gen/api/v2/models/v1VolumeDevice.ts new file mode 100644 index 0000000000..6df2dded17 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1VolumeDevice.ts @@ -0,0 +1,14 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1VolumeDevice { + /** devicePath is the path inside of the container that the device will be mapped to. */ + devicePath?: string; + /** name must match the name of a persistentVolumeClaim in the pod */ + name?: string; +} diff --git a/ui/src/gen/api/v2/models/v1VolumeMount.ts b/ui/src/gen/api/v2/models/v1VolumeMount.ts new file mode 100644 index 0000000000..538eb046d8 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1VolumeMount.ts @@ -0,0 +1,57 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1VolumeMount { + /** Path within the container at which the volume should be mounted. Must +not contain ':'. */ + mountPath?: string; + /** mountPropagation determines how mounts are propagated from the host +to container and the other way around. +When not set, MountPropagationNone is used. +This field is beta in 1.10. +When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified +(which defaults to None). ++optional */ + mountPropagation?: string; + /** This must match the Name of a Volume. */ + name?: string; + /** Mounted read-only if true, read-write otherwise (false or unspecified). +Defaults to false. ++optional */ + readOnly?: boolean; + /** RecursiveReadOnly specifies whether read-only mounts should be handled +recursively. + +If ReadOnly is false, this field has no meaning and must be unspecified. + +If ReadOnly is true, and this field is set to Disabled, the mount is not made +recursively read-only. If this field is set to IfPossible, the mount is made +recursively read-only, if it is supported by the container runtime. If this +field is set to Enabled, the mount is made recursively read-only if it is +supported by the container runtime, otherwise the pod will not be started and +an error will be generated to indicate the reason. + +If this field is set to IfPossible or Enabled, MountPropagation must be set to +None (or be unspecified, which defaults to None). + +If this field is not specified, it is treated as an equivalent of Disabled. + ++featureGate=RecursiveReadOnlyMounts ++optional */ + recursiveReadOnly?: string; + /** Path within the volume from which the container's volume should be mounted. +Defaults to "" (volume's root). ++optional */ + subPath?: string; + /** Expanded path within the volume from which the container's volume should be mounted. +Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. +Defaults to "" (volume's root). +SubPathExpr and SubPath are mutually exclusive. ++optional */ + subPathExpr?: string; +} diff --git a/ui/src/gen/api/v2/models/v1VolumeProjection.ts b/ui/src/gen/api/v2/models/v1VolumeProjection.ts new file mode 100644 index 0000000000..20b330e302 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1VolumeProjection.ts @@ -0,0 +1,82 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ClusterTrustBundleProjection } from './v1ClusterTrustBundleProjection'; +import type { V1ConfigMapProjection } from './v1ConfigMapProjection'; +import type { V1DownwardAPIProjection } from './v1DownwardAPIProjection'; +import type { V1PodCertificateProjection } from './v1PodCertificateProjection'; +import type { V1SecretProjection } from './v1SecretProjection'; +import type { V1ServiceAccountTokenProjection } from './v1ServiceAccountTokenProjection'; + +export interface V1VolumeProjection { + /** ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field +of ClusterTrustBundle objects in an auto-updating file. + +Alpha, gated by the ClusterTrustBundleProjection feature gate. + +ClusterTrustBundle objects can either be selected by name, or by the +combination of signer name and a label selector. + +Kubelet performs aggressive normalization of the PEM contents written +into the pod filesystem. Esoteric PEM features such as inter-block +comments and block headers are stripped. Certificates are deduplicated. +The ordering of certificates within the file is arbitrary, and Kubelet +may change the order over time. + ++featureGate=ClusterTrustBundleProjection ++optional */ + clusterTrustBundle?: V1ClusterTrustBundleProjection; + /** configMap information about the configMap data to project ++optional */ + configMap?: V1ConfigMapProjection; + /** downwardAPI information about the downwardAPI data to project ++optional */ + downwardAPI?: V1DownwardAPIProjection; + /** Projects an auto-rotating credential bundle (private key and certificate +chain) that the pod can use either as a TLS client or server. + +Kubelet generates a private key and uses it to send a +PodCertificateRequest to the named signer. Once the signer approves the +request and issues a certificate chain, Kubelet writes the key and +certificate chain to the pod filesystem. The pod does not start until +certificates have been issued for each podCertificate projected volume +source in its spec. + +Kubelet will begin trying to rotate the certificate at the time indicated +by the signer using the PodCertificateRequest.Status.BeginRefreshAt +timestamp. + +Kubelet can write a single file, indicated by the credentialBundlePath +field, or separate files, indicated by the keyPath and +certificateChainPath fields. + +The credential bundle is a single file in PEM format. The first PEM +entry is the private key (in PKCS#8 format), and the remaining PEM +entries are the certificate chain issued by the signer (typically, +signers will return their certificate chain in leaf-to-root order). + +Prefer using the credential bundle format, since your application code +can read it atomically. If you use keyPath and certificateChainPath, +your application must make two separate file reads. If these coincide +with a certificate rotation, it is possible that the private key and leaf +certificate you read may not correspond to each other. Your application +will need to check for this condition, and re-read until they are +consistent. + +The named signer controls chooses the format of the certificate it +issues; consult the signer implementation's documentation to learn how to +use the certificates it issues. + ++featureGate=PodCertificateProjection +optional */ + podCertificate?: V1PodCertificateProjection; + /** secret information about the secret data to project ++optional */ + secret?: V1SecretProjection; + /** serviceAccountToken is information about the serviceAccountToken data to project ++optional */ + serviceAccountToken?: V1ServiceAccountTokenProjection; +} diff --git a/ui/src/gen/api/v2/models/v1VolumeResourceRequirements.ts b/ui/src/gen/api/v2/models/v1VolumeResourceRequirements.ts new file mode 100644 index 0000000000..8d73f0c5ef --- /dev/null +++ b/ui/src/gen/api/v2/models/v1VolumeResourceRequirements.ts @@ -0,0 +1,21 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ResourceList } from './v1ResourceList'; + +export interface V1VolumeResourceRequirements { + /** Limits describes the maximum amount of compute resources allowed. +More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ ++optional */ + limits?: V1ResourceList; + /** Requests describes the minimum amount of compute resources required. +If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, +otherwise to an implementation-defined value. Requests cannot exceed Limits. +More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ ++optional */ + requests?: V1ResourceList; +} diff --git a/ui/src/gen/api/v2/models/v1VsphereVirtualDiskVolumeSource.ts b/ui/src/gen/api/v2/models/v1VsphereVirtualDiskVolumeSource.ts new file mode 100644 index 0000000000..2f63aaefb9 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1VsphereVirtualDiskVolumeSource.ts @@ -0,0 +1,23 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1VsphereVirtualDiskVolumeSource { + /** fsType is filesystem type to mount. +Must be a filesystem type supported by the host operating system. +Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. ++optional */ + fsType?: string; + /** storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. ++optional */ + storagePolicyID?: string; + /** storagePolicyName is the storage Policy Based Management (SPBM) profile name. ++optional */ + storagePolicyName?: string; + /** volumePath is the path that identifies vSphere volume vmdk */ + volumePath?: string; +} diff --git a/ui/src/gen/api/v2/models/v1WeightedPodAffinityTerm.ts b/ui/src/gen/api/v2/models/v1WeightedPodAffinityTerm.ts new file mode 100644 index 0000000000..53773dfb65 --- /dev/null +++ b/ui/src/gen/api/v2/models/v1WeightedPodAffinityTerm.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1PodAffinityTerm } from './v1PodAffinityTerm'; + +export interface V1WeightedPodAffinityTerm { + /** Required. A pod affinity term, associated with the corresponding weight. */ + podAffinityTerm?: V1PodAffinityTerm; + /** weight associated with matching the corresponding podAffinityTerm, +in the range 1-100. */ + weight?: number; +} diff --git a/ui/src/gen/api/v2/models/v1WindowsSecurityContextOptions.ts b/ui/src/gen/api/v2/models/v1WindowsSecurityContextOptions.ts new file mode 100644 index 0000000000..a2a778b93a --- /dev/null +++ b/ui/src/gen/api/v2/models/v1WindowsSecurityContextOptions.ts @@ -0,0 +1,30 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface V1WindowsSecurityContextOptions { + /** GMSACredentialSpec is where the GMSA admission webhook +(https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the +GMSA credential spec named by the GMSACredentialSpecName field. ++optional */ + gmsaCredentialSpec?: string; + /** GMSACredentialSpecName is the name of the GMSA credential spec to use. ++optional */ + gmsaCredentialSpecName?: string; + /** HostProcess determines if a container should be run as a 'Host Process' container. +All of a Pod's containers must have the same effective HostProcess value +(it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). +In addition, if HostProcess is true then HostNetwork must also be set to true. ++optional */ + hostProcess?: boolean; + /** The UserName in Windows to run the entrypoint of the container process. +Defaults to the user specified in image metadata if unspecified. +May also be set in PodSecurityContext. If set in both SecurityContext and +PodSecurityContext, the value specified in SecurityContext takes precedence. ++optional */ + runAsUserName?: string; +} diff --git a/ui/src/gen/api/v2/models/verification.ts b/ui/src/gen/api/v2/models/verification.ts new file mode 100644 index 0000000000..c88713fbdc --- /dev/null +++ b/ui/src/gen/api/v2/models/verification.ts @@ -0,0 +1,22 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { AnalysisRunMetadata } from './analysisRunMetadata'; +import type { AnalysisTemplateReference } from './analysisTemplateReference'; +import type { AnalysisRunArgument } from './analysisRunArgument'; + +export interface Verification { + /** AnalysisRunMetadata contains optional metadata that should be applied to +all AnalysisRuns. */ + analysisRunMetadata?: AnalysisRunMetadata; + /** AnalysisTemplates is a list of AnalysisTemplates from which AnalysisRuns +should be created to verify a Stage's current Freight is fit to be promoted +downstream. */ + analysisTemplates?: AnalysisTemplateReference[]; + /** Args lists arguments that should be added to all AnalysisRuns. */ + args?: AnalysisRunArgument[]; +} diff --git a/ui/src/gen/api/v2/models/verificationInfo.ts b/ui/src/gen/api/v2/models/verificationInfo.ts new file mode 100644 index 0000000000..e011f3a7ce --- /dev/null +++ b/ui/src/gen/api/v2/models/verificationInfo.ts @@ -0,0 +1,31 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { AnalysisRunReference } from './analysisRunReference'; + +export interface VerificationInfo { + /** Actor is the name of the entity that initiated or aborted the +Verification process. */ + actor?: string; + /** AnalysisRun is a reference to the Argo Rollouts AnalysisRun that implements +the Verification process. */ + analysisRun?: AnalysisRunReference; + /** FinishTime is the time at which the Verification process finished. */ + finishTime?: string; + /** ID is the identifier of the Verification process. */ + id?: string; + /** Message may contain additional information about why the verification +process is in its current phase. */ + message?: string; + /** Phase describes the current phase of the Verification process. Generally, +this will be a reflection of the underlying AnalysisRun's phase, however, +there are exceptions to this, such as in the case where an AnalysisRun +cannot be launched successfully. */ + phase?: string; + /** StartTime is the time at which the Verification process was started. */ + startTime?: string; +} diff --git a/ui/src/gen/api/v2/models/verifiedStage.ts b/ui/src/gen/api/v2/models/verifiedStage.ts new file mode 100644 index 0000000000..20b7e8a3eb --- /dev/null +++ b/ui/src/gen/api/v2/models/verifiedStage.ts @@ -0,0 +1,18 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface VerifiedStage { + /** LongestCompletedSoak represents the longest definite time interval wherein +the Freight was in CONTINUOUS use by the Stage. This value is updated as +Freight EXITS the Stage. If the Freight is currently in use by the Stage, +the time elapsed since the Freight ENTERED the Stage is its current soak +time, which may exceed the value of this field. */ + longestSoak?: string; + /** VerifiedAt is the time at which the Freight was verified in the Stage. */ + verifiedAt?: string; +} diff --git a/ui/src/gen/api/v2/models/warehouse.ts b/ui/src/gen/api/v2/models/warehouse.ts new file mode 100644 index 0000000000..3fa1d008ac --- /dev/null +++ b/ui/src/gen/api/v2/models/warehouse.ts @@ -0,0 +1,33 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1ObjectMeta } from './v1ObjectMeta'; +import type { WarehouseSpec } from './warehouseSpec'; +import type { WarehouseStatus } from './warehouseStatus'; + +export interface Warehouse { + /** 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 ++optional */ + apiVersion?: string; + /** 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 ++optional */ + kind?: string; + metadata?: V1ObjectMeta; + /** Spec describes sources of artifacts. + ++kubebuilder:validation:Required */ + spec: WarehouseSpec; + /** Status describes the Warehouse's most recently observed state. */ + status?: WarehouseStatus; +} diff --git a/ui/src/gen/api/v2/models/warehouseList.ts b/ui/src/gen/api/v2/models/warehouseList.ts new file mode 100644 index 0000000000..e34ba484c0 --- /dev/null +++ b/ui/src/gen/api/v2/models/warehouseList.ts @@ -0,0 +1,27 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { Warehouse } from './warehouse'; +import type { V1ListMeta } from './v1ListMeta'; + +export interface WarehouseList { + /** 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 ++optional */ + apiVersion?: string; + items?: Warehouse[]; + /** 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 ++optional */ + kind?: string; + metadata?: V1ListMeta; +} diff --git a/ui/src/gen/api/v2/models/warehouseSpec.ts b/ui/src/gen/api/v2/models/warehouseSpec.ts new file mode 100644 index 0000000000..4d7b909547 --- /dev/null +++ b/ui/src/gen/api/v2/models/warehouseSpec.ts @@ -0,0 +1,55 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { FreightCreationCriteria } from './freightCreationCriteria'; +import type { WarehouseSpecSubscriptionsItem } from './warehouseSpecSubscriptionsItem'; + +export interface WarehouseSpec { + /** FreightCreationCriteria defines criteria that must be satisfied for Freight +to be created automatically from new artifacts following discovery. This +field has no effect when the FreightCreationPolicy is `Manual`. + ++kubebuilder:validation:Optional */ + freightCreationCriteria?: FreightCreationCriteria; + /** FreightCreationPolicy describes how Freight is created by this Warehouse. +This field is optional. When left unspecified, the field is implicitly +treated as if its value were "Automatic". + +Accepted values: + +- "Automatic": New Freight is created automatically when any new artifact + is discovered. +- "Manual": New Freight is never created automatically. + ++kubebuilder:default=Automatic ++kubebuilder:validation:Optional */ + freightCreationPolicy?: string; + /** Interval is the reconciliation interval for this Warehouse. On each +reconciliation, the Warehouse will discover new artifacts and optionally +produce new Freight. This field is optional. When left unspecified, the +field is implicitly treated as if its value were "5m0s". + ++kubebuilder:validation:Type=string ++kubebuilder:validation:Pattern=`^([0-9]+(\.[0-9]+)?(s|m|h))+$` ++kubebuilder:default="5m0s" ++akuity:test-kubebuilder-pattern=Duration */ + interval?: string; + /** Shard is the name of the shard that this Warehouse belongs to. This is an +optional field. If not specified, the Warehouse will belong to the default +shard. A defaulting webhook will sync this field with the value of the +kargo.akuity.io/shard label. When the shard label is not present or differs +from the value of this field, the defaulting webhook will set the label to +the value of this field. If the shard label is present and this field is +empty, the defaulting webhook will set the value of this field to the value +of the shard label. */ + shard?: string; + /** Subscriptions describes sources of artifacts to be included in Freight +produced by this Warehouse. + ++kubebuilder:validation:MinItems=1 */ + subscriptions?: WarehouseSpecSubscriptionsItem[]; +} diff --git a/ui/src/gen/api/v2/models/createSharedRepoCredentials201.ts b/ui/src/gen/api/v2/models/warehouseSpecSubscriptionsItem.ts similarity index 69% rename from ui/src/gen/api/v2/models/createSharedRepoCredentials201.ts rename to ui/src/gen/api/v2/models/warehouseSpecSubscriptionsItem.ts index 2aaac5b0b8..56b052926d 100644 --- a/ui/src/gen/api/v2/models/createSharedRepoCredentials201.ts +++ b/ui/src/gen/api/v2/models/warehouseSpecSubscriptionsItem.ts @@ -6,4 +6,4 @@ * OpenAPI spec version: v1alpha1 */ -export type CreateSharedRepoCredentials201 = { [key: string]: unknown }; +export type WarehouseSpecSubscriptionsItem = { [key: string]: unknown }; diff --git a/ui/src/gen/api/v2/models/warehouseStats.ts b/ui/src/gen/api/v2/models/warehouseStats.ts new file mode 100644 index 0000000000..dc4afa9680 --- /dev/null +++ b/ui/src/gen/api/v2/models/warehouseStats.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { HealthStats } from './healthStats'; + +export interface WarehouseStats { + /** Count contains the total number of Warehouses in the Project. */ + count?: number; + /** Health contains a summary of the collective health of a Project's +Warehouses. */ + health?: HealthStats; +} diff --git a/ui/src/gen/api/v2/models/warehouseStatus.ts b/ui/src/gen/api/v2/models/warehouseStatus.ts new file mode 100644 index 0000000000..f5d4171bc2 --- /dev/null +++ b/ui/src/gen/api/v2/models/warehouseStatus.ts @@ -0,0 +1,32 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { V1Condition } from './v1Condition'; +import type { DiscoveredArtifacts } from './discoveredArtifacts'; + +export interface WarehouseStatus { + /** Conditions contains the last observations of the Warehouse's current +state. ++patchMergeKey=type ++patchStrategy=merge ++listType=map ++listMapKey=type */ + conditions?: V1Condition[]; + /** DiscoveredArtifacts holds the artifacts discovered by the Warehouse. */ + discoveredArtifacts?: DiscoveredArtifacts; + /** LastFreightID is a reference to the system-assigned identifier (name) of +the most recent Freight produced by the Warehouse. */ + lastFreightID?: string; + /** LastHandledRefresh holds the value of the most recent AnnotationKeyRefresh +annotation that was handled by the controller. This field can be used to +determine whether the request to refresh the resource has been handled. ++optional */ + lastHandledRefresh?: string; + /** ObservedGeneration represents the .metadata.generation that this Warehouse +was reconciled against. */ + observedGeneration?: number; +} diff --git a/ui/src/gen/api/v2/models/webhookReceiverConfig.ts b/ui/src/gen/api/v2/models/webhookReceiverConfig.ts new file mode 100644 index 0000000000..f0392ae217 --- /dev/null +++ b/ui/src/gen/api/v2/models/webhookReceiverConfig.ts @@ -0,0 +1,57 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ +import type { ArtifactoryWebhookReceiverConfig } from './artifactoryWebhookReceiverConfig'; +import type { AzureWebhookReceiverConfig } from './azureWebhookReceiverConfig'; +import type { BitbucketWebhookReceiverConfig } from './bitbucketWebhookReceiverConfig'; +import type { DockerHubWebhookReceiverConfig } from './dockerHubWebhookReceiverConfig'; +import type { GenericWebhookReceiverConfig } from './genericWebhookReceiverConfig'; +import type { GiteaWebhookReceiverConfig } from './giteaWebhookReceiverConfig'; +import type { GitHubWebhookReceiverConfig } from './gitHubWebhookReceiverConfig'; +import type { GitLabWebhookReceiverConfig } from './gitLabWebhookReceiverConfig'; +import type { HarborWebhookReceiverConfig } from './harborWebhookReceiverConfig'; +import type { QuayWebhookReceiverConfig } from './quayWebhookReceiverConfig'; + +export interface WebhookReceiverConfig { + /** Artifactory contains the configuration for a webhook receiver that is +compatible with JFrog Artifactory payloads. */ + artifactory?: ArtifactoryWebhookReceiverConfig; + /** Azure contains the configuration for a webhook receiver that is compatible +with Azure Container Registry (ACR) and Azure DevOps payloads. */ + azure?: AzureWebhookReceiverConfig; + /** Bitbucket contains the configuration for a webhook receiver that is +compatible with Bitbucket payloads. */ + bitbucket?: BitbucketWebhookReceiverConfig; + /** DockerHub contains the configuration for a webhook receiver that is +compatible with DockerHub payloads. */ + dockerhub?: DockerHubWebhookReceiverConfig; + /** Generic contains the configuration for a generic webhook receiver. */ + generic?: GenericWebhookReceiverConfig; + /** Gitea contains the configuration for a webhook receiver that is compatible +with Gitea payloads. */ + gitea?: GiteaWebhookReceiverConfig; + /** GitHub contains the configuration for a webhook receiver that is compatible +with GitHub payloads. */ + github?: GitHubWebhookReceiverConfig; + /** GitLab contains the configuration for a webhook receiver that is compatible +with GitLab payloads. */ + gitlab?: GitLabWebhookReceiverConfig; + /** Harbor contains the configuration for a webhook receiver that is compatible +with Harbor payloads. */ + harbor?: HarborWebhookReceiverConfig; + /** Name is the name of the webhook receiver. + ++kubebuilder:validation:Required ++kubebuilder:validation:MinLength=1 ++kubebuilder:validation:MaxLength=253 ++kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` ++akuity:test-kubebuilder-pattern=KubernetesName */ + name: string; + /** Quay contains the configuration for a webhook receiver that is compatible +with Quay payloads. */ + quay?: QuayWebhookReceiverConfig; +} diff --git a/ui/src/gen/api/v2/models/webhookReceiverDetails.ts b/ui/src/gen/api/v2/models/webhookReceiverDetails.ts new file mode 100644 index 0000000000..475b78e3cc --- /dev/null +++ b/ui/src/gen/api/v2/models/webhookReceiverDetails.ts @@ -0,0 +1,16 @@ +/** + * Generated by orval v7.19.0 🍺 + * Do not edit manually. + * Kargo API + * REST API for Kargo + * OpenAPI spec version: v1alpha1 + */ + +export interface WebhookReceiverDetails { + /** Name is the name of the webhook receiver. */ + name?: string; + /** Path is the path to the receiver's webhook endpoint. */ + path?: string; + /** URL includes the full address of the receiver's webhook endpoint. */ + url?: string; +} diff --git a/ui/src/gen/api/v2/rbac/rbac.ts b/ui/src/gen/api/v2/rbac/rbac.ts index d665a6b858..449bf133a7 100644 --- a/ui/src/gen/api/v2/rbac/rbac.ts +++ b/ui/src/gen/api/v2/rbac/rbac.ts @@ -23,25 +23,18 @@ import type { import type { CreateAPITokenRequestBody, - CreateProjectAPIToken201, - CreateProjectRole201, CreateProjectRoleBodyBody, - CreateSystemAPIToken201, - GetProjectAPIToken200, GetProjectRole200, - GetSystemAPIToken200, GetSystemRole200, - Grant200, GrantRequest, - ListProjectAPITokens200, ListProjectAPITokensParams, ListProjectRoles200, - ListSystemAPITokens200, ListSystemAPITokensParams, ListSystemRoles200, - Revoke200, + RbacRole, RevokeRequest, - UpdateRole200 + V1Secret, + V1SecretList } from '.././models'; import { customFetch } from '../../../../lib/api/custom-fetch'; @@ -54,7 +47,7 @@ resource containing heavily redacted Secrets. * @summary List project-level API tokens */ export type listProjectAPITokensResponse200 = { - data: ListProjectAPITokens200; + data: V1SecretList; status: 200; }; @@ -225,7 +218,7 @@ redacted Kubernetes Secret resource. * @summary Retrieve a project-level API token */ export type getProjectAPITokenResponse200 = { - data: GetProjectAPIToken200; + data: V1Secret; status: 200; }; @@ -607,7 +600,7 @@ resources. * @summary Create a project-level Kargo Role virtual resource */ export type createProjectRoleResponse201 = { - data: CreateProjectRole201; + data: RbacRole; status: 201; }; @@ -705,7 +698,7 @@ to a project-level Kargo Role. * @summary Grant permissions */ export type grantResponse200 = { - data: Grant200; + data: RbacRole; status: 200; }; @@ -798,7 +791,7 @@ permissions from a project-level Kargo Role. * @summary Revoke permissions */ export type revokeResponse200 = { - data: Revoke200; + data: RbacRole; status: 200; }; @@ -1034,7 +1027,7 @@ resources. * @summary Update a project-level Kargo Role virtual resource */ export type updateRoleResponse200 = { - data: UpdateRole200; + data: RbacRole; status: 200; }; @@ -1228,7 +1221,7 @@ redacted form. * @summary Create a project-level API token */ export type createProjectAPITokenResponse201 = { - data: CreateProjectAPIToken201; + data: V1Secret; status: 201; }; @@ -1327,7 +1320,7 @@ resource containing heavily redacted Secrets. * @summary List system-level API tokens */ export type listSystemAPITokensResponse200 = { - data: ListSystemAPITokens200; + data: V1SecretList; status: 200; }; @@ -1486,7 +1479,7 @@ redacted Kubernetes Secret resource. * @summary Retrieve a system-level API token */ export type getSystemAPITokenResponse200 = { - data: GetSystemAPIToken200; + data: V1Secret; status: 200; }; @@ -1981,7 +1974,7 @@ a redacted form. * @summary Create a system-level API token */ export type createSystemAPITokenResponse201 = { - data: CreateSystemAPIToken201; + data: V1Secret; status: 201; }; diff --git a/ui/src/gen/api/v2/system/system.ts b/ui/src/gen/api/v2/system/system.ts index 49e7061019..e6acaf15a6 100644 --- a/ui/src/gen/api/v2/system/system.ts +++ b/ui/src/gen/api/v2/system/system.ts @@ -23,7 +23,7 @@ import type { import type { AdminLoginResponse, - GetClusterConfig200, + ClusterConfig, GetConfigResponse, PublicConfig, VersionInfo @@ -99,7 +99,7 @@ export const useAdminLogin = ( * @summary Retrieve the ClusterConfig */ export type getClusterConfigResponse200 = { - data: GetClusterConfig200; + data: ClusterConfig; status: 200; }; diff --git a/ui/src/gen/api/v2/verifications/verifications.ts b/ui/src/gen/api/v2/verifications/verifications.ts index f87b3a3ecc..63483e23b2 100644 --- a/ui/src/gen/api/v2/verifications/verifications.ts +++ b/ui/src/gen/api/v2/verifications/verifications.ts @@ -22,12 +22,12 @@ import type { } from '@tanstack/react-query'; import type { - GetAnalysisRun200, GetAnalysisRunLogsParams, - GetAnalysisTemplate200, - GetClusterAnalysisTemplate200, - ListAnalysisTemplates200, - ListClusterAnalysisTemplates200 + RolloutsAnalysisRun, + RolloutsAnalysisTemplate, + RolloutsAnalysisTemplateList, + RolloutsClusterAnalysisTemplate, + RolloutsClusterAnalysisTemplateList } from '.././models'; import { customFetch } from '../../../../lib/api/custom-fetch'; @@ -39,7 +39,7 @@ type SecondParameter unknown> = Parameters[1]; * @summary Retrieve an AnalysisRun */ export type getAnalysisRunResponse200 = { - data: GetAnalysisRun200; + data: RolloutsAnalysisRun; status: 200; }; @@ -362,7 +362,7 @@ export function useGetAnalysisRunLogs< * @summary List AnalysisTemplates */ export type listAnalysisTemplatesResponse200 = { - data: ListAnalysisTemplates200; + data: RolloutsAnalysisTemplateList; status: 200; }; @@ -509,7 +509,7 @@ namespace. * @summary Retrieve an AnalysisTemplate */ export type getAnalysisTemplateResponse200 = { - data: GetAnalysisTemplate200; + data: RolloutsAnalysisTemplate; status: 200; }; @@ -953,7 +953,7 @@ ClusterAnalysisTemplateList resource. * @summary List ClusterAnalysisTemplates */ export type listClusterAnalysisTemplatesResponse200 = { - data: ListClusterAnalysisTemplates200; + data: RolloutsClusterAnalysisTemplateList; status: 200; }; @@ -1092,7 +1092,7 @@ export function useListClusterAnalysisTemplates< * @summary Retrieve a ClusterAnalysisTemplate */ export type getClusterAnalysisTemplateResponse200 = { - data: GetClusterAnalysisTemplate200; + data: RolloutsClusterAnalysisTemplate; status: 200; }; diff --git a/ui/src/gen/directives/argocd-common.json b/ui/src/gen/directives/argocd-common.json new file mode 100644 index 0000000000..db400b36c9 --- /dev/null +++ b/ui/src/gen/directives/argocd-common.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ArgoCDCommonDefs", + "definitions": { + "argoCDAppSelector": { + "type": "object", + "description": "Selector to match Argo CD Application resources by labels. Must contain at least one selection criterion.", + "additionalProperties": false, + "properties": { + "matchLabels": { + "type": "object", + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is 'key', the operator is 'In', and the values array contains only 'value'. The requirements are ANDed.", + "additionalProperties": { + "type": "string" + } + }, + "matchExpressions": { + "type": "array", + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string", + "description": "key is the label key that the selector applies to.", + "minLength": 1 + }, + "operator": { + "type": "string", + "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", + "enum": [ + "In", + "NotIn", + "Exists", + "DoesNotExist" + ] + }, + "values": { + "type": "array", + "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", + "items": { + "type": "string" + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/ui/src/gen/directives/argocd-update-config.json b/ui/src/gen/directives/argocd-update-config.json index 3d5f5dbd63..679f6c912a 100644 --- a/ui/src/gen/directives/argocd-update-config.json +++ b/ui/src/gen/directives/argocd-update-config.json @@ -154,52 +154,6 @@ } } }, - "argoCDAppSelector": { - "type": "object", - "description": "Selector to match Argo CD Application resources by labels. Must contain at least one selection criterion.", - "additionalProperties": false, - "properties": { - "matchLabels": { - "type": "object", - "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is 'key', the operator is 'In', and the values array contains only 'value'. The requirements are ANDed.", - "additionalProperties": { - "type": "string" - } - }, - "matchExpressions": { - "type": "array", - "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", - "items": { - "type": "object", - "additionalProperties": false, - "properties": { - "key": { - "type": "string", - "description": "key is the label key that the selector applies to.", - "minLength": 1 - }, - "operator": { - "type": "string", - "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", - "enum": [ - "In", - "NotIn", - "Exists", - "DoesNotExist" - ] - }, - "values": { - "type": "array", - "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", - "items": { - "type": "string" - } - } - } - } - } - } - }, "argoCDAppSourceUpdate": { "type": "object", "additionalProperties": false, diff --git a/ui/src/gen/directives/argocd-wait-config.json b/ui/src/gen/directives/argocd-wait-config.json new file mode 100644 index 0000000000..8f6dd29730 --- /dev/null +++ b/ui/src/gen/directives/argocd-wait-config.json @@ -0,0 +1,167 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "ArgoCDWaitConfig", + "definitions": { + "argoCDAppWait": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Specifies the exact name of an Argo CD Application resource to wait for. Mutually exclusive with 'selector'.", + "minLength": 1 + }, + "namespace": { + "type": "string", + "description": "Specifies the namespace of the Argo CD Application. If left unspecified, the namespace will be the controller's configured default.", + "minLength": 1 + }, + "selector": { + "description": "Specifies a label selector to match Argo CD Application resources to wait for. Mutually exclusive with 'name'.", + "type": "object", + "additionalProperties": false, + "properties": { + "matchLabels": { + "type": "object", + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is 'key', the operator is 'In', and the values array contains only 'value'. The requirements are ANDed.", + "additionalProperties": { + "type": "string" + } + }, + "matchExpressions": { + "type": "array", + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string", + "description": "key is the label key that the selector applies to.", + "minLength": 1 + }, + "operator": { + "type": "string", + "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", + "enum": [ + "In", + "NotIn", + "Exists", + "DoesNotExist" + ] + }, + "values": { + "type": "array", + "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "waitFor": { + "type": "array", + "description": "Specifies the conditions to wait for. Valid values are 'health', 'sync', 'operation', 'suspended', and 'degraded'. Health-related conditions (health, suspended, degraded) are OR'd. All other conditions are AND'd. Defaults to ['health', 'sync', 'operation'] when omitted.", + "items": { + "type": "string", + "enum": [ + "health", + "sync", + "operation", + "suspended", + "degraded" + ] + }, + "uniqueItems": true + } + } + } + }, + "type": "object", + "additionalProperties": false, + "properties": { + "apps": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Specifies the exact name of an Argo CD Application resource to wait for. Mutually exclusive with 'selector'.", + "minLength": 1 + }, + "namespace": { + "type": "string", + "description": "Specifies the namespace of the Argo CD Application. If left unspecified, the namespace will be the controller's configured default.", + "minLength": 1 + }, + "selector": { + "description": "Specifies a label selector to match Argo CD Application resources to wait for. Mutually exclusive with 'name'.", + "type": "object", + "additionalProperties": false, + "properties": { + "matchLabels": { + "type": "object", + "description": "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is 'key', the operator is 'In', and the values array contains only 'value'. The requirements are ANDed.", + "additionalProperties": { + "type": "string" + } + }, + "matchExpressions": { + "type": "array", + "description": "matchExpressions is a list of label selector requirements. The requirements are ANDed.", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string", + "description": "key is the label key that the selector applies to.", + "minLength": 1 + }, + "operator": { + "type": "string", + "description": "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", + "enum": [ + "In", + "NotIn", + "Exists", + "DoesNotExist" + ] + }, + "values": { + "type": "array", + "description": "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "waitFor": { + "type": "array", + "description": "Specifies the conditions to wait for. Valid values are 'health', 'sync', 'operation', 'suspended', and 'degraded'. Health-related conditions (health, suspended, degraded) are OR'd. All other conditions are AND'd. Defaults to ['health', 'sync', 'operation'] when omitted.", + "items": { + "type": "string", + "enum": [ + "health", + "sync", + "operation", + "suspended", + "degraded" + ] + }, + "uniqueItems": true + } + } + } + } + } +} \ No newline at end of file diff --git a/ui/src/gen/directives/git-clone-config.json b/ui/src/gen/directives/git-clone-config.json index 077d8bc752..6159217eba 100644 --- a/ui/src/gen/directives/git-clone-config.json +++ b/ui/src/gen/directives/git-clone-config.json @@ -14,7 +14,7 @@ }, "repoURL": { "type": "string", - "description": "The URL of a remote Git repository to clone. Required.", + "description": "The URL of a remote Git repository to clone. Required. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1 }, "author": { diff --git a/ui/src/gen/directives/git-merge-pr-config.json b/ui/src/gen/directives/git-merge-pr-config.json index e77a746d25..d5d7895a31 100644 --- a/ui/src/gen/directives/git-merge-pr-config.json +++ b/ui/src/gen/directives/git-merge-pr-config.json @@ -6,7 +6,7 @@ "properties": { "repoURL": { "type": "string", - "description": "The URL of the remote Git repository containing the pull request.", + "description": "The URL of the remote Git repository containing the pull request. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1, "format": "uri" }, @@ -33,6 +33,11 @@ "wait": { "type": "boolean", "description": "If true, the step will return RUNNING instead of FAILED when the PR is not yet mergeable. The merge will be retried on the next reconciliation until it succeeds or times out. Default is false." + }, + "mergeMethod": { + "type": "string", + "description": "The merge method to use when merging the pull request. Options are provider-specific.", + "minLength": 1 } } } \ No newline at end of file diff --git a/ui/src/gen/directives/git-open-pr-config.json b/ui/src/gen/directives/git-open-pr-config.json index 0abda5ad36..daf8259b3c 100644 --- a/ui/src/gen/directives/git-open-pr-config.json +++ b/ui/src/gen/directives/git-open-pr-config.json @@ -25,7 +25,7 @@ }, "repoURL": { "type": "string", - "description": "The URL of a remote Git repository to clone.", + "description": "The URL of a remote Git repository to clone. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1, "format": "uri" }, diff --git a/ui/src/gen/directives/git-wait-for-pr-config.json b/ui/src/gen/directives/git-wait-for-pr-config.json index bbdeabcc1e..0b252aadf2 100644 --- a/ui/src/gen/directives/git-wait-for-pr-config.json +++ b/ui/src/gen/directives/git-wait-for-pr-config.json @@ -26,7 +26,7 @@ }, "repoURL": { "type": "string", - "description": "The URL of a remote Git repository to clone.", + "description": "The URL of a remote Git repository to clone. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead.", "minLength": 1, "format": "uri" } diff --git a/ui/src/gen/directives/oci-push-config.json b/ui/src/gen/directives/oci-push-config.json new file mode 100644 index 0000000000..12f9b0b126 --- /dev/null +++ b/ui/src/gen/directives/oci-push-config.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "OCIPushConfig", + "type": "object", + "additionalProperties": false, + "properties": { + "srcRef": { + "type": "string", + "description": "SrcRef is the source OCI artifact reference with tag or digest (e.g. 'registry/repo:tag' or 'registry/repo@sha256:...'). Use 'oci://' prefix for Helm charts.", + "minLength": 1, + "pattern": "^(oci://)?[a-zA-Z0-9._-]+(:\\d+)?(/[a-zA-Z0-9._-]+)*[@:][a-zA-Z0-9._:-]+$" + }, + "destRef": { + "type": "string", + "description": "DestRef is the destination reference including tag (e.g. 'registry/repo:tag' or 'oci://registry/repo:tag'). For retag-in-place, use the same repo as srcRef with the new tag.", + "minLength": 1, + "pattern": "^(oci://)?[a-zA-Z0-9._-]+(:\\d+)?(/[a-zA-Z0-9._-]+)*[:][a-zA-Z0-9._-]+$" + }, + "annotations": { + "type": "object", + "description": "Annotations to set on the destination artifact. Keys may be prefixed with 'index:' or 'manifest:' to scope them to the index or image manifest respectively. Unprefixed keys default to the image manifest. For single images, 'index:'-prefixed keys are ignored.", + "additionalProperties": { + "type": "string" + } + }, + "insecureSkipTLSVerify": { + "type": "boolean", + "description": "Whether to skip TLS verification when communicating with registries. Defaults to false." + } + } +} \ No newline at end of file diff --git a/ui/src/gen/directives/toml-parse-config.json b/ui/src/gen/directives/toml-parse-config.json new file mode 100644 index 0000000000..0d2d838142 --- /dev/null +++ b/ui/src/gen/directives/toml-parse-config.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TOMLParseConfig", + "definitions": { + "tomlParse": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The name of the output variable to store the result." + }, + "fromExpression": { + "type": "string", + "minLength": 1, + "description": "The expression used to extract data from the TOML file." + } + } + } + }, + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string", + "description": "The path to the TOML file to be parsed.", + "minLength": 1 + }, + "outputs": { + "type": "array", + "description": "An array of outputs to extract from the TOML file.", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The name of the output variable to store the result." + }, + "fromExpression": { + "type": "string", + "minLength": 1, + "description": "The expression used to extract data from the TOML file." + } + } + } + } + } +} \ No newline at end of file diff --git a/ui/src/gen/directives/toml-update-config.json b/ui/src/gen/directives/toml-update-config.json new file mode 100644 index 0000000000..35cd0a3d75 --- /dev/null +++ b/ui/src/gen/directives/toml-update-config.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TOMLUpdateConfig", + "definitions": { + "tomlUpdate": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string", + "description": "The key whose value needs to be updated. For nested values, use a TOML dot notation path.", + "minLength": 1 + }, + "value": { + "description": "The new value for the specified key." + } + } + } + }, + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string", + "description": "The path to a TOML file.", + "minLength": 1 + }, + "updates": { + "type": "array", + "description": "A list of updates to apply to the TOML file.", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "key": { + "type": "string", + "description": "The key whose value needs to be updated. For nested values, use a TOML dot notation path.", + "minLength": 1 + }, + "value": { + "description": "The new value for the specified key." + } + } + } + } + } +} \ No newline at end of file diff --git a/ui/src/gen/schema/warehouses.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/warehouses.kargo.akuity.io_v1alpha1.json index 8df77a89c8..0a36467cac 100644 --- a/ui/src/gen/schema/warehouses.kargo.akuity.io_v1alpha1.json +++ b/ui/src/gen/schema/warehouses.kargo.akuity.io_v1alpha1.json @@ -210,7 +210,7 @@ "type": "array" }, "repoURL": { - "description": "RepoURL is the repository URL of the GitSubscription.", + "description": "RepoURL is the repository URL of the GitSubscription.\n", "minLength": 1, "pattern": "(?:^(ssh|https?)://(?:([\\w-]+)(:(.+))?@)?([\\w-]+(?:\\.[\\w-]+)*)(?::(\\d{1,5}))?(/.*)$)|(?:^([\\w-]+)@([\\w+]+(?:\\.[\\w-]+)*):(/?.*))", "type": "string" diff --git a/ui/src/gen/subscriptions/chart.json b/ui/src/gen/subscriptions/chart.json index 63f471bca1..db6cb39e99 100644 --- a/ui/src/gen/subscriptions/chart.json +++ b/ui/src/gen/subscriptions/chart.json @@ -24,6 +24,10 @@ "maximum": 100, "default": 20, "description": "DiscoveryLimit is an optional limit on the number of chart versions that can be discovered for this subscription. The limit is applied after filtering charts based on the semverConstraint field. The upper limit for this field is 100." + }, + "insecureSkipTLSVerify": { + "type": "boolean", + "description": "InsecureSkipTLSVerify specifies whether certificate verification errors should be ignored when connecting to the repository. This should be enabled only with great caution." } }, "additionalProperties": false diff --git a/ui/src/gen/subscriptions/git.json b/ui/src/gen/subscriptions/git.json index 06abb02edf..0fe89a60f8 100644 --- a/ui/src/gen/subscriptions/git.json +++ b/ui/src/gen/subscriptions/git.json @@ -8,7 +8,7 @@ "type": "string", "minLength": 1, "pattern": "(?:^(ssh|https?)://(?:([\\w-]+)(:(.+))?@)?([\\w-]+(?:\\.[\\w-]+)*)(?::(\\d{1,5}))?(/.*)$)|(?:^([\\w-]+)@([\\w+]+(?:\\.[\\w-]+)*):(/?.*))$", - "description": "URL is the repository's URL. This is a required field." + "description": "URL is the repository's URL. This is a required field. Deprecated: Support for SSH URLs (ssh:// and SCP-style git@host:path) is deprecated as of v1.10.0 and will be removed in v1.13.0. Use HTTPS URLs instead." }, "commitSelectionStrategy": { "type": "string", @@ -90,6 +90,11 @@ "maximum": 100, "default": 20, "description": "DiscoveryLimit is an optional limit on the number of commits that can be discovered for this subscription. The upper limit is 100." + }, + "since": { + "type": "string", + "format": "date-time", + "description": "An optional date (RFC 3339) that limits commit discovery to commits at or after this date. When specified, discovery stops upon reaching a commit older than this date. When left unspecified, there is no cutoff." } }, "additionalProperties": false diff --git a/ui/src/lib/api/custom-fetch.ts b/ui/src/lib/api/custom-fetch.ts index c83168aa8a..34b55d8be4 100644 --- a/ui/src/lib/api/custom-fetch.ts +++ b/ui/src/lib/api/custom-fetch.ts @@ -6,50 +6,91 @@ * - Include authentication headers * - Handle common error scenarios * - * The UI team should customize this based on how authentication - * is handled in the current application. + * Orval generates hooks that expect a response envelope: + * { data: T, status: number, headers: Headers } */ -// TODO: Import your auth token getter from the appropriate location -// import { getAuthToken } from '@/auth'; +import { authTokenKey, redirectToQueryParam, refreshTokenKey } from '@ui/config/auth'; +import { paths } from '@ui/config/paths'; -/** - * Get the API base URL from environment or default to current origin. - * Adjust this based on your deployment configuration. - */ const getBaseUrl = (): string => { - // In development, you might use a different API URL if (import.meta.env.VITE_API_URL) { return import.meta.env.VITE_API_URL; } - // In production, API is typically on the same origin return ''; }; +const logout = () => { + localStorage.removeItem(authTokenKey); + localStorage.removeItem(refreshTokenKey); + window.location.replace(`${paths.login}?${redirectToQueryParam}=${window.location.pathname}`); +}; + +const renewToken = () => { + window.location.replace( + `${paths.tokenRenew}?${redirectToQueryParam}=${window.location.pathname}` + ); +}; + /** * Custom fetch function used by all generated API hooks. * - * Orval calls this function with (url, options) signature. + * Returns a response envelope { data, status, headers } as expected + * by orval-generated hooks. * - * @param url - The API endpoint path (e.g., "/v2/projects") + * @param url - The API endpoint path (e.g., "/v1beta1/projects") * @param options - The fetch options (method, body, headers, etc.) - * @returns Promise resolving to the parsed response data + * @returns Promise resolving to the response envelope */ export const customFetch = async (url: string, options?: RequestInit): Promise => { const baseUrl = getBaseUrl(); const fullUrl = `${baseUrl}${url}`; - // TODO: Get the auth token from your auth state/context - // const token = getAuthToken(); - const token: string | null = null; // Placeholder - implement auth token retrieval + const token = localStorage.getItem(authTokenKey); + const refreshToken = localStorage.getItem(refreshTokenKey); + + if (token) { + let isTokenExpired: boolean; + try { + isTokenExpired = Date.now() >= JSON.parse(atob(token.split('.')[1])).exp * 1000; + } catch (_) { + logout(); + throw new ApiError(401, 'Unauthorized', 'Invalid token'); + } + + if (isTokenExpired && refreshToken) { + renewToken(); + throw new ApiError(401, 'Unauthorized', 'Token expired'); + } - const headers: HeadersInit = { - 'Content-Type': 'application/json', - ...options?.headers + if (isTokenExpired && !refreshToken) { + logout(); + throw new ApiError(401, 'Unauthorized', 'Token expired'); + } + } + + const headers: Record = { + 'Content-Type': 'application/json' }; + // Preserve any explicitly passed headers (may override Content-Type for text/plain bodies) + if (options?.headers) { + const incoming = options.headers; + if (incoming instanceof Headers) { + incoming.forEach((value, key) => { + headers[key] = value; + }); + } else if (Array.isArray(incoming)) { + for (const [key, value] of incoming) { + headers[key] = value; + } + } else { + Object.assign(headers, incoming); + } + } + if (token) { - (headers as Record)['Authorization'] = `Bearer ${token}`; + headers['Authorization'] = `Bearer ${token}`; } const response = await fetch(fullUrl, { @@ -57,31 +98,37 @@ export const customFetch = async (url: string, options?: RequestInit): Promis headers }); - // Handle non-2xx responses + if (response.status === 401) { + logout(); + } + if (!response.ok) { - // Try to parse error body for more details let errorBody: unknown; try { errorBody = await response.json(); } catch { errorBody = await response.text(); } - throw new ApiError(response.status, response.statusText, errorBody); } - // Handle 204 No Content if (response.status === 204) { - return undefined as T; + return { data: undefined, status: 204, headers: response.headers } as T; + } + + const contentType = response.headers.get('content-type') ?? ''; + let data: unknown; + if (contentType.includes('application/json')) { + data = await response.json(); + } else { + data = await response.text(); } - // Parse and return JSON response - return response.json(); + return { data, status: response.status, headers: response.headers } as T; }; /** * Custom error class for API errors. - * Provides structured error information for error handling in the UI. */ export class ApiError extends Error { constructor( @@ -93,44 +140,26 @@ export class ApiError extends Error { this.name = 'ApiError'; } - /** - * Check if this is a specific HTTP status code. - */ is(status: number): boolean { return this.status === status; } - /** - * Check if this is a client error (4xx). - */ isClientError(): boolean { return this.status >= 400 && this.status < 500; } - /** - * Check if this is a server error (5xx). - */ isServerError(): boolean { return this.status >= 500; } - /** - * Check if this is an authentication error (401). - */ isUnauthorized(): boolean { return this.status === 401; } - /** - * Check if this is a forbidden error (403). - */ isForbidden(): boolean { return this.status === 403; } - /** - * Check if this is a not found error (404). - */ isNotFound(): boolean { return this.status === 404; } diff --git a/ui/vite.config.mts b/ui/vite.config.mts index c7c3f3789c..2a44c60321 100644 --- a/ui/vite.config.mts +++ b/ui/vite.config.mts @@ -51,6 +51,10 @@ export default defineConfig({ '/akuity.io.kargo.service.v1alpha1.KargoService': { target: API_URL, changeOrigin: true + }, + '/v1beta1': { + target: API_URL, + changeOrigin: true } }, port: 3333