feat: scaffold job execution API
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
# This file configures golangci-lint with module plugins.
|
||||||
|
# When you run 'make lint', it will automatically build a custom golangci-lint binary
|
||||||
|
# with all the plugins listed below.
|
||||||
|
#
|
||||||
|
# See: https://golangci-lint.run/plugins/module-plugins/
|
||||||
|
version: v2.13.1
|
||||||
|
plugins:
|
||||||
|
# logcheck validates structured logging calls and parameters (e.g., balanced key-value pairs)
|
||||||
|
- module: "sigs.k8s.io/logtools"
|
||||||
|
import: "sigs.k8s.io/logtools/logcheck/gclplugin"
|
||||||
|
version: latest
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
|
||||||
|
# Ignore everything by default and re-include only needed files
|
||||||
|
**
|
||||||
|
|
||||||
|
# Re-include Go source files (but not *_test.go)
|
||||||
|
# If you use Podman, re-include your source directories by name,
|
||||||
|
# such as !cmd, !api, and !internal.
|
||||||
|
# See https://github.com/containers/buildah/issues/6417
|
||||||
|
!**/*.go
|
||||||
|
**/*_test.go
|
||||||
|
|
||||||
|
# Re-include Go module files
|
||||||
|
!go.mod
|
||||||
|
!go.sum
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
name: Verify
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: [self-hosted, pod]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Verify generated files and tests
|
||||||
|
run: |
|
||||||
|
make test
|
||||||
|
git diff --exit-code
|
||||||
|
|
||||||
|
lint:
|
||||||
|
runs-on: [self-hosted, pod]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: make lint
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
/bin/
|
/bin/
|
||||||
/dist/
|
/dist/
|
||||||
/coverage/
|
/coverage/
|
||||||
|
/cover.out
|
||||||
|
|
||||||
# Local configuration and credentials
|
# Local configuration and credentials
|
||||||
.env
|
.env
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
version: "2"
|
||||||
|
run:
|
||||||
|
allow-parallel-runners: true
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- copyloopvar
|
||||||
|
- depguard
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- ginkgolinter
|
||||||
|
- goconst
|
||||||
|
- gocyclo
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- lll
|
||||||
|
- modernize
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- prealloc
|
||||||
|
- revive
|
||||||
|
- staticcheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- unused
|
||||||
|
- logcheck
|
||||||
|
settings:
|
||||||
|
custom:
|
||||||
|
logcheck:
|
||||||
|
type: "module"
|
||||||
|
description: Checks Go logging calls for Kubernetes logging conventions.
|
||||||
|
depguard:
|
||||||
|
rules:
|
||||||
|
forbid-sort-pkg:
|
||||||
|
deny:
|
||||||
|
- pkg: sort
|
||||||
|
desc: Should be replaced with slices package
|
||||||
|
revive:
|
||||||
|
rules:
|
||||||
|
- name: comment-spacings
|
||||||
|
- name: import-shadowing
|
||||||
|
modernize:
|
||||||
|
disable:
|
||||||
|
- omitzero
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
rules:
|
||||||
|
- linters:
|
||||||
|
- lll
|
||||||
|
path: api/*
|
||||||
|
- linters:
|
||||||
|
- dupl
|
||||||
|
- lll
|
||||||
|
path: internal/*
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
# Build the manager binary
|
||||||
|
# Override BASE_IMAGE to build from another registry, e.g. docker.io/library/golang:1.27.1
|
||||||
|
ARG BASE_IMAGE=golang:1.27.1
|
||||||
|
FROM ${BASE_IMAGE} AS builder
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
|
||||||
|
WORKDIR /workspace
|
||||||
|
# Copy the Go Modules manifests
|
||||||
|
COPY go.mod go.mod
|
||||||
|
COPY go.sum go.sum
|
||||||
|
# cache deps before building and copying source so that we don't need to re-download as much
|
||||||
|
# and so that source changes don't invalidate our downloaded layer
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the Go source (relies on .dockerignore to filter)
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build
|
||||||
|
# the GOARCH has no default value to allow the binary to be built according to the host where the command
|
||||||
|
# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO
|
||||||
|
# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore,
|
||||||
|
# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform.
|
||||||
|
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go
|
||||||
|
|
||||||
|
# Use distroless as minimal base image to package the manager binary
|
||||||
|
# Refer to https://github.com/GoogleContainerTools/distroless for more details
|
||||||
|
FROM gcr.io/distroless/static:nonroot
|
||||||
|
WORKDIR /
|
||||||
|
COPY --from=builder /workspace/manager .
|
||||||
|
USER 65532:65532
|
||||||
|
|
||||||
|
ENTRYPOINT ["/manager"]
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
# Image URL to use all building/pushing image targets
|
||||||
|
IMG ?= controller:latest
|
||||||
|
# YEAR defines the year value used for substituting the YEAR placeholder in the boilerplate header.
|
||||||
|
YEAR ?= $(shell date +%Y)
|
||||||
|
|
||||||
|
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
|
||||||
|
ifeq (,$(shell go env GOBIN))
|
||||||
|
GOBIN=$(shell go env GOPATH)/bin
|
||||||
|
else
|
||||||
|
GOBIN=$(shell go env GOBIN)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# CONTAINER_TOOL defines the container tool to be used for building images.
|
||||||
|
# Be aware that the target commands are only tested with Docker which is
|
||||||
|
# scaffolded by default. However, you might want to replace it to use other
|
||||||
|
# tools. (i.e. podman)
|
||||||
|
CONTAINER_TOOL ?= docker
|
||||||
|
|
||||||
|
# Setting SHELL to bash allows bash commands to be executed by recipes.
|
||||||
|
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
|
||||||
|
SHELL = /usr/bin/env bash -o pipefail
|
||||||
|
.SHELLFLAGS = -ec
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: build
|
||||||
|
|
||||||
|
##@ General
|
||||||
|
|
||||||
|
# The help target prints out all targets with their descriptions organized
|
||||||
|
# beneath their categories. The categories are represented by '##@' and the
|
||||||
|
# target descriptions by '##'. The awk command is responsible for reading the
|
||||||
|
# entire set of makefiles included in this invocation, looking for lines of the
|
||||||
|
# file as xyz: ## something, and then pretty-format the target and help. Then,
|
||||||
|
# if there's a line with ##@ something, that gets pretty-printed as a category.
|
||||||
|
# More info on the usage of ANSI control characters for terminal formatting:
|
||||||
|
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
|
||||||
|
# More info on the awk command:
|
||||||
|
# http://linuxcommand.org/lc3_adv_awk.php
|
||||||
|
|
||||||
|
.PHONY: help
|
||||||
|
help: ## Display this help.
|
||||||
|
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
##@ Development
|
||||||
|
|
||||||
|
.PHONY: manifests
|
||||||
|
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
|
||||||
|
"$(CONTROLLER_GEN)" rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
|
||||||
|
|
||||||
|
.PHONY: generate
|
||||||
|
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
|
||||||
|
"$(CONTROLLER_GEN)" object paths="./..."
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt: ## Run go fmt against code.
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
|
.PHONY: vet
|
||||||
|
vet: ## Run go vet against code.
|
||||||
|
go vet ./...
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: manifests generate fmt vet setup-envtest ## Run tests.
|
||||||
|
KUBEBUILDER_ASSETS="$(shell "$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path)" go test ./... -coverprofile cover.out
|
||||||
|
|
||||||
|
.PHONY: lint
|
||||||
|
lint: golangci-lint ## Run golangci-lint linter
|
||||||
|
"$(GOLANGCI_LINT)" run
|
||||||
|
|
||||||
|
.PHONY: lint-fix
|
||||||
|
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
|
||||||
|
"$(GOLANGCI_LINT)" run --fix
|
||||||
|
|
||||||
|
.PHONY: lint-config
|
||||||
|
lint-config: golangci-lint ## Verify golangci-lint linter configuration
|
||||||
|
"$(GOLANGCI_LINT)" config verify
|
||||||
|
|
||||||
|
##@ Build
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: manifests generate fmt vet ## Build manager binary.
|
||||||
|
go build -o bin/manager cmd/main.go
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: manifests generate fmt vet ## Run a controller from your host.
|
||||||
|
go run ./cmd/main.go
|
||||||
|
|
||||||
|
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
|
||||||
|
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
|
||||||
|
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
|
||||||
|
# Override BASE_IMAGE to build from another registry, e.g.
|
||||||
|
# make docker-build IMG=<img> BASE_IMAGE=docker.io/library/golang:1.27.1
|
||||||
|
.PHONY: docker-build
|
||||||
|
docker-build: ## Build docker image with the manager.
|
||||||
|
$(CONTAINER_TOOL) build $(if $(BASE_IMAGE),--build-arg BASE_IMAGE=$(BASE_IMAGE)) -t ${IMG} .
|
||||||
|
|
||||||
|
.PHONY: docker-push
|
||||||
|
docker-push: ## Push docker image with the manager.
|
||||||
|
$(CONTAINER_TOOL) push ${IMG}
|
||||||
|
|
||||||
|
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
|
||||||
|
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
|
||||||
|
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
|
||||||
|
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
|
||||||
|
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
|
||||||
|
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
|
||||||
|
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
|
||||||
|
.PHONY: docker-buildx
|
||||||
|
docker-buildx: ## Build and push docker image for the manager for cross-platform support
|
||||||
|
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
|
||||||
|
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
|
||||||
|
- $(CONTAINER_TOOL) buildx create --name ayatori-builder
|
||||||
|
$(CONTAINER_TOOL) buildx use ayatori-builder
|
||||||
|
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) $(if $(BASE_IMAGE),--build-arg BASE_IMAGE=$(BASE_IMAGE)) --tag ${IMG} -f Dockerfile.cross .
|
||||||
|
- $(CONTAINER_TOOL) buildx rm ayatori-builder
|
||||||
|
rm Dockerfile.cross
|
||||||
|
|
||||||
|
.PHONY: build-installer
|
||||||
|
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
|
||||||
|
mkdir -p dist
|
||||||
|
cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG}
|
||||||
|
"$(KUSTOMIZE)" build config/default > dist/install.yaml
|
||||||
|
|
||||||
|
##@ Deployment
|
||||||
|
|
||||||
|
ifndef ignore-not-found
|
||||||
|
ignore-not-found = false
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: install
|
||||||
|
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
|
||||||
|
@out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \
|
||||||
|
if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" apply -f -; else echo "No CRDs to install; skipping."; fi
|
||||||
|
|
||||||
|
.PHONY: uninstall
|
||||||
|
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||||
|
@out="$$( "$(KUSTOMIZE)" build config/crd 2>/dev/null || true )"; \
|
||||||
|
if [ -n "$$out" ]; then echo "$$out" | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f -; else echo "No CRDs to delete; skipping."; fi
|
||||||
|
|
||||||
|
.PHONY: deploy
|
||||||
|
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
|
||||||
|
cd config/manager && "$(KUSTOMIZE)" edit set image controller=${IMG}
|
||||||
|
"$(KUSTOMIZE)" build config/default | "$(KUBECTL)" apply -f -
|
||||||
|
|
||||||
|
.PHONY: undeploy
|
||||||
|
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
|
||||||
|
"$(KUSTOMIZE)" build config/default | "$(KUBECTL)" delete --ignore-not-found=$(ignore-not-found) -f -
|
||||||
|
|
||||||
|
##@ Dependencies
|
||||||
|
|
||||||
|
## Location to install dependencies to
|
||||||
|
LOCALBIN ?= $(shell pwd)/bin
|
||||||
|
$(LOCALBIN):
|
||||||
|
mkdir -p "$(LOCALBIN)"
|
||||||
|
|
||||||
|
## Tool Binaries
|
||||||
|
KUBECTL ?= kubectl
|
||||||
|
KUSTOMIZE ?= $(LOCALBIN)/kustomize
|
||||||
|
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
|
||||||
|
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
||||||
|
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
|
||||||
|
|
||||||
|
## Tool Versions
|
||||||
|
KUSTOMIZE_VERSION ?= v5.8.1
|
||||||
|
CONTROLLER_TOOLS_VERSION ?= v0.22.0
|
||||||
|
|
||||||
|
#ENVTEST_VERSION is the controller-runtime version to use for setup-envtest, derived from go.mod
|
||||||
|
ENVTEST_VERSION ?= $(shell v='$(call gomodver,sigs.k8s.io/controller-runtime)'; \
|
||||||
|
[ -n "$$v" ] || { echo "Set ENVTEST_VERSION manually (controller-runtime replace has no tag)" >&2; exit 1; }; \
|
||||||
|
printf '%s\n' "$$v")
|
||||||
|
|
||||||
|
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
|
||||||
|
ENVTEST_K8S_VERSION ?= $(shell v='$(call gomodver,k8s.io/api)'; \
|
||||||
|
[ -n "$$v" ] || { echo "Set ENVTEST_K8S_VERSION manually (k8s.io/api replace has no tag)" >&2; exit 1; }; \
|
||||||
|
printf '%s\n' "$$v" | sed -E 's/^v?[0-9]+\.([0-9]+).*/1.\1/')
|
||||||
|
|
||||||
|
GOLANGCI_LINT_VERSION ?= v2.13.1
|
||||||
|
.PHONY: kustomize
|
||||||
|
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
|
||||||
|
$(KUSTOMIZE): $(LOCALBIN)
|
||||||
|
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
|
||||||
|
|
||||||
|
.PHONY: controller-gen
|
||||||
|
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
|
||||||
|
$(CONTROLLER_GEN): $(LOCALBIN)
|
||||||
|
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
|
||||||
|
|
||||||
|
.PHONY: setup-envtest
|
||||||
|
setup-envtest: envtest ## Download the binaries required for ENVTEST in the local bin directory.
|
||||||
|
@echo "Setting up envtest binaries for Kubernetes version $(ENVTEST_K8S_VERSION)..."
|
||||||
|
@"$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path || { \
|
||||||
|
echo "Error: Failed to set up envtest binaries for version $(ENVTEST_K8S_VERSION)."; \
|
||||||
|
exit 1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
.PHONY: envtest
|
||||||
|
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
|
||||||
|
$(ENVTEST): $(LOCALBIN)
|
||||||
|
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))
|
||||||
|
|
||||||
|
.PHONY: golangci-lint
|
||||||
|
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
|
||||||
|
$(GOLANGCI_LINT): $(LOCALBIN)
|
||||||
|
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/v2/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
|
||||||
|
@test -f .custom-gcl.yml && { \
|
||||||
|
echo "Building custom golangci-lint with plugins..." && \
|
||||||
|
$(GOLANGCI_LINT) custom --destination $(LOCALBIN) --name golangci-lint-custom && \
|
||||||
|
mv -f $(LOCALBIN)/golangci-lint-custom $(GOLANGCI_LINT); \
|
||||||
|
} || true
|
||||||
|
|
||||||
|
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
|
||||||
|
# $1 - target path with name of binary
|
||||||
|
# $2 - package url which can be installed
|
||||||
|
# $3 - specific version of package
|
||||||
|
define go-install-tool
|
||||||
|
@[ -f "$(1)-$(3)" ] && [ "$$(readlink -- "$(1)" 2>/dev/null)" = "$(1)-$(3)" ] || { \
|
||||||
|
set -e; \
|
||||||
|
package=$(2)@$(3) ;\
|
||||||
|
echo "Downloading $${package}" ;\
|
||||||
|
rm -f "$(1)" ;\
|
||||||
|
GOBIN="$(LOCALBIN)" go install $${package} ;\
|
||||||
|
mv "$(LOCALBIN)/$$(basename "$(1)")" "$(1)-$(3)" ;\
|
||||||
|
} ;\
|
||||||
|
ln -sf "$$(realpath "$(1)-$(3)")" "$(1)"
|
||||||
|
endef
|
||||||
|
|
||||||
|
define gomodver
|
||||||
|
$(shell go list -m -f '{{if .Replace}}{{.Replace.Version}}{{else}}{{.Version}}{{end}}' $(1) 2>/dev/null)
|
||||||
|
endef
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Code generated by tool. DO NOT EDIT.
|
||||||
|
# This file is used to track the info used to scaffold your project
|
||||||
|
# and allow the plugins properly work.
|
||||||
|
# More info: https://book.kubebuilder.io/reference/project-config.html
|
||||||
|
cliVersion: 4.16.0
|
||||||
|
domain: ayatori.ddupan.top
|
||||||
|
layout:
|
||||||
|
- go.kubebuilder.io/v4
|
||||||
|
multigroup: true
|
||||||
|
projectName: ayatori
|
||||||
|
repo: git.ddupan.top/panxiao81/ayatori
|
||||||
|
resources:
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
namespaced: true
|
||||||
|
domain: ayatori.ddupan.top
|
||||||
|
group: execution
|
||||||
|
kind: Job
|
||||||
|
path: git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1
|
||||||
|
version: v1alpha1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
domain: ayatori.ddupan.top
|
||||||
|
group: execution
|
||||||
|
kind: JobClass
|
||||||
|
path: git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1
|
||||||
|
version: v1alpha1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
domain: ayatori.ddupan.top
|
||||||
|
group: execution
|
||||||
|
kind: KubernetesExecutionParameters
|
||||||
|
path: git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1
|
||||||
|
version: v1alpha1
|
||||||
|
- api:
|
||||||
|
crdVersion: v1
|
||||||
|
domain: ayatori.ddupan.top
|
||||||
|
group: execution
|
||||||
|
kind: OpenSandboxExecutionParameters
|
||||||
|
path: git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1
|
||||||
|
version: v1alpha1
|
||||||
|
version: "3"
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Package v1alpha1 contains API Schema definitions for the execution v1alpha1 API group.
|
||||||
|
// +kubebuilder:object:generate=true
|
||||||
|
// +groupName=execution.ayatori.ddupan.top
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// SchemeGroupVersion is group version used to register these objects.
|
||||||
|
// This name is used by applyconfiguration generators (e.g. controller-gen).
|
||||||
|
SchemeGroupVersion = schema.GroupVersion{Group: "execution.ayatori.ddupan.top", Version: "v1alpha1"}
|
||||||
|
|
||||||
|
// GroupVersion is an alias for SchemeGroupVersion, for backward compatibility.
|
||||||
|
GroupVersion = SchemeGroupVersion
|
||||||
|
|
||||||
|
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
||||||
|
SchemeBuilder = runtime.NewSchemeBuilder(func(scheme *runtime.Scheme) error {
|
||||||
|
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// AddToScheme adds the types in this group-version to the given scheme.
|
||||||
|
AddToScheme = SchemeBuilder.AddToScheme
|
||||||
|
)
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
JobConditionAccepted = "Accepted"
|
||||||
|
JobConditionScheduled = "Scheduled"
|
||||||
|
JobConditionSucceeded = "Succeeded"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JobDesiredState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
JobDesiredStateRunning JobDesiredState = "Running"
|
||||||
|
JobDesiredStateCancelled JobDesiredState = "Cancelled"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskSpec struct {
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Image string `json:"image"`
|
||||||
|
// +optional
|
||||||
|
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Command []string `json:"command,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Args []string `json:"args,omitempty"`
|
||||||
|
// +optional
|
||||||
|
WorkingDir string `json:"workingDir,omitempty"`
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=name
|
||||||
|
// +optional
|
||||||
|
Env []EnvVar `json:"env,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:validation:XValidation:rule="has(self.value) != has(self.valueFrom)",message="exactly one of value or valueFrom must be set"
|
||||||
|
type EnvVar struct {
|
||||||
|
// +kubebuilder:validation:Pattern=`^[A-Za-z_][A-Za-z0-9_]*$`
|
||||||
|
Name string `json:"name"`
|
||||||
|
// +optional
|
||||||
|
Value *string `json:"value,omitempty"`
|
||||||
|
// +optional
|
||||||
|
ValueFrom *EnvVarSource `json:"valueFrom,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:validation:XValidation:rule="has(self.secretKeyRef) != has(self.configMapKeyRef)",message="exactly one key reference must be set"
|
||||||
|
type EnvVarSource struct {
|
||||||
|
// +optional
|
||||||
|
SecretKeyRef *corev1.SecretKeySelector `json:"secretKeyRef,omitempty"`
|
||||||
|
// +optional
|
||||||
|
ConfigMapKeyRef *corev1.ConfigMapKeySelector `json:"configMapKeyRef,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResourceValues struct {
|
||||||
|
// +optional
|
||||||
|
CPU *resource.Quantity `json:"cpu,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Memory *resource.Quantity `json:"memory,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionResourceRequirements struct {
|
||||||
|
// +optional
|
||||||
|
Requests ResourceValues `json:"requests,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Limits ResourceValues `json:"limits,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self.task == oldSelf.task",message="task is immutable"
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self.resources == oldSelf.resources",message="resources are immutable"
|
||||||
|
// +kubebuilder:validation:XValidation:rule="has(self.activeDeadlineSeconds) == has(oldSelf.activeDeadlineSeconds) && (!has(self.activeDeadlineSeconds) || self.activeDeadlineSeconds == oldSelf.activeDeadlineSeconds)",message="activeDeadlineSeconds is immutable"
|
||||||
|
// +kubebuilder:validation:XValidation:rule="has(self.jobClassName) == has(oldSelf.jobClassName) && (!has(self.jobClassName) || self.jobClassName == oldSelf.jobClassName)",message="jobClassName is immutable"
|
||||||
|
// +kubebuilder:validation:XValidation:rule="oldSelf.desiredState == self.desiredState || (oldSelf.desiredState == 'Running' && self.desiredState == 'Cancelled')",message="desiredState may only transition from Running to Cancelled"
|
||||||
|
type JobSpec struct {
|
||||||
|
// +optional
|
||||||
|
JobClassName string `json:"jobClassName,omitempty"`
|
||||||
|
Task TaskSpec `json:"task"`
|
||||||
|
// +optional
|
||||||
|
Resources ExecutionResourceRequirements `json:"resources,omitempty"`
|
||||||
|
// +kubebuilder:validation:Minimum=1
|
||||||
|
// +optional
|
||||||
|
ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty"`
|
||||||
|
// +kubebuilder:validation:Minimum=0
|
||||||
|
// +optional
|
||||||
|
TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty"`
|
||||||
|
// +kubebuilder:validation:Enum=Running;Cancelled
|
||||||
|
// +kubebuilder:default=Running
|
||||||
|
// +optional
|
||||||
|
DesiredState JobDesiredState `json:"desiredState,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParametersReference struct {
|
||||||
|
Group string `json:"group"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
// +optional
|
||||||
|
UID types.UID `json:"uid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResolvedJobClassReference struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
UID types.UID `json:"uid"`
|
||||||
|
ControllerName string `json:"controllerName"`
|
||||||
|
ParametersRef ParametersReference `json:"parametersRef"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionReference struct {
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Type string `json:"type"`
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionStatus struct {
|
||||||
|
Adapter string `json:"adapter"`
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
|
// +optional
|
||||||
|
References []ExecutionReference `json:"references,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobResult struct {
|
||||||
|
// +optional
|
||||||
|
ExitCode *int32 `json:"exitCode,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Reason string `json:"reason,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobStatus struct {
|
||||||
|
// +optional
|
||||||
|
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
|
// +optional
|
||||||
|
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||||
|
// +optional
|
||||||
|
ResolvedJobClass *ResolvedJobClassReference `json:"resolvedJobClass,omitempty"`
|
||||||
|
// +optional
|
||||||
|
EffectiveResources ExecutionResourceRequirements `json:"effectiveResources,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Execution *ExecutionStatus `json:"execution,omitempty"`
|
||||||
|
// +optional
|
||||||
|
StartTime *metav1.Time `json:"startTime,omitempty"`
|
||||||
|
// +optional
|
||||||
|
CompletionTime *metav1.Time `json:"completionTime,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Result *JobResult `json:"result,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
// +kubebuilder:printcolumn:name="Accepted",type=string,JSONPath=`.status.conditions[?(@.type=='Accepted')].status`
|
||||||
|
// +kubebuilder:printcolumn:name="Scheduled",type=string,JSONPath=`.status.conditions[?(@.type=='Scheduled')].status`
|
||||||
|
// +kubebuilder:printcolumn:name="Succeeded",type=string,JSONPath=`.status.conditions[?(@.type=='Succeeded')].status`
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
|
type Job struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitzero"`
|
||||||
|
Spec JobSpec `json:"spec"`
|
||||||
|
// +optional
|
||||||
|
Status JobStatus `json:"status,omitzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
type JobList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitzero"`
|
||||||
|
Items []Job `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(func(s *runtime.Scheme) error {
|
||||||
|
s.AddKnownTypes(SchemeGroupVersion, &Job{}, &JobList{})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
JobClassConditionAccepted = "Accepted"
|
||||||
|
JobClassConditionReady = "Ready"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExecutionResourcePolicy struct {
|
||||||
|
// +optional
|
||||||
|
Defaults ExecutionResourceRequirements `json:"defaults,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Minimum ExecutionResourceRequirements `json:"minimum,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Maximum ExecutionResourceRequirements `json:"maximum,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self.controllerName == oldSelf.controllerName",message="controllerName is immutable"
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self.parametersRef == oldSelf.parametersRef",message="parametersRef is immutable"
|
||||||
|
type JobClassSpec struct {
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=253
|
||||||
|
ControllerName string `json:"controllerName"`
|
||||||
|
ParametersRef ParametersReference `json:"parametersRef"`
|
||||||
|
// +optional
|
||||||
|
AllowedNamespaces *metav1.LabelSelector `json:"allowedNamespaces,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Resources ExecutionResourcePolicy `json:"resources,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JobClassStatus struct {
|
||||||
|
// +optional
|
||||||
|
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
|
// +optional
|
||||||
|
Conditions []metav1.Condition `json:"conditions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:subresource:status
|
||||||
|
// +kubebuilder:resource:scope=Cluster
|
||||||
|
// +kubebuilder:printcolumn:name="Controller",type=string,JSONPath=`.spec.controllerName`
|
||||||
|
// +kubebuilder:printcolumn:name="Accepted",type=string,JSONPath=`.status.conditions[?(@.type=='Accepted')].status`
|
||||||
|
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=='Ready')].status`
|
||||||
|
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||||
|
type JobClass struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitzero"`
|
||||||
|
Spec JobClassSpec `json:"spec"`
|
||||||
|
// +optional
|
||||||
|
Status JobClassStatus `json:"status,omitzero"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
type JobClassList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitzero"`
|
||||||
|
Items []JobClass `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(func(s *runtime.Scheme) error {
|
||||||
|
s.AddKnownTypes(SchemeGroupVersion, &JobClass{}, &JobClassList{})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KubernetesSchedulingParameters struct {
|
||||||
|
// +optional
|
||||||
|
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KubernetesExecutionParametersSpec struct {
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
ServiceAccountName string `json:"serviceAccountName"`
|
||||||
|
// +optional
|
||||||
|
RuntimeClassName string `json:"runtimeClassName,omitempty"`
|
||||||
|
// +optional
|
||||||
|
Scheduling KubernetesSchedulingParameters `json:"scheduling,omitempty"`
|
||||||
|
// +optional
|
||||||
|
PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"`
|
||||||
|
// +kubebuilder:validation:Enum=Always;Never;IfNotPresent
|
||||||
|
// +kubebuilder:default=IfNotPresent
|
||||||
|
// +optional
|
||||||
|
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:resource:scope=Cluster
|
||||||
|
type KubernetesExecutionParameters struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitzero"`
|
||||||
|
Spec KubernetesExecutionParametersSpec `json:"spec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
type KubernetesExecutionParametersList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitzero"`
|
||||||
|
Items []KubernetesExecutionParameters `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(func(s *runtime.Scheme) error {
|
||||||
|
s.AddKnownTypes(SchemeGroupVersion, &KubernetesExecutionParameters{}, &KubernetesExecutionParametersList{})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NamespacedKeyReference struct {
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenSandboxRequestMapping string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OpenSandboxRequestMappingAdmissionOnly OpenSandboxRequestMapping = "AdmissionOnly"
|
||||||
|
OpenSandboxRequestMappingNative OpenSandboxRequestMapping = "Native"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:validation:XValidation:rule="self.allowInsecureHTTP || self.endpoint.startsWith('https://')",message="endpoint must use HTTPS unless allowInsecureHTTP is true"
|
||||||
|
type OpenSandboxExecutionParametersSpec struct {
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
APIKeySecretRef NamespacedKeyReference `json:"apiKeySecretRef"`
|
||||||
|
// +optional
|
||||||
|
PoolRef string `json:"poolRef,omitempty"`
|
||||||
|
// +kubebuilder:validation:Enum=AdmissionOnly;Native
|
||||||
|
// +kubebuilder:default=AdmissionOnly
|
||||||
|
// +optional
|
||||||
|
RequestMapping OpenSandboxRequestMapping `json:"requestMapping,omitempty"`
|
||||||
|
// +optional
|
||||||
|
AllowSecretEnv bool `json:"allowSecretEnv,omitempty"`
|
||||||
|
// +optional
|
||||||
|
AllowImageAuth bool `json:"allowImageAuth,omitempty"`
|
||||||
|
// AllowInsecureHTTP is intended for isolated development environments only.
|
||||||
|
// +optional
|
||||||
|
AllowInsecureHTTP bool `json:"allowInsecureHTTP,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
// +kubebuilder:resource:scope=Cluster
|
||||||
|
type OpenSandboxExecutionParameters struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitzero"`
|
||||||
|
Spec OpenSandboxExecutionParametersSpec `json:"spec"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
type OpenSandboxExecutionParametersList struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ListMeta `json:"metadata,omitzero"`
|
||||||
|
Items []OpenSandboxExecutionParameters `json:"items"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
SchemeBuilder.Register(func(s *runtime.Scheme) error {
|
||||||
|
s.AddKnownTypes(SchemeGroupVersion, &OpenSandboxExecutionParameters{}, &OpenSandboxExecutionParametersList{})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package v1alpha1_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
executionv1alpha1 "git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJobCRDValidation(t *testing.T) {
|
||||||
|
if os.Getenv("KUBEBUILDER_ASSETS") == "" {
|
||||||
|
t.Skip("KUBEBUILDER_ASSETS is unset; run make test to execute API integration tests")
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme := runtime.NewScheme()
|
||||||
|
if err := executionv1alpha1.AddToScheme(scheme); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := corev1.AddToScheme(scheme); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
crdPath, err := filepath.Abs("../../../config/crd/bases")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
environment := &envtest.Environment{CRDDirectoryPaths: []string{crdPath}}
|
||||||
|
config, err := environment.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("start envtest: %v", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := environment.Stop(); err != nil {
|
||||||
|
t.Errorf("stop envtest: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
client, err := ctrlclient.New(config, ctrlclient.Options{Scheme: scheme})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
namespace := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "api-validation"}}
|
||||||
|
if err := client.Create(ctx, namespace); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("defaults desired state", func(t *testing.T) {
|
||||||
|
job := validJob("defaults")
|
||||||
|
if err := client.Create(ctx, job); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if job.Spec.DesiredState != executionv1alpha1.JobDesiredStateRunning {
|
||||||
|
t.Fatalf("desiredState = %q, want Running", job.Spec.DesiredState)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("rejects ambiguous environment value", func(t *testing.T) {
|
||||||
|
literal := "visible"
|
||||||
|
job := validJob("invalid-env")
|
||||||
|
job.Spec.Task.Env = []executionv1alpha1.EnvVar{{
|
||||||
|
Name: "TOKEN",
|
||||||
|
Value: &literal,
|
||||||
|
ValueFrom: &executionv1alpha1.EnvVarSource{
|
||||||
|
SecretKeyRef: &corev1.SecretKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: "token"}, Key: "value"},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
if err := client.Create(ctx, job); !apierrors.IsInvalid(err) {
|
||||||
|
t.Fatalf("Create() error = %v, want Invalid", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("rejects immutable task update", func(t *testing.T) {
|
||||||
|
job := validJob("immutable")
|
||||||
|
if err := client.Create(ctx, job); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
job.Spec.Task.Image = "docker.io/library/busybox:1.37"
|
||||||
|
if err := client.Update(ctx, job); !apierrors.IsInvalid(err) {
|
||||||
|
t.Fatalf("Update() error = %v, want Invalid", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("allows one-way cancellation", func(t *testing.T) {
|
||||||
|
job := validJob("cancel")
|
||||||
|
if err := client.Create(ctx, job); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
job.Spec.DesiredState = executionv1alpha1.JobDesiredStateCancelled
|
||||||
|
if err := client.Update(ctx, job); err != nil {
|
||||||
|
t.Fatalf("cancel update: %v", err)
|
||||||
|
}
|
||||||
|
job.Spec.DesiredState = executionv1alpha1.JobDesiredStateRunning
|
||||||
|
if err := client.Update(ctx, job); !apierrors.IsInvalid(err) {
|
||||||
|
t.Fatalf("reverse cancellation error = %v, want Invalid", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func validJob(name string) *executionv1alpha1.Job {
|
||||||
|
return &executionv1alpha1.Job{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "api-validation"},
|
||||||
|
Spec: executionv1alpha1.JobSpec{
|
||||||
|
Task: executionv1alpha1.TaskSpec{Image: "docker.io/library/alpine:3.22"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,676 @@
|
|||||||
|
//go:build !ignore_autogenerated
|
||||||
|
|
||||||
|
// Code generated by controller-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *EnvVar) DeepCopyInto(out *EnvVar) {
|
||||||
|
*out = *in
|
||||||
|
if in.Value != nil {
|
||||||
|
in, out := &in.Value, &out.Value
|
||||||
|
*out = new(string)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.ValueFrom != nil {
|
||||||
|
in, out := &in.ValueFrom, &out.ValueFrom
|
||||||
|
*out = new(EnvVarSource)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVar.
|
||||||
|
func (in *EnvVar) DeepCopy() *EnvVar {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(EnvVar)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *EnvVarSource) DeepCopyInto(out *EnvVarSource) {
|
||||||
|
*out = *in
|
||||||
|
if in.SecretKeyRef != nil {
|
||||||
|
in, out := &in.SecretKeyRef, &out.SecretKeyRef
|
||||||
|
*out = new(v1.SecretKeySelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.ConfigMapKeyRef != nil {
|
||||||
|
in, out := &in.ConfigMapKeyRef, &out.ConfigMapKeyRef
|
||||||
|
*out = new(v1.ConfigMapKeySelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvVarSource.
|
||||||
|
func (in *EnvVarSource) DeepCopy() *EnvVarSource {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(EnvVarSource)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ExecutionReference) DeepCopyInto(out *ExecutionReference) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecutionReference.
|
||||||
|
func (in *ExecutionReference) DeepCopy() *ExecutionReference {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ExecutionReference)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ExecutionResourcePolicy) DeepCopyInto(out *ExecutionResourcePolicy) {
|
||||||
|
*out = *in
|
||||||
|
in.Defaults.DeepCopyInto(&out.Defaults)
|
||||||
|
in.Minimum.DeepCopyInto(&out.Minimum)
|
||||||
|
in.Maximum.DeepCopyInto(&out.Maximum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecutionResourcePolicy.
|
||||||
|
func (in *ExecutionResourcePolicy) DeepCopy() *ExecutionResourcePolicy {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ExecutionResourcePolicy)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ExecutionResourceRequirements) DeepCopyInto(out *ExecutionResourceRequirements) {
|
||||||
|
*out = *in
|
||||||
|
in.Requests.DeepCopyInto(&out.Requests)
|
||||||
|
in.Limits.DeepCopyInto(&out.Limits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecutionResourceRequirements.
|
||||||
|
func (in *ExecutionResourceRequirements) DeepCopy() *ExecutionResourceRequirements {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ExecutionResourceRequirements)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ExecutionStatus) DeepCopyInto(out *ExecutionStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.References != nil {
|
||||||
|
in, out := &in.References, &out.References
|
||||||
|
*out = make([]ExecutionReference, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecutionStatus.
|
||||||
|
func (in *ExecutionStatus) DeepCopy() *ExecutionStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ExecutionStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Job) DeepCopyInto(out *Job) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Job.
|
||||||
|
func (in *Job) DeepCopy() *Job {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Job)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Job) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobClass) DeepCopyInto(out *JobClass) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobClass.
|
||||||
|
func (in *JobClass) DeepCopy() *JobClass {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobClass)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *JobClass) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobClassList) DeepCopyInto(out *JobClassList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]JobClass, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobClassList.
|
||||||
|
func (in *JobClassList) DeepCopy() *JobClassList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobClassList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *JobClassList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobClassSpec) DeepCopyInto(out *JobClassSpec) {
|
||||||
|
*out = *in
|
||||||
|
out.ParametersRef = in.ParametersRef
|
||||||
|
if in.AllowedNamespaces != nil {
|
||||||
|
in, out := &in.AllowedNamespaces, &out.AllowedNamespaces
|
||||||
|
*out = new(metav1.LabelSelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
in.Resources.DeepCopyInto(&out.Resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobClassSpec.
|
||||||
|
func (in *JobClassSpec) DeepCopy() *JobClassSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobClassSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobClassStatus) DeepCopyInto(out *JobClassStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]metav1.Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobClassStatus.
|
||||||
|
func (in *JobClassStatus) DeepCopy() *JobClassStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobClassStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobList) DeepCopyInto(out *JobList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]Job, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobList.
|
||||||
|
func (in *JobList) DeepCopy() *JobList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *JobList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobResult) DeepCopyInto(out *JobResult) {
|
||||||
|
*out = *in
|
||||||
|
if in.ExitCode != nil {
|
||||||
|
in, out := &in.ExitCode, &out.ExitCode
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobResult.
|
||||||
|
func (in *JobResult) DeepCopy() *JobResult {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobResult)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobSpec) DeepCopyInto(out *JobSpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Task.DeepCopyInto(&out.Task)
|
||||||
|
in.Resources.DeepCopyInto(&out.Resources)
|
||||||
|
if in.ActiveDeadlineSeconds != nil {
|
||||||
|
in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.TTLSecondsAfterFinished != nil {
|
||||||
|
in, out := &in.TTLSecondsAfterFinished, &out.TTLSecondsAfterFinished
|
||||||
|
*out = new(int32)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobSpec.
|
||||||
|
func (in *JobSpec) DeepCopy() *JobSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *JobStatus) DeepCopyInto(out *JobStatus) {
|
||||||
|
*out = *in
|
||||||
|
if in.Conditions != nil {
|
||||||
|
in, out := &in.Conditions, &out.Conditions
|
||||||
|
*out = make([]metav1.Condition, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.ResolvedJobClass != nil {
|
||||||
|
in, out := &in.ResolvedJobClass, &out.ResolvedJobClass
|
||||||
|
*out = new(ResolvedJobClassReference)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
in.EffectiveResources.DeepCopyInto(&out.EffectiveResources)
|
||||||
|
if in.Execution != nil {
|
||||||
|
in, out := &in.Execution, &out.Execution
|
||||||
|
*out = new(ExecutionStatus)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.StartTime != nil {
|
||||||
|
in, out := &in.StartTime, &out.StartTime
|
||||||
|
*out = (*in).DeepCopy()
|
||||||
|
}
|
||||||
|
if in.CompletionTime != nil {
|
||||||
|
in, out := &in.CompletionTime, &out.CompletionTime
|
||||||
|
*out = (*in).DeepCopy()
|
||||||
|
}
|
||||||
|
if in.Result != nil {
|
||||||
|
in, out := &in.Result, &out.Result
|
||||||
|
*out = new(JobResult)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobStatus.
|
||||||
|
func (in *JobStatus) DeepCopy() *JobStatus {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(JobStatus)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *KubernetesExecutionParameters) DeepCopyInto(out *KubernetesExecutionParameters) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesExecutionParameters.
|
||||||
|
func (in *KubernetesExecutionParameters) DeepCopy() *KubernetesExecutionParameters {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(KubernetesExecutionParameters)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *KubernetesExecutionParameters) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *KubernetesExecutionParametersList) DeepCopyInto(out *KubernetesExecutionParametersList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]KubernetesExecutionParameters, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesExecutionParametersList.
|
||||||
|
func (in *KubernetesExecutionParametersList) DeepCopy() *KubernetesExecutionParametersList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(KubernetesExecutionParametersList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *KubernetesExecutionParametersList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *KubernetesExecutionParametersSpec) DeepCopyInto(out *KubernetesExecutionParametersSpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Scheduling.DeepCopyInto(&out.Scheduling)
|
||||||
|
if in.PodSecurityContext != nil {
|
||||||
|
in, out := &in.PodSecurityContext, &out.PodSecurityContext
|
||||||
|
*out = new(v1.PodSecurityContext)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesExecutionParametersSpec.
|
||||||
|
func (in *KubernetesExecutionParametersSpec) DeepCopy() *KubernetesExecutionParametersSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(KubernetesExecutionParametersSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *KubernetesSchedulingParameters) DeepCopyInto(out *KubernetesSchedulingParameters) {
|
||||||
|
*out = *in
|
||||||
|
if in.NodeSelector != nil {
|
||||||
|
in, out := &in.NodeSelector, &out.NodeSelector
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if in.Tolerations != nil {
|
||||||
|
in, out := &in.Tolerations, &out.Tolerations
|
||||||
|
*out = make([]v1.Toleration, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesSchedulingParameters.
|
||||||
|
func (in *KubernetesSchedulingParameters) DeepCopy() *KubernetesSchedulingParameters {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(KubernetesSchedulingParameters)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *NamespacedKeyReference) DeepCopyInto(out *NamespacedKeyReference) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespacedKeyReference.
|
||||||
|
func (in *NamespacedKeyReference) DeepCopy() *NamespacedKeyReference {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(NamespacedKeyReference)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *OpenSandboxExecutionParameters) DeepCopyInto(out *OpenSandboxExecutionParameters) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
out.Spec = in.Spec
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenSandboxExecutionParameters.
|
||||||
|
func (in *OpenSandboxExecutionParameters) DeepCopy() *OpenSandboxExecutionParameters {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(OpenSandboxExecutionParameters)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *OpenSandboxExecutionParameters) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *OpenSandboxExecutionParametersList) DeepCopyInto(out *OpenSandboxExecutionParametersList) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||||
|
if in.Items != nil {
|
||||||
|
in, out := &in.Items, &out.Items
|
||||||
|
*out = make([]OpenSandboxExecutionParameters, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenSandboxExecutionParametersList.
|
||||||
|
func (in *OpenSandboxExecutionParametersList) DeepCopy() *OpenSandboxExecutionParametersList {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(OpenSandboxExecutionParametersList)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *OpenSandboxExecutionParametersList) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *OpenSandboxExecutionParametersSpec) DeepCopyInto(out *OpenSandboxExecutionParametersSpec) {
|
||||||
|
*out = *in
|
||||||
|
out.APIKeySecretRef = in.APIKeySecretRef
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenSandboxExecutionParametersSpec.
|
||||||
|
func (in *OpenSandboxExecutionParametersSpec) DeepCopy() *OpenSandboxExecutionParametersSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(OpenSandboxExecutionParametersSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ParametersReference) DeepCopyInto(out *ParametersReference) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParametersReference.
|
||||||
|
func (in *ParametersReference) DeepCopy() *ParametersReference {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ParametersReference)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ResolvedJobClassReference) DeepCopyInto(out *ResolvedJobClassReference) {
|
||||||
|
*out = *in
|
||||||
|
out.ParametersRef = in.ParametersRef
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResolvedJobClassReference.
|
||||||
|
func (in *ResolvedJobClassReference) DeepCopy() *ResolvedJobClassReference {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ResolvedJobClassReference)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ResourceValues) DeepCopyInto(out *ResourceValues) {
|
||||||
|
*out = *in
|
||||||
|
if in.CPU != nil {
|
||||||
|
in, out := &in.CPU, &out.CPU
|
||||||
|
x := (*in).DeepCopy()
|
||||||
|
*out = &x
|
||||||
|
}
|
||||||
|
if in.Memory != nil {
|
||||||
|
in, out := &in.Memory, &out.Memory
|
||||||
|
x := (*in).DeepCopy()
|
||||||
|
*out = &x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceValues.
|
||||||
|
func (in *ResourceValues) DeepCopy() *ResourceValues {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ResourceValues)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *TaskSpec) DeepCopyInto(out *TaskSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.ImagePullSecrets != nil {
|
||||||
|
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
|
||||||
|
*out = make([]v1.LocalObjectReference, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Command != nil {
|
||||||
|
in, out := &in.Command, &out.Command
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Args != nil {
|
||||||
|
in, out := &in.Args, &out.Args
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Env != nil {
|
||||||
|
in, out := &in.Env, &out.Env
|
||||||
|
*out = make([]EnvVar, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskSpec.
|
||||||
|
func (in *TaskSpec) DeepCopy() *TaskSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(TaskSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
+184
@@ -0,0 +1,184 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||||
|
// to ensure that exec-entrypoint and run can make use of them.
|
||||||
|
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
|
||||||
|
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
|
|
||||||
|
executionv1alpha1 "git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1"
|
||||||
|
// +kubebuilder:scaffold:imports
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
scheme = runtime.NewScheme()
|
||||||
|
setupLog = ctrl.Log.WithName("setup")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||||
|
|
||||||
|
utilruntime.Must(executionv1alpha1.AddToScheme(scheme))
|
||||||
|
// +kubebuilder:scaffold:scheme
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint:gocyclo
|
||||||
|
func main() {
|
||||||
|
var metricsAddr string
|
||||||
|
var metricsCertPath, metricsCertName, metricsCertKey string
|
||||||
|
var webhookCertPath, webhookCertName, webhookCertKey string
|
||||||
|
var webhookPort int
|
||||||
|
var enableLeaderElection bool
|
||||||
|
var probeAddr string
|
||||||
|
var secureMetrics bool
|
||||||
|
var enableHTTP2 bool
|
||||||
|
var tlsOpts []func(*tls.Config)
|
||||||
|
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
|
||||||
|
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
|
||||||
|
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||||
|
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
|
||||||
|
"Enable leader election for controller manager. "+
|
||||||
|
"Enabling this will ensure there is only one active controller manager.")
|
||||||
|
flag.BoolVar(&secureMetrics, "metrics-secure", true,
|
||||||
|
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
|
||||||
|
flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.")
|
||||||
|
flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.")
|
||||||
|
flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.")
|
||||||
|
flag.IntVar(&webhookPort, "webhook-port", 9443, "Port the webhook server listens on. "+
|
||||||
|
"Defaults to 9443. Set -1 to disable the webhook server.")
|
||||||
|
flag.StringVar(&metricsCertPath, "metrics-cert-path", "",
|
||||||
|
"The directory that contains the metrics server certificate.")
|
||||||
|
flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
|
||||||
|
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
|
||||||
|
flag.BoolVar(&enableHTTP2, "enable-http2", false,
|
||||||
|
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
|
||||||
|
opts := zap.Options{
|
||||||
|
Development: true,
|
||||||
|
}
|
||||||
|
opts.BindFlags(flag.CommandLine)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||||
|
|
||||||
|
// if the enable-http2 flag is false (the default), http/2 should be disabled
|
||||||
|
// due to its vulnerabilities. More specifically, disabling http/2 will
|
||||||
|
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
|
||||||
|
// Rapid Reset CVEs. For more information see:
|
||||||
|
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
|
||||||
|
// - https://github.com/advisories/GHSA-4374-p667-p6c8
|
||||||
|
disableHTTP2 := func(c *tls.Config) {
|
||||||
|
setupLog.Info("Disabling HTTP/2")
|
||||||
|
c.NextProtos = []string{"http/1.1"}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !enableHTTP2 {
|
||||||
|
tlsOpts = append(tlsOpts, disableHTTP2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial webhook TLS options
|
||||||
|
webhookTLSOpts := tlsOpts
|
||||||
|
webhookServerOptions := webhook.Options{
|
||||||
|
TLSOpts: webhookTLSOpts,
|
||||||
|
Port: webhookPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(webhookCertPath) > 0 {
|
||||||
|
setupLog.Info("Initializing webhook certificate watcher using provided certificates",
|
||||||
|
"webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey)
|
||||||
|
|
||||||
|
webhookServerOptions.CertDir = webhookCertPath
|
||||||
|
webhookServerOptions.CertName = webhookCertName
|
||||||
|
webhookServerOptions.KeyName = webhookCertKey
|
||||||
|
}
|
||||||
|
|
||||||
|
webhookServer := webhook.NewServer(webhookServerOptions)
|
||||||
|
|
||||||
|
// Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
|
||||||
|
// More info:
|
||||||
|
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/metrics/server
|
||||||
|
// - https://book.kubebuilder.io/reference/metrics.html
|
||||||
|
metricsServerOptions := metricsserver.Options{
|
||||||
|
BindAddress: metricsAddr,
|
||||||
|
SecureServing: secureMetrics,
|
||||||
|
TLSOpts: tlsOpts,
|
||||||
|
}
|
||||||
|
|
||||||
|
if secureMetrics {
|
||||||
|
// FilterProvider is used to protect the metrics endpoint with authn/authz.
|
||||||
|
// These configurations ensure that only authorized users and service accounts
|
||||||
|
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
|
||||||
|
// https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/metrics/filters#WithAuthenticationAndAuthorization
|
||||||
|
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the certificate is not specified, controller-runtime will automatically
|
||||||
|
// generate self-signed certificates for the metrics server. While convenient for development and testing,
|
||||||
|
// this setup is not recommended for production.
|
||||||
|
//
|
||||||
|
// TODO(user): If you enable certManager, uncomment the following lines:
|
||||||
|
// - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
|
||||||
|
// managed by cert-manager for the metrics server.
|
||||||
|
// - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
|
||||||
|
if len(metricsCertPath) > 0 {
|
||||||
|
setupLog.Info("Initializing metrics certificate watcher using provided certificates",
|
||||||
|
"metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey)
|
||||||
|
|
||||||
|
metricsServerOptions.CertDir = metricsCertPath
|
||||||
|
metricsServerOptions.CertName = metricsCertName
|
||||||
|
metricsServerOptions.KeyName = metricsCertKey
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||||
|
Scheme: scheme,
|
||||||
|
Metrics: metricsServerOptions,
|
||||||
|
WebhookServer: webhookServer,
|
||||||
|
HealthProbeBindAddress: probeAddr,
|
||||||
|
LeaderElection: enableLeaderElection,
|
||||||
|
LeaderElectionID: "a6325ed6.ddupan.top",
|
||||||
|
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
|
||||||
|
// when the Manager ends. This requires the binary to immediately end when the
|
||||||
|
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
|
||||||
|
// speeds up voluntary leader transitions as the new leader don't have to wait
|
||||||
|
// LeaseDuration time first.
|
||||||
|
//
|
||||||
|
// In the default scaffold provided, the program ends immediately after
|
||||||
|
// the manager stops, so would be fine to enable this option. However,
|
||||||
|
// if you are doing or is intended to do any operation such as perform cleanups
|
||||||
|
// after the manager stops then its usage might be unsafe.
|
||||||
|
// LeaderElectionReleaseOnCancel: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
setupLog.Error(err, "Failed to start manager")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:scaffold:builder
|
||||||
|
|
||||||
|
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
|
||||||
|
setupLog.Error(err, "Failed to set up health check")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
|
||||||
|
setupLog.Error(err, "Failed to set up ready check")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
setupLog.Info("Starting manager")
|
||||||
|
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||||
|
setupLog.Error(err, "Failed to run manager")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.22.0
|
||||||
|
name: jobclasses.execution.ayatori.ddupan.top
|
||||||
|
spec:
|
||||||
|
group: execution.ayatori.ddupan.top
|
||||||
|
names:
|
||||||
|
kind: JobClass
|
||||||
|
listKind: JobClassList
|
||||||
|
plural: jobclasses
|
||||||
|
singular: jobclass
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- additionalPrinterColumns:
|
||||||
|
- jsonPath: .spec.controllerName
|
||||||
|
name: Controller
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.conditions[?(@.type=='Accepted')].status
|
||||||
|
name: Accepted
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.conditions[?(@.type=='Ready')].status
|
||||||
|
name: Ready
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: |-
|
||||||
|
APIVersion defines the versioned schema of this representation of an object.
|
||||||
|
Servers should convert recognized schemas to the latest internal value, and
|
||||||
|
may reject unrecognized values.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: |-
|
||||||
|
Kind is a string value representing the REST resource this object represents.
|
||||||
|
Servers may infer this from the endpoint the client submits requests to.
|
||||||
|
Cannot be updated.
|
||||||
|
In CamelCase.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
properties:
|
||||||
|
allowedNamespaces:
|
||||||
|
description: |-
|
||||||
|
A label selector is a label query over a set of resources. The result of matchLabels and
|
||||||
|
matchExpressions are ANDed. An empty label selector matches all objects. A null
|
||||||
|
label selector matches no objects.
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
description: matchExpressions is a list of label selector requirements.
|
||||||
|
The requirements are ANDed.
|
||||||
|
items:
|
||||||
|
description: |-
|
||||||
|
A label selector requirement is a selector that contains values, a key, and an operator that
|
||||||
|
relates the key and values.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: key is the label key that the selector applies
|
||||||
|
to.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: |-
|
||||||
|
operator represents a key's relationship to a set of values.
|
||||||
|
Valid operators are In, NotIn, Exists and DoesNotExist.
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
description: |-
|
||||||
|
values is an array of string values. If the operator is In or NotIn,
|
||||||
|
the values array must be non-empty. If the operator is Exists or DoesNotExist,
|
||||||
|
the values array must be empty. This array is replaced during a strategic
|
||||||
|
merge patch.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-type: atomic
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- operator
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-type: atomic
|
||||||
|
matchLabels:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: |-
|
||||||
|
matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
|
||||||
|
map is equivalent to an element of matchExpressions, whose key field is "key", the
|
||||||
|
operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
x-kubernetes-map-type: atomic
|
||||||
|
controllerName:
|
||||||
|
maxLength: 253
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
parametersRef:
|
||||||
|
properties:
|
||||||
|
group:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
uid:
|
||||||
|
description: |-
|
||||||
|
UID is a type that holds unique ID values, including UUIDs. Because we
|
||||||
|
don't ONLY use UUIDs, this is an alias to string. Being a type captures
|
||||||
|
intent and helps make sure that UIDs and names do not get conflated.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- group
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
resources:
|
||||||
|
properties:
|
||||||
|
defaults:
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
maximum:
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
minimum:
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- controllerName
|
||||||
|
- parametersRef
|
||||||
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: controllerName is immutable
|
||||||
|
rule: self.controllerName == oldSelf.controllerName
|
||||||
|
- message: parametersRef is immutable
|
||||||
|
rule: self.parametersRef == oldSelf.parametersRef
|
||||||
|
status:
|
||||||
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: Condition contains details for one aspect of the current
|
||||||
|
state of this API Resource.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: |-
|
||||||
|
message is a human readable message indicating details about the transition.
|
||||||
|
This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
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.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
maxLength: 316
|
||||||
|
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])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
observedGeneration:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
@@ -0,0 +1,408 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.22.0
|
||||||
|
name: jobs.execution.ayatori.ddupan.top
|
||||||
|
spec:
|
||||||
|
group: execution.ayatori.ddupan.top
|
||||||
|
names:
|
||||||
|
kind: Job
|
||||||
|
listKind: JobList
|
||||||
|
plural: jobs
|
||||||
|
singular: job
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- additionalPrinterColumns:
|
||||||
|
- jsonPath: .status.conditions[?(@.type=='Accepted')].status
|
||||||
|
name: Accepted
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.conditions[?(@.type=='Scheduled')].status
|
||||||
|
name: Scheduled
|
||||||
|
type: string
|
||||||
|
- jsonPath: .status.conditions[?(@.type=='Succeeded')].status
|
||||||
|
name: Succeeded
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: Age
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: |-
|
||||||
|
APIVersion defines the versioned schema of this representation of an object.
|
||||||
|
Servers should convert recognized schemas to the latest internal value, and
|
||||||
|
may reject unrecognized values.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: |-
|
||||||
|
Kind is a string value representing the REST resource this object represents.
|
||||||
|
Servers may infer this from the endpoint the client submits requests to.
|
||||||
|
Cannot be updated.
|
||||||
|
In CamelCase.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
properties:
|
||||||
|
activeDeadlineSeconds:
|
||||||
|
format: int64
|
||||||
|
minimum: 1
|
||||||
|
type: integer
|
||||||
|
desiredState:
|
||||||
|
default: Running
|
||||||
|
enum:
|
||||||
|
- Running
|
||||||
|
- Cancelled
|
||||||
|
type: string
|
||||||
|
jobClassName:
|
||||||
|
type: string
|
||||||
|
resources:
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
task:
|
||||||
|
properties:
|
||||||
|
args:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
command:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
env:
|
||||||
|
items:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
pattern: ^[A-Za-z_][A-Za-z0-9_]*$
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
valueFrom:
|
||||||
|
properties:
|
||||||
|
configMapKeyRef:
|
||||||
|
description: Selects a key from a ConfigMap.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: |-
|
||||||
|
The key to select from the ConfigMap's Data field.
|
||||||
|
Keys in the BinaryData field are not currently propagated to container env vars.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
default: ""
|
||||||
|
description: |-
|
||||||
|
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
|
||||||
|
type: string
|
||||||
|
optional:
|
||||||
|
description: Specify whether the ConfigMap or its
|
||||||
|
key must be defined
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
type: object
|
||||||
|
x-kubernetes-map-type: atomic
|
||||||
|
secretKeyRef:
|
||||||
|
description: SecretKeySelector selects a key of a Secret.
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
description: The key of the secret to select from. Must
|
||||||
|
be a valid secret key.
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
default: ""
|
||||||
|
description: |-
|
||||||
|
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
|
||||||
|
type: string
|
||||||
|
optional:
|
||||||
|
description: Specify whether the Secret or its key
|
||||||
|
must be defined
|
||||||
|
type: boolean
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
type: object
|
||||||
|
x-kubernetes-map-type: atomic
|
||||||
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: exactly one key reference must be set
|
||||||
|
rule: has(self.secretKeyRef) != has(self.configMapKeyRef)
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: exactly one of value or valueFrom must be set
|
||||||
|
rule: has(self.value) != has(self.valueFrom)
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- name
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
image:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
imagePullSecrets:
|
||||||
|
items:
|
||||||
|
description: |-
|
||||||
|
LocalObjectReference contains enough information to let you locate the
|
||||||
|
referenced object inside the same namespace.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
default: ""
|
||||||
|
description: |-
|
||||||
|
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
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
x-kubernetes-map-type: atomic
|
||||||
|
type: array
|
||||||
|
workingDir:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- image
|
||||||
|
type: object
|
||||||
|
ttlSecondsAfterFinished:
|
||||||
|
format: int32
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- task
|
||||||
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: task is immutable
|
||||||
|
rule: self.task == oldSelf.task
|
||||||
|
- message: resources are immutable
|
||||||
|
rule: self.resources == oldSelf.resources
|
||||||
|
- message: activeDeadlineSeconds is immutable
|
||||||
|
rule: has(self.activeDeadlineSeconds) == has(oldSelf.activeDeadlineSeconds)
|
||||||
|
&& (!has(self.activeDeadlineSeconds) || self.activeDeadlineSeconds
|
||||||
|
== oldSelf.activeDeadlineSeconds)
|
||||||
|
- message: jobClassName is immutable
|
||||||
|
rule: has(self.jobClassName) == has(oldSelf.jobClassName) && (!has(self.jobClassName)
|
||||||
|
|| self.jobClassName == oldSelf.jobClassName)
|
||||||
|
- message: desiredState may only transition from Running to Cancelled
|
||||||
|
rule: oldSelf.desiredState == self.desiredState || (oldSelf.desiredState
|
||||||
|
== 'Running' && self.desiredState == 'Cancelled')
|
||||||
|
status:
|
||||||
|
properties:
|
||||||
|
completionTime:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: Condition contains details for one aspect of the current
|
||||||
|
state of this API Resource.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: |-
|
||||||
|
message is a human readable message indicating details about the transition.
|
||||||
|
This may be an empty string.
|
||||||
|
maxLength: 32768
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: int64
|
||||||
|
minimum: 0
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
maxLength: 1024
|
||||||
|
minLength: 1
|
||||||
|
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.
|
||||||
|
enum:
|
||||||
|
- "True"
|
||||||
|
- "False"
|
||||||
|
- Unknown
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: type of condition in CamelCase or in foo.example.com/CamelCase.
|
||||||
|
maxLength: 316
|
||||||
|
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])$
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- lastTransitionTime
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
effectiveResources:
|
||||||
|
properties:
|
||||||
|
limits:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
requests:
|
||||||
|
properties:
|
||||||
|
cpu:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
memory:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
execution:
|
||||||
|
properties:
|
||||||
|
adapter:
|
||||||
|
type: string
|
||||||
|
references:
|
||||||
|
items:
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-map-keys:
|
||||||
|
- type
|
||||||
|
x-kubernetes-list-type: map
|
||||||
|
required:
|
||||||
|
- adapter
|
||||||
|
type: object
|
||||||
|
observedGeneration:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
resolvedJobClass:
|
||||||
|
properties:
|
||||||
|
controllerName:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
parametersRef:
|
||||||
|
properties:
|
||||||
|
group:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
uid:
|
||||||
|
description: |-
|
||||||
|
UID is a type that holds unique ID values, including UUIDs. Because we
|
||||||
|
don't ONLY use UUIDs, this is an alias to string. Being a type captures
|
||||||
|
intent and helps make sure that UIDs and names do not get conflated.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- group
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
uid:
|
||||||
|
description: |-
|
||||||
|
UID is a type that holds unique ID values, including UUIDs. Because we
|
||||||
|
don't ONLY use UUIDs, this is an alias to string. Being a type captures
|
||||||
|
intent and helps make sure that UIDs and names do not get conflated.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- controllerName
|
||||||
|
- name
|
||||||
|
- parametersRef
|
||||||
|
- uid
|
||||||
|
type: object
|
||||||
|
result:
|
||||||
|
properties:
|
||||||
|
exitCode:
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
reason:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
startTime:
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.22.0
|
||||||
|
name: kubernetesexecutionparameters.execution.ayatori.ddupan.top
|
||||||
|
spec:
|
||||||
|
group: execution.ayatori.ddupan.top
|
||||||
|
names:
|
||||||
|
kind: KubernetesExecutionParameters
|
||||||
|
listKind: KubernetesExecutionParametersList
|
||||||
|
plural: kubernetesexecutionparameters
|
||||||
|
singular: kubernetesexecutionparameters
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: |-
|
||||||
|
APIVersion defines the versioned schema of this representation of an object.
|
||||||
|
Servers should convert recognized schemas to the latest internal value, and
|
||||||
|
may reject unrecognized values.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: |-
|
||||||
|
Kind is a string value representing the REST resource this object represents.
|
||||||
|
Servers may infer this from the endpoint the client submits requests to.
|
||||||
|
Cannot be updated.
|
||||||
|
In CamelCase.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
properties:
|
||||||
|
imagePullPolicy:
|
||||||
|
default: IfNotPresent
|
||||||
|
description: PullPolicy describes a policy for if/when to pull a container
|
||||||
|
image
|
||||||
|
enum:
|
||||||
|
- Always
|
||||||
|
- Never
|
||||||
|
- IfNotPresent
|
||||||
|
type: string
|
||||||
|
podSecurityContext:
|
||||||
|
description: |-
|
||||||
|
PodSecurityContext holds pod-level security attributes and common container settings.
|
||||||
|
Some fields are also present in container.securityContext. Field values of
|
||||||
|
container.securityContext take precedence over field values of PodSecurityContext.
|
||||||
|
properties:
|
||||||
|
appArmorProfile:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: |-
|
||||||
|
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".
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
fsGroup:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
fsGroupChangePolicy:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
runAsGroup:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
runAsNonRoot:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: boolean
|
||||||
|
runAsUser:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
seLinuxChangePolicy:
|
||||||
|
description: |-
|
||||||
|
seLinuxChangePolicy defines how the container's SELinux label is applied to all volumes used by the Pod.
|
||||||
|
It has no effect on nodes that do not support SELinux or to volumes does not support SELinux.
|
||||||
|
Valid values are "MountOption" and "Recursive".
|
||||||
|
|
||||||
|
"Recursive" means relabeling of all files on all Pod volumes by the container runtime.
|
||||||
|
This may be slow for large volumes, but allows mixing privileged and unprivileged Pods sharing the same volume on the same node.
|
||||||
|
|
||||||
|
"MountOption" mounts all eligible Pod volumes with `-o context` mount option.
|
||||||
|
This requires all Pods that share the same volume to use the same SELinux label.
|
||||||
|
It is not possible to share the same volume among privileged and unprivileged Pods.
|
||||||
|
Eligible volumes are in-tree FibreChannel and iSCSI volumes, and all CSI volumes
|
||||||
|
whose CSI driver announces SELinux support by setting spec.seLinuxMount: true in their
|
||||||
|
CSIDriver instance. Other volumes are always re-labelled recursively.
|
||||||
|
|
||||||
|
If not specified, "MountOption" is used.
|
||||||
|
|
||||||
|
This field affects only Pods that have SELinux label set, either in PodSecurityContext or in SecurityContext of all containers.
|
||||||
|
|
||||||
|
All Pods that use the same volume should use the same seLinuxChangePolicy, otherwise some pods can get stuck in ContainerCreating state.
|
||||||
|
Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
type: string
|
||||||
|
seLinuxOptions:
|
||||||
|
description: |-
|
||||||
|
The SELinux context to be applied to all containers.
|
||||||
|
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.
|
||||||
|
properties:
|
||||||
|
level:
|
||||||
|
description: Level is SELinux level label that applies to
|
||||||
|
the container.
|
||||||
|
type: string
|
||||||
|
role:
|
||||||
|
description: Role is a SELinux role label that applies to
|
||||||
|
the container.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type is a SELinux type label that applies to
|
||||||
|
the container.
|
||||||
|
type: string
|
||||||
|
user:
|
||||||
|
description: User is a SELinux user label that applies to
|
||||||
|
the container.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
seccompProfile:
|
||||||
|
description: |-
|
||||||
|
The seccomp options to use by the containers in this pod.
|
||||||
|
Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
properties:
|
||||||
|
localhostProfile:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
supplementalGroups:
|
||||||
|
description: |-
|
||||||
|
A list of groups applied to the first process run in each container, in
|
||||||
|
addition to the container's primary GID and fsGroup (if specified). If
|
||||||
|
the SupplementalGroupsPolicy feature is enabled, the
|
||||||
|
supplementalGroupsPolicy field determines whether these are in addition
|
||||||
|
to or instead of any group memberships defined in the container image.
|
||||||
|
If unspecified, no additional groups are added, though group memberships
|
||||||
|
defined in the container image may still be used, depending on the
|
||||||
|
supplementalGroupsPolicy field.
|
||||||
|
Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
items:
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-type: atomic
|
||||||
|
supplementalGroupsPolicy:
|
||||||
|
description: |-
|
||||||
|
Defines how supplemental groups of the first container processes are calculated.
|
||||||
|
Valid values are "Merge" and "Strict". If not specified, "Merge" is used.
|
||||||
|
(Alpha) Using the field requires the SupplementalGroupsPolicy feature gate to be enabled
|
||||||
|
and the container runtime must implement support for this feature.
|
||||||
|
Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
type: string
|
||||||
|
sysctls:
|
||||||
|
description: |-
|
||||||
|
Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported
|
||||||
|
sysctls (by the container runtime) might fail to launch.
|
||||||
|
Note that this field cannot be set when spec.os.name is windows.
|
||||||
|
items:
|
||||||
|
description: Sysctl defines a kernel parameter to be set
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name of a property to set
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
description: Value of a property to set
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- value
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
x-kubernetes-list-type: atomic
|
||||||
|
windowsOptions:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
properties:
|
||||||
|
gmsaCredentialSpec:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
gmsaCredentialSpecName:
|
||||||
|
description: GMSACredentialSpecName is the name of the GMSA
|
||||||
|
credential spec to use.
|
||||||
|
type: string
|
||||||
|
hostProcess:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: boolean
|
||||||
|
runAsUserName:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
runtimeClassName:
|
||||||
|
type: string
|
||||||
|
scheduling:
|
||||||
|
properties:
|
||||||
|
nodeSelector:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
tolerations:
|
||||||
|
items:
|
||||||
|
description: |-
|
||||||
|
The pod this Toleration is attached to tolerates any taint that matches
|
||||||
|
the triple <key,value,effect> using the matching operator <operator>.
|
||||||
|
properties:
|
||||||
|
effect:
|
||||||
|
description: |-
|
||||||
|
Effect indicates the taint effect to match. Empty means match all taint effects.
|
||||||
|
When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
description: |-
|
||||||
|
Operator represents a key's relationship to the value.
|
||||||
|
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
|
||||||
|
Exists is equivalent to wildcard for value, so that a pod can
|
||||||
|
tolerate all taints of a particular category.
|
||||||
|
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
|
||||||
|
type: string
|
||||||
|
tolerationSeconds:
|
||||||
|
description: |-
|
||||||
|
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.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
value:
|
||||||
|
description: |-
|
||||||
|
Value is the taint value the toleration matches to.
|
||||||
|
If the operator is Exists, the value should be empty, otherwise just a regular string.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
serviceAccountName:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- serviceAccountName
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.22.0
|
||||||
|
name: opensandboxexecutionparameters.execution.ayatori.ddupan.top
|
||||||
|
spec:
|
||||||
|
group: execution.ayatori.ddupan.top
|
||||||
|
names:
|
||||||
|
kind: OpenSandboxExecutionParameters
|
||||||
|
listKind: OpenSandboxExecutionParametersList
|
||||||
|
plural: opensandboxexecutionparameters
|
||||||
|
singular: opensandboxexecutionparameters
|
||||||
|
scope: Cluster
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: |-
|
||||||
|
APIVersion defines the versioned schema of this representation of an object.
|
||||||
|
Servers should convert recognized schemas to the latest internal value, and
|
||||||
|
may reject unrecognized values.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: |-
|
||||||
|
Kind is a string value representing the REST resource this object represents.
|
||||||
|
Servers may infer this from the endpoint the client submits requests to.
|
||||||
|
Cannot be updated.
|
||||||
|
In CamelCase.
|
||||||
|
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
properties:
|
||||||
|
allowImageAuth:
|
||||||
|
type: boolean
|
||||||
|
allowInsecureHTTP:
|
||||||
|
description: AllowInsecureHTTP is intended for isolated development
|
||||||
|
environments only.
|
||||||
|
type: boolean
|
||||||
|
allowSecretEnv:
|
||||||
|
type: boolean
|
||||||
|
apiKeySecretRef:
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- key
|
||||||
|
- name
|
||||||
|
- namespace
|
||||||
|
type: object
|
||||||
|
endpoint:
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
poolRef:
|
||||||
|
type: string
|
||||||
|
requestMapping:
|
||||||
|
default: AdmissionOnly
|
||||||
|
enum:
|
||||||
|
- AdmissionOnly
|
||||||
|
- Native
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- apiKeySecretRef
|
||||||
|
- endpoint
|
||||||
|
type: object
|
||||||
|
x-kubernetes-validations:
|
||||||
|
- message: endpoint must use HTTPS unless allowInsecureHTTP is true
|
||||||
|
rule: self.allowInsecureHTTP || self.endpoint.startsWith('https://')
|
||||||
|
required:
|
||||||
|
- spec
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# This kustomization.yaml is not intended to be run by itself,
|
||||||
|
# since it depends on service name and namespace that are out of this kustomize package.
|
||||||
|
# It should be run by config/default
|
||||||
|
resources:
|
||||||
|
- bases/execution.ayatori.ddupan.top_jobs.yaml
|
||||||
|
- bases/execution.ayatori.ddupan.top_jobclasses.yaml
|
||||||
|
- bases/execution.ayatori.ddupan.top_kubernetesexecutionparameters.yaml
|
||||||
|
- bases/execution.ayatori.ddupan.top_opensandboxexecutionparameters.yaml
|
||||||
|
# +kubebuilder:scaffold:crdkustomizeresource
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
|
||||||
|
# patches here are for enabling the conversion webhook for each CRD
|
||||||
|
# +kubebuilder:scaffold:crdkustomizewebhookpatch
|
||||||
|
|
||||||
|
# [WEBHOOK] To enable webhook, uncomment the following section
|
||||||
|
# the following config is for teaching kustomize how to do kustomization for CRDs.
|
||||||
|
#configurations:
|
||||||
|
#- kustomizeconfig.yaml
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
|
||||||
|
nameReference:
|
||||||
|
- kind: Service
|
||||||
|
version: v1
|
||||||
|
fieldSpecs:
|
||||||
|
- kind: CustomResourceDefinition
|
||||||
|
version: v1
|
||||||
|
group: apiextensions.k8s.io
|
||||||
|
path: spec/conversion/webhook/clientConfig/service/name
|
||||||
|
|
||||||
|
varReference:
|
||||||
|
- path: metadata/annotations
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# This patch adds the args, volumes, and ports to allow the manager to use the metrics-server certs.
|
||||||
|
|
||||||
|
# Add the volumeMount for the metrics-server certs
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/containers/0/volumeMounts/-
|
||||||
|
value:
|
||||||
|
mountPath: /tmp/k8s-metrics-server/metrics-certs
|
||||||
|
name: metrics-certs
|
||||||
|
readOnly: true
|
||||||
|
|
||||||
|
# Add the --metrics-cert-path argument for the metrics server
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/containers/0/args/-
|
||||||
|
value: --metrics-cert-path=/tmp/k8s-metrics-server/metrics-certs
|
||||||
|
|
||||||
|
# Add the metrics-server certs volume configuration
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/volumes/-
|
||||||
|
value:
|
||||||
|
name: metrics-certs
|
||||||
|
secret:
|
||||||
|
secretName: metrics-server-cert
|
||||||
|
optional: false
|
||||||
|
items:
|
||||||
|
- key: ca.crt
|
||||||
|
path: ca.crt
|
||||||
|
- key: tls.crt
|
||||||
|
path: tls.crt
|
||||||
|
- key: tls.key
|
||||||
|
path: tls.key
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
# Adds namespace to all resources.
|
||||||
|
namespace: ayatori-system
|
||||||
|
|
||||||
|
# Value of this field is prepended to the
|
||||||
|
# names of all resources, e.g. a deployment named
|
||||||
|
# "wordpress" becomes "alices-wordpress".
|
||||||
|
# Note that it should also match with the prefix (text before '-') of the namespace
|
||||||
|
# field above.
|
||||||
|
namePrefix: ayatori-
|
||||||
|
|
||||||
|
# Labels to add to all resources and selectors.
|
||||||
|
#labels:
|
||||||
|
#- includeSelectors: true
|
||||||
|
# pairs:
|
||||||
|
# someName: someValue
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ../crd
|
||||||
|
- ../rbac
|
||||||
|
- ../manager
|
||||||
|
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||||
|
# crd/kustomization.yaml
|
||||||
|
#- ../webhook
|
||||||
|
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
|
||||||
|
#- ../certmanager
|
||||||
|
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
|
||||||
|
#- ../prometheus
|
||||||
|
# [METRICS] Expose the controller manager metrics service.
|
||||||
|
- metrics_service.yaml
|
||||||
|
# [NETWORK POLICY] Control ingress to metrics and webhook ports.
|
||||||
|
# Allow metrics traffic from pods in namespaces labeled 'metrics: enabled'.
|
||||||
|
# Allow webhook traffic from all sources.
|
||||||
|
#- ../network-policy
|
||||||
|
|
||||||
|
# Uncomment the patches line if you enable Metrics
|
||||||
|
patches:
|
||||||
|
# [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443.
|
||||||
|
# More info: https://book.kubebuilder.io/reference/metrics
|
||||||
|
- path: manager_metrics_patch.yaml
|
||||||
|
target:
|
||||||
|
kind: Deployment
|
||||||
|
|
||||||
|
# Uncomment the patches line if you enable Metrics and CertManager
|
||||||
|
# [METRICS-WITH-CERTS] To enable metrics protected with certManager, uncomment the following line.
|
||||||
|
# This patch will protect the metrics with certManager self-signed certs.
|
||||||
|
#- path: cert_metrics_manager_patch.yaml
|
||||||
|
# target:
|
||||||
|
# kind: Deployment
|
||||||
|
|
||||||
|
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||||
|
# crd/kustomization.yaml
|
||||||
|
#- path: manager_webhook_patch.yaml
|
||||||
|
# target:
|
||||||
|
# kind: Deployment
|
||||||
|
|
||||||
|
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
|
||||||
|
# Uncomment the following replacements to add the cert-manager CA injection annotations
|
||||||
|
#replacements:
|
||||||
|
# - source: # Uncomment the following block to enable certificates for metrics
|
||||||
|
# kind: Service
|
||||||
|
# version: v1
|
||||||
|
# name: controller-manager-metrics-service
|
||||||
|
# fieldPath: metadata.name
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: metrics-certs
|
||||||
|
# fieldPaths:
|
||||||
|
# - spec.dnsNames.0
|
||||||
|
# - spec.dnsNames.1
|
||||||
|
# options:
|
||||||
|
# delimiter: '.'
|
||||||
|
# index: 0
|
||||||
|
# create: true
|
||||||
|
# - select: # Uncomment the following to set the Service name for TLS config in Prometheus ServiceMonitor
|
||||||
|
# kind: ServiceMonitor
|
||||||
|
# group: monitoring.coreos.com
|
||||||
|
# version: v1
|
||||||
|
# name: controller-manager-metrics-monitor
|
||||||
|
# fieldPaths:
|
||||||
|
# - spec.endpoints.0.tlsConfig.serverName
|
||||||
|
# options:
|
||||||
|
# delimiter: '.'
|
||||||
|
# index: 0
|
||||||
|
# create: true
|
||||||
|
|
||||||
|
# - source:
|
||||||
|
# kind: Service
|
||||||
|
# version: v1
|
||||||
|
# name: controller-manager-metrics-service
|
||||||
|
# fieldPath: metadata.namespace
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: metrics-certs
|
||||||
|
# fieldPaths:
|
||||||
|
# - spec.dnsNames.0
|
||||||
|
# - spec.dnsNames.1
|
||||||
|
# options:
|
||||||
|
# delimiter: '.'
|
||||||
|
# index: 1
|
||||||
|
# create: true
|
||||||
|
# - select: # Uncomment the following to set the Service namespace for TLS in Prometheus ServiceMonitor
|
||||||
|
# kind: ServiceMonitor
|
||||||
|
# group: monitoring.coreos.com
|
||||||
|
# version: v1
|
||||||
|
# name: controller-manager-metrics-monitor
|
||||||
|
# fieldPaths:
|
||||||
|
# - spec.endpoints.0.tlsConfig.serverName
|
||||||
|
# options:
|
||||||
|
# delimiter: '.'
|
||||||
|
# index: 1
|
||||||
|
# create: true
|
||||||
|
|
||||||
|
# - source: # Uncomment the following block if you have any webhook
|
||||||
|
# kind: Service
|
||||||
|
# version: v1
|
||||||
|
# name: webhook-service
|
||||||
|
# fieldPath: .metadata.name # Name of the service
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPaths:
|
||||||
|
# - .spec.dnsNames.0
|
||||||
|
# - .spec.dnsNames.1
|
||||||
|
# options:
|
||||||
|
# delimiter: '.'
|
||||||
|
# index: 0
|
||||||
|
# create: true
|
||||||
|
# - source:
|
||||||
|
# kind: Service
|
||||||
|
# version: v1
|
||||||
|
# name: webhook-service
|
||||||
|
# fieldPath: .metadata.namespace # Namespace of the service
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPaths:
|
||||||
|
# - .spec.dnsNames.0
|
||||||
|
# - .spec.dnsNames.1
|
||||||
|
# options:
|
||||||
|
# delimiter: '.'
|
||||||
|
# index: 1
|
||||||
|
# create: true
|
||||||
|
|
||||||
|
# - source: # Uncomment the following block if you have a ValidatingWebhook (--programmatic-validation)
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert # This name should match the one in certificate.yaml
|
||||||
|
# fieldPath: .metadata.namespace # Namespace of the certificate CR
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: ValidatingWebhookConfiguration
|
||||||
|
# fieldPaths:
|
||||||
|
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||||
|
# options:
|
||||||
|
# delimiter: '/'
|
||||||
|
# index: 0
|
||||||
|
# create: true
|
||||||
|
# - source:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPath: .metadata.name
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: ValidatingWebhookConfiguration
|
||||||
|
# fieldPaths:
|
||||||
|
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||||
|
# options:
|
||||||
|
# delimiter: '/'
|
||||||
|
# index: 1
|
||||||
|
# create: true
|
||||||
|
|
||||||
|
# - source: # Uncomment the following block if you have a DefaultingWebhook (--defaulting )
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPath: .metadata.namespace # Namespace of the certificate CR
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: MutatingWebhookConfiguration
|
||||||
|
# fieldPaths:
|
||||||
|
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||||
|
# options:
|
||||||
|
# delimiter: '/'
|
||||||
|
# index: 0
|
||||||
|
# create: true
|
||||||
|
# - source:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPath: .metadata.name
|
||||||
|
# targets:
|
||||||
|
# - select:
|
||||||
|
# kind: MutatingWebhookConfiguration
|
||||||
|
# fieldPaths:
|
||||||
|
# - .metadata.annotations.[cert-manager.io/inject-ca-from]
|
||||||
|
# options:
|
||||||
|
# delimiter: '/'
|
||||||
|
# index: 1
|
||||||
|
# create: true
|
||||||
|
|
||||||
|
# - source: # Uncomment the following block if you have a ConversionWebhook (--conversion)
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPath: .metadata.namespace # Namespace of the certificate CR
|
||||||
|
# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD.
|
||||||
|
# +kubebuilder:scaffold:crdkustomizecainjectionns
|
||||||
|
# - source:
|
||||||
|
# kind: Certificate
|
||||||
|
# group: cert-manager.io
|
||||||
|
# version: v1
|
||||||
|
# name: serving-cert
|
||||||
|
# fieldPath: .metadata.name
|
||||||
|
# targets: # Do not remove or uncomment the following scaffold marker; required to generate code for target CRD.
|
||||||
|
# +kubebuilder:scaffold:crdkustomizecainjectionname
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# This patch adds the args to allow exposing the metrics endpoint using HTTPS
|
||||||
|
- op: add
|
||||||
|
path: /spec/template/spec/containers/0/args/0
|
||||||
|
value: --metrics-bind-address=:8443
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: controller-manager-metrics-service
|
||||||
|
namespace: system
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: https
|
||||||
|
port: 8443
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: 8443
|
||||||
|
selector:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
resources:
|
||||||
|
- manager.yaml
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: system
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
|
labels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
kubectl.kubernetes.io/default-container: manager
|
||||||
|
labels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
spec:
|
||||||
|
# TODO(user): Uncomment the following code to configure the nodeAffinity expression
|
||||||
|
# according to the platforms which are supported by your solution.
|
||||||
|
# It is considered best practice to support multiple architectures. You can
|
||||||
|
# build your manager image using the makefile target docker-buildx.
|
||||||
|
# affinity:
|
||||||
|
# nodeAffinity:
|
||||||
|
# requiredDuringSchedulingIgnoredDuringExecution:
|
||||||
|
# nodeSelectorTerms:
|
||||||
|
# - matchExpressions:
|
||||||
|
# - key: kubernetes.io/arch
|
||||||
|
# operator: In
|
||||||
|
# values:
|
||||||
|
# - amd64
|
||||||
|
# - arm64
|
||||||
|
# - ppc64le
|
||||||
|
# - s390x
|
||||||
|
# - key: kubernetes.io/os
|
||||||
|
# operator: In
|
||||||
|
# values:
|
||||||
|
# - linux
|
||||||
|
securityContext:
|
||||||
|
# Projects are configured by default to adhere to the "restricted" Pod Security Standards.
|
||||||
|
# This ensures that deployments meet the highest security requirements for Kubernetes.
|
||||||
|
# For more details, see: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
|
||||||
|
runAsNonRoot: true
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
containers:
|
||||||
|
- command:
|
||||||
|
- /manager
|
||||||
|
args:
|
||||||
|
- --leader-elect
|
||||||
|
- --health-probe-bind-address=:8081
|
||||||
|
image: controller:latest
|
||||||
|
name: manager
|
||||||
|
ports:
|
||||||
|
- containerPort: 8081
|
||||||
|
name: health
|
||||||
|
protocol: TCP
|
||||||
|
securityContext:
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- "ALL"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8081
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /readyz
|
||||||
|
port: 8081
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
# TODO(user): Configure the resources accordingly based on the project requirements.
|
||||||
|
# More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 128Mi
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 64Mi
|
||||||
|
volumeMounts: []
|
||||||
|
volumes: []
|
||||||
|
serviceAccountName: controller-manager
|
||||||
|
terminationGracePeriodSeconds: 10
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Allow metrics traffic from pods in namespaces labeled 'metrics: enabled'.
|
||||||
|
# Add this label to namespaces whose pods should scrape metrics.
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: allow-metrics-traffic
|
||||||
|
namespace: system
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
# Allow pods in namespaces labeled 'metrics: enabled' to scrape metrics.
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
metrics: enabled # Only from namespaces with this label
|
||||||
|
ports:
|
||||||
|
- port: 8443
|
||||||
|
protocol: TCP
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
resources:
|
||||||
|
- allow-metrics-traffic.yaml
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
resources:
|
||||||
|
- monitor.yaml
|
||||||
|
|
||||||
|
# [PROMETHEUS-WITH-CERTS] The following patch configures the ServiceMonitor in ../prometheus
|
||||||
|
# to securely reference certificates created and managed by cert-manager.
|
||||||
|
# Additionally, ensure that you uncomment the [METRICS WITH CERTMANAGER] patch under config/default/kustomization.yaml
|
||||||
|
# to mount the "metrics-server-cert" secret in the Manager Deployment.
|
||||||
|
#patches:
|
||||||
|
# - path: monitor_tls_patch.yaml
|
||||||
|
# target:
|
||||||
|
# kind: ServiceMonitor
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Prometheus Monitor Service (Metrics)
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: controller-manager-metrics-monitor
|
||||||
|
namespace: system
|
||||||
|
spec:
|
||||||
|
endpoints:
|
||||||
|
- path: /metrics
|
||||||
|
port: https # Ensure this is the name of the port that exposes HTTPS metrics
|
||||||
|
scheme: https
|
||||||
|
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||||
|
tlsConfig:
|
||||||
|
# TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables
|
||||||
|
# certificate verification, exposing the system to potential man-in-the-middle attacks.
|
||||||
|
# For production environments, it is recommended to use cert-manager for automatic TLS certificate management.
|
||||||
|
# To apply this configuration, enable cert-manager and use the patch located at config/prometheus/servicemonitor_tls_patch.yaml,
|
||||||
|
# which securely references the certificate from the 'metrics-server-cert' secret.
|
||||||
|
insecureSkipVerify: true
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
control-plane: controller-manager
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Patch for Prometheus ServiceMonitor to enable secure TLS configuration
|
||||||
|
# using certificates managed by cert-manager
|
||||||
|
- op: replace
|
||||||
|
path: /spec/endpoints/0/tlsConfig
|
||||||
|
value:
|
||||||
|
# SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
|
||||||
|
serverName: SERVICE_NAME.SERVICE_NAMESPACE.svc
|
||||||
|
insecureSkipVerify: false
|
||||||
|
ca:
|
||||||
|
secret:
|
||||||
|
name: metrics-server-cert
|
||||||
|
key: ca.crt
|
||||||
|
cert:
|
||||||
|
secret:
|
||||||
|
name: metrics-server-cert
|
||||||
|
key: tls.crt
|
||||||
|
keySecret:
|
||||||
|
name: metrics-server-cert
|
||||||
|
key: tls.key
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants full permissions ('*') over execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users authorized to modify roles and bindings within the cluster,
|
||||||
|
# enabling them to delegate specific permissions to other users or groups as needed.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-job-admin-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobs
|
||||||
|
verbs:
|
||||||
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobs/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants permissions to create, update, and delete resources within the execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users who need to manage these resources
|
||||||
|
# but should not control RBAC or manage permissions for others.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-job-editor-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobs
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobs/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants read-only access to execution.ayatori.ddupan.top resources.
|
||||||
|
# This role is intended for users who need visibility into these resources
|
||||||
|
# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-job-viewer-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobs
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobs/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants full permissions ('*') over execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users authorized to modify roles and bindings within the cluster,
|
||||||
|
# enabling them to delegate specific permissions to other users or groups as needed.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-jobclass-admin-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobclasses
|
||||||
|
verbs:
|
||||||
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobclasses/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants permissions to create, update, and delete resources within the execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users who need to manage these resources
|
||||||
|
# but should not control RBAC or manage permissions for others.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-jobclass-editor-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobclasses
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobclasses/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants read-only access to execution.ayatori.ddupan.top resources.
|
||||||
|
# This role is intended for users who need visibility into these resources
|
||||||
|
# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-jobclass-viewer-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobclasses
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- jobclasses/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants full permissions ('*') over execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users authorized to modify roles and bindings within the cluster,
|
||||||
|
# enabling them to delegate specific permissions to other users or groups as needed.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-kubernetesexecutionparameters-admin-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- kubernetesexecutionparameters
|
||||||
|
verbs:
|
||||||
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- kubernetesexecutionparameters/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants permissions to create, update, and delete resources within the execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users who need to manage these resources
|
||||||
|
# but should not control RBAC or manage permissions for others.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-kubernetesexecutionparameters-editor-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- kubernetesexecutionparameters
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- kubernetesexecutionparameters/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants read-only access to execution.ayatori.ddupan.top resources.
|
||||||
|
# This role is intended for users who need visibility into these resources
|
||||||
|
# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-kubernetesexecutionparameters-viewer-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- kubernetesexecutionparameters
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- kubernetesexecutionparameters/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants full permissions ('*') over execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users authorized to modify roles and bindings within the cluster,
|
||||||
|
# enabling them to delegate specific permissions to other users or groups as needed.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-opensandboxexecutionparameters-admin-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- opensandboxexecutionparameters
|
||||||
|
verbs:
|
||||||
|
- '*'
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- opensandboxexecutionparameters/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants permissions to create, update, and delete resources within the execution.ayatori.ddupan.top.
|
||||||
|
# This role is intended for users who need to manage these resources
|
||||||
|
# but should not control RBAC or manage permissions for others.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-opensandboxexecutionparameters-editor-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- opensandboxexecutionparameters
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- opensandboxexecutionparameters/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# This rule is not used by the project ayatori itself.
|
||||||
|
# It is provided to allow the cluster admin to help manage permissions for users.
|
||||||
|
#
|
||||||
|
# Grants read-only access to execution.ayatori.ddupan.top resources.
|
||||||
|
# This role is intended for users who need visibility into these resources
|
||||||
|
# without permissions to modify them. It is ideal for monitoring purposes and limited-access viewing.
|
||||||
|
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: execution-opensandboxexecutionparameters-viewer-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- opensandboxexecutionparameters
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- execution.ayatori.ddupan.top
|
||||||
|
resources:
|
||||||
|
- opensandboxexecutionparameters/status
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
resources:
|
||||||
|
# All RBAC will be applied under this service account in
|
||||||
|
# the deployment namespace. You may comment out this resource
|
||||||
|
# if your manager will use a service account that exists at
|
||||||
|
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
|
||||||
|
# subjects if changing service account names.
|
||||||
|
- service_account.yaml
|
||||||
|
- role.yaml
|
||||||
|
- role_binding.yaml
|
||||||
|
- leader_election_role.yaml
|
||||||
|
- leader_election_role_binding.yaml
|
||||||
|
# The following RBAC configurations are used to protect
|
||||||
|
# the metrics endpoint with authn/authz. These configurations
|
||||||
|
# ensure that only authorized users and service accounts
|
||||||
|
# can access the metrics endpoint. Comment the following
|
||||||
|
# permissions if you want to disable this protection.
|
||||||
|
# More info: https://book.kubebuilder.io/reference/metrics.html
|
||||||
|
- metrics_auth_role.yaml
|
||||||
|
- metrics_auth_role_binding.yaml
|
||||||
|
- metrics_reader_role.yaml
|
||||||
|
# For each CRD, "Admin", "Editor" and "Viewer" roles are scaffolded by
|
||||||
|
# default, aiding admins in cluster management. Those roles are
|
||||||
|
# not used by the ayatori itself. You can comment the following lines
|
||||||
|
# if you do not want those helpers be installed with your Project.
|
||||||
|
- execution_opensandboxexecutionparameters_admin_role.yaml
|
||||||
|
- execution_opensandboxexecutionparameters_editor_role.yaml
|
||||||
|
- execution_opensandboxexecutionparameters_viewer_role.yaml
|
||||||
|
- execution_kubernetesexecutionparameters_admin_role.yaml
|
||||||
|
- execution_kubernetesexecutionparameters_editor_role.yaml
|
||||||
|
- execution_kubernetesexecutionparameters_viewer_role.yaml
|
||||||
|
- execution_jobclass_admin_role.yaml
|
||||||
|
- execution_jobclass_editor_role.yaml
|
||||||
|
- execution_jobclass_viewer_role.yaml
|
||||||
|
- execution_job_admin_role.yaml
|
||||||
|
- execution_job_editor_role.yaml
|
||||||
|
- execution_job_viewer_role.yaml
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# permissions to do leader election.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: leader-election-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- coordination.k8s.io
|
||||||
|
resources:
|
||||||
|
- leases
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- create
|
||||||
|
- update
|
||||||
|
- patch
|
||||||
|
- delete
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- events
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: leader-election-rolebinding
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: leader-election-role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: metrics-auth-role
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- authentication.k8s.io
|
||||||
|
resources:
|
||||||
|
- tokenreviews
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- apiGroups:
|
||||||
|
- authorization.k8s.io
|
||||||
|
resources:
|
||||||
|
- subjectaccessreviews
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: metrics-auth-rolebinding
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: metrics-auth-role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: metrics-reader
|
||||||
|
rules:
|
||||||
|
- nonResourceURLs:
|
||||||
|
- "/metrics"
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: manager-role
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: manager-rolebinding
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: manager-role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: controller-manager
|
||||||
|
namespace: system
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: execution.ayatori.ddupan.top/v1alpha1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: job-sample
|
||||||
|
spec:
|
||||||
|
jobClassName: default
|
||||||
|
task:
|
||||||
|
image: docker.io/library/alpine:3.22
|
||||||
|
command: ["/bin/sh", "-c"]
|
||||||
|
args: ["echo hello from Ayatori"]
|
||||||
|
ttlSecondsAfterFinished: 3600
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: execution.ayatori.ddupan.top/v1alpha1
|
||||||
|
kind: JobClass
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: default
|
||||||
|
spec:
|
||||||
|
controllerName: execution.ayatori.ddupan.top/kubernetes
|
||||||
|
parametersRef:
|
||||||
|
group: execution.ayatori.ddupan.top
|
||||||
|
kind: KubernetesExecutionParameters
|
||||||
|
name: default
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
apiVersion: execution.ayatori.ddupan.top/v1alpha1
|
||||||
|
kind: KubernetesExecutionParameters
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: default
|
||||||
|
spec:
|
||||||
|
serviceAccountName: ayatori-job
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: execution.ayatori.ddupan.top/v1alpha1
|
||||||
|
kind: OpenSandboxExecutionParameters
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: ayatori
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
name: microvm
|
||||||
|
spec:
|
||||||
|
endpoint: https://opensandbox-api.example.internal
|
||||||
|
apiKeySecretRef:
|
||||||
|
namespace: ayatori-system
|
||||||
|
name: opensandbox-api
|
||||||
|
key: api-key
|
||||||
|
requestMapping: AdmissionOnly
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
## Append samples of your project ##
|
||||||
|
resources:
|
||||||
|
- execution_v1alpha1_job.yaml
|
||||||
|
- execution_v1alpha1_jobclass.yaml
|
||||||
|
- execution_v1alpha1_kubernetesexecutionparameters.yaml
|
||||||
|
- execution_v1alpha1_opensandboxexecutionparameters.yaml
|
||||||
|
# +kubebuilder:scaffold:manifestskustomizesamples
|
||||||
@@ -131,8 +131,12 @@ spec:
|
|||||||
requestMapping: AdmissionOnly
|
requestMapping: AdmissionOnly
|
||||||
allowSecretEnv: true
|
allowSecretEnv: true
|
||||||
allowImageAuth: true
|
allowImageAuth: true
|
||||||
|
allowInsecureHTTP: false
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`endpoint` 默认必须使用 HTTPS。隔离的本地开发环境可以显式设置
|
||||||
|
`allowInsecureHTTP: true` 使用 HTTP;生产配置不得启用该开关。
|
||||||
|
|
||||||
## JobClass spec
|
## JobClass spec
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
module git.ddupan.top/panxiao81/ayatori
|
||||||
|
|
||||||
|
go 1.27.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
k8s.io/api v0.37.0
|
||||||
|
k8s.io/apimachinery v0.37.0
|
||||||
|
k8s.io/client-go v0.37.0
|
||||||
|
sigs.k8s.io/controller-runtime v0.25.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
cel.dev/expr v0.25.1 // indirect
|
||||||
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.1 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/go-logr/zapr v1.3.0 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v1.0.0 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v1.0.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/cmdutils v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/conv v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/fileutils v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/jsonutils v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/loading v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/mangling v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/netutils v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/pools v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/stringutils v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/typeutils v0.27.1 // indirect
|
||||||
|
github.com/go-openapi/swag/yamlutils v0.27.1 // indirect
|
||||||
|
github.com/google/cel-go v0.29.2 // indirect
|
||||||
|
github.com/google/gnostic-models v0.7.0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.24.0 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.2 // indirect
|
||||||
|
github.com/prometheus/common v0.70.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.21.1 // indirect
|
||||||
|
github.com/spf13/cobra v1.10.2 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.44.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.27.1 // indirect
|
||||||
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
|
||||||
|
golang.org/x/net v0.57.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.36.0 // indirect
|
||||||
|
golang.org/x/sync v0.22.0 // indirect
|
||||||
|
golang.org/x/sys v0.47.0 // indirect
|
||||||
|
golang.org/x/term v0.45.0 // indirect
|
||||||
|
golang.org/x/text v0.40.0 // indirect
|
||||||
|
golang.org/x/time v0.15.0 // indirect
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||||
|
google.golang.org/grpc v1.82.1 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
k8s.io/apiextensions-apiserver v0.37.0 // indirect
|
||||||
|
k8s.io/apiserver v0.37.0 // indirect
|
||||||
|
k8s.io/component-base v0.37.0 // indirect
|
||||||
|
k8s.io/klog/v2 v2.140.0 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad // indirect
|
||||||
|
k8s.io/streaming v0.37.0 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20260626114624-be93311217bd // indirect
|
||||||
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||||
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
|
||||||
|
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||||
|
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||||
|
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
|
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||||
|
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
|
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
|
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/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
|
github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
|
||||||
|
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.1/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
|
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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||||
|
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||||
|
github.com/go-openapi/jsonpointer v1.0.0 h1:kR9tHqY0CtZaOPVFm622dPVNhrvYpwr4uCxgL3h1H8s=
|
||||||
|
github.com/go-openapi/jsonpointer v1.0.0/go.mod h1:Z3rw7dWu1p9IgitXCFamSlA5lmDiklEB6vkaxcNZW5Y=
|
||||||
|
github.com/go-openapi/jsonreference v1.0.0 h1:jlmTr6torcd1YgDQvSfNmRtKzYDO4FGBkrAdlAVWnpY=
|
||||||
|
github.com/go-openapi/jsonreference v1.0.0/go.mod h1:jtwdyGbJk0Xhe5Y+rwtglQP6Sb1WZST4rT32LWB+sv0=
|
||||||
|
github.com/go-openapi/swag v0.27.1 h1:VotvOLWW8q/EAxB0YdsBBGC8XYyeL1YwBj2ungAGPNg=
|
||||||
|
github.com/go-openapi/swag v0.27.1/go.mod h1:GTkJPwHfhJp6MWr4/rCh64HVI3Ofu+tcsbfjfHmTxpE=
|
||||||
|
github.com/go-openapi/swag/cmdutils v0.27.1 h1:I7sYqaWVl5mq0NEmNQkAmFDyNin9ufvMX/p2zwtQaOE=
|
||||||
|
github.com/go-openapi/swag/cmdutils v0.27.1/go.mod h1:Sm1MVFMkF6guJJ+pQqHnQA3N0j9qALV3NxzDSv6bETM=
|
||||||
|
github.com/go-openapi/swag/conv v0.27.1 h1:8wi9ZG+olmY1wXphl93EWniPtbSPkXM/feH7FgjsvrU=
|
||||||
|
github.com/go-openapi/swag/conv v0.27.1/go.mod h1:QbqMivkpKhC3g1B1GGGOJ6ANewI3S62dbzYu3Duowqs=
|
||||||
|
github.com/go-openapi/swag/fileutils v0.27.1 h1:QQqBSoi5mW4XpU85nS0mLcA+zAE6vLzrb0QkmLKf9oM=
|
||||||
|
github.com/go-openapi/swag/fileutils v0.27.1/go.mod h1:VvJFZLTZS0AI854gEQz5tk7dBESdLjiNUMSZ/th2ry8=
|
||||||
|
github.com/go-openapi/swag/jsonutils v0.27.1 h1:SVgK3i4USzCU5mibOOS/l4ea2h9UQXy7J7RNLTjuXjU=
|
||||||
|
github.com/go-openapi/swag/jsonutils v0.27.1/go.mod h1:tdlEpZqdcQ17uj6J4YdK9vd8It5qWMwjWXOs0tjpRlk=
|
||||||
|
github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1 h1:mJu3COL9WEaZVp/Kf2PRMi7tPszPEJfSr/OO75ynCs8=
|
||||||
|
github.com/go-openapi/swag/jsonutils/fixtures_test v0.27.1/go.mod h1:mofwUWx70wvskwESqRJ//k/9kURmCgyJl5m5Ppoh5kY=
|
||||||
|
github.com/go-openapi/swag/loading v0.27.1 h1:/DxUgDXKbBX4bcn7r9uEXfJyzN5XpiJmZplzQTjrRCY=
|
||||||
|
github.com/go-openapi/swag/loading v0.27.1/go.mod h1:jvGh3iA2+zyUUycB5fgJWzeHnhrpvGnJJM0RVE9ZShE=
|
||||||
|
github.com/go-openapi/swag/mangling v0.27.1 h1:yC9D0HyUE8gbP+BfmGx9+AA89ikwZTMjESK3OnnoaqA=
|
||||||
|
github.com/go-openapi/swag/mangling v0.27.1/go.mod h1:jtBE2+V+3pILxOR7Vgce+Cwp6A2PgZbvVqfNntbVs0w=
|
||||||
|
github.com/go-openapi/swag/netutils v0.27.1 h1:mICMFoS82F5TZ4Zy3cqmcQk+BFeCp3Uyq3Np7GI0/qU=
|
||||||
|
github.com/go-openapi/swag/netutils v0.27.1/go.mod h1:J+WYyFMLtvtCGqa6jLv+YNUmIKI3ZRQRrvfNDMoQoEQ=
|
||||||
|
github.com/go-openapi/swag/pools v0.27.1 h1:9LeadcMyb2GJCbXX5hVQDbZ2Lq9TL4dCs/nx1j5DO0E=
|
||||||
|
github.com/go-openapi/swag/pools v0.27.1/go.mod h1:kVQefhSK5RWuRe7BXsL8htgBPAMpN7HDGpGEknqugeE=
|
||||||
|
github.com/go-openapi/swag/stringutils v0.27.1 h1:ZXePZ0r2p1qSjo8tD3Un4vFj8+FqlCkczxDrJIhYUp8=
|
||||||
|
github.com/go-openapi/swag/stringutils v0.27.1/go.mod h1:lzRN95CxXmA03XcDWHLOb6nOMcxCqR5rGY0lOgsfRoM=
|
||||||
|
github.com/go-openapi/swag/typeutils v0.27.1 h1:KSTdFlfnse4r6dP9IrEnwMldjE+zs71UeEB3//PtVXc=
|
||||||
|
github.com/go-openapi/swag/typeutils v0.27.1/go.mod h1:Srm0xFNRZ1Y+vCxJclo5qzx8aj+1pAKda/YfFPrG0dQ=
|
||||||
|
github.com/go-openapi/swag/yamlutils v0.27.1 h1:ftxv6xvXb1E3zohUc+okZ9nSqNb9StQX/FXnKZ98sQA=
|
||||||
|
github.com/go-openapi/swag/yamlutils v0.27.1/go.mod h1:bnxFIB1qewGRiZHypXGZ3fNgf13/0HfRgnS/iZBDrOo=
|
||||||
|
github.com/go-openapi/testify/enable/yaml/v2 v2.6.0 h1:gGHwAJ0R/5jU8BEGDbfRNR3hL68dAVi84WuOApp29B0=
|
||||||
|
github.com/go-openapi/testify/enable/yaml/v2 v2.6.0/go.mod h1:tY+St1SGq4NFl0QIqdTY4aEdbChAHxhyB77XQi9iJCo=
|
||||||
|
github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug=
|
||||||
|
github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/google/cel-go v0.29.2 h1:ZtDxkeiMmz0mxbKDYiNkE5Lk7V5edMRcaaDf2jX002k=
|
||||||
|
github.com/google/cel-go v0.29.2/go.mod h1:X0bD6iVNR8pkROSOoHVdgTkzmRcosof7WQqCD6wcMc8=
|
||||||
|
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||||
|
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||||
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
|
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/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/compress v1.19.0 h1:sXLILfc9jV2QYWkzFOPWStmcUVH2RHEB1JCdY2oVvCQ=
|
||||||
|
github.com/klauspost/compress v1.19.0/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||||
|
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
|
||||||
|
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.24.0 h1:5XStIklKuAtJSNpdD3s8XJj/Yv78IQmE1kbNk87JrAI=
|
||||||
|
github.com/prometheus/client_golang v1.24.0/go.mod h1:QcsNdotprC2nS4BTM2ucbcqxd2CeXTEa9jW7zHO9iDE=
|
||||||
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
|
github.com/prometheus/common v0.70.0 h1:bcpru3tWPVnxGnETLgOV5jbp/JRXgYEyv65CuBLAMMI=
|
||||||
|
github.com/prometheus/common v0.70.0/go.mod h1:S/SFasQmgGiYH6C81LKCtYa8QACgthGg5zxL2udV7SY=
|
||||||
|
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
|
||||||
|
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
|
||||||
|
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
|
||||||
|
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
|
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/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
|
||||||
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0 h1:qazEJlUOQzhCpzQpFETGby7EdqjI1wsd0W+6Gg1SCTU=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.44.0/go.mod h1:fOD2Yefuxixkx3ahVNf0O/PERb6r4OlbxfATVnYvzCo=
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
|
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/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
|
||||||
|
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
|
||||||
|
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||||
|
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||||
|
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
|
||||||
|
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
|
||||||
|
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||||
|
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||||
|
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||||
|
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
|
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||||
|
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0=
|
||||||
|
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w=
|
||||||
|
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||||
|
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||||
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
|
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
|
||||||
|
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
|
||||||
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
|
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
|
||||||
|
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
|
||||||
|
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI=
|
||||||
|
google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
k8s.io/api v0.37.0 h1:Z//Vj9N7RA/yS2sDmxyeo7h+RR4zbUrd2vrd3Z0TbB4=
|
||||||
|
k8s.io/api v0.37.0/go.mod h1:LKXgcJWMc+f4OLbP5SFR8rulEg07zZhpi/zMULiBImk=
|
||||||
|
k8s.io/apiextensions-apiserver v0.37.0 h1:zRMQ3+/LIE5oZ0tVvXwYHC+dIkSP5cjNWju7AZU1LOI=
|
||||||
|
k8s.io/apiextensions-apiserver v0.37.0/go.mod h1:HU0PfSBwchHL5iDau6jjt9zU6ryWkDDlaVUiq91NK80=
|
||||||
|
k8s.io/apimachinery v0.37.0 h1:Np2AbDtf8x6RDHiD8T9LbKJ9gaegeVNa8yNm5FuGKm0=
|
||||||
|
k8s.io/apimachinery v0.37.0/go.mod h1:RN3nhprFSCxOi5Selxd7oMTXOe/c+ZbcE7Im+TS2zkE=
|
||||||
|
k8s.io/apiserver v0.37.0 h1:TXg7OxsOWrAH8J4Zi/gBAZuMw1Dfdd+6cca2h4qjRqo=
|
||||||
|
k8s.io/apiserver v0.37.0/go.mod h1:OddHDF4gy9qyIb8o/3+qaeP6S0vEObWLgOygVqXksv0=
|
||||||
|
k8s.io/client-go v0.37.0 h1:nsN31fy8wBySuZ+QRnKmrjRSQLOG2rvoGN0tKd12zhQ=
|
||||||
|
k8s.io/client-go v0.37.0/go.mod h1:FcGqw+Ll/gNQiq+nPGY1Oyt9y7SgDh1d3MW3RFDEbn0=
|
||||||
|
k8s.io/component-base v0.37.0 h1:3SdSa4+itMdFTDFTeR8CxKGmSTSMXFlKL4ky8OqjguM=
|
||||||
|
k8s.io/component-base v0.37.0/go.mod h1:LjOebp4R9y6LODWZQv102ZQxGheLcDO2ZJLAw6bbh4I=
|
||||||
|
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
|
||||||
|
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I=
|
||||||
|
k8s.io/streaming v0.37.0 h1:iPBUZLZiKt5bV+lxJurASMOV07VuBhNpiwJt2//AWrM=
|
||||||
|
k8s.io/streaming v0.37.0/go.mod h1:APlJR26ZWRcVy5bIEj0QRrKUXROtBHPcxl2NT7EAzPU=
|
||||||
|
k8s.io/utils v0.0.0-20260626114624-be93311217bd h1:Ea7fgQ5we8Y9T0OX5o0dAHzQOBRI07D/dEYRaB9ZZEs=
|
||||||
|
k8s.io/utils v0.0.0-20260626114624-be93311217bd/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
|
||||||
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0 h1:/YpDJ4vReG7ZmzSpBGxduXgywWkJU9zHubgJG03MT+Y=
|
||||||
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.36.0/go.mod h1:tJo1aepTXyR+8Xs3sUsGBDk4Ub2AM5dPAPKJx0mpm5c=
|
||||||
|
sigs.k8s.io/controller-runtime v0.25.0 h1:44KgRUPew331KSJpNu8zJow3iTR5W0p/SfrHdw3lV40=
|
||||||
|
sigs.k8s.io/controller-runtime v0.25.0/go.mod h1:4QqLdT6z/L6Olj8JJCtvztid4/fnIiYsfaTFScegctc=
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.4.2 h1:qdOxHwrl2Kaag1aQEarlYcOA9vSyGCp3CIki3aW8c4Q=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.4.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||||
|
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||||
|
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package execution
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
executionv1alpha1 "git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JobState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
JobStateResolving JobState = "Resolving"
|
||||||
|
JobStateScheduling JobState = "Scheduling"
|
||||||
|
JobStateStarting JobState = "Starting"
|
||||||
|
JobStateRunning JobState = "Running"
|
||||||
|
JobStateCancelling JobState = "Cancelling"
|
||||||
|
JobStateResultUnknown JobState = "ResultUnknown"
|
||||||
|
JobStateSucceeded JobState = "Succeeded"
|
||||||
|
JobStateFailed JobState = "Failed"
|
||||||
|
JobStateCancelled JobState = "Cancelled"
|
||||||
|
JobStateDeleting JobState = "Deleting"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StateOf derives a presentation state from durable API facts. The derived
|
||||||
|
// state is deliberately not persisted as a second source of truth.
|
||||||
|
func StateOf(job *executionv1alpha1.Job) JobState {
|
||||||
|
if !job.DeletionTimestamp.IsZero() {
|
||||||
|
return JobStateDeleting
|
||||||
|
}
|
||||||
|
|
||||||
|
succeeded := condition(job.Status.Conditions, executionv1alpha1.JobConditionSucceeded)
|
||||||
|
if succeeded != nil {
|
||||||
|
switch succeeded.Status {
|
||||||
|
case metav1.ConditionTrue:
|
||||||
|
return JobStateSucceeded
|
||||||
|
case metav1.ConditionFalse:
|
||||||
|
if succeeded.Reason == "Cancelled" {
|
||||||
|
return JobStateCancelled
|
||||||
|
}
|
||||||
|
return JobStateFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if job.Spec.DesiredState == executionv1alpha1.JobDesiredStateCancelled {
|
||||||
|
return JobStateCancelling
|
||||||
|
}
|
||||||
|
if succeeded != nil && succeeded.Status == metav1.ConditionUnknown && succeeded.Reason == "ResultUnknown" {
|
||||||
|
return JobStateResultUnknown
|
||||||
|
}
|
||||||
|
if job.Status.StartTime != nil {
|
||||||
|
return JobStateRunning
|
||||||
|
}
|
||||||
|
if conditionTrue(job.Status.Conditions, executionv1alpha1.JobConditionScheduled) {
|
||||||
|
return JobStateStarting
|
||||||
|
}
|
||||||
|
if conditionTrue(job.Status.Conditions, executionv1alpha1.JobConditionAccepted) {
|
||||||
|
return JobStateScheduling
|
||||||
|
}
|
||||||
|
return JobStateResolving
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateStatus checks invariants that every adapter must preserve.
|
||||||
|
func ValidateStatus(job *executionv1alpha1.Job) error {
|
||||||
|
succeeded := condition(job.Status.Conditions, executionv1alpha1.JobConditionSucceeded)
|
||||||
|
terminal := succeeded != nil && (succeeded.Status == metav1.ConditionTrue || succeeded.Status == metav1.ConditionFalse)
|
||||||
|
if terminal && job.Status.CompletionTime == nil {
|
||||||
|
return fmt.Errorf("terminal job must have completionTime")
|
||||||
|
}
|
||||||
|
if job.Status.CompletionTime != nil && !terminal {
|
||||||
|
return fmt.Errorf("completionTime requires a terminal Succeeded condition")
|
||||||
|
}
|
||||||
|
if job.Status.StartTime != nil && !conditionTrue(job.Status.Conditions, executionv1alpha1.JobConditionScheduled) {
|
||||||
|
return fmt.Errorf("startTime requires Scheduled=True")
|
||||||
|
}
|
||||||
|
if job.Status.StartTime != nil && job.Status.CompletionTime != nil && job.Status.CompletionTime.Before(job.Status.StartTime) {
|
||||||
|
return fmt.Errorf("completionTime must not precede startTime")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func condition(conditions []metav1.Condition, conditionType string) *metav1.Condition {
|
||||||
|
for i := range conditions {
|
||||||
|
if conditions[i].Type == conditionType {
|
||||||
|
return &conditions[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func conditionTrue(conditions []metav1.Condition, conditionType string) bool {
|
||||||
|
current := condition(conditions, conditionType)
|
||||||
|
return current != nil && current.Status == metav1.ConditionTrue
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package execution
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
executionv1alpha1 "git.ddupan.top/panxiao81/ayatori/api/execution/v1alpha1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStateOf(t *testing.T) {
|
||||||
|
now := metav1.NewTime(time.Now())
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
job executionv1alpha1.Job
|
||||||
|
want JobState
|
||||||
|
}{
|
||||||
|
{name: "resolving", want: JobStateResolving},
|
||||||
|
{name: "scheduling", job: jobWithConditions(newCondition(executionv1alpha1.JobConditionAccepted, metav1.ConditionTrue, "Valid")), want: JobStateScheduling},
|
||||||
|
{name: "starting", job: jobWithConditions(newCondition(executionv1alpha1.JobConditionScheduled, metav1.ConditionTrue, "BackendCreated")), want: JobStateStarting},
|
||||||
|
{name: "running", job: executionv1alpha1.Job{Status: executionv1alpha1.JobStatus{StartTime: &now}}, want: JobStateRunning},
|
||||||
|
{name: "result unknown", job: jobWithConditions(newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionUnknown, "ResultUnknown")), want: JobStateResultUnknown},
|
||||||
|
{name: "cancelling", job: executionv1alpha1.Job{Spec: executionv1alpha1.JobSpec{DesiredState: executionv1alpha1.JobDesiredStateCancelled}}, want: JobStateCancelling},
|
||||||
|
{name: "succeeded", job: jobWithConditions(newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionTrue, "Completed")), want: JobStateSucceeded},
|
||||||
|
{name: "failed", job: jobWithConditions(newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionFalse, "ExitCode")), want: JobStateFailed},
|
||||||
|
{name: "cancelled", job: jobWithConditions(newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionFalse, "Cancelled")), want: JobStateCancelled},
|
||||||
|
{name: "terminal beats desired cancellation", job: func() executionv1alpha1.Job {
|
||||||
|
j := jobWithConditions(newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionTrue, "Completed"))
|
||||||
|
j.Spec.DesiredState = executionv1alpha1.JobDesiredStateCancelled
|
||||||
|
return j
|
||||||
|
}(), want: JobStateSucceeded},
|
||||||
|
{name: "deleting beats terminal", job: func() executionv1alpha1.Job {
|
||||||
|
j := jobWithConditions(newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionTrue, "Completed"))
|
||||||
|
j.DeletionTimestamp = &now
|
||||||
|
return j
|
||||||
|
}(), want: JobStateDeleting},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := StateOf(&tt.job); got != tt.want {
|
||||||
|
t.Fatalf("StateOf() = %q, want %q", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateStatus(t *testing.T) {
|
||||||
|
start := metav1.NewTime(time.Unix(100, 0))
|
||||||
|
finish := metav1.NewTime(time.Unix(200, 0))
|
||||||
|
earlier := metav1.NewTime(time.Unix(50, 0))
|
||||||
|
scheduled := newCondition(executionv1alpha1.JobConditionScheduled, metav1.ConditionTrue, "BackendCreated")
|
||||||
|
succeeded := newCondition(executionv1alpha1.JobConditionSucceeded, metav1.ConditionTrue, "Completed")
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
status executionv1alpha1.JobStatus
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{name: "empty status"},
|
||||||
|
{name: "running", status: executionv1alpha1.JobStatus{Conditions: []metav1.Condition{scheduled}, StartTime: &start}},
|
||||||
|
{name: "completed", status: executionv1alpha1.JobStatus{Conditions: []metav1.Condition{scheduled, succeeded}, StartTime: &start, CompletionTime: &finish}},
|
||||||
|
{name: "terminal without completion time", status: executionv1alpha1.JobStatus{Conditions: []metav1.Condition{succeeded}}, wantErr: true},
|
||||||
|
{name: "completion without terminal", status: executionv1alpha1.JobStatus{CompletionTime: &finish}, wantErr: true},
|
||||||
|
{name: "start without scheduling", status: executionv1alpha1.JobStatus{StartTime: &start}, wantErr: true},
|
||||||
|
{name: "completion before start", status: executionv1alpha1.JobStatus{Conditions: []metav1.Condition{scheduled, succeeded}, StartTime: &start, CompletionTime: &earlier}, wantErr: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := ValidateStatus(&executionv1alpha1.Job{Status: tt.status})
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Fatalf("ValidateStatus() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCondition(conditionType string, status metav1.ConditionStatus, reason string) metav1.Condition {
|
||||||
|
return metav1.Condition{Type: conditionType, Status: status, Reason: reason}
|
||||||
|
}
|
||||||
|
|
||||||
|
func jobWithConditions(conditions ...metav1.Condition) executionv1alpha1.Job {
|
||||||
|
return executionv1alpha1.Job{Status: executionv1alpha1.JobStatus{Conditions: conditions}}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user