diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..a3aab7a --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,3 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore build and test binaries. +bin/ diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..7f02333 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,26 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* +Dockerfile.cross + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +.vscode +*.swp +*.swo +*~ diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..93c493b --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,37 @@ +# Build the manager binary +FROM golang:1.20 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 +ENV GOPROXY=https://goproxy.cn,direct GO111MODULE=on +RUN go mod download + +# Copy the go source +COPY cmd/main.go cmd/main.go +COPY api/ api/ +COPY internal/controller/ internal/controller/ +COPY watcher watcher +COPY pkg pkg +COPY apiserver apiserver + +# Build +# the GOARCH has not a default value to allow the binary 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"] diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 0000000..5026be7 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,174 @@ + +# Image URL to use all building/pushing image targets +VER := $(shell git rev-parse HEAD) +VER_DEV := $(shell date +%m%d%H%M%S) +IMG ?= registry.zelda.io/zelda:${VER} +IMG_DEV ?= registry.zelda.io/zelda:${VER_DEV} +# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. +ENVTEST_K8S_VERSION = 1.28.0 + +# 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\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:headerFile="hack/boilerplate.go.txt" 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 envtest ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out + +##@ 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/ +.PHONY: docker-build +docker-build: ## Build docker image with the manager. + $(CONTAINER_TOOL) build -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=> 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 project-v3-builder + $(CONTAINER_TOOL) buildx use project-v3-builder + - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - $(CONTAINER_TOOL) buildx rm project-v3-builder + rm Dockerfile.cross + +##@ 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. + $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - + +.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. + $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - + +.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: ## 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 - + +##@ Build 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 + +## Tool Versions +KUSTOMIZE_VERSION ?= v5.1.1 +CONTROLLER_TOOLS_VERSION ?= v0.13.0 + +.PHONY: kustomize +kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. If wrong version is installed, it will be removed before downloading. +$(KUSTOMIZE): $(LOCALBIN) + @if test -x $(LOCALBIN)/kustomize && ! $(LOCALBIN)/kustomize version | grep -q $(KUSTOMIZE_VERSION); then \ + echo "$(LOCALBIN)/kustomize version is not expected $(KUSTOMIZE_VERSION). Removing it before installing."; \ + rm -rf $(LOCALBIN)/kustomize; \ + fi + test -s $(LOCALBIN)/kustomize || GOBIN=$(LOCALBIN) GO111MODULE=on go install sigs.k8s.io/kustomize/kustomize/v5@$(KUSTOMIZE_VERSION) + +.PHONY: controller-gen +controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. If wrong version is installed, it will be overwritten. +$(CONTROLLER_GEN): $(LOCALBIN) + test -s $(LOCALBIN)/controller-gen && $(LOCALBIN)/controller-gen --version | grep -q $(CONTROLLER_TOOLS_VERSION) || \ + GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION) + +.PHONY: envtest +envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. +$(ENVTEST): $(LOCALBIN) + test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest + +minikube-build: + $(shell eval $$(minikube -p minikube docker-env); docker build --build-arg VERSION=${VER_DEV} --build-arg MODE=Debug -t ${IMG_DEV} .) + +.PHONY: minikube-deploy +minikube-deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG_DEV} + $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - \ No newline at end of file diff --git a/backend/PROJECT b/backend/PROJECT new file mode 100644 index 0000000..7dd3454 --- /dev/null +++ b/backend/PROJECT @@ -0,0 +1,101 @@ +# 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 +domain: zelda.io +layout: +- go.kubebuilder.io/v4 +projectName: zelda +repo: github.com/ycyxuehan/zelda +resources: +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZProject + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZService + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZUser + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZGroup + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZRegistry + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZScript + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZBuildTemplate + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZRunTemplate + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZBuilder + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: zelda.io + group: zelda.io + kind: ZCustomHost + path: github.com/ycyxuehan/zelda/api/v1alpha1 + version: v1alpha1 +version: "3" diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..e331efc --- /dev/null +++ b/backend/README.md @@ -0,0 +1,94 @@ +# zelda +// TODO(user): Add simple overview of use/purpose + +## Description +// TODO(user): An in-depth paragraph about your project and overview of use + +## Getting Started +You’ll need a Kubernetes cluster to run against. You can use [KIND](https://sigs.k8s.io/kind) to get a local cluster for testing, or run against a remote cluster. +**Note:** Your controller will automatically use the current context in your kubeconfig file (i.e. whatever cluster `kubectl cluster-info` shows). + +### Running on the cluster +1. Install Instances of Custom Resources: + +```sh +kubectl apply -k config/samples/ +``` + +2. Build and push your image to the location specified by `IMG`: + +```sh +make docker-build docker-push IMG=/zelda:tag +``` + +3. Deploy the controller to the cluster with the image specified by `IMG`: + +```sh +make deploy IMG=/zelda:tag +``` + +### Uninstall CRDs +To delete the CRDs from the cluster: + +```sh +make uninstall +``` + +### Undeploy controller +UnDeploy the controller from the cluster: + +```sh +make undeploy +``` + +## Contributing +// TODO(user): Add detailed information on how you would like others to contribute to this project + +### How it works +This project aims to follow the Kubernetes [Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/). + +It uses [Controllers](https://kubernetes.io/docs/concepts/architecture/controller/), +which provide a reconcile function responsible for synchronizing resources until the desired state is reached on the cluster. + +### Test It Out +1. Install the CRDs into the cluster: + +```sh +make install +``` + +2. Run your controller (this will run in the foreground, so switch to a new terminal if you want to leave it running): + +```sh +make run +``` + +**NOTE:** You can also run this in one step by running: `make install run` + +### Modifying the API definitions +If you are editing the API definitions, generate the manifests such as CRs or CRDs using: + +```sh +make manifests +``` + +**NOTE:** Run `make --help` for more information on all potential `make` targets + +More information can be found via the [Kubebuilder Documentation](https://book.kubebuilder.io/introduction.html) + +## License + +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + diff --git a/backend/api/v1alpha1/groupversion_info.go b/backend/api/v1alpha1/groupversion_info.go new file mode 100644 index 0000000..a1c13c1 --- /dev/null +++ b/backend/api/v1alpha1/groupversion_info.go @@ -0,0 +1,36 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package v1alpha1 contains API Schema definitions for the zelda.io v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=zelda.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "zelda.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) diff --git a/backend/api/v1alpha1/zbuilder_types.go b/backend/api/v1alpha1/zbuilder_types.go new file mode 100644 index 0000000..c49087a --- /dev/null +++ b/backend/api/v1alpha1/zbuilder_types.go @@ -0,0 +1,331 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "path" + "strings" + + "github.com/ycyxuehan/zelda/pkg/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type Phase string + +const ( + PhaseCreating Phase = "Creating" + PhaseInitial Phase = "Initial" + PhaseBuild Phase = "Build" + PhasePackage Phase = "Package" + PhaseDeploy Phase = "Deploy" + PhaseCompleted Phase = "Completed" + PhasePending Phase = "Pending" + Succeeded string = "Succeeded" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +//Step status +type StepStatus struct { + Name string `json:"name,omitempty"` + Phase corev1.PodPhase `json:"phase,omitempty"` + StartedAt metav1.Time `json:"startedAt,omitempty"` + FinishedAt metav1.Time `json:"finishedAt,omitempty"` + Started *bool `json:"started,omitempty"` + Ready bool `json:"ready,omitempty"` + Message string `json:"message,omitempty"` + Reason string `json:"reason,omitempty"` + // corev1.ContainerStatus +} + +func NewStepStatus(status corev1.ContainerStatus) StepStatus { + stepStatus := StepStatus{} + stepStatus.Started = status.Started + stepStatus.Ready = status.Ready + stepStatus.Name = status.Name + //等待 + if status.State.Waiting != nil { + stepStatus.Phase = corev1.PodPending + stepStatus.Message = status.State.Waiting.Message + stepStatus.Reason = status.State.Waiting.Reason + } + //运行中 + if status.State.Running != nil { + stepStatus.Phase = corev1.PodRunning + stepStatus.StartedAt = status.State.Running.StartedAt + } + if status.State.Terminated != nil { + if status.State.Terminated.ExitCode != 0 { + stepStatus.Phase = corev1.PodFailed + } else { + stepStatus.Phase = corev1.PodPhase(PhaseCompleted) + } + stepStatus.FinishedAt = status.State.Terminated.FinishedAt + stepStatus.Reason = status.State.Terminated.Reason + } + + return stepStatus +} + +// ZBuilderSpec defines the desired state of ZBuilder +type ZBuilderSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZBuilder. Edit zbuilder_types.go to remove/update + // Foo string `json:"foo,omitempty"` + Project corev1.ObjectReference `json:"project,omitempty"` + SubProject string `json:"subProject,omitempty"` + Branch string `json:"branch,omitempty"` + CommitHash string `json:"commitHash,omitempty"` + ZService corev1.ObjectReference `json:"zservice,omitempty"` + Creator string `json:"creator,omitempty"` + Build bool `json:"build,omitempty"` + Package bool `json:"package,omitempty"` + Deploy bool `json:"deploy,omitempty"` +} + +// ZBuilderStatus defines the observed state of ZBuilder +type ZBuilderStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + Steps []StepStatus `json:"steps,omitempty"` + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + FinishedAt *metav1.Time `json:"finishedAt,omitempty"` + Phase Phase `json:"phase,omitempty"` + Message string `json:"message,omitempty"` + Reason string `json:"reason,omitempty"` + RunAt string `json:"RunAt,omitempty"` +} + +func NewZbuilderStatus(podStatus *corev1.PodStatus) ZBuilderStatus { + zbuilderStatus := ZBuilderStatus{} + if podStatus == nil { + return zbuilderStatus + } + + for _, cs := range podStatus.ContainerStatuses { + zbuilderStatus.Steps = append(zbuilderStatus.Steps, NewStepStatus(cs)) + } + zbuilderStatus.CreatedAt = podStatus.StartTime + switch podStatus.Phase { + case corev1.PodPending: + zbuilderStatus.Phase = PhasePending + case corev1.PodRunning: + zbuilderStatus.Phase = PhaseBuild + } + + zbuilderStatus.Message = podStatus.Message + zbuilderStatus.RunAt = podStatus.HostIP + + return zbuilderStatus +} + +func (zbuilderStatus *ZBuilderStatus) SetPhase(phase Phase) { + zbuilderStatus.Phase = phase +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZBuilder is the Schema for the zbuilders API +type ZBuilder struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZBuilderSpec `json:"spec,omitempty"` + Status ZBuilderStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZBuilderList contains a list of ZBuilder +type ZBuilderList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZBuilder `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZBuilder{}, &ZBuilderList{}) +} + +//返回workdir的volume mount +func (zb *ZBuilder) VolumeMountWorkDir() corev1.VolumeMount { + return corev1.VolumeMount{ + Name: "workdir", + MountPath: "/workdir", + } +} + +//返回dockerconfig 的volumeMount +func (zb *ZBuilder) VolumeMountDockerConfig() corev1.VolumeMount { + return corev1.VolumeMount{ + Name: "dockerconfig", + MountPath: "/root/.docker", + } +} + +//返回workdir的volume +func (zb *ZBuilder) VolumeWorkDir() corev1.Volume { + return corev1.Volume{ + Name: "workdir", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{}, + }, + } +} + +func (zb *ZBuilder) VolumeDockerConfig(secret string) corev1.Volume { + return corev1.Volume{ + Name: "dockerconfig", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secret, + }, + }, + } +} + +//编译容器 +func (zb *ZBuilder) Containers(template *ZBuildTemplateSpec, workdir string) []corev1.Container { + containers := []corev1.Container{} + for _, step := range template.Steps { + volumeMounts := []corev1.VolumeMount{zb.VolumeMountWorkDir(), zb.VolumeMountDockerConfig()} + volumeMounts = append(volumeMounts, step.VolumeMounts...) + container := corev1.Container{ + Image: step.Image, + VolumeMounts: volumeMounts, + Args: step.Args, + Command: step.Commands, + Env: utils.MergeEnv(utils.MergeOverrideByFirst, zb.DefaultEnv(), step.Env), + Name: step.Name, + WorkingDir: workdir, + } + containers = append(containers, container) + } + return containers +} + +//初始化容器,下载git文件 +func (zb *ZBuilder) InitContainers(gitImage, gitRepo, dockerfile, dockerfilePath string) []corev1.Container { + containers := []corev1.Container{ + //下载git仓库 + { + Image: gitImage, + VolumeMounts: []corev1.VolumeMount{zb.VolumeMountWorkDir()}, + Command: []string{"git"}, + Args: []string{"clone", "-b", zb.Spec.Branch, gitRepo}, + WorkingDir: "/workdir", + }, + //写入Dockerfile + { + Image: gitImage, + VolumeMounts: []corev1.VolumeMount{zb.VolumeMountWorkDir()}, + Command: []string{"echo"}, + Args: []string{"-e", "${DOCKERFILE}", ">", dockerfilePath}, + WorkingDir: "/workdir", + Env: []corev1.EnvVar{ + { + Name: "DOCKERFILE", + Value: dockerfile, + }, + }, + }, + } + return containers +} + +//根据builder创建podspec +func (zb *ZBuilder) PodSpec(template *ZBuildTemplateSpec, gitImage string, gitRepo string, subProject *SubProject, registry *ZRegistry) corev1.PodSpec { + vols := []corev1.Volume{zb.VolumeWorkDir(), zb.VolumeDockerConfig(registry.GetName())} + vols = append(vols, subProject.BuildSpec.Volumes...) + spec := corev1.PodSpec{ + InitContainers: zb.InitContainers(gitImage, gitRepo, subProject.BuildSpec.Dockerfile, zb.WorkPath(zb.RepoPath(gitRepo), subProject.Path, "Dockerfile")), + Containers: zb.Containers(template, zb.WorkPath(zb.RepoPath(gitRepo), subProject.Path)), + // ImagePullSecrets: secrets, + Volumes: vols, + RestartPolicy: corev1.RestartPolicyNever, + } + return spec +} + +func (zb *ZBuilder) Pod(template *ZBuildTemplateSpec, gitImage string, gitRepo string, subProject *SubProject, registry *ZRegistry) corev1.Pod { + spec := zb.PodSpec(template, gitImage, gitRepo, subProject, registry) + pod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: zb.GetName(), + Namespace: zb.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zb.Owner(), + }, + Labels: zb.ResourceLabels(), + }, + Spec: spec, + } + return pod +} + +//根据repo获取project path +func (zb *ZBuilder) RepoPath(repo string) string { + strs := strings.Split(repo, "/") + if len(strs) < 1 { + return "" + } + str := strs[len(strs)-1] + strs = strings.Split(str, ".") + if len(strs) < 1 { + return str + } + return strs[0] +} + +func (zb *ZBuilder) WorkPath(spath ...string) string { + return path.Join("/workdir", path.Join(spath...)) +} + +//这里返回默认env,默认env提供一些基本信息 +func (zb *ZBuilder) DefaultEnv() []corev1.EnvVar { + return []corev1.EnvVar{ + {Name: "BRANCH", Value: zb.Spec.Branch}, + {Name: "COMMIT_HASH", Value: zb.Spec.CommitHash}, + } +} + +//Owner +func (zb *ZBuilder) Owner() metav1.OwnerReference { + bTrue := true + return metav1.OwnerReference{ + APIVersion: GroupVersion.Version, + Kind: "ZBuilder", + Name: zb.GetName(), + BlockOwnerDeletion: &bTrue, + Controller: &bTrue, + UID: zb.GetUID(), + } +} + +//Labels +func (zb *ZBuilder) ResourceLabels() map[string]string { + labels := make(map[string]string) + labels["builders.zelda.io"] = zb.Name + labels["projects.zelda.io"] = zb.Spec.Project.Name + labels["users.zelda.io"] = zb.Spec.Creator + labels["projects.zelda.io/branch"] = zb.Spec.Branch + return labels +} diff --git a/backend/api/v1alpha1/zbuildtemplate_types.go b/backend/api/v1alpha1/zbuildtemplate_types.go new file mode 100644 index 0000000..9619b67 --- /dev/null +++ b/backend/api/v1alpha1/zbuildtemplate_types.go @@ -0,0 +1,76 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +type BuildStep struct { + Name string `json:"name,omitempty"` + Image string `json:"image,omitempty"` + Commands []string `json:"commands,omitempty"` + VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"` + Env []corev1.EnvVar `json:"env,omitempty"` + Args []string `json:"args,omitempty"` +} + +// ZBuildTemplateSpec defines the desired state of ZBuildTemplate +type ZBuildTemplateSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZBuildTemplate. Edit zbuildtemplate_types.go to remove/update + // Foo string `json:"foo,omitempty"` + Steps []BuildStep `json:"steps,omitempty"` + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` +} + +// ZBuildTemplateStatus defines the observed state of ZBuildTemplate +type ZBuildTemplateStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZBuildTemplate is the Schema for the zbuildtemplates API +type ZBuildTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZBuildTemplateSpec `json:"spec,omitempty"` + Status ZBuildTemplateStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZBuildTemplateList contains a list of ZBuildTemplate +type ZBuildTemplateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZBuildTemplate `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZBuildTemplate{}, &ZBuildTemplateList{}) +} diff --git a/backend/api/v1alpha1/zcustomhost_types.go b/backend/api/v1alpha1/zcustomhost_types.go new file mode 100644 index 0000000..9a27fc4 --- /dev/null +++ b/backend/api/v1alpha1/zcustomhost_types.go @@ -0,0 +1,66 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ZCustomHostSpec defines the desired state of ZCustomHost +type ZCustomHostSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZCustomHost. Edit zcustomhost_types.go to remove/update + // Foo string `json:"foo,omitempty"` + HostAlias []corev1.HostAlias `json:"hostAlias,omitempty"` +} + +// ZCustomHostStatus defines the observed state of ZCustomHost +type ZCustomHostStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZCustomHost is the Schema for the zcustomhosts API +type ZCustomHost struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZCustomHostSpec `json:"spec,omitempty"` + Status ZCustomHostStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZCustomHostList contains a list of ZCustomHost +type ZCustomHostList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZCustomHost `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZCustomHost{}, &ZCustomHostList{}) +} diff --git a/backend/api/v1alpha1/zgroup_types.go b/backend/api/v1alpha1/zgroup_types.go new file mode 100644 index 0000000..c3f8690 --- /dev/null +++ b/backend/api/v1alpha1/zgroup_types.go @@ -0,0 +1,174 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "encoding/json" + "fmt" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ZGroupSpec defines the desired state of ZGroup +type ZGroupSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZGroup. Edit zgroup_types.go to remove/update + // Foo string `json:"foo,omitempty"` + Rulers []rbacv1.PolicyRule `json:"rulers,omitempty"` + ClusterRulers []rbacv1.PolicyRule `json:"clusterRulers,omitempty"` + Secrets []corev1.ObjectReference `json:"secrets,omitempty"` +} + +// ZGroupStatus defines the observed state of ZGroup +type ZGroupStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZGroup is the Schema for the zgroups API +type ZGroup struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZGroupSpec `json:"spec,omitempty"` + Status ZGroupStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZGroupList contains a list of ZGroup +type ZGroupList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZGroup `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZGroup{}, &ZGroupList{}) +} + +func (zg *ZGroup) Owner() metav1.OwnerReference { + bTrue := true + return metav1.OwnerReference{ + Name: zg.GetName(), + APIVersion: GroupVersion.Version, + Kind: "ZGroup", + UID: zg.GetUID(), + Controller: &bTrue, + BlockOwnerDeletion: &bTrue, + } +} + +func (zg *ZGroup) ResourceLabels() map[string]string { + labels := make(map[string]string) + labels["groups.zelda.io"] = zg.GetName() + return labels +} + +//返回Role +func (zg *ZGroup) Role() *rbacv1.Role { + if len(zg.Spec.Rulers) == 0 { + return nil + } + role := rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: zg.Name, + Namespace: zg.Namespace, + OwnerReferences: []metav1.OwnerReference{ + zg.Owner(), + }, + Labels: zg.ResourceLabels(), + }, + Rules: zg.Spec.Rulers, + } + return &role +} + +//返回ClusterRole +func (zg *ZGroup) ClusterRole() *rbacv1.ClusterRole { + if len(zg.Spec.Rulers) == 0 { + return nil + } + role := rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: zg.Name, + OwnerReferences: []metav1.OwnerReference{ + zg.Owner(), + }, + Labels: zg.ResourceLabels(), + }, + Rules: zg.Spec.ClusterRulers, + } + return &role +} + +//返回zgroup是否有变更 +func (zg *ZGroup) IsSpecChanged() (bool, error) { + old := ZGroup{} + latestConfiguration, ok := zg.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"] + if !ok { + return false, fmt.Errorf("not found annotation") + } + err := json.Unmarshal([]byte(latestConfiguration), &old) + if err != nil { //无法获得旧配置 + return false, err + } + + oldString, err := json.Marshal(&old.Spec) + if err != nil { + return false, err + } + newString, err := json.Marshal(&zg.Spec) + if err != nil { + return false, err + } + if string(oldString) != string(newString) { + return true, nil + } + return false, nil +} + +//返回role的namespacedname +func (zg *ZGroup) NamespacedNameRole() types.NamespacedName { + return types.NamespacedName{ + Namespace: zg.GetNamespace(), + Name: zg.GetName(), + } +} + +//返回cluster role的namespaced name +func (zg *ZGroup) NamespacedNameClusterRole() types.NamespacedName { + return types.NamespacedName{ + Name: zg.GetName(), + } +} + +//ruler和cluster ruler 都为空时,返回true +func (zg *ZGroup) IsEmpty() bool { + return len(zg.Spec.Rulers) == 0 && len(zg.Spec.ClusterRulers) == 0 +} diff --git a/backend/api/v1alpha1/zproject_types.go b/backend/api/v1alpha1/zproject_types.go new file mode 100644 index 0000000..4bda922 --- /dev/null +++ b/backend/api/v1alpha1/zproject_types.go @@ -0,0 +1,103 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +type GitSpec struct { + Repo string `json:"repo,omitempty"` + ID int `json:"id,omitempty"` +} + +type BuildSpec struct { + Template corev1.ObjectReference `json:"template,omitempty"` + Volumes []corev1.Volume `json:"volumes,omitempty"` + Dockerfile string `json:"dockerfile,omitempty"` +} + +type SubProject struct { + Name string `json:"name,omitempty"` + Path string `json:"path,omitempty"` + BuildSpec BuildSpec `json:"buildSpec,omitempty"` + // RunSpec RunSpec `json:"runSpec,omitempty"` +} + +// ZProjectSpec defines the desired state of ZProject +type ZProjectSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZProject. Edit zproject_types.go to remove/update + //Foo string `json:"foo,omitempty"` + Git GitSpec `json:"git,omitempty"` + Registry corev1.ObjectReference `json:"registry,omitempty"` + // ImageName string `json:"imageName,omitempty"` + SubProjects []SubProject `json:"subProjects,omitempty"` +} + +// ZProjectStatus defines the observed state of ZProject +type ZProjectStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZProject is the Schema for the zprojects API +type ZProject struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZProjectSpec `json:"spec,omitempty"` + Status ZProjectStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZProjectList contains a list of ZProject +type ZProjectList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZProject `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZProject{}, &ZProjectList{}) +} + +func (zp *ZProject) SubProject(name string) *SubProject { + for _, sub := range zp.Spec.SubProjects { + if sub.Name == name { + return &sub + } + } + return nil +} + +func (zp *ZProject) NamespacedNameRegistry() types.NamespacedName { + return types.NamespacedName{ + Namespace: zp.Spec.Registry.Namespace, + Name: zp.Spec.Registry.Name, + } +} diff --git a/backend/api/v1alpha1/zregistry_types.go b/backend/api/v1alpha1/zregistry_types.go new file mode 100644 index 0000000..eeaf8bf --- /dev/null +++ b/backend/api/v1alpha1/zregistry_types.go @@ -0,0 +1,194 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/ycyxuehan/zelda/pkg/utils" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ZRegistrySpec defines the desired state of ZRegistry +type ZRegistrySpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZRegistry. Edit zregistry_types.go to remove/update + // Foo string `json:"foo,omitempty"` + Server string `json:"server,omitempty"` + Namespace string `json:"namespace,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Portal string `json:"portal,omitempty"` +} + +// ZRegistryStatus defines the observed state of ZRegistry +type ZRegistryStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZRegistry is the Schema for the zregistries API +type ZRegistry struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZRegistrySpec `json:"spec,omitempty"` + Status ZRegistryStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZRegistryList contains a list of ZRegistry +type ZRegistryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZRegistry `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZRegistry{}, &ZRegistryList{}) +} + +//返回imagetag的registry部分 +func (zr *ZRegistry) FullImageTag(baseTag string) string { + if zr.Spec.Server == "" { + return baseTag + } + if zr.Spec.Namespace == "" { + return strings.Join([]string{zr.Spec.Server, baseTag}, "/") + } + return strings.Join([]string{zr.Spec.Server, zr.Spec.Namespace, baseTag}, "/") +} + +//返回登陆registry的secret名称,不需要登陆,返回空 +func (zr *ZRegistry) ImagePullSecretName() string { + if zr.Spec.Username == "" || zr.Spec.Password == "" { + return "" + } + return zr.GetName() +} + +//返回登陆registry的secret reference,不需要登陆,返回nil +func (zr *ZRegistry) ImagePullSecret() *corev1.LocalObjectReference { + if zr.Spec.Username == "" || zr.Spec.Password == "" { + return nil + } + return &corev1.LocalObjectReference{ + Name: zr.GetName(), + } +} + +//返回子资源secret的namespaced name +func (zr *ZRegistry) NamespacedNameSecret() types.NamespacedName { + return types.NamespacedName{ + Namespace: zr.GetNamespace(), + Name: zr.GetName(), + } +} + +//返回子资源secret的name +func (zr *ZRegistry) SecreteName() string { + return zr.GetName() +} + +// +func (zr *ZRegistry) Owner() metav1.OwnerReference { + bTrue := true + return metav1.OwnerReference{ + Name: zr.GetName(), + APIVersion: GroupVersion.Version, + Kind: "ZRegistry", + UID: zr.GetUID(), + Controller: &bTrue, + BlockOwnerDeletion: &bTrue, + } +} + +func (zr *ZRegistry) ResourceLabels() map[string]string { + labels := make(map[string]string) + labels["registries.zelda.io"] = zr.GetName() + return labels +} + +//返回指定namespace的secret +func (zr *ZRegistry) NamespacedSecret(namespace string) *corev1.Secret { + stringData := make(map[string]string) + config := utils.NewDockerConfig(zr.Spec.Server, zr.Spec.Username, zr.Spec.Password) + stringData["config.json"] = config.String() + stringData[".dockerconfigjson"] = config.String() + secret := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: zr.GetName(), + Namespace: namespace, + OwnerReferences: []metav1.OwnerReference{ + zr.Owner(), + }, + Labels: zr.ResourceLabels(), + }, + StringData: stringData, + } + return &secret +} + +//返回registry所在namespace的secrete +func (zr *ZRegistry) Secret() *corev1.Secret { + return zr.NamespacedSecret(zr.GetNamespace()) +} + +func (zr *ZRegistry) SecretReference() corev1.LocalObjectReference { + return corev1.LocalObjectReference{ + Name: zr.GetName(), + } +} + +//返回zuser是否有变更 +func (zr *ZRegistry) IsSpecChanged() (bool, error) { + old := ZRegistry{} + latestConfiguration, ok := zr.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"] + if !ok { + return false, fmt.Errorf("not found annotation") + } + err := json.Unmarshal([]byte(latestConfiguration), &old) + if err != nil { //无法获得旧配置 + return false, err + } + + oldString, err := json.Marshal(&old.Spec) + if err != nil { + return false, err + } + newString, err := json.Marshal(&zr.Spec) + if err != nil { + return false, err + } + if string(oldString) != string(newString) { + return true, nil + } + return false, nil +} diff --git a/backend/api/v1alpha1/zruntemplate_types.go b/backend/api/v1alpha1/zruntemplate_types.go new file mode 100644 index 0000000..fa41043 --- /dev/null +++ b/backend/api/v1alpha1/zruntemplate_types.go @@ -0,0 +1,72 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ZRunTemplateSpec defines the desired state of ZRunTemplate +type ZRunTemplateSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZRunTemplate. Edit zruntemplate_types.go to remove/update + // Foo string `json:"foo,omitempty"` + // corev1.PodSpec `json:",inline"` + InitContainers []corev1.Container `json:"initContainers,omitempty"` + Containers []corev1.Container `json:"containers,omitempty"` + RestartPolicy corev1.RestartPolicy `json:"restartPolicy,omitempty"` + // Anffinity *corev1.Affinity `json:"anffinity,omitempty"` + Dockerfile string `json:"dockerfile,omitempty"` + Type string `json:"type,omitempty"` +} + +// ZRunTemplateStatus defines the observed state of ZRunTemplate +type ZRunTemplateStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZRunTemplate is the Schema for the zruntemplates API +type ZRunTemplate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZRunTemplateSpec `json:"spec,omitempty"` + Status ZRunTemplateStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZRunTemplateList contains a list of ZRunTemplate +type ZRunTemplateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZRunTemplate `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZRunTemplate{}, &ZRunTemplateList{}) +} diff --git a/backend/api/v1alpha1/zscript_types.go b/backend/api/v1alpha1/zscript_types.go new file mode 100644 index 0000000..63ec987 --- /dev/null +++ b/backend/api/v1alpha1/zscript_types.go @@ -0,0 +1,71 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ZScriptSpec defines the desired state of ZScript +type ZScriptSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZScript. Edit zscript_types.go to remove/update + // Foo string `json:"foo,omitempty"` + RunSpec RunSpec `json:"runSpec,omitempty"` //run template for the script + Path string `json:"path,omitempty"` //script path + Project corev1.ObjectReference `json:"project,omitempty"` //存放脚本的项目 + Branch string `json:"branch,omitempty"` //code branch + Env []corev1.EnvVar `json:"env,omitempty"` //env + CustomHost corev1.ObjectReference `json:"customHost,omitempty"` //host aliases, link to resource ZCustomHost +} + +// ZScriptStatus defines the observed state of ZScript +type ZScriptStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZScript is the Schema for the zscripts API +type ZScript struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZScriptSpec `json:"spec,omitempty"` + Status ZScriptStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZScriptList contains a list of ZScript +type ZScriptList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZScript `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZScript{}, &ZScriptList{}) +} diff --git a/backend/api/v1alpha1/zservice_types.go b/backend/api/v1alpha1/zservice_types.go new file mode 100644 index 0000000..dbe6481 --- /dev/null +++ b/backend/api/v1alpha1/zservice_types.go @@ -0,0 +1,507 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/ycyxuehan/zelda/pkg/utils" + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +type ServiceSpec struct { + Name string `json:"name,omitempty"` + Ports []corev1.ServicePort `json:"ports,omitempty"` + Type corev1.ServiceType `json:"type,omitempty"` +} + +func (ss *ServiceSpec) ServiceSpec(selector map[string]string) corev1.ServiceSpec { + spec := corev1.ServiceSpec{ + Ports: ss.Ports, + Selector: selector, + Type: ss.Type, + } + return spec +} + +//Pod status +type PodStatus struct { + Name string `json:"name,omitempty"` + Phase corev1.PodPhase `json:"phase,omitempty"` + RunAt string `json:"runAt,omitempty"` + Message string `json:"message,omitempty"` +} + +type PodStatusMap map[string]PodStatus + +//Deployment status +type DeploymentStatus struct { + AvailableReplicas int32 `json:"availableReplicas,omitempty"` + ReadyReplicas int32 `json:"readyReplicas,omitempty"` + Replicas int32 `json:"replicas,omitempty"` + UpdatedReplicas int32 `json:"updatedReplicas,omitempty"` + UnavailableReplicas int32 `json:"unavailableReplicas,omitempty"` +} + +//Job status +type JobStatus struct { + CompletionTime *metav1.Time `json:"completionTime,omitempty"` + Succeeded int32 `json:"succeeded,omitempty"` + StartTime *metav1.Time `json:"startTime,omitempty"` + Active int32 `json:"active,omitempty"` + Failed int32 `json:"failed,omitempty"` +} + +type RunSpec struct { + Template corev1.ObjectReference `json:"template,omitempty"` + Volumes []corev1.Volume `json:"volumes,omitempty"` +} + +// ZServiceSpec defines the desired state of ZService +type ZServiceSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZService. Edit zservice_types.go to remove/update + // Foo string `json:"foo,omitempty"` + Env []corev1.EnvVar `json:"env,omitempty"` + Version string `json:"version,omitempty"` + // Volumes []corev1.Volume `json:"volumes,omitempty"` + Services []ServiceSpec `json:"services,omitempty"` + CustomHost corev1.ObjectReference `json:"customHosts,omitempty"` + NodeSelector corev1.NodeSelector `json:"nodeSelector,omitempty"` + PodAffinity corev1.PodAffinity `json:"podAffinity,omitempty"` + PodAntiAffinity corev1.PodAntiAffinity `json:"podAntiAffinity,omitempty"` + Kind string `json:"kind,omitempty"` + Creator corev1.ObjectReference `json:"creator,omitempty"` + Project corev1.ObjectReference `json:"project,omitempty"` + SubProject string `json:"subProject,omitempty"` + RunSpec RunSpec `json:"runSpec,omitempty"` +} + +// ZServiceStatus defines the observed state of ZService +type ZServiceStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + Branch string `json:"branch,omitempty"` + Target string `json:"target,omitempty"` + PodStatus PodStatusMap `json:"podStatus,omitempty"` + DeploymentStatus DeploymentStatus `json:"deploymentStatus,omitempty"` + JobStatus JobStatus `json:"jobStatus,omitempty"` + UpdatedAt *metav1.Time `json:"updatedAt,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZService is the Schema for the zservices API +type ZService struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZServiceSpec `json:"spec,omitempty"` + Status ZServiceStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZServiceList contains a list of ZService +type ZServiceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZService `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZService{}, &ZServiceList{}) +} + +type NewClientObjectOption struct { + ZRunTemplateSpec *ZRunTemplateSpec + Registry *ZRegistry + UserSecrets []corev1.LocalObjectReference + HostAlias []corev1.HostAlias +} + +//返回子对象的namespaced name +func (zs *ZService) NamespacedNameResource() types.NamespacedName { + return types.NamespacedName{ + Namespace: zs.GetNamespace(), + Name: zs.GetName(), + } +} + +//返回runTemplate的namespaced name +func (zs *ZService) NamespacedNameRunTemplate() types.NamespacedName { + return types.NamespacedName{ + Namespace: zs.Spec.RunSpec.Template.Namespace, + Name: zs.Spec.RunSpec.Template.Name, + } +} + +//返回project的namespaced name +func (zs *ZService) NamespacedNameProject() types.NamespacedName { + return types.NamespacedName{ + Namespace: zs.Spec.Project.Namespace, + Name: zs.Spec.Project.Name, + } +} + +//返回CustomHost的namespaced name +func (zs *ZService) NamespacedNameCustomHost() types.NamespacedName { + return types.NamespacedName{ + Namespace: zs.Spec.CustomHost.Namespace, + Name: zs.Spec.CustomHost.Name, + } +} + +//返回user的namespaced name +func (zs *ZService) NamespacedNameUser() types.NamespacedName { + return types.NamespacedName{ + Namespace: zs.Spec.Creator.Namespace, + Name: zs.Spec.Creator.Name, + } +} + +//返回zservice的owner reference +func (zs *ZService) Owner() metav1.OwnerReference { + bTrue := true + return metav1.OwnerReference{ + Name: zs.GetName(), + APIVersion: GroupVersion.Version, + Kind: "ZService", + UID: zs.GetUID(), + Controller: &bTrue, + BlockOwnerDeletion: &bTrue, + } +} + +//返回子资源的labels +func (zs *ZService) ResourceLabels() map[string]string { + labels := make(map[string]string) + labels["zservices.zelda.io"] = zs.GetName() + labels["projects.zelda.io"] = zs.Spec.Project.Name + labels["projects.selda.io/subproject"] = zs.Spec.SubProject + return labels +} + +//返回子资源的模板的labels,这里使用不一样的label,防止重复更新状态 +func (zs *ZService) ResourceTemplateLabels() map[string]string { + labels := make(map[string]string) + labels["zservices.zelda.io"] = zs.GetName() + // labels["projects.zelda.io"] = zs.Spec.Project.Name + // labels["projects.selda.io/subproject"] = zs.Spec.SubProject + return labels +} + +//返回子资源selector +func (zs *ZService) Selector() *metav1.LabelSelector { + return &metav1.LabelSelector{ + MatchLabels: zs.ResourceTemplateLabels(), + } +} + +//返回项目的imagetag +func (zs *ZService) ImageTagBase() string { + return strings.Join([]string{zs.Spec.SubProject, zs.Spec.Version}, ":") +} + +//更新模板中的image为项目的image +func (zs *ZService) UpdateContainerImage(image string, contaienrs ...corev1.Container) []corev1.Container { + res := []corev1.Container{} + for _, c := range contaienrs { + if c.Image == "$PROJECT_IMAGE" { + c.Image = image + } + res = append(res, c) + } + return res +} + +//合并环境变量 +func (zs *ZService) MergeContainerEnv(containers ...corev1.Container) []corev1.Container { + res := []corev1.Container{} + for _, c := range containers { + envs := zs.Spec.Env + envs = append(envs, c.Env...) + mergedEnv := utils.MergeEnv(utils.MergeOverrideByFirst, envs) + c.Env = mergedEnv + res = append(res, c) + } + return res +} + +//返回image tag +func (zs *ZService) ImageTag(registry *ZRegistry) string { + image := zs.ImageTagBase() + if registry != nil { + image = registry.FullImageTag(image) + } + return image +} + +//返回pod spec +func (zs *ZService) PodSpec(option *NewClientObjectOption) corev1.PodSpec { + image := zs.ImageTag(option.Registry) + secrets := option.UserSecrets + if option.Registry != nil { + secrets = append(secrets, corev1.LocalObjectReference{ + Name: option.Registry.ImagePullSecretName(), + }) + } + + initContainers := zs.UpdateContainerImage(image, option.ZRunTemplateSpec.InitContainers...) + containers := zs.UpdateContainerImage(image, option.ZRunTemplateSpec.Containers...) + initContainers = zs.MergeContainerEnv(initContainers...) + containers = zs.MergeContainerEnv(containers...) + + spec := corev1.PodSpec{ + InitContainers: initContainers, + Containers: containers, + ImagePullSecrets: secrets, + Volumes: zs.Spec.RunSpec.Volumes, + HostAliases: option.HostAlias, + } + return spec +} + +//返回pod template +func (zs *ZService) PodTemplateSpec(option *NewClientObjectOption) corev1.PodTemplateSpec { + spec := corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: zs.ResourceTemplateLabels(), + }, + Spec: zs.PodSpec(option), + } + return spec +} + +//返回pod对象 +func (zs *ZService) Pod(option *NewClientObjectOption) *corev1.Pod { + pod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: zs.GetName(), + Namespace: zs.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zs.Owner(), + }, + Labels: zs.ResourceLabels(), + }, + Spec: zs.PodSpec(option), + } + return &pod +} + +//返回deployment spec +func (zs *ZService) DeploymentSpec(option *NewClientObjectOption) appsv1.DeploymentSpec { + spec := appsv1.DeploymentSpec{ + Selector: zs.Selector(), + Template: zs.PodTemplateSpec(option), + } + return spec +} + +//返回deployment +func (zs *ZService) Deployment(option *NewClientObjectOption) *appsv1.Deployment { + spec := zs.DeploymentSpec(option) + deployment := appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: zs.GetName(), + Namespace: zs.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zs.Owner(), + }, + Labels: zs.ResourceLabels(), + }, + Spec: spec, + } + + return &deployment +} + +//返回需要创建的service +func (zs *ZService) Services() []corev1.Service { + services := []corev1.Service{} + for _, svc := range zs.Spec.Services { + objectMeta := metav1.ObjectMeta{ + Name: svc.Name, + Namespace: zs.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zs.Owner(), + }, + Labels: zs.ResourceLabels(), + } + service := corev1.Service{ + ObjectMeta: objectMeta, + Spec: svc.ServiceSpec(zs.ResourceTemplateLabels()), + } + services = append(services, service) + } + return services +} + +//返回JobSpec +func (zs *ZService) JobSpec(option *NewClientObjectOption) batchv1.JobSpec { + spec := batchv1.JobSpec{ + Selector: zs.Selector(), + Template: zs.PodTemplateSpec(option), + } + return spec +} + +//返回job +func (zs *ZService) Job(option *NewClientObjectOption) *batchv1.Job { + job := batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: zs.GetName(), + Namespace: zs.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zs.Owner(), + }, + Labels: zs.ResourceLabels(), + }, + Spec: zs.JobSpec(option), + } + return &job +} + +//检查spec是否有变更 +func (zs *ZService) IsSpecChanged() (bool, error) { + oldZService := ZService{} + latestConfiguration, ok := zs.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"] + if !ok { + return false, fmt.Errorf("not found annotation") + } + err := json.Unmarshal([]byte(latestConfiguration), &oldZService) + if err != nil { //无法获得旧配置 + return false, err + } + + oldString, err := json.Marshal(&oldZService.Spec) + if err != nil { + return false, err + } + newString, err := json.Marshal(&zs.Spec) + if err != nil { + return false, err + } + if string(oldString) != string(newString) { + return true, nil + } + return false, nil +} + +//返回client object +func (zs *ZService) ClientObject(option *NewClientObjectOption) client.Object { + switch zs.Spec.Kind { + case "Deployment": + return zs.Deployment(option) + case "Job": + return zs.Job(option) + case "Pod": + return zs.Pod(option) + default: + return nil + + } +} + +//更新状态, 更新deployment +func (zs *ZService) UpdateStatusDeployment(name string, status *appsv1.DeploymentStatus) { + if status == nil { + return + } + zs.Status.Target = name + zs.Status.DeploymentStatus = DeploymentStatus{ + AvailableReplicas: status.AvailableReplicas, + ReadyReplicas: status.ReadyReplicas, + Replicas: status.Replicas, + UpdatedReplicas: status.UpdatedReplicas, + UnavailableReplicas: status.UnavailableReplicas, + } +} + +//更新状态,更新job +func (zs *ZService) UpdateStatusJob(name string, status *batchv1.JobStatus) { + if status == nil { + return + } + zs.Status.Target = name + zs.Status.JobStatus = JobStatus{ + CompletionTime: status.CompletionTime, + Succeeded: status.Succeeded, + StartTime: status.StartTime, + Failed: status.Failed, + Active: status.Active, + } +} + +//更新状态, 更新pod +func (zs *ZService) UpdateStatusPod(name string, status *corev1.PodStatus) { + if status == nil { + return + } + if zs.Spec.Kind == "Pod" { + zs.Status.Target = name + } + podStatus := PodStatus{ + Name: name, + Phase: status.Phase, + RunAt: status.HostIP, + Message: status.Message, + } + zs.Status.PodStatus[name] = podStatus +} + +//更新状态 +func (zs *ZService) UpdateStatus(managedResource client.Object) error { + switch zs.Spec.Kind { + case "Deployment": + dp, ok := managedResource.(*appsv1.Deployment) + if !ok { + return fmt.Errorf("object type error, it not a deployment") + } + zs.UpdateStatusDeployment(dp.GetName(), dp.Status.DeepCopy()) + case "Job": + job, ok := managedResource.(*batchv1.Job) + if !ok { + return fmt.Errorf("object type error, it not a deployment") + } + zs.UpdateStatusJob(job.GetName(), job.Status.DeepCopy()) + case "Pod": + pod, ok := managedResource.(*corev1.Pod) + if !ok { + return fmt.Errorf("object type error, it not a deployment") + } + zs.UpdateStatusPod(pod.GetName(), pod.Status.DeepCopy()) + default: + return fmt.Errorf("unkown kind") + } + now := metav1.Now() + zs.Status.UpdatedAt = &now + return nil +} diff --git a/backend/api/v1alpha1/zuser_types.go b/backend/api/v1alpha1/zuser_types.go new file mode 100644 index 0000000..c59f0e1 --- /dev/null +++ b/backend/api/v1alpha1/zuser_types.go @@ -0,0 +1,223 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "encoding/json" + "fmt" + + "github.com/ycyxuehan/zelda/pkg/utils" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// ZUserSpec defines the desired state of ZUser +type ZUserSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Foo is an example field of ZUser. Edit zuser_types.go to remove/update + // Foo string `json:"foo,omitempty"` + Password string `json:"password,omitempty"` + Group string `json:"group,omitempty"` + NotifyMedia string `json:"notifyMedia,omitempty"` //user接收消息的媒介 + Secrets []corev1.ObjectReference `json:"secrets,omitempty"` +} + +// ZUserStatus defines the observed state of ZUser +type ZUserStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + CreatedAt *metav1.Time `json:"createdAt,omitempty"` + Token string `json:"token,omitempty"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// ZUser is the Schema for the zusers API +type ZUser struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ZUserSpec `json:"spec,omitempty"` + Status ZUserStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// ZUserList contains a list of ZUser +type ZUserList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ZUser `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ZUser{}, &ZUserList{}) +} + +func (zu *ZUser) Owner() metav1.OwnerReference { + bTrue := true + return metav1.OwnerReference{ + Name: zu.GetName(), + APIVersion: GroupVersion.Version, + Kind: "ZUser", + UID: zu.GetUID(), + Controller: &bTrue, + BlockOwnerDeletion: &bTrue, + } +} + +func (zu *ZUser) ResourceLabels() map[string]string { + labels := make(map[string]string) + labels["users.zelda.io"] = zu.GetName() + labels["groups.zelda.io"] = zu.Spec.Group + return labels +} + +//返回zgroup的namespacedname +func (zu *ZUser) NamespacedNameGroup() types.NamespacedName { + return types.NamespacedName{ + Namespace: zu.GetNamespace(), + Name: zu.Spec.Group, + } +} + +//返回zgroup的namespacedname +func (zu *ZUser) NamespacedNameServiceAccount() types.NamespacedName { + return types.NamespacedName{ + Namespace: zu.GetNamespace(), + Name: zu.GetName(), + } +} + +//返回zgroup的namespacedname +func (zu *ZUser) NamespacedNameRoleBinding() types.NamespacedName { + return types.NamespacedName{ + Namespace: zu.GetNamespace(), + Name: zu.GetName(), + } +} + +//返回zgroup的namespacedname +func (zu *ZUser) NamespacedNameClusterRoleBinding() types.NamespacedName { + return types.NamespacedName{ + Name: zu.GetName(), + } +} + +//返回user对应的ServiceAccount +func (zu *ZUser) ServiceAccount(groupSecrets []corev1.ObjectReference) *corev1.ServiceAccount { + secrets, _ := utils.MergeObjectReferences(utils.MergeOverrideByLatest, groupSecrets, zu.Spec.Secrets) //这里忽略错误,因为mergetype不可能出错 + sa := corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: zu.GetName(), + Namespace: zu.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zu.Owner(), + }, + Labels: zu.ResourceLabels(), + }, + Secrets: secrets, + } + return &sa +} + +//返回ServiceAccount的RoleBinding +func (zu *ZUser) RoleBinding() *rbacv1.RoleBinding { + roleBinding := rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: zu.GetName(), + Namespace: zu.GetNamespace(), + OwnerReferences: []metav1.OwnerReference{ + zu.Owner(), + }, + Labels: zu.ResourceLabels(), + }, + Subjects: []rbacv1.Subject{ + { + Kind: rbacv1.ServiceAccountKind, + Namespace: zu.GetNamespace(), + Name: zu.GetName(), + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "Role", + Name: zu.Spec.Group, + }, + } + return &roleBinding +} + +//ServiceAccount的ClusterRoleBinding +func (zu *ZUser) ClusterRoleBinding() *rbacv1.ClusterRoleBinding { + roleBinding := rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: zu.GetName(), + OwnerReferences: []metav1.OwnerReference{ + zu.Owner(), + }, + Labels: zu.ResourceLabels(), + }, + Subjects: []rbacv1.Subject{ + { + Kind: rbacv1.ServiceAccountKind, + Namespace: zu.GetNamespace(), + Name: zu.GetName(), + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "ClusterRole", + Name: zu.Spec.Group, + }, + } + return &roleBinding +} + +//返回zuser是否有变更 +func (zu *ZUser) IsSpecChanged() (bool, error) { + old := ZUser{} + latestConfiguration, ok := zu.GetAnnotations()["kubectl.kubernetes.io/last-applied-configuration"] + if !ok { + return false, fmt.Errorf("not found annotation") + } + err := json.Unmarshal([]byte(latestConfiguration), &old) + if err != nil { //无法获得旧配置 + return false, err + } + + oldString, err := json.Marshal(&old.Spec) + if err != nil { + return false, err + } + newString, err := json.Marshal(&zu.Spec) + if err != nil { + return false, err + } + if string(oldString) != string(newString) { + return true, nil + } + return false, nil +} diff --git a/backend/api/v1alpha1/zz_generated.deepcopy.go b/backend/api/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000..ab79bdf --- /dev/null +++ b/backend/api/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,915 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZBuildTemplate) DeepCopyInto(out *ZBuildTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuildTemplate. +func (in *ZBuildTemplate) DeepCopy() *ZBuildTemplate { + if in == nil { + return nil + } + out := new(ZBuildTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZBuildTemplate) 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 *ZBuildTemplateList) DeepCopyInto(out *ZBuildTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZBuildTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuildTemplateList. +func (in *ZBuildTemplateList) DeepCopy() *ZBuildTemplateList { + if in == nil { + return nil + } + out := new(ZBuildTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZBuildTemplateList) 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 *ZBuildTemplateSpec) DeepCopyInto(out *ZBuildTemplateSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuildTemplateSpec. +func (in *ZBuildTemplateSpec) DeepCopy() *ZBuildTemplateSpec { + if in == nil { + return nil + } + out := new(ZBuildTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZBuildTemplateStatus) DeepCopyInto(out *ZBuildTemplateStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuildTemplateStatus. +func (in *ZBuildTemplateStatus) DeepCopy() *ZBuildTemplateStatus { + if in == nil { + return nil + } + out := new(ZBuildTemplateStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZBuilder) DeepCopyInto(out *ZBuilder) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuilder. +func (in *ZBuilder) DeepCopy() *ZBuilder { + if in == nil { + return nil + } + out := new(ZBuilder) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZBuilder) 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 *ZBuilderList) DeepCopyInto(out *ZBuilderList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZBuilder, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuilderList. +func (in *ZBuilderList) DeepCopy() *ZBuilderList { + if in == nil { + return nil + } + out := new(ZBuilderList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZBuilderList) 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 *ZBuilderSpec) DeepCopyInto(out *ZBuilderSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuilderSpec. +func (in *ZBuilderSpec) DeepCopy() *ZBuilderSpec { + if in == nil { + return nil + } + out := new(ZBuilderSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZBuilderStatus) DeepCopyInto(out *ZBuilderStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZBuilderStatus. +func (in *ZBuilderStatus) DeepCopy() *ZBuilderStatus { + if in == nil { + return nil + } + out := new(ZBuilderStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZCustomHost) DeepCopyInto(out *ZCustomHost) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZCustomHost. +func (in *ZCustomHost) DeepCopy() *ZCustomHost { + if in == nil { + return nil + } + out := new(ZCustomHost) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZCustomHost) 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 *ZCustomHostList) DeepCopyInto(out *ZCustomHostList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZCustomHost, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZCustomHostList. +func (in *ZCustomHostList) DeepCopy() *ZCustomHostList { + if in == nil { + return nil + } + out := new(ZCustomHostList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZCustomHostList) 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 *ZCustomHostSpec) DeepCopyInto(out *ZCustomHostSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZCustomHostSpec. +func (in *ZCustomHostSpec) DeepCopy() *ZCustomHostSpec { + if in == nil { + return nil + } + out := new(ZCustomHostSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZCustomHostStatus) DeepCopyInto(out *ZCustomHostStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZCustomHostStatus. +func (in *ZCustomHostStatus) DeepCopy() *ZCustomHostStatus { + if in == nil { + return nil + } + out := new(ZCustomHostStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZGroup) DeepCopyInto(out *ZGroup) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZGroup. +func (in *ZGroup) DeepCopy() *ZGroup { + if in == nil { + return nil + } + out := new(ZGroup) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZGroup) 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 *ZGroupList) DeepCopyInto(out *ZGroupList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZGroup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZGroupList. +func (in *ZGroupList) DeepCopy() *ZGroupList { + if in == nil { + return nil + } + out := new(ZGroupList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZGroupList) 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 *ZGroupSpec) DeepCopyInto(out *ZGroupSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZGroupSpec. +func (in *ZGroupSpec) DeepCopy() *ZGroupSpec { + if in == nil { + return nil + } + out := new(ZGroupSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZGroupStatus) DeepCopyInto(out *ZGroupStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZGroupStatus. +func (in *ZGroupStatus) DeepCopy() *ZGroupStatus { + if in == nil { + return nil + } + out := new(ZGroupStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZProject) DeepCopyInto(out *ZProject) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZProject. +func (in *ZProject) DeepCopy() *ZProject { + if in == nil { + return nil + } + out := new(ZProject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZProject) 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 *ZProjectList) DeepCopyInto(out *ZProjectList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZProject, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZProjectList. +func (in *ZProjectList) DeepCopy() *ZProjectList { + if in == nil { + return nil + } + out := new(ZProjectList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZProjectList) 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 *ZProjectSpec) DeepCopyInto(out *ZProjectSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZProjectSpec. +func (in *ZProjectSpec) DeepCopy() *ZProjectSpec { + if in == nil { + return nil + } + out := new(ZProjectSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZProjectStatus) DeepCopyInto(out *ZProjectStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZProjectStatus. +func (in *ZProjectStatus) DeepCopy() *ZProjectStatus { + if in == nil { + return nil + } + out := new(ZProjectStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZRegistry) DeepCopyInto(out *ZRegistry) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRegistry. +func (in *ZRegistry) DeepCopy() *ZRegistry { + if in == nil { + return nil + } + out := new(ZRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZRegistry) 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 *ZRegistryList) DeepCopyInto(out *ZRegistryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZRegistry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRegistryList. +func (in *ZRegistryList) DeepCopy() *ZRegistryList { + if in == nil { + return nil + } + out := new(ZRegistryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZRegistryList) 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 *ZRegistrySpec) DeepCopyInto(out *ZRegistrySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRegistrySpec. +func (in *ZRegistrySpec) DeepCopy() *ZRegistrySpec { + if in == nil { + return nil + } + out := new(ZRegistrySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZRegistryStatus) DeepCopyInto(out *ZRegistryStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRegistryStatus. +func (in *ZRegistryStatus) DeepCopy() *ZRegistryStatus { + if in == nil { + return nil + } + out := new(ZRegistryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZRunTemplate) DeepCopyInto(out *ZRunTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRunTemplate. +func (in *ZRunTemplate) DeepCopy() *ZRunTemplate { + if in == nil { + return nil + } + out := new(ZRunTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZRunTemplate) 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 *ZRunTemplateList) DeepCopyInto(out *ZRunTemplateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZRunTemplate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRunTemplateList. +func (in *ZRunTemplateList) DeepCopy() *ZRunTemplateList { + if in == nil { + return nil + } + out := new(ZRunTemplateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZRunTemplateList) 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 *ZRunTemplateSpec) DeepCopyInto(out *ZRunTemplateSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRunTemplateSpec. +func (in *ZRunTemplateSpec) DeepCopy() *ZRunTemplateSpec { + if in == nil { + return nil + } + out := new(ZRunTemplateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZRunTemplateStatus) DeepCopyInto(out *ZRunTemplateStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZRunTemplateStatus. +func (in *ZRunTemplateStatus) DeepCopy() *ZRunTemplateStatus { + if in == nil { + return nil + } + out := new(ZRunTemplateStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZScript) DeepCopyInto(out *ZScript) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZScript. +func (in *ZScript) DeepCopy() *ZScript { + if in == nil { + return nil + } + out := new(ZScript) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZScript) 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 *ZScriptList) DeepCopyInto(out *ZScriptList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZScript, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZScriptList. +func (in *ZScriptList) DeepCopy() *ZScriptList { + if in == nil { + return nil + } + out := new(ZScriptList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZScriptList) 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 *ZScriptSpec) DeepCopyInto(out *ZScriptSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZScriptSpec. +func (in *ZScriptSpec) DeepCopy() *ZScriptSpec { + if in == nil { + return nil + } + out := new(ZScriptSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZScriptStatus) DeepCopyInto(out *ZScriptStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZScriptStatus. +func (in *ZScriptStatus) DeepCopy() *ZScriptStatus { + if in == nil { + return nil + } + out := new(ZScriptStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZService) DeepCopyInto(out *ZService) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZService. +func (in *ZService) DeepCopy() *ZService { + if in == nil { + return nil + } + out := new(ZService) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZService) 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 *ZServiceList) DeepCopyInto(out *ZServiceList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZService, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZServiceList. +func (in *ZServiceList) DeepCopy() *ZServiceList { + if in == nil { + return nil + } + out := new(ZServiceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZServiceList) 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 *ZServiceSpec) DeepCopyInto(out *ZServiceSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZServiceSpec. +func (in *ZServiceSpec) DeepCopy() *ZServiceSpec { + if in == nil { + return nil + } + out := new(ZServiceSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZServiceStatus) DeepCopyInto(out *ZServiceStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZServiceStatus. +func (in *ZServiceStatus) DeepCopy() *ZServiceStatus { + if in == nil { + return nil + } + out := new(ZServiceStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZUser) DeepCopyInto(out *ZUser) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZUser. +func (in *ZUser) DeepCopy() *ZUser { + if in == nil { + return nil + } + out := new(ZUser) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZUser) 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 *ZUserList) DeepCopyInto(out *ZUserList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ZUser, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZUserList. +func (in *ZUserList) DeepCopy() *ZUserList { + if in == nil { + return nil + } + out := new(ZUserList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZUserList) 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 *ZUserSpec) DeepCopyInto(out *ZUserSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZUserSpec. +func (in *ZUserSpec) DeepCopy() *ZUserSpec { + if in == nil { + return nil + } + out := new(ZUserSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZUserStatus) DeepCopyInto(out *ZUserStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZUserStatus. +func (in *ZUserStatus) DeepCopy() *ZUserStatus { + if in == nil { + return nil + } + out := new(ZUserStatus) + in.DeepCopyInto(out) + return out +} diff --git a/backend/apiserver/apiserver.go b/backend/apiserver/apiserver.go new file mode 100644 index 0000000..a5fd338 --- /dev/null +++ b/backend/apiserver/apiserver.go @@ -0,0 +1,99 @@ +package apiserver + +import ( + "context" + "fmt" + "os" + + "github.com/gin-gonic/gin" + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + authapi "github.com/ycyxuehan/zelda/apiserver/auth/api" + proxyapi "github.com/ycyxuehan/zelda/apiserver/proxy/api" + corev1 "k8s.io/api/core/v1" + kubeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type APIServer struct { + client kubeclient.Client + authManager authapi.AuthManager + proxies []proxyapi.Proxy + namesapce string + zserviceHandler *ZServiceHandler +} + +func NewAPIServer(client kubeclient.Client, authManager authapi.AuthManager) *APIServer { + server := &APIServer{ + client: client, + authManager: authManager, + zserviceHandler: NewZServiceHandler(client), + } + server.setNamespace() + return server +} + +func (a *APIServer) setNamespace() error { + data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace") + a.namesapce = string(data) + return err +} + +func (a *APIServer) UseProxies(proxies ...proxyapi.Proxy) { + a.proxies = append(a.proxies, proxies...) +} + +//设置路由 +func (a *APIServer) SetRoute(engine *gin.Engine) { + //添加认证接口 + authGroup := engine.Group("/auth") + a.authManager.InitAuthRoute(a.IdentifyFunc(), authGroup) + //添加代理接口 + for _, proxy := range a.proxies { + proxyGroup := engine.Group(proxy.Path()) + proxyGroup.Use(a.authManager.MiddleWare()) + proxyGroup.GET("/", proxy.Proxy()) + proxyGroup.PUT("/", proxy.Proxy()) + proxyGroup.POST("/", proxy.Proxy()) + proxyGroup.PATCH("/", proxy.Proxy()) + proxyGroup.DELETE("/", proxy.Proxy()) + proxyGroup.OPTIONS("/", proxy.Proxy()) + } + //添加服务接口 + apiGroup := engine.Group("/api/v1alpha1") + apiGroup.Use(a.authManager.MiddleWare()) + + //zservice + zserviceGroup := apiGroup.Group("/zservice") + zserviceGroup.GET("/:name/restart", a.zserviceHandler.HandleRestart) + zserviceGroup.GET("/:name/start", a.zserviceHandler.HandleStart) + zserviceGroup.GET("/:name/stop", a.zserviceHandler.HandleStop) + zserviceGroup.POST("/:name/scale", a.zserviceHandler.HandleScale) + zserviceGroup.POST("/:name/version", a.zserviceHandler.HandleChangeVersion) + +} + +func (a *APIServer) IdentifyFunc() authapi.IdentifyFunc { + return func(ar *authapi.AuthentitionRequest) (authapi.IdentifyResult, error) { + zuser := zeldaiov1alpha1.ZUser{} + err := a.client.Get(context.Background(), kubeclient.ObjectKey{Namespace: a.namesapce, Name: ar.Username}, &zuser) + if err != nil { + return authapi.IdentifyResult{}, err + } + if ar.Password != zuser.Spec.Password { + return authapi.IdentifyResult{}, fmt.Errorf("password is invalid") + } + //密码验证通过,获取kubernetes token + secret := corev1.Secret{} + err = a.client.Get(context.Background(), kubeclient.ObjectKey{Namespace: a.namesapce, Name: zuser.Status.Token}, &secret) + if err != nil { + return authapi.IdentifyResult{}, err + } + //这里处理证书和token + return authapi.IdentifyResult{KubernetesToken: secret.StringData["token"], Cert: secret.StringData["ca.crt"]}, nil + } +} + +func (a *APIServer)Run(addr string)error{ + engine := gin.Default() + a.SetRoute(engine) + return engine.Run(addr) +} \ No newline at end of file diff --git a/backend/apiserver/auth/api/types.go b/backend/apiserver/auth/api/types.go new file mode 100644 index 0000000..250b356 --- /dev/null +++ b/backend/apiserver/auth/api/types.go @@ -0,0 +1,40 @@ +package api + +import "github.com/gin-gonic/gin" + +type AuthentitionRequest struct { + ClientID string `json:"clientID,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + // Namespace string `json:"namespace,omitempty"` + Token string `json:"token,omitempty"` + Group string + KubernetesToken string +} + +type AuthentitionResponse struct { + Token string `json:"token,omitempty"` + // Username string `json:"username,omitempty"` + // Group string `json:"group,omitempty"` + Error error `json:"error,omitempty"` + Message string `json:"message,omitempty"` + Code int `json:"code"` +} + +type IdentifyResult struct { + KubernetesToken string + Cert string +} + +//验证账号密码的方法,这里想把这一块单独剥离出去,这样不同的auth就更加抽象化 +//返回值分别是 kubernetes token, +type IdentifyFunc func(*AuthentitionRequest) (IdentifyResult, error) + +type AuthManager interface { + Login(IdentifyFunc, *AuthentitionRequest) *AuthentitionResponse + Logout(*AuthentitionRequest) *AuthentitionResponse + Refresh(*AuthentitionRequest) *AuthentitionResponse + KubernetesToken(*AuthentitionRequest) (string, error) + MiddleWare() gin.HandlerFunc + InitAuthRoute(IdentifyFunc, *gin.RouterGroup) +} diff --git a/backend/apiserver/auth/jwt/handler.go b/backend/apiserver/auth/jwt/handler.go new file mode 100644 index 0000000..05ad002 --- /dev/null +++ b/backend/apiserver/auth/jwt/handler.go @@ -0,0 +1,50 @@ +package jwt + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/ycyxuehan/zelda/apiserver/auth/api" +) + +//登录 +func (m *manager) HandlerLogin(identifyFunc api.IdentifyFunc) gin.HandlerFunc { + return func(c *gin.Context) { + authRequest := api.AuthentitionRequest{} + err := c.Bind(&authRequest) + if err != nil { + c.JSON(http.StatusOK, &api.AuthentitionResponse{Error: err}) + return + } + resp := m.Login(identifyFunc, &authRequest) + c.JSON(http.StatusOK, resp) + } +} + +//登出 +func (m *manager) HandlerLogout() gin.HandlerFunc { + return func(c *gin.Context) { + authRequest := api.AuthentitionRequest{} + err := c.Bind(&authRequest) + if err != nil { + c.JSON(http.StatusOK, &api.AuthentitionResponse{Error: err}) + return + } + resp := m.Logout(&authRequest) + c.JSON(http.StatusOK, resp) + } +} + +//刷新token +func (m *manager) HandlerRefreshToken() gin.HandlerFunc { + return func(c *gin.Context) { + authRequest := api.AuthentitionRequest{} + err := c.Bind(&authRequest) + if err != nil { + c.JSON(http.StatusOK, &api.AuthentitionResponse{Error: err}) + return + } + resp := m.Refresh(&authRequest) + c.JSON(http.StatusOK, resp) + } +} diff --git a/backend/apiserver/auth/jwt/manager.go b/backend/apiserver/auth/jwt/manager.go new file mode 100644 index 0000000..e178d39 --- /dev/null +++ b/backend/apiserver/auth/jwt/manager.go @@ -0,0 +1,231 @@ +package jwt + +import ( + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + gojwt "github.com/golang-jwt/jwt" + "github.com/ycyxuehan/zelda/apiserver/auth/api" +) + +type TokenClaim struct { + Username string `json:"username"` + Group string `json:"group"` + gojwt.StandardClaims +} + +func (t *TokenClaim) Expired() bool { + return t.ExpiresAt <= time.Now().Unix() +} + +type tokenCache struct { + kubernetesToken string + claim *TokenClaim + cert string +} + +type manager struct { + tokenStore map[string]tokenCache + secret string + term time.Duration +} + +func NewManager(secret string, term time.Duration) api.AuthManager { + m := manager{ + tokenStore: make(map[string]tokenCache), + secret: secret, + term: term, + } + return &m +} + +//登录 +func (m *manager) Login(f api.IdentifyFunc, data *api.AuthentitionRequest) *api.AuthentitionResponse { + if _, ok := m.IsLogined(data.Username); ok { + return &api.AuthentitionResponse{Error: fmt.Errorf("user is already logined"), Code: 1000} + } + res, err := f(data) + if err != nil { + return &api.AuthentitionResponse{Error: err, Code: 1001} + } + tokenClaim, err := m.GenerateTokenClaim(data) + if err != nil { + return &api.AuthentitionResponse{Error: err, Code: 1002} + } + tokenString, err := m.GenerateToken(tokenClaim) + if err != nil { + return &api.AuthentitionResponse{Error: err, Code: 1003} + } + //存储登录状态 + m.StoreLoginState(data.Username, res, tokenClaim) + + return &api.AuthentitionResponse{Token: tokenString} +} + +func (m *manager) Logout(data *api.AuthentitionRequest) *api.AuthentitionResponse { + //解析token,确认有logout权限 + claim, err := m.ParseTokenClaim(data.Token) + if err != nil { + return &api.AuthentitionResponse{Error: err, Code: 1004} + + } + if c, ok := m.IsLogined(claim.Username); ok { + if claim.ExpiresAt == c.ExpiresAt { + delete(m.tokenStore, data.Username) + return &api.AuthentitionResponse{Message: "success"} + } + } + return &api.AuthentitionResponse{Error: fmt.Errorf("user not login or token invalid"), Code: 1005} +} + +func (m *manager) Refresh(data *api.AuthentitionRequest) *api.AuthentitionResponse { + cliam, err := m.ParseTokenClaim(data.Token) + if err != nil { + return &api.AuthentitionResponse{Error: err, Code: 1006} + } + //已过期 + if cliam.Valid() != nil { + return &api.AuthentitionResponse{Error: fmt.Errorf("cannot use an invalid token to refresh: %v", err), Code: 1007} + + } + //找不到登陆状态 + if _, ok := m.IsLogined(cliam.Username); !ok { + return &api.AuthentitionResponse{Error: fmt.Errorf("token invalid, user maybe not login"), Code: 1005} + + } + //重置有效期 + cliam.ExpiresAt = time.Now().Add(m.term).Unix() + m.ReSetTokenClaim(cliam) + + tokenStr, err := m.GenerateToken(cliam) + + if err != nil { + return &api.AuthentitionResponse{Error: err, Code: 1003} + } + + return &api.AuthentitionResponse{Token: tokenStr} +} + +func (m *manager) KubernetesToken(data *api.AuthentitionRequest) (string, error) { + if t, ok := m.tokenStore[data.Username]; ok { + return t.kubernetesToken, nil + } + return "", fmt.Errorf("not found") +} + +func (m *manager) KubernetesCert(data *api.AuthentitionRequest) (string, error) { + if t, ok := m.tokenStore[data.Username]; ok { + return t.cert, nil + } + return "", fmt.Errorf("not found") +} + +//生成token claim对象 +func (m *manager) GenerateTokenClaim(data *api.AuthentitionRequest) (*TokenClaim, error) { + now := time.Now() + claim := TokenClaim{ + Username: data.Username, + Group: data.Group, + StandardClaims: gojwt.StandardClaims{ + ExpiresAt: now.Add(m.term).Unix(), + }, + } + return &claim, nil +} + +//从string解析token claim +func (m *manager) ParseTokenClaim(token string) (*TokenClaim, error) { + tokenClaims, err := gojwt.ParseWithClaims(token, &TokenClaim{}, func(token *gojwt.Token) (interface{}, error) { + return m.secret, nil + }) + + if tokenClaims != nil { + if claims, ok := tokenClaims.Claims.(*TokenClaim); ok && tokenClaims.Valid { + return claims, nil + } + } + // + return nil, err +} + +//从token claim 生成 string token +func (m *manager) GenerateToken(claim *TokenClaim) (string, error) { + tokenClaims := gojwt.NewWithClaims(gojwt.SigningMethodHS256, claim) + token, err := tokenClaims.SignedString(m.secret) + return token, err +} + +//存储登录状态 +func (m *manager) StoreLoginState(user string, result api.IdentifyResult, claim *TokenClaim) { + //储存登录状态 + t := tokenCache{ + kubernetesToken: result.KubernetesToken, + claim: claim, + cert: result.Cert, + } + m.tokenStore[user] = t +} + +//是否已登录 +func (m *manager) IsLogined(user string) (*TokenClaim, bool) { + t, ok := m.tokenStore[user] + if ok { + return t.claim, true + } + return nil, false +} + +//重置token状态 +func (m *manager) ReSetTokenClaim(claim *TokenClaim) { + if t, ok := m.tokenStore[claim.Username]; ok { + t.claim = claim + m.tokenStore[claim.Username] = t + } +} + +//token是否有效 +func (m *manager) TokenValid(claim *TokenClaim) bool { + if t, ok := m.tokenStore[claim.Username]; ok { + if t.claim.ExpiresAt == claim.ExpiresAt && claim.Valid() == nil { + return true + } + } + return false +} + +//中间件 +func (m *manager) MiddleWare() gin.HandlerFunc { + return func(c *gin.Context) { + tokenString := c.GetHeader("AccessToken") + if tokenString == "" { + c.AbortWithStatus(http.StatusUnauthorized) + return + } + tokenClaim, err := m.ParseTokenClaim(tokenString) + if err != nil { + c.AbortWithError(http.StatusUnauthorized, err) + return + } + if m.TokenValid(tokenClaim) { + c.AbortWithError(http.StatusUnauthorized, fmt.Errorf("token invalid")) + return + } + t, err := m.KubernetesToken(&api.AuthentitionRequest{Username: tokenClaim.Username}) + if err != nil || t == "" { + c.AbortWithError(http.StatusUnauthorized, fmt.Errorf("k8s token not found")) + } + c.Request.Header.Set("Authorization", fmt.Sprintf("bearer %s", t)) + cert, _ := m.KubernetesCert(&api.AuthentitionRequest{Username: tokenClaim.Username}) + c.Request.Header.Set("cert", cert) + c.Next() + } +} + +//初始化auth接口 +func (m *manager) InitAuthRoute(identifyFunc api.IdentifyFunc, authGroup *gin.RouterGroup) { + authGroup.POST("/login", m.HandlerLogin(identifyFunc)) + authGroup.POST("/logout", m.HandlerLogout()) + authGroup.POST("/refresh", m.HandlerRefreshToken()) +} diff --git a/backend/apiserver/auth/oauth2/oauth2.go b/backend/apiserver/auth/oauth2/oauth2.go new file mode 100644 index 0000000..7891812 --- /dev/null +++ b/backend/apiserver/auth/oauth2/oauth2.go @@ -0,0 +1,79 @@ +//这是使用官方例子改的, 试试能不能接上微信 +package oauth2 + +import ( + "github.com/gin-gonic/gin" + "github.com/go-oauth2/oauth2/v4/generates" + "github.com/go-oauth2/oauth2/v4/manage" + "github.com/go-oauth2/oauth2/v4/models" + "github.com/go-oauth2/oauth2/v4/store" + "github.com/ycyxuehan/zelda/apiserver/auth/api" +) + +type OAuth2 struct { + oauth2Manager *manage.Manager + clientStore *store.ClientStore + id string + secret string + domain string +} + +func NewManager(id, secret, domain string) (api.AuthManager, error) { + o2 := &OAuth2{ + id: id, + secret: secret, + domain: domain, + } + + o2.createStore() + o2.createManager() + + return o2, nil +} + +func (o *OAuth2) createStore() { + clientStore := store.NewClientStore() + clientStore.Set(o.id, &models.Client{ + ID: o.id, + Secret: o.secret, + Domain: o.domain, + }) +} + +func (o *OAuth2) createManager() { + o.oauth2Manager = manage.NewDefaultManager() + o.oauth2Manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg) + + // token store + o.oauth2Manager.MustTokenStorage(store.NewMemoryTokenStore()) + + // generate jwt access token + // manager.MapAccessGenerate(generates.NewJWTAccessGenerate("", []byte("00000000"), jwt.SigningMethodHS512)) + o.oauth2Manager.MapAccessGenerate(generates.NewAccessGenerate()) + o.oauth2Manager.MapClientStorage(o.clientStore) + +} + +func (o *OAuth2) Login(f api.IdentifyFunc, data *api.AuthentitionRequest) *api.AuthentitionResponse { + return nil +} + +func (o *OAuth2) Logout(*api.AuthentitionRequest) *api.AuthentitionResponse { + return nil +} + +func (o *OAuth2) Refresh(*api.AuthentitionRequest) *api.AuthentitionResponse { + return nil +} + +func (o *OAuth2) KubernetesToken(*api.AuthentitionRequest) (string, error) { + return "", nil +} + +func (o *OAuth2) MiddleWare() gin.HandlerFunc { + return func(c *gin.Context) {} +} + +//初始化auth接口 +func (o *OAuth2) InitAuthRoute(identifyFunc api.IdentifyFunc, authGroup *gin.RouterGroup) { +} diff --git a/backend/apiserver/controllers/zbuilder/types.go b/backend/apiserver/controllers/zbuilder/types.go new file mode 100644 index 0000000..2b14c34 --- /dev/null +++ b/backend/apiserver/controllers/zbuilder/types.go @@ -0,0 +1 @@ +package zbuilder \ No newline at end of file diff --git a/backend/apiserver/controllers/zservice/types.go b/backend/apiserver/controllers/zservice/types.go new file mode 100644 index 0000000..af450ca --- /dev/null +++ b/backend/apiserver/controllers/zservice/types.go @@ -0,0 +1,11 @@ +package zservice + +import kubeclient "sigs.k8s.io/controller-runtime/pkg/client" + +type Controller interface { + +} + +func New(client kubeclient.Client) Controller { + return &ctrl{client: client} +} \ No newline at end of file diff --git a/backend/apiserver/controllers/zservice/zservice.go b/backend/apiserver/controllers/zservice/zservice.go new file mode 100644 index 0000000..aa3c550 --- /dev/null +++ b/backend/apiserver/controllers/zservice/zservice.go @@ -0,0 +1,29 @@ +package zservice + +import ( + kubeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type ctrl struct { + client kubeclient.Client +} + +func (c *ctrl) Restart(name string) error { + return nil +} + +func (c *ctrl) Stop(name string) error { + return nil +} + +func (c *ctrl) Start(name string) error { + return nil +} + +func (c *ctrl) Scale(name string, replicas int) error { + return nil +} + +func (c *ctrl) ChangeVersion(name string, version string) error { + return nil +} \ No newline at end of file diff --git a/backend/apiserver/controllers/zuser/types.go b/backend/apiserver/controllers/zuser/types.go new file mode 100644 index 0000000..c7fc4cf --- /dev/null +++ b/backend/apiserver/controllers/zuser/types.go @@ -0,0 +1,16 @@ +package zuser + +import ( + kubeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type ZUserController interface { + +} + +func New( clt kubeclient.Client )ZUserController{ + c := &ctrl{ + kubeClient: clt, + } + return c +} \ No newline at end of file diff --git a/backend/apiserver/controllers/zuser/zuser.go b/backend/apiserver/controllers/zuser/zuser.go new file mode 100644 index 0000000..bad15c9 --- /dev/null +++ b/backend/apiserver/controllers/zuser/zuser.go @@ -0,0 +1,8 @@ +package zuser +import( + kubeclient "sigs.k8s.io/controller-runtime/pkg/client" + +) +type ctrl struct { + kubeClient kubeclient.Client +} diff --git a/backend/apiserver/handle_zservice.go b/backend/apiserver/handle_zservice.go new file mode 100644 index 0000000..6439357 --- /dev/null +++ b/backend/apiserver/handle_zservice.go @@ -0,0 +1,36 @@ +package apiserver + +import ( + "github.com/gin-gonic/gin" + kubeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type ZServiceHandler struct { + client kubeclient.Client +} + +func NewZServiceHandler(client kubeclient.Client) *ZServiceHandler { + return &ZServiceHandler{client: client} +} + + + +func (z *ZServiceHandler) HandleStart(c *gin.Context) { + +} + +func (z *ZServiceHandler) HandleStop(c *gin.Context) { + +} + +func (z *ZServiceHandler) HandleRestart(c *gin.Context) { + +} + +func (z *ZServiceHandler) HandleScale(c *gin.Context) { + +} + +func (z *ZServiceHandler) HandleChangeVersion(c *gin.Context) { + +} diff --git a/backend/apiserver/proxy/api/types.go b/backend/apiserver/proxy/api/types.go new file mode 100644 index 0000000..25730d1 --- /dev/null +++ b/backend/apiserver/proxy/api/types.go @@ -0,0 +1,16 @@ +package api + +import ( + "github.com/gin-gonic/gin" +) + +const ( + HTTPS = "HTTPS" + HTTP = "HTTP" +) + +type Proxy interface { + Proxy() gin.HandlerFunc + WithCerts(...string) + Path() string +} diff --git a/backend/apiserver/proxy/kubeapi/kubeapi.go b/backend/apiserver/proxy/kubeapi/kubeapi.go new file mode 100644 index 0000000..1615a3e --- /dev/null +++ b/backend/apiserver/proxy/kubeapi/kubeapi.go @@ -0,0 +1,84 @@ +package kubeapi + +import ( + "crypto/tls" + "crypto/x509" + // "encoding/base64" + // "fmt" + "net" + "net/http" + "net/http/httputil" + "time" + + "github.com/gin-gonic/gin" + "github.com/ycyxuehan/zelda/apiserver/proxy/api" +) + +type kubeAPI struct { + domain string + path string + certs []string +} + +func NewKubeAPI(domain, path string) api.Proxy { + return &kubeAPI{ + path: path, + domain: domain, + } +} + +func (k *kubeAPI) Proxy() gin.HandlerFunc { + return func(c *gin.Context) { + cert := "" + director := func(req *http.Request) { + req.URL.Scheme = api.HTTPS + req.URL.Host = k.domain + req.Header.Set("Content-Type", c.GetHeader("Content-Type")) + req.Header.Set("Content-Length", c.GetHeader("Content-Length")) + // if c.Request.Method == http.MethodPost || c.Request.Method == http.MethodPatch || c.Request.Method == http.MethodPut { + req.Header.Set("Content-Type", "application/json") + // } + req.Host = k.domain + //watch模式需要提升协议为websocket + watch := c.Query("watch") + follow := c.Query("follow") + if watch == "true" || follow == "true" { + // fmt.Println("watch mode,允许升级为websocket") + req.Header.Set("Upgrade", "websocket") + } + //从header获取cert + cert = req.Header.Get("cert") + req.Header.Del("cert") //删除cert + } + proxy := &httputil.ReverseProxy{Director: director} + certs := x509.NewCertPool() + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: &tls.Config{}, //InsecureSkipVerify: true + } + //如果有证书,加入 + if ok := certs.AppendCertsFromPEM([]byte(cert)); ok { + transport.TLSClientConfig.RootCAs = certs + } + proxy.Transport = transport + proxy.ServeHTTP(c.Writer, c.Request) + } +} + +func (k *kubeAPI) WithCerts(certs ...string) { + k.certs = append(k.certs, certs...) +} + +func (k *kubeAPI) Path() string { + return k.path +} diff --git a/backend/cmd/main.go b/backend/cmd/main.go new file mode 100644 index 0000000..2520e7d --- /dev/null +++ b/backend/cmd/main.go @@ -0,0 +1,193 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "flag" + "os" + "time" + + // 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" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + "github.com/ycyxuehan/zelda/apiserver" + "github.com/ycyxuehan/zelda/apiserver/auth/jwt" + "github.com/ycyxuehan/zelda/apiserver/proxy/kubeapi" + "github.com/ycyxuehan/zelda/internal/controller" + //+kubebuilder:scaffold:imports +) + +var ( + scheme = runtime.NewScheme() + setupLog = ctrl.Log.WithName("setup") +) + +func init() { + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + + utilruntime.Must(zeldaiov1alpha1.AddToScheme(scheme)) + //+kubebuilder:scaffold:scheme +} + +func main() { + var metricsAddr string + var enableLeaderElection bool + var probeAddr string + var apiAddr, authSecret string + var authTTL int64 + flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") + 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.StringVar(&apiAddr, "api-address", ":80", "api addr to listen") + flag.StringVar(&authSecret, "auth-secret", "abcdefghigklmnop1234", "auth token encrypt secret") + flag.Int64Var(&authTTL, "auth-ttl", 86400, "token invalid time, default 86400 second") + + opts := zap.Options{ + Development: true, + } + opts.BindFlags(flag.CommandLine) + flag.Parse() + + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ + Scheme: scheme, + Metrics: metricsserver.Options{BindAddress: metricsAddr}, + HealthProbeBindAddress: probeAddr, + LeaderElection: enableLeaderElection, + LeaderElectionID: "4a7792b3.zelda.io", + // 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, "unable to start manager") + os.Exit(1) + } + + if err = (&controller.ZProjectReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZProject") + os.Exit(1) + } + if err = (&controller.ZServiceReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZService") + os.Exit(1) + } + if err = (&controller.ZUserReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZUser") + os.Exit(1) + } + if err = (&controller.ZGroupReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZGroup") + os.Exit(1) + } + if err = (&controller.ZRegistryReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZRegistry") + os.Exit(1) + } + if err = (&controller.ZScriptReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZScript") + os.Exit(1) + } + if err = (&controller.ZBuildTemplateReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZBuildTemplate") + os.Exit(1) + } + if err = (&controller.ZRunTemplateReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZRunTemplate") + os.Exit(1) + } + if err = (&controller.ZBuilderReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZBuilder") + os.Exit(1) + } + if err = (&controller.ZCustomHostReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "ZCustomHost") + os.Exit(1) + } + //+kubebuilder:scaffold:builder + + if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up health check") + os.Exit(1) + } + if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { + setupLog.Error(err, "unable to set up ready check") + os.Exit(1) + } + // + setupLog.Info("starting webserver") + am := jwt.NewManager(authSecret, time.Duration(authTTL) * time.Second) + svr := apiserver.NewAPIServer(mgr.GetClient(), am) + svr.UseProxies(kubeapi.NewKubeAPI("kubernetes.default.svc", "/kubernetes")) + go svr.Run(apiAddr) + setupLog.Info("starting manager") + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + setupLog.Error(err, "problem running manager") + os.Exit(1) + } +} diff --git a/backend/config/crd/bases/zelda.io_zbuilders.yaml b/backend/config/crd/bases/zelda.io_zbuilders.yaml new file mode 100644 index 0000000..80635e8 --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zbuilders.yaml @@ -0,0 +1,203 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zbuilders.zelda.io +spec: + group: zelda.io + names: + kind: ZBuilder + listKind: ZBuilderList + plural: zbuilders + singular: zbuilder + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZBuilder is the Schema for the zbuilders API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZBuilderSpec defines the desired state of ZBuilder + properties: + branch: + type: string + build: + type: boolean + commitHash: + type: string + creator: + type: string + deploy: + type: boolean + package: + type: boolean + project: + description: Foo is an example field of ZBuilder. Edit zbuilder_types.go + to remove/update Foo string `json:"foo,omitempty"` + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + subProject: + type: string + zservice: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + type: object + status: + description: ZBuilderStatus defines the observed state of ZBuilder + properties: + RunAt: + type: string + createdAt: + format: date-time + type: string + finishedAt: + format: date-time + type: string + message: + type: string + phase: + type: string + reason: + type: string + steps: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file' + items: + description: 'EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! + NOTE: json tags are required. Any new fields you add must have + json tags for the fields to be serialized. Step status' + properties: + finishedAt: + format: date-time + type: string + message: + type: string + name: + type: string + phase: + description: PodPhase is a label for the condition of a pod + at the current time. + type: string + ready: + type: boolean + reason: + type: string + started: + type: boolean + startedAt: + format: date-time + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zbuildtemplates.yaml b/backend/config/crd/bases/zelda.io_zbuildtemplates.yaml new file mode 100644 index 0000000..fd5d185 --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zbuildtemplates.yaml @@ -0,0 +1,232 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zbuildtemplates.zelda.io +spec: + group: zelda.io + names: + kind: ZBuildTemplate + listKind: ZBuildTemplateList + plural: zbuildtemplates + singular: zbuildtemplate + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZBuildTemplate is the Schema for the zbuildtemplates API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZBuildTemplateSpec defines the desired state of ZBuildTemplate + properties: + imagePullSecrets: + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + steps: + description: Foo is an example field of ZBuildTemplate. Edit zbuildtemplate_types.go + to remove/update Foo string `json:"foo,omitempty"` + items: + properties: + args: + items: + type: string + type: array + commands: + items: + type: string + type: array + env: + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. + If a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + 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 + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + 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 + required: + - name + type: object + type: array + image: + type: string + name: + type: string + volumeMounts: + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the volume + should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are + propagated from the host to container and the other + way around. When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves similarly + to SubPath but environment variable references $(VAR_NAME) + are expanded using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath are mutually + exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + type: object + type: array + type: object + status: + description: ZBuildTemplateStatus defines the observed state of ZBuildTemplate + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zcustomhosts.yaml b/backend/config/crd/bases/zelda.io_zcustomhosts.yaml new file mode 100644 index 0000000..79b7d37 --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zcustomhosts.yaml @@ -0,0 +1,62 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zcustomhosts.zelda.io +spec: + group: zelda.io + names: + kind: ZCustomHost + listKind: ZCustomHostList + plural: zcustomhosts + singular: zcustomhost + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZCustomHost is the Schema for the zcustomhosts API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZCustomHostSpec defines the desired state of ZCustomHost + properties: + hostAlias: + description: Foo is an example field of ZCustomHost. Edit zcustomhost_types.go + to remove/update Foo string `json:"foo,omitempty"` + items: + description: HostAlias holds the mapping between IP and hostnames + that will be injected as an entry in the pod's hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + ip: + description: IP address of the host file entry. + type: string + type: object + type: array + type: object + status: + description: ZCustomHostStatus defines the observed state of ZCustomHost + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zgroups.yaml b/backend/config/crd/bases/zelda.io_zgroups.yaml new file mode 100644 index 0000000..85bb52c --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zgroups.yaml @@ -0,0 +1,208 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zgroups.zelda.io +spec: + group: zelda.io + names: + kind: ZGroup + listKind: ZGroupList + plural: zgroups + singular: zgroup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZGroup is the Schema for the zgroups API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZGroupSpec defines the desired state of ZGroup + properties: + clusterRulers: + items: + description: PolicyRule holds information that describes a policy + rule, but does not contain information about who the rule applies + to or which namespace the rule applies to. + properties: + apiGroups: + description: APIGroups is the name of the APIGroup that contains + the resources. If multiple API groups are specified, any + action requested against one of the enumerated resources in + any API group will be allowed. "" represents the core API + group and "*" represents all API groups. + items: + type: string + type: array + nonResourceURLs: + description: NonResourceURLs is a set of partial urls that a + user should have access to. *s are allowed, but only as the + full, final step in the path Since non-resource URLs are not + namespaced, this field is only applicable for ClusterRoles + referenced from a ClusterRoleBinding. Rules can either apply + to API resources (such as "pods" or "secrets") or non-resource + URL paths (such as "/api"), but not both. + items: + type: string + type: array + resourceNames: + description: ResourceNames is an optional white list of names + that the rule applies to. An empty set means that everything + is allowed. + items: + type: string + type: array + resources: + description: Resources is a list of resources this rule applies + to. '*' represents all resources. + items: + type: string + type: array + verbs: + description: Verbs is a list of Verbs that apply to ALL the + ResourceKinds contained in this rule. '*' represents all verbs. + items: + type: string + type: array + required: + - verbs + type: object + type: array + rulers: + description: Foo is an example field of ZGroup. Edit zgroup_types.go + to remove/update Foo string `json:"foo,omitempty"` + items: + description: PolicyRule holds information that describes a policy + rule, but does not contain information about who the rule applies + to or which namespace the rule applies to. + properties: + apiGroups: + description: APIGroups is the name of the APIGroup that contains + the resources. If multiple API groups are specified, any + action requested against one of the enumerated resources in + any API group will be allowed. "" represents the core API + group and "*" represents all API groups. + items: + type: string + type: array + nonResourceURLs: + description: NonResourceURLs is a set of partial urls that a + user should have access to. *s are allowed, but only as the + full, final step in the path Since non-resource URLs are not + namespaced, this field is only applicable for ClusterRoles + referenced from a ClusterRoleBinding. Rules can either apply + to API resources (such as "pods" or "secrets") or non-resource + URL paths (such as "/api"), but not both. + items: + type: string + type: array + resourceNames: + description: ResourceNames is an optional white list of names + that the rule applies to. An empty set means that everything + is allowed. + items: + type: string + type: array + resources: + description: Resources is a list of resources this rule applies + to. '*' represents all resources. + items: + type: string + type: array + verbs: + description: Verbs is a list of Verbs that apply to ALL the + ResourceKinds contained in this rule. '*' represents all verbs. + items: + type: string + type: array + required: + - verbs + type: object + type: array + secrets: + items: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many fields + which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. Invalid + usage help. It is impossible to add specific help for individual + usage. In most embedded usages, there are particular restrictions + like, \"must refer only to types A and B\" or \"UID not honored\" + or \"name must be restricted\". Those cannot be well described + when embedded. 3. Inconsistent validation. Because the usages + are different, the validation rules are different by usage, which + makes it hard for users to predict what will happen. 4. The fields + are both imprecise and overly precise. Kind is not a precise + mapping to a URL. This can produce ambiguity during interpretation + and require a REST mapping. In most cases, the dependency is + on the group,resource tuple and the version of the actual struct + is irrelevant. 5. We cannot easily change it. Because this type + is embedded in many locations, updates to this type will affect + numerous schemas. Don't make new APIs embed an underspecified + API type they do not control. \n Instead of using this type, create + a locally provided and used type that is well-focused on your + reference. For example, ServiceReferences for admission registration: + https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + type: object + status: + description: ZGroupStatus defines the observed state of ZGroup + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zprojects.yaml b/backend/config/crd/bases/zelda.io_zprojects.yaml new file mode 100644 index 0000000..c7bf2df --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zprojects.yaml @@ -0,0 +1,1933 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zprojects.zelda.io +spec: + group: zelda.io + names: + kind: ZProject + listKind: ZProjectList + plural: zprojects + singular: zproject + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZProject is the Schema for the zprojects API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZProjectSpec defines the desired state of ZProject + properties: + git: + description: Foo is an example field of ZProject. Edit zproject_types.go + to remove/update Foo string `json:"foo,omitempty"` + properties: + id: + type: integer + repo: + type: string + type: object + registry: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + subProjects: + description: ImageName string `json:"imageName,omitempty"` + items: + properties: + buildSpec: + properties: + dockerfile: + type: string + template: + description: "ObjectReference contains enough information + to let you inspect or modify the referred object. --- + New uses of this type are discouraged because of difficulty + describing its usage when embedded in APIs. 1. Ignored + fields. It includes many fields which are not generally + honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid + usage help. It is impossible to add specific help for + individual usage. In most embedded usages, there are + particular restrictions like, \"must refer only to types + A and B\" or \"UID not honored\" or \"name must be restricted\". + Those cannot be well described when embedded. 3. Inconsistent + validation. Because the usages are different, the validation + rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both + imprecise and overly precise. Kind is not a precise mapping + to a URL. This can produce ambiguity during interpretation + and require a REST mapping. In most cases, the dependency + is on the group,resource tuple and the version of the + actual struct is irrelevant. 5. We cannot easily change + it. Because this type is embedded in many locations, + updates to this type will affect numerous schemas. Don't + make new APIs embed an underspecified API type they do + not control. \n Instead of using this type, create a locally + provided and used type that is well-focused on your reference. + For example, ServiceReferences for admission registration: + https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead + of an entire object, this string should contain a + valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container + within a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container + that triggered the event) or if no container name + is specified "spec.containers[2]" (container with + index 2 in this pod). This syntax is chosen only to + have some well-defined way of referencing a part of + an object. TODO: this design is not final and this + field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this + reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + volumes: + items: + description: Volume represents a named volume in a pod + that may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS + Disk resource that is attached to a kubelet''s host + machine and then exposed to the pod. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the + readOnly setting in VolumeMounts. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk + mount on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in + the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed availability + set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name and + Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on + the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is + a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default + is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default is + /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret for + User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados + user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Examples: "ext4", + "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to + a secret object containing parameters used to + connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume + in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that + should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced ConfigMap + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the ConfigMap, the volume + setup will error unless it is marked optional. + Paths must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver + that handles this volume. Consult with your + admin for the correct name as registered in + the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", + "ntfs". If not provided, the empty value is + passed to the associated CSI driver which will + determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive information + to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if + no secret is required. If the secret object + contains more than one secret, all secret references + are passed. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for supported + values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about + the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to + set permissions on this file, must be + an octal value between 0000 and 0777 or + a decimal value between 0 and 511. YAML + accepts both octal and decimal values, + JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the file + mode, like fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the + container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu + and requests.memory) are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default + is "" which means to use the node''s default + medium. Must be an empty string (default) or + Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of + local storage required for this EmptyDir volume. + The size limit is also applicable for memory + medium. The maximum usage on memory medium EmptyDir + would be the minimum value between the SizeLimit + specified here and the sum of memory limits + of all containers in a pod. The default is nil + which means that the limit is undefined. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + 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 + ephemeral: + description: "ephemeral represents a volume that is + handled by a cluster storage driver. The volume's + lifecycle is tied to the pod that defines it - it + will be created before the pod starts, and deleted + when the pod is removed. \n Use this if: a) the + volume is only needed while the pod runs, b) features + of normal volumes like restoring from snapshot or + capacity tracking are needed, c) the storage driver + is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning + through a PersistentVolumeClaim (see EphemeralVolumeSource + for more information on the connection between this + volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that + persist for longer than the lifecycle of an individual + pod. \n Use CSI for light-weight local ephemeral + volumes if the CSI driver is meant to be used that + way - see the documentation of the driver for more + information. \n A pod can use both types of ephemeral + volumes and persistent volumes at the same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone + PVC to provision the volume. The pod in which + this EphemeralVolumeSource is embedded will + be the owner of the PVC, i.e. the PVC will be + deleted together with the pod. The name of + the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the + pod if the concatenated name is not valid for + a PVC (for example, too long). \n An existing + PVC with that name that is not owned by the + pod will *not* be used for the pod to avoid + using an unrelated volume by mistake. Starting + the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to + updated with an owner reference to the pod once + the pod exists. Normally this should not be + necessary, but it may be useful when manually + reconstructing a broken cluster. \n This field + is read-only and no changes will be made by + Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will + be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into + the PVC that gets created from this template. + The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains the + desired access modes the volume should + have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be + used to specify either: * An existing + VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, + it will create a new volume based on + the contents of the specified data source. + When the AnyVolumeDataSource feature + gate is enabled, dataSource contents + will be copied to dataSourceRef, and + dataSourceRef contents will be copied + to dataSource when dataSourceRef.namespace + is not specified. If the namespace is + specified, then dataSourceRef will not + be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies + the object from which to populate the + volume with data, if a non-empty volume + is desired. This may be any object from + a non-empty API group (non core object) + or a PersistentVolumeClaim object. When + this field is specified, volume binding + will only succeed if the type of the + specified object matches some installed + volume populator or dynamic provisioner. + This field will replace the functionality + of the dataSource field and as such + if both fields are non-empty, they must + have the same value. For backwards compatibility, + when namespace isn''t specified in dataSourceRef, + both fields (dataSource and dataSourceRef) + will be set to the same value automatically + if one of them is empty and the other + is non-empty. When namespace is specified + in dataSourceRef, dataSource isn''t + set to the same value and must be empty. + There are three important differences + between dataSource and dataSourceRef: + * While dataSource only allows two specific + types of objects, dataSourceRef allows + any non-core object, as well as PersistentVolumeClaim + objects. * While dataSource ignores + disallowed values (dropping them), dataSourceRef + preserves all values, and generates + an error if a disallowed value is specified. + * While dataSource only allows local + objects, dataSourceRef allows objects + in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource + feature gate to be enabled. (Alpha) + Using the namespace field of dataSourceRef + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, the + specified Kind must be in the core + API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note + that when a namespace is specified, + a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. See + the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the + minimum resources the volume should + have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements that + are lower than previous value but must + still be higher than capacity recorded + in the status field of the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names + of resources, defined in spec.resourceClaims, + that are used by this container. + \n This is an alpha field and requires + enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry in pod.spec.resourceClaims + of the Pod where this field + is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the + maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the + minimum amount of compute resources + required. If Requests is omitted + for a container, it defaults to + Limits if that is explicitly specified, + otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + 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 + required: + - key + - operator + type: object + type: array + 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 + storageClassName: + description: 'storageClassName is the + name of the StorageClass required by + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type + of volume is required by the claim. + Value of Filesystem is implied when + not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume backing + this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine and + then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. TODO: how do we prevent errors + in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or combination + of targetWWNs and lun must be set, but not both + simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using an exec + based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". The default filesystem depends on FlexVolume + script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to + false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret object + is specified. If the secret object contains + more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the + Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset for + Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the + volume that you want to mount. Tip: Ensure that + the filesystem type is supported by the host + operating system. Examples: "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in the + volume that you want to mount. If omitted, the + default is to mount by volume name. Examples: + For volume /dev/sda1, you specify the partition + as "1". Similarly, the volume partition for + /dev/sda is "0" (or you can leave the property + empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD + resource in GCE. Used to identify the disk in + GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo is + deprecated. To provision a container with a git + repo, mount an EmptyDir into an InitContainer that + clones the repo using git, then mount the EmptyDir + into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will be + the git repository. Otherwise, if specified, + the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the + specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount + on the host that shares a pod''s lifetime. More + info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that + details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. + Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file + or directory on the host machine that is directly + exposed to the container. This is generally used + for system agents or other privileged things that + are allowed to see the host machine. Most containers + will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use + host directory mounts and who can/can not mount + host directories as read/write.' + properties: + path: + description: 'path of the directory on the host. + If the path is a symlink, it will follow the + link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine and + then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new iSCSI + interface : will + be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name + that uses an iSCSI transport. Defaults to 'default' + (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for + iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. + The Portal is either an IP or ip_addr:port if + the port is other than default (typically TCP + ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host + that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS + server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS + export to be mounted with read-only permissions. + Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address + of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same + namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets + host machine + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon + Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type supported + by the host operating system. Ex. "ext4", "xfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used + to set permissions on created files by default. + Must be an octal value between 0000 and 0777 + or a decimal value between 0 and 511. YAML accepts + both octal and decimal values, JSON requires + decimal values for mode bits. Directories within + the path are not affected by this setting. This + might be in conflict with other options that + affect the file mode, like fsGroup, and the + result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced ConfigMap will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the ConfigMap, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about + the downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only annotations, + labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is + written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits + used to set permissions on this + file, must be an octal value + between 0000 and 0777 or a decimal + value between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If not + specified, the volume defaultMode + will be used. This might be + in conflict with other options + that affect the file mode, like + fsGroup, and the result can + be other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file + to be created. Must not be absolute + or contain the ''..'' path. + Must be utf-8 encoded. The first + item of the relative path must + not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are currently + supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the + secret data to project + properties: + items: + description: items if unspecified, each + key-value pair in the Data field of + the referenced Secret will be projected + into the volume as a file whose name + is the key and content is the value. + If specified, the listed keys will + be projected into the specified paths, + and unlisted keys will not be present. + If a key is specified which is not + present in the Secret, the volume + setup will error unless it is marked + optional. Paths must be relative and + may not contain the '..' path or start + with '..'. + items: + description: Maps a string key to + a path within a volume. + properties: + key: + description: key is the key to + project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an octal + value between 0000 and 0777 + or a decimal value between 0 + and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. + If not specified, the volume + defaultMode will be used. This + might be in conflict with other + options that affect the file + mode, like fsGroup, and the + result can be other mode bits + set.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map the + key to. May not be an absolute + path. May not contain the path + element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to + project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself with + an identifier specified in the audience + of the token, and otherwise should + reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the + requested duration of validity of + the service account token. As the + token approaches expiration, the kubelet + volume plugin will proactively rotate + the service account token. The kubelet + will start trying to rotate the token + if the token is older than 80 percent + of its time to live or if the token + is older than 24 hours.Defaults to + 1 hour and must be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file to + project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on + the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default + is no group + type: string + readOnly: + description: readOnly here will force the Quobyte + volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string + as host:port pair (multiple entries are separated + with commas) which acts as the central registry + for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned + Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults + to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of + the volume that you want to mount. Tip: Ensure + that the filesystem type is supported by the + host operating system. Examples: "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. More + info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph + monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default + is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default + is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the + ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the + ScaleIO Protection Domain for the configured + storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation will + fail. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL + communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the + storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that is + associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should + populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits + used to set permissions on created files by + default. Must be an octal value between 0000 + and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, + JSON requires decimal values for mode bits. + Defaults to 0644. Directories within the path + are not affected by this setting. This might + be in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced Secret + will be projected into the volume as a file + whose name is the key and content is the value. + If specified, the listed keys will be projected + into the specified paths, and unlisted keys + will not be present. If a key is specified which + is not present in the Secret, the volume setup + will error unless it is marked optional. Paths + must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits + used to set permissions on this file. + Must be an octal value between 0000 and + 0777 or a decimal value between 0 and + 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. If not specified, the volume + defaultMode will be used. This might be + in conflict with other options that affect + the file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path of + the file to map the key to. May not be + an absolute path. May not contain the + path element '..'. May not start with + the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the + Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret + in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to + mount. Must be a filesystem type supported by + the host operating system. Ex. "ext4", "xfs", + "ntfs". Implicitly inferred to be "ext4" if + unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to + use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope + of the volume within StorageOS. If no namespace + is specified then the Pod's namespace will be + used. This allows the Kubernetes name scoping + to be mirrored within StorageOS for tighter + integration. Set VolumeName to any name to override + the default behaviour. Set to "default" if you + are not using namespaces within StorageOS. Namespaces + that do not pre-exist within StorageOS will + be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. + Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs", "ntfs". + Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy + Based Management (SPBM) profile ID associated + with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + name: + type: string + path: + type: string + type: object + type: array + type: object + status: + description: ZProjectStatus defines the observed state of ZProject + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zregistries.yaml b/backend/config/crd/bases/zelda.io_zregistries.yaml new file mode 100644 index 0000000..cdf953a --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zregistries.yaml @@ -0,0 +1,57 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zregistries.zelda.io +spec: + group: zelda.io + names: + kind: ZRegistry + listKind: ZRegistryList + plural: zregistries + singular: zregistry + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZRegistry is the Schema for the zregistries API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZRegistrySpec defines the desired state of ZRegistry + properties: + namespace: + type: string + password: + type: string + portal: + type: string + server: + description: Foo is an example field of ZRegistry. Edit zregistry_types.go + to remove/update Foo string `json:"foo,omitempty"` + type: string + username: + type: string + type: object + status: + description: ZRegistryStatus defines the observed state of ZRegistry + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zruntemplates.yaml b/backend/config/crd/bases/zelda.io_zruntemplates.yaml new file mode 100644 index 0000000..fa958a4 --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zruntemplates.yaml @@ -0,0 +1,2625 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zruntemplates.zelda.io +spec: + group: zelda.io + names: + kind: ZRunTemplate + listKind: ZRunTemplateList + plural: zruntemplates + singular: zruntemplate + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZRunTemplate is the Schema for the zruntemplates API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZRunTemplateSpec defines the desired state of ZRunTemplate + properties: + containers: + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container image''s + CMD is used if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If a variable + cannot be resolved, the reference in the input string will + be unchanged. Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within a shell. + The container image''s ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the reference + in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: + i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether + the variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. + If a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + 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 + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + 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 + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment variables + in the container. The keys defined within a source must be + a C_IDENTIFIER. All invalid keys will be reported as an event + when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take + precedence. Values defined by an Env with a duplicate key + will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management + to default or override container images in workload controllers + like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take + in response to container lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately after a container + is created. If the handler fails, the container is terminated + and restarted according to its restart policy. Other management + of the container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's + filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, you need + to explicitly call out to that shell. Exit status + of 0 is treated as live/healthy and non-zero is + unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward compatibility. + There are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before a container + is terminated due to an API request or management event + such as liveness/startup probe failure, preemption, resource + contention, etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the container + will eventually terminate within the Pod''s termination + grace period (unless delayed by finalizers). Other management + of the container blocks until the hook completes or until + the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's + filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, you need + to explicitly call out to that shell. Exit status + of 0 is treated as live/healthy and non-zero is + unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward compatibility. + There are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. Container + will be restarted if the probe fails. Cannot be updated. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not + specifying a port here DOES NOT prevent that port from being + exposed. Any port which is listening on the default "0.0.0.0" + address inside a container will be accessible from the network. + Modifying this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: Number of port to expose on the pod's IP + address. This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: Number of port to expose on the host. If + specified, this must be a valid port number, 0 < x < + 65536. If HostNetwork is specified, this must match + ContainerPort. Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in a pod + must have a unique name. Name for the port that can + be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe + fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this resource + resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified resource + is resized. If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only + be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests + cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior of + individual containers in a pod. This field may only be set + for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod''s restart policy + and the container type. Setting the RestartPolicy as "Always" + for the init container will have the following effect: this + init container will be continually restarted on exit until + all regular containers have terminated. Once all regular containers + have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init + containers and is often referred to as a "sidecar" container. + Although this init container still starts in the init container + sequence, it does not wait for the container to complete before + proceeding to the next init container. Instead, the next init + container starts immediately after this init container is + started, or after any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options the + container should be run with. If set, the fields of SecurityContext + override the equivalent fields of PodSecurityContext. More + info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN Note that this field cannot be set + when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by + the container runtime. Note that this field cannot be + set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent to + root on the host. Defaults to false. Note that this field + cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to + use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. Note that this field cannot + be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when + spec.os.name is windows. + 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 PodSecurityContext. 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 PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a + random SELinux context for each container. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when + spec.os.name is windows. + 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 this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + Note that this field cannot be set when spec.os.name is + windows. + 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: \n 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 + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options from the PodSecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is + linux. + 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 + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully + initialized. If specified, no other probes are executed until + this completes successfully. If this probe fails, the Pod + will be restarted, just as if the livenessProbe failed. This + can be used to provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time to load + data or warm a cache, than during steady-state operation. + This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate a buffer + for stdin in the container runtime. If this is not set, reads + from stdin in the container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the + stdin channel after it has been opened by a single attach. + When stdin is true the stdin stream will remain open across + multiple attach sessions. If stdinOnce is set to true, stdin + is opened on container start, is empty until the first client + attaches to stdin, and then remains open and accepts data + until the client disconnects, at which time stdin is closed + and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the + container''s termination message will be written is mounted + into the container''s filesystem. Message written is intended + to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. + The total message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be + populated. File will use the contents of terminationMessagePath + to populate the container status message on both success and + failure. FallbackToLogsOnError will use the last chunk of + container log output if the termination message file is empty + and the container exited with an error. The log output is + limited to 2048 bytes or 80 lines, whichever is smaller. Defaults + to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY for + itself, also requires 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the volume + should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are + propagated from the host to container and the other + way around. When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves similarly + to SubPath but environment variable references $(VAR_NAME) + are expanded using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath are mutually + exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which might + be configured in the container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + dockerfile: + description: Anffinity *corev1.Affinity `json:"anffinity,omitempty"` + type: string + initContainers: + description: Foo is an example field of ZRunTemplate. Edit zruntemplate_types.go + to remove/update Foo string `json:"foo,omitempty"` corev1.PodSpec + `json:",inline"` + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The container image''s + CMD is used if this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. If a variable + cannot be resolved, the reference in the input string will + be unchanged. Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references + will never be expanded, regardless of whether the variable + exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within a shell. + The container image''s ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, the reference + in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: + i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether + the variable exists or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. + If a variable cannot be resolved, the reference in the + input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) + syntax: i.e. "$$(VAR_NAME)" will produce the string + literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists + or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + 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 + fieldRef: + description: 'Selects a field of the pod: supports + metadata.name, metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + 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 + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment variables + in the container. The keys defined within a source must be + a C_IDENTIFIER. All invalid keys will be reported as an event + when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take + precedence. Values defined by an Env with a duplicate key + will take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management + to default or override container images in workload controllers + like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent + otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take + in response to container lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately after a container + is created. If the handler fails, the container is terminated + and restarted according to its restart policy. Other management + of the container blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's + filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, you need + to explicitly call out to that shell. Exit status + of 0 is treated as live/healthy and non-zero is + unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward compatibility. + There are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately before a container + is terminated due to an API request or management event + such as liveness/startup probe failure, preemption, resource + contention, etc. The handler is not called if the container + crashes or exits. The Pod''s termination grace period + countdown begins before the PreStop hook is executed. + Regardless of the outcome of the handler, the container + will eventually terminate within the Pod''s termination + grace period (unless delayed by finalizers). Other management + of the container blocks until the hook completes or until + the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for + the command is root ('/') in the container's + filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions + ('|', etc) won't work. To use a shell, you need + to explicitly call out to that shell. Exit status + of 0 is treated as live/healthy and non-zero is + unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to + the pod IP. You probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the + host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is NOT supported + as a LifecycleHandler and kept for the backward compatibility. + There are no validation of this field and lifecycle + hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access + on the container. Number must be in the range + 1 to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. Container + will be restarted if the probe fails. Cannot be updated. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not + specifying a port here DOES NOT prevent that port from being + exposed. Any port which is listening on the default "0.0.0.0" + address inside a container will be accessible from the network. + Modifying this array with strategic merge patch may corrupt + the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: Number of port to expose on the pod's IP + address. This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: Number of port to expose on the host. If + specified, this must be a valid port number, 0 < x < + 65536. If HostNetwork is specified, this must match + ContainerPort. Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be an IANA_SVC_NAME + and unique within the pod. Each named port in a pod + must have a unique name. Name for the port that can + be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe + fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: 'Name of the resource to which this resource + resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified resource + is resized. If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only + be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests + cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + restartPolicy: + description: 'RestartPolicy defines the restart behavior of + individual containers in a pod. This field may only be set + for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod''s restart policy + and the container type. Setting the RestartPolicy as "Always" + for the init container will have the following effect: this + init container will be continually restarted on exit until + all regular containers have terminated. Once all regular containers + have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init + containers and is often referred to as a "sidecar" container. + Although this init container still starts in the init container + sequence, it does not wait for the container to complete before + proceeding to the next init container. Instead, the next init + container starts immediately after this init container is + started, or after any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options the + container should be run with. If set, the fields of SecurityContext + override the equivalent fields of PodSecurityContext. More + info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether + a process can gain more privileges than its parent process. + This bool directly controls if the no_new_privs flag will + be set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) run as Privileged + 2) has CAP_SYS_ADMIN Note that this field cannot be set + when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by + the container runtime. Note that this field cannot be + set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. Processes + in privileged containers are essentially equivalent to + root on the host. Defaults to false. Note that this field + cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to + use for the containers. The default is DefaultProcMount + which uses the container runtime defaults for readonly + paths and masked paths. This requires the ProcMountType + feature flag to be enabled. Note that this field cannot + be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root + filesystem. Default is false. Note that this field cannot + be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container + process. Uses runtime default if unset. May also be set + in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when + spec.os.name is windows. + 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 PodSecurityContext. 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 PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a + random SELinux context for each container. May also be + set in PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in SecurityContext + takes precedence. Note that this field cannot be set when + spec.os.name is windows. + 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 this container. + If seccomp options are provided at both the pod & container + level, the container options override the pod options. + Note that this field cannot be set when spec.os.name is + windows. + 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: \n 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 + windowsOptions: + description: The Windows specific settings applied to all + containers. If unspecified, the options from the PodSecurityContext + will be used. If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is + linux. + 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 + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully + initialized. If specified, no other probes are executed until + this completes successfully. If this probe fails, the Pod + will be restarted, just as if the livenessProbe failed. This + can be used to provide different probe parameters at the beginning + of a Pod''s lifecycle, when it might take a long time to load + data or warm a cache, than during steady-state operation. + This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: Command is the command line to execute + inside the container, the working directory for the + command is root ('/') in the container's filesystem. + The command is simply exec'd, it is not run inside + a shell, so traditional shell instructions ('|', etc) + won't work. To use a shell, you need to explicitly + call out to that shell. Exit status of 0 is treated + as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures for the probe + to be considered failed after having succeeded. Defaults + to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the service to + place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default behavior + is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: Host name to connect to, defaults to the + pod IP. You probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: The header field name. This will + be canonicalized upon output, so case-variant + names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the container has + started before liveness probes are initiated. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes for the probe + to be considered successful after having failed. Defaults + to 1. Must be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port to access on + the container. Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully upon probe failure. The grace + period is the duration in seconds after the processes + running in the pod are sent a termination signal and the + time when the processes are forcibly halted with a kill + signal. Set this value longer than the expected cleanup + time for your process. If this value is nil, the pod's + terminationGracePeriodSeconds will be used. Otherwise, + this value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates + stop immediately via the kill signal (no opportunity to + shut down). This is a beta field and requires enabling + ProbeTerminationGracePeriod feature gate. Minimum value + is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which the probe times + out. Defaults to 1 second. Minimum value is 1. More info: + https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate a buffer + for stdin in the container runtime. If this is not set, reads + from stdin in the container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the + stdin channel after it has been opened by a single attach. + When stdin is true the stdin stream will remain open across + multiple attach sessions. If stdinOnce is set to true, stdin + is opened on container start, is empty until the first client + attaches to stdin, and then remains open and accepts data + until the client disconnects, at which time stdin is closed + and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin + will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the + container''s termination message will be written is mounted + into the container''s filesystem. Message written is intended + to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. + The total message length across all containers will be limited + to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be + populated. File will use the contents of terminationMessagePath + to populate the container status message on both success and + failure. FallbackToLogsOnError will use the last chunk of + container log output if the termination message file is empty + and the container exited with an error. The log output is + limited to 2048 bytes or 80 lines, whichever is smaller. Defaults + to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY for + itself, also requires 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: Path within the container at which the volume + should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are + propagated from the host to container and the other + way around. When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise + (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's + volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which + the container's volume should be mounted. Behaves similarly + to SubPath but environment variable references $(VAR_NAME) + are expanded using the container's environment. Defaults + to "" (volume's root). SubPathExpr and SubPath are mutually + exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If not specified, + the container runtime's default will be used, which might + be configured in the container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + restartPolicy: + description: RestartPolicy describes how the container should be restarted. + Only one of the following restart policies may be specified. If + none of the following policies is specified, the default one is + RestartPolicyAlways. + type: string + type: + type: string + type: object + status: + description: ZRunTemplateStatus defines the observed state of ZRunTemplate + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zscripts.yaml b/backend/config/crd/bases/zelda.io_zscripts.yaml new file mode 100644 index 0000000..282b74f --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zscripts.yaml @@ -0,0 +1,1963 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zscripts.zelda.io +spec: + group: zelda.io + names: + kind: ZScript + listKind: ZScriptList + plural: zscripts + singular: zscript + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZScript is the Schema for the zscripts API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZScriptSpec defines the desired state of ZScript + properties: + branch: + type: string + customHost: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + env: + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using + the previously defined environment variables in the container + and any service environment variables. If a variable cannot + be resolved, the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the + string literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists or + not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + 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 + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, + status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + 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 + required: + - name + type: object + type: array + path: + type: string + project: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + runSpec: + description: Foo is an example field of ZScript. Edit zscript_types.go + to remove/update Foo string `json:"foo,omitempty"` + properties: + template: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many + fields which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. + Invalid usage help. It is impossible to add specific help for + individual usage. In most embedded usages, there are particular + restrictions like, \"must refer only to types A and B\" or \"UID + not honored\" or \"name must be restricted\". Those cannot be + well described when embedded. 3. Inconsistent validation. Because + the usages are different, the validation rules are different + by usage, which makes it hard for users to predict what will + happen. 4. The fields are both imprecise and overly precise. + \ Kind is not a precise mapping to a URL. This can produce ambiguity + during interpretation and require a REST mapping. In most cases, + the dependency is on the group,resource tuple and the version + of the actual struct is irrelevant. 5. We cannot easily change + it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type + that is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead + of an entire object, this string should contain a valid + JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part + of an object. TODO: this design is not final and this field + is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + volumes: + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the readOnly + setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount + on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in + the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the + blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure managed + data disk (only in managed availability set). defaults + to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host + that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is a collection + of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is + the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference + to the authentication secret for User, default is + empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados user + name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret + object containing parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume in + cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value pair + in the Data field of the referenced ConfigMap will + be projected into the volume as a file whose name + is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. If a + key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver that + handles this volume. Consult with your admin for the + correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the + associated CSI driver which will determine the default + filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to + the secret object containing sensitive information + to pass to the CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This field is optional, + and may be empty if no secret is required. If the + secret object contains more than one secret, all secret + references are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. Consult + your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about the + pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the + pod: only annotations, labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to set + permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict with + other options that affect the file mode, like + fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must not + be absolute or contain the ''..'' path. Must + be utf-8 encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default is + "" which means to use the node''s default medium. + Must be an empty string (default) or Memory. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local + storage required for this EmptyDir volume. The size + limit is also applicable for memory medium. The maximum + usage on memory medium EmptyDir would be the minimum + value between the SizeLimit specified here and the + sum of memory limits of all containers in a pod. The + default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + 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 + ephemeral: + description: "ephemeral represents a volume that is handled + by a cluster storage driver. The volume's lifecycle is + tied to the pod that defines it - it will be created before + the pod starts, and deleted when the pod is removed. \n + Use this if: a) the volume is only needed while the pod + runs, b) features of normal volumes like restoring from + snapshot or capacity tracking are needed, c) the storage + driver is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for + more information on the connection between this volume + type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that persist + for longer than the lifecycle of an individual pod. \n + Use CSI for light-weight local ephemeral volumes if the + CSI driver is meant to be used that way - see the documentation + of the driver for more information. \n A pod can use both + types of ephemeral volumes and persistent volumes at the + same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC + to provision the volume. The pod in which this EphemeralVolumeSource + is embedded will be the owner of the PVC, i.e. the + PVC will be deleted together with the pod. The name + of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the pod if + the concatenated name is not valid for a PVC (for + example, too long). \n An existing PVC with that name + that is not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is meant + to be used by the pod, the PVC has to updated with + an owner reference to the pod once the pod exists. + Normally this should not be necessary, but it may + be useful when manually reconstructing a broken cluster. + \n This field is read-only and no changes will be + made by Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will be rejected + during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into the + PVC that gets created from this template. The + same fields as in a PersistentVolumeClaim are + also valid here. + properties: + accessModes: + description: 'accessModes contains the desired + access modes the volume should have. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used to + specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, it + will create a new volume based on the contents + of the specified data source. When the AnyVolumeDataSource + feature gate is enabled, dataSource contents + will be copied to dataSourceRef, and dataSourceRef + contents will be copied to dataSource when + dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the object + from which to populate the volume with data, + if a non-empty volume is desired. This may + be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding + will only succeed if the type of the specified + object matches some installed volume populator + or dynamic provisioner. This field will replace + the functionality of the dataSource field + and as such if both fields are non-empty, + they must have the same value. For backwards + compatibility, when namespace isn''t specified + in dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to the same + value automatically if one of them is empty + and the other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and must be empty. + There are three important differences between + dataSource and dataSourceRef: * While dataSource + only allows two specific types of objects, + dataSourceRef allows any non-core object, + as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values + (dropping them), dataSourceRef preserves all + values, and generates an error if a disallowed + value is specified. * While dataSource only + allows local objects, dataSourceRef allows + objects in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using the namespace + field of dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note that + when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferenceGrant + documentation for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the minimum + resources the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to specify + resource requirements that are lower than + previous value but must still be higher than + capacity recorded in the status field of the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + 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 + required: + - key + - operator + type: object + type: array + 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 + storageClassName: + description: 'storageClassName is the name of + the StorageClass required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of + volume is required by the claim. Value of + Filesystem is implied when not included in + claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that + is attached to a kubelet's host machine and then exposed + to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world wide identifiers + (wwids) Either wwids or combination of targetWWNs + and lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume resource + that is provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use + for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The default filesystem + depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference + to the secret object containing sensitive information + to pass to the plugin scripts. This may be empty if + no secret object is specified. If the secret object + contains more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the Flocker + control service being running + properties: + datasetName: + description: datasetName is Name of the dataset stored + as metadata -> name on the dataset for Flocker should + be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then + exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource + in GCE. Used to identify the disk in GCE. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision + a container with a git repo, mount an EmptyDir into an + InitContainer that clones the repo using git, then mount + the EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, + the volume directory will be the git repository. Otherwise, + if specified, the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount on + the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More + info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. Defaults + to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file or + directory on the host machine that is directly exposed + to the container. This is generally used for system agents + or other privileged things that are allowed to see the + host machine. Most containers will NOT need this. More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host + directory mounts and who can/can not mount host directories + as read/write.' + properties: + path: + description: 'path of the directory on the host. If + the path is a symlink, it will follow the link to + the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource that + is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that + uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal List. + The portal is either an IP or ip_addr:port if the + port is other than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. The + Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL and + unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that + shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export + to be mounted with read-only permissions. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting + in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type to + mount Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used to set + permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this + setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along + with other supported volume types + properties: + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: audience is the intended audience + of the token. A recipient of a token must + identify itself with an identifier specified + in the audience of the token, and otherwise + should reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested + duration of validity of the service account + token. As the token approaches expiration, + the kubelet volume plugin will proactively + rotate the service account token. The kubelet + will start trying to rotate the token if + the token is older than 80 percent of its + time to live or if the token is older than + 24 hours.Defaults to 1 hour and must be + at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative to + the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default is + no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume + to be mounted with read-only permissions. Defaults + to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string as + host:port pair (multiple entries are separated with + commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned Quobyte + volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to + serivceaccount user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default is + rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default is + admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for + ScaleIO user and other sensitive information. If this + is not provided, Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage + for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool + associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already + created in the ScaleIO system that is associated with + this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value pair + in the Data field of the referenced Secret will be + projected into the volume as a file whose name is + the key and content is the value. If specified, the + listed keys will be projected into the specified paths, + and unlisted keys will not be present. If a key is + specified which is not present in the Secret, the + volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in + the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for + obtaining the StorageOS API credentials. If not specified, + default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name of + the StorageOS volume. Volume names are only unique + within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of + the volume within StorageOS. If no namespace is specified + then the Pod's namespace will be used. This allows + the Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. Set + to "default" if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist within + StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + type: object + status: + description: ZScriptStatus defines the observed state of ZScript + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zservices.yaml b/backend/config/crd/bases/zelda.io_zservices.yaml new file mode 100644 index 0000000..8a6d279 --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zservices.yaml @@ -0,0 +1,2844 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zservices.zelda.io +spec: + group: zelda.io + names: + kind: ZService + listKind: ZServiceList + plural: zservices + singular: zservice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZService is the Schema for the zservices API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZServiceSpec defines the desired state of ZService + properties: + creator: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + customHosts: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + env: + description: Foo is an example field of ZService. Edit zservice_types.go + to remove/update Foo string `json:"foo,omitempty"` + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using + the previously defined environment variables in the container + and any service environment variables. If a variable cannot + be resolved, the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the + string literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists or + not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + 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 + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, + status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + 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 + required: + - name + type: object + type: array + kind: + type: string + nodeSelector: + description: A node selector represents the union of the results of + one or more label queries over a set of nodes; that is, it represents + the OR of the selectors represented by the node selector terms. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms + are ORed. + items: + description: A null or empty node selector term matches no objects. + The requirements of them are ANDed. The TopologySelectorTerm + type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's + labels. + items: + description: A node selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: Represents a key's relationship to a + set of values. Valid operators are In, NotIn, Exists, + DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator + is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. If the operator is Gt or Lt, + the values array must have a single element, which + will be interpreted as an integer. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements by node's + fields. + items: + description: A node selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: Represents a key's relationship to a + set of values. Valid operators are In, NotIn, Exists, + DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator + is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. If the operator is Gt or Lt, + the values array must have a single element, which + will be interpreted as an integer. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + podAffinity: + description: Pod affinity is a group of inter pod affinity scheduling + rules. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes + that satisfy the affinity expressions specified by this field, + but it may choose a node that violates one or more of the expressions. + The node that is most preferred is the one with the greatest + sum of weights, i.e. for each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling affinity + expressions, etc.), compute a sum by iterating through the elements + of this field and adding "weight" to the sum if the node has + pods which matches the corresponding podAffinityTerm; the node(s) + with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with + the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied to the + union of the namespaces selected by this field and + the ones listed in the namespaces field. null selector + and null or empty namespaces list means "this pod's + namespace". An empty selector ({}) matches all namespaces. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaces: + description: namespaces specifies a static list of namespace + names that the term applies to. The term is applied + to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. null or + empty namespaces list and null namespaceSelector means + "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where + co-located is defined as running on a node whose value + of the label with key topologyKey matches that of + any node on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the corresponding + podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field + are not met at scheduling time, the pod will not be scheduled + onto the node. If the affinity requirements specified by this + field cease to be met at some point during pod execution (e.g. + due to a pod label update), the system may or may not try to + eventually evict the pod from its node. When there are multiple + elements, the lists of nodes corresponding to each podAffinityTerm + are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching the + labelSelector relative to the given namespace(s)) that this + pod should be co-located (affinity) or not co-located (anti-affinity) + with, where co-located is defined as running on a node whose + value of the label with key matches that of + any node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, in this + case pods. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaceSelector: + description: A label query over the set of namespaces that + the term applies to. The term is applied to the union + of the namespaces selected by this field and the ones + listed in the namespaces field. null selector and null + or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaces: + description: namespaces specifies a static list of namespace + names that the term applies to. The term is applied to + the union of the namespaces listed in this field and the + ones selected by namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) or + not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located + is defined as running on a node whose value of the label + with key topologyKey matches that of any node on which + any of the selected pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Pod anti affinity is a group of inter pod anti affinity + scheduling rules. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes + that satisfy the anti-affinity expressions specified by this + field, but it may choose a node that violates one or more of + the expressions. The node that is most preferred is the one + with the greatest sum of weights, i.e. for each node that meets + all of the scheduling requirements (resource request, requiredDuringScheduling + anti-affinity expressions, etc.), compute a sum by iterating + through the elements of this field and adding "weight" to the + sum if the node has pods which matches the corresponding podAffinityTerm; + the node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with + the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, + in this case pods. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaceSelector: + description: A label query over the set of namespaces + that the term applies to. The term is applied to the + union of the namespaces selected by this field and + the ones listed in the namespaces field. null selector + and null or empty namespaces list means "this pod's + namespace". An empty selector ({}) matches all namespaces. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaces: + description: namespaces specifies a static list of namespace + names that the term applies to. The term is applied + to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. null or + empty namespaces list and null namespaceSelector means + "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) + or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where + co-located is defined as running on a node whose value + of the label with key topologyKey matches that of + any node on which any of the selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the corresponding + podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this + field are not met at scheduling time, the pod will not be scheduled + onto the node. If the anti-affinity requirements specified by + this field cease to be met at some point during pod execution + (e.g. due to a pod label update), the system may or may not + try to eventually evict the pod from its node. When there are + multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching the + labelSelector relative to the given namespace(s)) that this + pod should be co-located (affinity) or not co-located (anti-affinity) + with, where co-located is defined as running on a node whose + value of the label with key matches that of + any node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, in this + case pods. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaceSelector: + description: A label query over the set of namespaces that + the term applies to. The term is applied to the union + of the namespaces selected by this field and the ones + listed in the namespaces field. null selector and null + or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + 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 + required: + - key + - operator + type: object + type: array + 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 + namespaces: + description: namespaces specifies a static list of namespace + names that the term applies to. The term is applied to + the union of the namespaces listed in this field and the + ones selected by namespaceSelector. null or empty namespaces + list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) or + not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located + is defined as running on a node whose value of the label + with key topologyKey matches that of any node on which + any of the selected pods is running. Empty topologyKey + is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + project: + description: "ObjectReference contains enough information to let you + inspect or modify the referred object. --- New uses of this type + are discouraged because of difficulty describing its usage when + embedded in APIs. 1. Ignored fields. It includes many fields which + are not generally honored. For instance, ResourceVersion and FieldPath + are both very rarely valid in actual usage. 2. Invalid usage help. + \ It is impossible to add specific help for individual usage. In + most embedded usages, there are particular restrictions like, \"must + refer only to types A and B\" or \"UID not honored\" or \"name must + be restricted\". Those cannot be well described when embedded. 3. + Inconsistent validation. Because the usages are different, the + validation rules are different by usage, which makes it hard for + users to predict what will happen. 4. The fields are both imprecise + and overly precise. Kind is not a precise mapping to a URL. This + can produce ambiguity during interpretation and require a REST mapping. + \ In most cases, the dependency is on the group,resource tuple and + the version of the actual struct is irrelevant. 5. We cannot easily + change it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type that + is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + runSpec: + properties: + template: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many + fields which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. + Invalid usage help. It is impossible to add specific help for + individual usage. In most embedded usages, there are particular + restrictions like, \"must refer only to types A and B\" or \"UID + not honored\" or \"name must be restricted\". Those cannot be + well described when embedded. 3. Inconsistent validation. Because + the usages are different, the validation rules are different + by usage, which makes it hard for users to predict what will + happen. 4. The fields are both imprecise and overly precise. + \ Kind is not a precise mapping to a URL. This can produce ambiguity + during interpretation and require a REST mapping. In most cases, + the dependency is on the group,resource tuple and the version + of the actual struct is irrelevant. 5. We cannot easily change + it. Because this type is embedded in many locations, updates + to this type will affect numerous schemas. Don't make new APIs + embed an underspecified API type they do not control. \n Instead + of using this type, create a locally provided and used type + that is well-focused on your reference. For example, ServiceReferences + for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead + of an entire object, this string should contain a valid + JSON/Go field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part + of an object. TODO: this design is not final and this field + is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + volumes: + items: + description: Volume represents a named volume in a pod that + may be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk + resource that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force the readOnly + setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent + disk resource in AWS (Amazon EBS volume). More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount + on the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: + None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in + the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the + blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single + blob disk per storage account Managed: azure managed + data disk (only in managed availability set). defaults + to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service + mount on the host and bind mount to the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that + contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host + that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors is a collection + of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted + root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is + the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference + to the authentication secret for User, default is + empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the rados user + name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume attached + and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Examples: "ext4", "xfs", "ntfs". Implicitly + inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret + object containing parameters used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the volume in + cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should + populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value pair + in the Data field of the referenced ConfigMap will + be projected into the volume as a file whose name + is the key and content is the value. If specified, + the listed keys will be projected into the specified + paths, and unlisted keys will not be present. If a + key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents + ephemeral storage that is handled by certain external + CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI driver that + handles this volume. Consult with your admin for the + correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the + associated CSI driver which will determine the default + filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to + the secret object containing sensitive information + to pass to the CSI driver to complete the CSI NodePublishVolume + and NodeUnpublishVolume calls. This field is optional, + and may be empty if no secret is required. If the + secret object contains more than one secret, all secret + references are passed. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only configuration + for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. Consult + your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about the + pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on created + files by default. Must be a Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: Items is a list of downward API volume + file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the + pod: only annotations, labels, name and namespace + are supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in + the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used to set + permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode + bits. If not specified, the volume defaultMode + will be used. This might be in conflict with + other options that affect the file mode, like + fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must not + be absolute or contain the ''..'' path. Must + be utf-8 encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: + only resources limits and requests (limits.cpu, + limits.memory, requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required for + volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of + the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary directory + that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type of storage + medium should back this directory. The default is + "" which means to use the node''s default medium. + Must be an empty string (default) or Memory. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount of local + storage required for this EmptyDir volume. The size + limit is also applicable for memory medium. The maximum + usage on memory medium EmptyDir would be the minimum + value between the SizeLimit specified here and the + sum of memory limits of all containers in a pod. The + default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + 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 + ephemeral: + description: "ephemeral represents a volume that is handled + by a cluster storage driver. The volume's lifecycle is + tied to the pod that defines it - it will be created before + the pod starts, and deleted when the pod is removed. \n + Use this if: a) the volume is only needed while the pod + runs, b) features of normal volumes like restoring from + snapshot or capacity tracking are needed, c) the storage + driver is specified through a storage class, and d) the + storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for + more information on the connection between this volume + type and PersistentVolumeClaim). \n Use PersistentVolumeClaim + or one of the vendor-specific APIs for volumes that persist + for longer than the lifecycle of an individual pod. \n + Use CSI for light-weight local ephemeral volumes if the + CSI driver is meant to be used that way - see the documentation + of the driver for more information. \n A pod can use both + types of ephemeral volumes and persistent volumes at the + same time." + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC + to provision the volume. The pod in which this EphemeralVolumeSource + is embedded will be the owner of the PVC, i.e. the + PVC will be deleted together with the pod. The name + of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` + array entry. Pod validation will reject the pod if + the concatenated name is not valid for a PVC (for + example, too long). \n An existing PVC with that name + that is not owned by the pod will *not* be used for + the pod to avoid using an unrelated volume by mistake. + Starting the pod is then blocked until the unrelated + PVC is removed. If such a pre-created PVC is meant + to be used by the pod, the PVC has to updated with + an owner reference to the pod once the pod exists. + Normally this should not be necessary, but it may + be useful when manually reconstructing a broken cluster. + \n This field is read-only and no changes will be + made by Kubernetes to the PVC after it has been created. + \n Required, must not be nil." + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when creating + it. No other fields are allowed and will be rejected + during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. + The entire content is copied unchanged into the + PVC that gets created from this template. The + same fields as in a PersistentVolumeClaim are + also valid here. + properties: + accessModes: + description: 'accessModes contains the desired + access modes the volume should have. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can be used to + specify either: * An existing VolumeSnapshot + object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller + can support the specified data source, it + will create a new volume based on the contents + of the specified data source. When the AnyVolumeDataSource + feature gate is enabled, dataSource contents + will be copied to dataSourceRef, and dataSourceRef + contents will be copied to dataSource when + dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef + will not be copied to dataSource.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: 'dataSourceRef specifies the object + from which to populate the volume with data, + if a non-empty volume is desired. This may + be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding + will only succeed if the type of the specified + object matches some installed volume populator + or dynamic provisioner. This field will replace + the functionality of the dataSource field + and as such if both fields are non-empty, + they must have the same value. For backwards + compatibility, when namespace isn''t specified + in dataSourceRef, both fields (dataSource + and dataSourceRef) will be set to the same + value automatically if one of them is empty + and the other is non-empty. When namespace + is specified in dataSourceRef, dataSource + isn''t set to the same value and must be empty. + There are three important differences between + dataSource and dataSourceRef: * While dataSource + only allows two specific types of objects, + dataSourceRef allows any non-core object, + as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values + (dropping them), dataSourceRef preserves all + values, and generates an error if a disallowed + value is specified. * While dataSource only + allows local objects, dataSourceRef allows + objects in any namespaces. (Beta) Using this + field requires the AnyVolumeDataSource feature + gate to be enabled. (Alpha) Using the namespace + field of dataSourceRef requires the CrossNamespaceVolumeDataSource + feature gate to be enabled.' + properties: + apiGroup: + description: APIGroup is the group for the + resource being referenced. If APIGroup + is not specified, the specified Kind must + be in the core API group. For any other + third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource + being referenced + type: string + name: + description: Name is the name of resource + being referenced + type: string + namespace: + description: Namespace is the namespace + of resource being referenced Note that + when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferenceGrant + documentation for details. (Alpha) This + field requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents the minimum + resources the volume should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed to specify + resource requirements that are lower than + previous value but must still be higher than + capacity recorded in the status field of the + claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the names of + resources, defined in spec.resourceClaims, + that are used by this container. \n This + is an alpha field and requires enabling + the DynamicResourceAllocation feature + gate. \n This field is immutable. It can + only be set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. + If Requests is omitted for a container, + it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query over + volumes to consider for binding. + 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 + required: + - key + - operator + type: object + type: array + 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 + storageClassName: + description: 'storageClassName is the name of + the StorageClass required by the claim. More + info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of + volume is required by the claim. Value of + Filesystem is implied when not included in + claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that + is attached to a kubelet's host machine and then exposed + to the pod. + properties: + fsType: + description: 'fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world wide identifiers + (wwids) Either wwids or combination of targetWWNs + and lun must be set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume resource + that is provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use + for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". The default filesystem + depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds + extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults to false + (read/write). ReadOnly here will force the ReadOnly + setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference + to the secret object containing sensitive information + to pass to the plugin scripts. This may be empty if + no secret object is specified. If the secret object + contains more than one secret, all secrets are passed + to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached + to a kubelet's host machine. This depends on the Flocker + control service being running + properties: + datasetName: + description: datasetName is Name of the dataset stored + as metadata -> name on the dataset for Flocker should + be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. + This is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource + that is attached to a kubelet''s host machine and then + exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume + that you want to mount. If omitted, the default is + to mount by volume name. Examples: For volume /dev/sda1, + you specify the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can leave the + property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the PD resource + in GCE. Used to identify the disk in GCE. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository at a particular + revision. DEPRECATED: GitRepo is deprecated. To provision + a container with a git repo, mount an EmptyDir into an + InitContainer that clones the repo using git, then mount + the EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, + the volume directory will be the git repository. Otherwise, + if specified, the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs mount on + the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name that details + Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More + info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs + volume to be mounted with read-only permissions. Defaults + to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing file or + directory on the host machine that is directly exposed + to the container. This is generally used for system agents + or other privileged things that are allowed to see the + host machine. Most containers will NOT need this. More + info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- TODO(jonesdl) We need to restrict who can use host + directory mounts and who can/can not mount host directories + as read/write.' + properties: + path: + description: 'path of the directory on the host. If + the path is a symlink, it will follow the link to + the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource that + is attached to a kubelet''s host machine and then exposed + to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support + iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support + iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator + Name. If initiatorName is specified with iscsiInterface + simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that + uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal List. + The portal is either an IP or ip_addr:port if the + port is other than default (typically TCP ports 860 + and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the ReadOnly setting + in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI + target and initiator authentication + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target Portal. The + Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and + 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL and + unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that + shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export + to be mounted with read-only permissions. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of + the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents + a reference to a PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting + in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume + attached and mounted on kubelets host machine + properties: + fsType: + description: fSType represents the filesystem type to + mount Must be a filesystem type supported by the host + operating system. Ex. "ext4", "xfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx + volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits used to set + permissions on created files by default. Must be an + octal value between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this + setting. This might be in conflict with other options + that affect the file mode, like fsGroup, and the result + can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along + with other supported volume types + properties: + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the ConfigMap, the volume setup will + error unless it is marked optional. Paths + must be relative and may not contain the + '..' path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the + downwardAPI data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used. + This might be in conflict with other + options that affect the file mode, + like fsGroup, and the result can be + other mode bits set.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret + data to project + properties: + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. If + a key is specified which is not present + in the Secret, the volume setup will error + unless it is marked optional. Paths must + be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used. This might be in conflict + with other options that affect the + file mode, like fsGroup, and the result + can be other mode bits set.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional field specify whether + the Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information + about the serviceAccountToken data to project + properties: + audience: + description: audience is the intended audience + of the token. A recipient of a token must + identify itself with an identifier specified + in the audience of the token, and otherwise + should reject the token. The audience defaults + to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested + duration of validity of the service account + token. As the token approaches expiration, + the kubelet volume plugin will proactively + rotate the service account token. The kubelet + will start trying to rotate the token if + the token is older than 80 percent of its + time to live or if the token is older than + 24 hours.Defaults to 1 hour and must be + at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative to + the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: group to map volume access to Default is + no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume + to be mounted with read-only permissions. Defaults + to false. + type: boolean + registry: + description: registry represents a single or multiple + Quobyte Registry services specified as a string as + host:port pair (multiple entries are separated with + commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume + in the Backend Used with dynamically provisioned Quobyte + volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to + serivceaccount user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device mount + on the host that shares a pod''s lifetime. More info: + https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type of the volume + that you want to mount. Tip: Ensure that the filesystem + type is supported by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" + if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from + compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. Default is + rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly + setting in VolumeMounts. Defaults to false. More info: + https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides keyring. + Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. Default is + admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for + ScaleIO user and other sensitive information. If this + is not provided, Login operation will fail. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage + for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool + associated with the protection domain. + type: string + system: + description: system is the name of the storage system + as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already + created in the ScaleIO system that is associated with + this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that should populate + this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used + to set permissions on created files by default. Must + be an octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal and + decimal values, JSON requires decimal values for mode + bits. Defaults to 0644. Directories within the path + are not affected by this setting. This might be in + conflict with other options that affect the file mode, + like fsGroup, and the result can be other mode bits + set.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value pair + in the Data field of the referenced Secret will be + projected into the volume as a file whose name is + the key and content is the value. If specified, the + listed keys will be projected into the specified paths, + and unlisted keys will not be present. If a key is + specified which is not present in the Secret, the + volume setup will error unless it is marked optional. + Paths must be relative and may not contain the '..' + path or start with '..'. + items: + description: Maps a string key to a path within a + volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used + to set permissions on this file. Must be an + octal value between 0000 and 0777 or a decimal + value between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal values + for mode bits. If not specified, the volume + defaultMode will be used. This might be in conflict + with other options that affect the file mode, + like fsGroup, and the result can be other mode + bits set.' + format: int32 + type: integer + path: + description: path is the relative path of the + file to map the key to. May not be an absolute + path. May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret + or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in + the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for + obtaining the StorageOS API credentials. If not specified, + default values will be attempted. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable name of + the StorageOS volume. Volume names are only unique + within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of + the volume within StorageOS. If no namespace is specified + then the Pod's namespace will be used. This allows + the Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. Set + to "default" if you are not using namespaces within + StorageOS. Namespaces that do not pre-exist within + StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: fsType is filesystem type to mount. Must + be a filesystem type supported by the host operating + system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy + Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + services: + description: Volumes []corev1.Volume `json:"volumes,omitempty"` + items: + properties: + name: + type: string + ports: + items: + description: ServicePort contains information on service's + port. + properties: + appProtocol: + description: "The application protocol for this port. + This is used as a hint for implementations to offer + richer behavior for protocols that they understand. + This field follows standard Kubernetes label syntax. + Valid values are either: \n * Un-prefixed protocol names + - reserved for IANA standard service names (as per RFC-6335 + and https://www.iana.org/assignments/service-names). + \n * Kubernetes-defined prefixed names: * 'kubernetes.io/h2c' + - HTTP/2 over cleartext as described in https://www.rfc-editor.org/rfc/rfc7540 + * 'kubernetes.io/ws' - WebSocket over cleartext as + described in https://www.rfc-editor.org/rfc/rfc6455 + * 'kubernetes.io/wss' - WebSocket over TLS as described + in https://www.rfc-editor.org/rfc/rfc6455 \n * Other + protocols should use implementation-defined prefixed + names such as mycompany.com/my-custom-protocol." + type: string + name: + description: The name of this port within the service. + This must be a DNS_LABEL. All ports within a ServiceSpec + must have unique names. When considering the endpoints + for a Service, this must match the 'name' field in the + EndpointPort. Optional if only one ServicePort is defined + on this service. + type: string + nodePort: + description: 'The port on each node on which this service + is exposed when type is NodePort or LoadBalancer. Usually + assigned by the system. If a value is specified, in-range, + and not in use it will be used, otherwise the operation + will fail. If not specified, a port will be allocated + if this Service requires one. If this field is specified + when creating a Service which does not need it, creation + will fail. This field will be wiped when updating a + Service to no longer need it (e.g. changing type from + NodePort to ClusterIP). More info: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport' + format: int32 + type: integer + port: + description: The port that will be exposed by this service. + format: int32 + type: integer + protocol: + default: TCP + description: The IP protocol for this port. Supports "TCP", + "UDP", and "SCTP". Default is TCP. + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: 'Number or name of the port to access on + the pods targeted by the service. Number must be in + the range 1 to 65535. Name must be an IANA_SVC_NAME. + If this is a string, it will be looked up as a named + port in the target Pod''s container ports. If this is + not specified, the value of the ''port'' field is used + (an identity map). This field is ignored for services + with clusterIP=None, and should be omitted or set equal + to the ''port'' field. More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service' + x-kubernetes-int-or-string: true + required: + - port + type: object + type: array + type: + description: Service Type string describes ingress methods for + a service + type: string + type: object + type: array + subProject: + type: string + version: + type: string + type: object + status: + description: ZServiceStatus defines the observed state of ZService + properties: + branch: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file' + type: string + deploymentStatus: + description: Deployment status + properties: + availableReplicas: + format: int32 + type: integer + readyReplicas: + format: int32 + type: integer + replicas: + format: int32 + type: integer + unavailableReplicas: + format: int32 + type: integer + updatedReplicas: + format: int32 + type: integer + type: object + jobStatus: + description: Job status + properties: + active: + format: int32 + type: integer + completionTime: + format: date-time + type: string + failed: + format: int32 + type: integer + startTime: + format: date-time + type: string + succeeded: + format: int32 + type: integer + type: object + podStatus: + additionalProperties: + description: Pod status + properties: + message: + type: string + name: + type: string + phase: + description: PodPhase is a label for the condition of a pod + at the current time. + type: string + runAt: + type: string + type: object + type: object + target: + type: string + updatedAt: + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/bases/zelda.io_zusers.yaml b/backend/config/crd/bases/zelda.io_zusers.yaml new file mode 100644 index 0000000..d7aa0cc --- /dev/null +++ b/backend/config/crd/bases/zelda.io_zusers.yaml @@ -0,0 +1,125 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.13.0 + name: zusers.zelda.io +spec: + group: zelda.io + names: + kind: ZUser + listKind: ZUserList + plural: zusers + singular: zuser + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ZUser is the Schema for the zusers API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + 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: + description: ZUserSpec defines the desired state of ZUser + properties: + group: + type: string + notifyMedia: + type: string + password: + description: Foo is an example field of ZUser. Edit zuser_types.go + to remove/update Foo string `json:"foo,omitempty"` + type: string + secrets: + items: + description: "ObjectReference contains enough information to let + you inspect or modify the referred object. --- New uses of this + type are discouraged because of difficulty describing its usage + when embedded in APIs. 1. Ignored fields. It includes many fields + which are not generally honored. For instance, ResourceVersion + and FieldPath are both very rarely valid in actual usage. 2. Invalid + usage help. It is impossible to add specific help for individual + usage. In most embedded usages, there are particular restrictions + like, \"must refer only to types A and B\" or \"UID not honored\" + or \"name must be restricted\". Those cannot be well described + when embedded. 3. Inconsistent validation. Because the usages + are different, the validation rules are different by usage, which + makes it hard for users to predict what will happen. 4. The fields + are both imprecise and overly precise. Kind is not a precise + mapping to a URL. This can produce ambiguity during interpretation + and require a REST mapping. In most cases, the dependency is + on the group,resource tuple and the version of the actual struct + is irrelevant. 5. We cannot easily change it. Because this type + is embedded in many locations, updates to this type will affect + numerous schemas. Don't make new APIs embed an underspecified + API type they do not control. \n Instead of using this type, create + a locally provided and used type that is well-focused on your + reference. For example, ServiceReferences for admission registration: + https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 + ." + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + type: object + status: + description: ZUserStatus defines the observed state of ZUser + properties: + createdAt: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file' + format: date-time + type: string + token: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/config/crd/kustomization.yaml b/backend/config/crd/kustomization.yaml new file mode 100644 index 0000000..5b6ec5b --- /dev/null +++ b/backend/config/crd/kustomization.yaml @@ -0,0 +1,48 @@ +# 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/zelda.io_zprojects.yaml +- bases/zelda.io_zservices.yaml +- bases/zelda.io_zusers.yaml +- bases/zelda.io_zgroups.yaml +- bases/zelda.io_zregistries.yaml +- bases/zelda.io_zscripts.yaml +- bases/zelda.io_zbuildtemplates.yaml +- bases/zelda.io_zruntemplates.yaml +- bases/zelda.io_zbuilders.yaml +- bases/zelda.io_zcustomhosts.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 +#- path: patches/webhook_in_zprojects.yaml +#- path: patches/webhook_in_zservices.yaml +#- path: patches/webhook_in_zusers.yaml +#- path: patches/webhook_in_zgroups.yaml +#- path: patches/webhook_in_zregistries.yaml +#- path: patches/webhook_in_zscripts.yaml +#- path: patches/webhook_in_zbuildtemplates.yaml +#- path: patches/webhook_in_zruntemplates.yaml +#- path: patches/webhook_in_zbuilders.yaml +#- path: patches/webhook_in_zcustomhosts.yaml +#+kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +#- path: patches/cainjection_in_zprojects.yaml +#- path: patches/cainjection_in_zservices.yaml +#- path: patches/cainjection_in_zusers.yaml +#- path: patches/cainjection_in_zgroups.yaml +#- path: patches/cainjection_in_zregistries.yaml +#- path: patches/cainjection_in_zscripts.yaml +#- path: patches/cainjection_in_zbuildtemplates.yaml +#- path: patches/cainjection_in_zruntemplates.yaml +#- path: patches/cainjection_in_zbuilders.yaml +#- path: patches/cainjection_in_zcustomhosts.yaml +#+kubebuilder:scaffold:crdkustomizecainjectionpatch + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/backend/config/crd/kustomizeconfig.yaml b/backend/config/crd/kustomizeconfig.yaml new file mode 100644 index 0000000..ec5c150 --- /dev/null +++ b/backend/config/crd/kustomizeconfig.yaml @@ -0,0 +1,19 @@ +# 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 + +namespace: +- kind: CustomResourceDefinition + version: v1 + group: apiextensions.k8s.io + path: spec/conversion/webhook/clientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/backend/config/crd/patches/cainjection_in_zbuilders.yaml b/backend/config/crd/patches/cainjection_in_zbuilders.yaml new file mode 100644 index 0000000..62fc14b --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zbuilders.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zbuilders.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zbuildtemplates.yaml b/backend/config/crd/patches/cainjection_in_zbuildtemplates.yaml new file mode 100644 index 0000000..9dd9d49 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zbuildtemplates.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zbuildtemplates.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zcustomhosts.yaml b/backend/config/crd/patches/cainjection_in_zcustomhosts.yaml new file mode 100644 index 0000000..2045d02 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zcustomhosts.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zcustomhosts.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zgroups.yaml b/backend/config/crd/patches/cainjection_in_zgroups.yaml new file mode 100644 index 0000000..a966652 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zgroups.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zgroups.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zprojects.yaml b/backend/config/crd/patches/cainjection_in_zprojects.yaml new file mode 100644 index 0000000..a7c7cf6 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zprojects.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zprojects.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zregistries.yaml b/backend/config/crd/patches/cainjection_in_zregistries.yaml new file mode 100644 index 0000000..3363fce --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zregistries.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zregistries.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zruntemplates.yaml b/backend/config/crd/patches/cainjection_in_zruntemplates.yaml new file mode 100644 index 0000000..6b7c353 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zruntemplates.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zruntemplates.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zscripts.yaml b/backend/config/crd/patches/cainjection_in_zscripts.yaml new file mode 100644 index 0000000..05fe555 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zscripts.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zscripts.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zservices.yaml b/backend/config/crd/patches/cainjection_in_zservices.yaml new file mode 100644 index 0000000..07e3fc4 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zservices.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zservices.zelda.io diff --git a/backend/config/crd/patches/cainjection_in_zusers.yaml b/backend/config/crd/patches/cainjection_in_zusers.yaml new file mode 100644 index 0000000..9202331 --- /dev/null +++ b/backend/config/crd/patches/cainjection_in_zusers.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME + name: zusers.zelda.io diff --git a/backend/config/crd/patches/webhook_in_zbuilders.yaml b/backend/config/crd/patches/webhook_in_zbuilders.yaml new file mode 100644 index 0000000..825e15a --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zbuilders.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zbuilders.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zbuildtemplates.yaml b/backend/config/crd/patches/webhook_in_zbuildtemplates.yaml new file mode 100644 index 0000000..910a33a --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zbuildtemplates.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zbuildtemplates.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zcustomhosts.yaml b/backend/config/crd/patches/webhook_in_zcustomhosts.yaml new file mode 100644 index 0000000..2e9fb3a --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zcustomhosts.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zcustomhosts.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zgroups.yaml b/backend/config/crd/patches/webhook_in_zgroups.yaml new file mode 100644 index 0000000..5dc0fba --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zgroups.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zgroups.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zprojects.yaml b/backend/config/crd/patches/webhook_in_zprojects.yaml new file mode 100644 index 0000000..e16a6ad --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zprojects.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zprojects.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zregistries.yaml b/backend/config/crd/patches/webhook_in_zregistries.yaml new file mode 100644 index 0000000..82d3af7 --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zregistries.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zregistries.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zruntemplates.yaml b/backend/config/crd/patches/webhook_in_zruntemplates.yaml new file mode 100644 index 0000000..c77c3ab --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zruntemplates.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zruntemplates.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zscripts.yaml b/backend/config/crd/patches/webhook_in_zscripts.yaml new file mode 100644 index 0000000..dc03583 --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zscripts.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zscripts.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zservices.yaml b/backend/config/crd/patches/webhook_in_zservices.yaml new file mode 100644 index 0000000..4ca8fb8 --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zservices.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zservices.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/crd/patches/webhook_in_zusers.yaml b/backend/config/crd/patches/webhook_in_zusers.yaml new file mode 100644 index 0000000..e4a4ffe --- /dev/null +++ b/backend/config/crd/patches/webhook_in_zusers.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: zusers.zelda.io +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/backend/config/default/kustomization.yaml b/backend/config/default/kustomization.yaml new file mode 100644 index 0000000..0c0d950 --- /dev/null +++ b/backend/config/default/kustomization.yaml @@ -0,0 +1,144 @@ +# Adds namespace to all resources. +namespace: zelda-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: zelda- + +# 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 + +patchesStrategicMerge: +# Protect the /metrics endpoint by putting it behind auth. +# If you want your controller-manager to expose the /metrics +# endpoint w/o any authn/z, please comment the following line. +- manager_auth_proxy_patch.yaml + + + +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in +# crd/kustomization.yaml +#- manager_webhook_patch.yaml + +# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. +# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. +# 'CERTMANAGER' needs to be enabled to use ca injection +#- webhookcainjection_patch.yaml + +# [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: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs +# 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 +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 0 +# create: true +# - select: +# kind: CustomResourceDefinition +# 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 # this name should match the one in certificate.yaml +# fieldPath: .metadata.name +# targets: +# - select: +# kind: ValidatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# - select: +# kind: MutatingWebhookConfiguration +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# - select: +# kind: CustomResourceDefinition +# fieldPaths: +# - .metadata.annotations.[cert-manager.io/inject-ca-from] +# options: +# delimiter: '/' +# index: 1 +# create: true +# - source: # Add cert-manager annotation to the webhook Service +# kind: Service +# version: v1 +# name: webhook-service +# fieldPath: .metadata.name # namespace of the service +# targets: +# - select: +# kind: Certificate +# group: cert-manager.io +# version: v1 +# 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 +# fieldPaths: +# - .spec.dnsNames.0 +# - .spec.dnsNames.1 +# options: +# delimiter: '.' +# index: 1 +# create: true diff --git a/backend/config/default/manager_auth_proxy_patch.yaml b/backend/config/default/manager_auth_proxy_patch.yaml new file mode 100644 index 0000000..73fad2a --- /dev/null +++ b/backend/config/default/manager_auth_proxy_patch.yaml @@ -0,0 +1,39 @@ +# This patch inject a sidecar container which is a HTTP proxy for the +# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: kube-rbac-proxy + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - "ALL" + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.14.1 + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=0" + ports: + - containerPort: 8443 + protocol: TCP + name: https + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - name: manager + args: + - "--health-probe-bind-address=:8081" + - "--metrics-bind-address=127.0.0.1:8080" + - "--leader-elect" diff --git a/backend/config/default/manager_config_patch.yaml b/backend/config/default/manager_config_patch.yaml new file mode 100644 index 0000000..f6f5891 --- /dev/null +++ b/backend/config/default/manager_config_patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller-manager + namespace: system +spec: + template: + spec: + containers: + - name: manager diff --git a/backend/config/manager/kustomization.yaml b/backend/config/manager/kustomization.yaml new file mode 100644 index 0000000..b4ac913 --- /dev/null +++ b/backend/config/manager/kustomization.yaml @@ -0,0 +1,8 @@ +resources: +- manager.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: +- name: controller + newName: registry.zelda.io/zelda + newTag: "0907174632" diff --git a/backend/config/manager/manager.yaml b/backend/config/manager/manager.yaml new file mode 100644 index 0000000..b8438dd --- /dev/null +++ b/backend/config/manager/manager.yaml @@ -0,0 +1,118 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: namespace + app.kubernetes.io/instance: system + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + 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: deployment + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize +spec: + selector: + matchLabels: + control-plane: controller-manager + replicas: 1 + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + 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: + runAsNonRoot: true + # TODO(user): For common cases that do not require escalating privileges + # it is recommended to ensure that all your Pods/Containers are restrictive. + # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted + # Please uncomment the following code if your project does NOT have to work on old Kubernetes + # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). + # seccompProfile: + # type: RuntimeDefault + containers: + - command: + - /manager + args: + - --leader-elect + image: controller:latest + name: manager + imagePullPolicy: IfNotPresent + securityContext: + 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 + serviceAccountName: controller-manager + terminationGracePeriodSeconds: 10 + +--- +apiVersion: v1 +kind: Service +metadata: + name: zelda-manager + namespace: system +spec: + selector: + control-plane: controller-manager + ports: + - port: 80 + targetPort: 80 + nodePort: 30080 + type: NodePort diff --git a/backend/config/prometheus/kustomization.yaml b/backend/config/prometheus/kustomization.yaml new file mode 100644 index 0000000..ed13716 --- /dev/null +++ b/backend/config/prometheus/kustomization.yaml @@ -0,0 +1,2 @@ +resources: +- monitor.yaml diff --git a/backend/config/prometheus/monitor.yaml b/backend/config/prometheus/monitor.yaml new file mode 100644 index 0000000..dbc7e64 --- /dev/null +++ b/backend/config/prometheus/monitor.yaml @@ -0,0 +1,26 @@ + +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: servicemonitor + app.kubernetes.io/instance: controller-manager-metrics-monitor + app.kubernetes.io/component: metrics + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-monitor + namespace: system +spec: + endpoints: + - path: /metrics + port: https + scheme: https + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + tlsConfig: + insecureSkipVerify: true + selector: + matchLabels: + control-plane: controller-manager diff --git a/backend/config/rbac/auth_proxy_client_clusterrole.yaml b/backend/config/rbac/auth_proxy_client_clusterrole.yaml new file mode 100644 index 0000000..a569091 --- /dev/null +++ b/backend/config/rbac/auth_proxy_client_clusterrole.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: metrics-reader +rules: +- nonResourceURLs: + - "/metrics" + verbs: + - get diff --git a/backend/config/rbac/auth_proxy_role.yaml b/backend/config/rbac/auth_proxy_role.yaml new file mode 100644 index 0000000..a6b4272 --- /dev/null +++ b/backend/config/rbac/auth_proxy_role.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: proxy-role + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: proxy-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create diff --git a/backend/config/rbac/auth_proxy_role_binding.yaml b/backend/config/rbac/auth_proxy_role_binding.yaml new file mode 100644 index 0000000..5c4e40d --- /dev/null +++ b/backend/config/rbac/auth_proxy_role_binding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/instance: proxy-rolebinding + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: proxy-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: proxy-role +subjects: +- kind: ServiceAccount + name: controller-manager + namespace: system diff --git a/backend/config/rbac/auth_proxy_service.yaml b/backend/config/rbac/auth_proxy_service.yaml new file mode 100644 index 0000000..7c268a9 --- /dev/null +++ b/backend/config/rbac/auth_proxy_service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + control-plane: controller-manager + app.kubernetes.io/name: service + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/component: kube-rbac-proxy + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: controller-manager-metrics-service + namespace: system +spec: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: + control-plane: controller-manager diff --git a/backend/config/rbac/kustomization.yaml b/backend/config/rbac/kustomization.yaml new file mode 100644 index 0000000..731832a --- /dev/null +++ b/backend/config/rbac/kustomization.yaml @@ -0,0 +1,18 @@ +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 +# Comment the following 4 lines if you want to disable +# the auth proxy (https://github.com/brancz/kube-rbac-proxy) +# which protects your /metrics endpoint. +- auth_proxy_service.yaml +- auth_proxy_role.yaml +- auth_proxy_role_binding.yaml +- auth_proxy_client_clusterrole.yaml diff --git a/backend/config/rbac/leader_election_role.yaml b/backend/config/rbac/leader_election_role.yaml new file mode 100644 index 0000000..9ee81b4 --- /dev/null +++ b/backend/config/rbac/leader_election_role.yaml @@ -0,0 +1,44 @@ +# permissions to do leader election. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/name: role + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + 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 diff --git a/backend/config/rbac/leader_election_role_binding.yaml b/backend/config/rbac/leader_election_role_binding.yaml new file mode 100644 index 0000000..370bacd --- /dev/null +++ b/backend/config/rbac/leader_election_role_binding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: rolebinding + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + 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 diff --git a/backend/config/rbac/role.yaml b/backend/config/rbac/role.yaml new file mode 100644 index 0000000..1e49c9f --- /dev/null +++ b/backend/config/rbac/role.yaml @@ -0,0 +1,502 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manager-role +rules: +- apiGroups: + - '*' + resources: + - pods + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - '*' + resources: + - pods/status + verbs: + - get + - patch + - update +- apiGroups: + - '*' + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - '*' + resources: + - secrets/finalizers + verbs: + - update +- apiGroups: + - '*' + resources: + - secrets/status + verbs: + - get + - patch + - update +- apiGroups: + - '*' + resources: + - serviceaccounts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - '*' + resources: + - serviceaccounts/finalizers + verbs: + - update +- apiGroups: + - '*' + resources: + - serviceaccounts/status + verbs: + - get + - patch + - update +- apiGroups: + - '*' + resources: + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - '*' + resources: + - services/status + verbs: + - get + - patch + - update +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - deployments/status + verbs: + - get + - patch + - update +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - batch + resources: + - jobs/status + verbs: + - get + - patch + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - clusterrolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - clusterrolebindings/finalizers + verbs: + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - clusterrolebindings/status + verbs: + - get + - patch + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - clusterroles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - clusterroles/finalizers + verbs: + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - clusterroles/status + verbs: + - get + - patch + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - rolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - rolebindings/finalizers + verbs: + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - rolebindings/status + verbs: + - get + - patch + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - roles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - roles/finalizers + verbs: + - update +- apiGroups: + - rbac.authorization.k8s.io/v1 + resources: + - roles/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zbuilders + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zbuilders/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zbuilders/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zbuildtemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zbuildtemplates/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zbuildtemplates/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zcustomhosts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zcustomhosts/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zcustomhosts/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zgroups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zgroups/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zgroups/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zprojects + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zprojects/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zprojects/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zregistries + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zregistries/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zregistries/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zruntemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zruntemplates/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zruntemplates/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zscripts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zscripts/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zscripts/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zservices + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zservices/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zservices/status + verbs: + - get + - patch + - update +- apiGroups: + - zelda.io + resources: + - zusers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zusers/finalizers + verbs: + - update +- apiGroups: + - zelda.io + resources: + - zusers/status + verbs: + - get + - patch + - update diff --git a/backend/config/rbac/role_binding.yaml b/backend/config/rbac/role_binding.yaml new file mode 100644 index 0000000..68ce357 --- /dev/null +++ b/backend/config/rbac/role_binding.yaml @@ -0,0 +1,19 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + 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 diff --git a/backend/config/rbac/service_account.yaml b/backend/config/rbac/service_account.yaml new file mode 100644 index 0000000..3732783 --- /dev/null +++ b/backend/config/rbac/service_account.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/instance: controller-manager-sa + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: controller-manager + namespace: system diff --git a/backend/config/rbac/zbuilder_editor_role.yaml b/backend/config/rbac/zbuilder_editor_role.yaml new file mode 100644 index 0000000..e611dfc --- /dev/null +++ b/backend/config/rbac/zbuilder_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zbuilders. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zbuilder-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zbuilder-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zbuilders + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zbuilders/status + verbs: + - get diff --git a/backend/config/rbac/zbuilder_viewer_role.yaml b/backend/config/rbac/zbuilder_viewer_role.yaml new file mode 100644 index 0000000..96e0010 --- /dev/null +++ b/backend/config/rbac/zbuilder_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zbuilders. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zbuilder-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zbuilder-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zbuilders + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zbuilders/status + verbs: + - get diff --git a/backend/config/rbac/zbuildtemplate_editor_role.yaml b/backend/config/rbac/zbuildtemplate_editor_role.yaml new file mode 100644 index 0000000..a179b5a --- /dev/null +++ b/backend/config/rbac/zbuildtemplate_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zbuildtemplates. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zbuildtemplate-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zbuildtemplate-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zbuildtemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zbuildtemplates/status + verbs: + - get diff --git a/backend/config/rbac/zbuildtemplate_viewer_role.yaml b/backend/config/rbac/zbuildtemplate_viewer_role.yaml new file mode 100644 index 0000000..97baac5 --- /dev/null +++ b/backend/config/rbac/zbuildtemplate_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zbuildtemplates. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zbuildtemplate-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zbuildtemplate-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zbuildtemplates + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zbuildtemplates/status + verbs: + - get diff --git a/backend/config/rbac/zcustomhost_editor_role.yaml b/backend/config/rbac/zcustomhost_editor_role.yaml new file mode 100644 index 0000000..d198a5e --- /dev/null +++ b/backend/config/rbac/zcustomhost_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zcustomhosts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zcustomhost-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zcustomhost-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zcustomhosts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zcustomhosts/status + verbs: + - get diff --git a/backend/config/rbac/zcustomhost_viewer_role.yaml b/backend/config/rbac/zcustomhost_viewer_role.yaml new file mode 100644 index 0000000..6c53b54 --- /dev/null +++ b/backend/config/rbac/zcustomhost_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zcustomhosts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zcustomhost-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zcustomhost-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zcustomhosts + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zcustomhosts/status + verbs: + - get diff --git a/backend/config/rbac/zgroup_editor_role.yaml b/backend/config/rbac/zgroup_editor_role.yaml new file mode 100644 index 0000000..f2813cb --- /dev/null +++ b/backend/config/rbac/zgroup_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zgroups. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zgroup-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zgroup-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zgroups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zgroups/status + verbs: + - get diff --git a/backend/config/rbac/zgroup_viewer_role.yaml b/backend/config/rbac/zgroup_viewer_role.yaml new file mode 100644 index 0000000..5b6c0fa --- /dev/null +++ b/backend/config/rbac/zgroup_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zgroups. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zgroup-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zgroup-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zgroups + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zgroups/status + verbs: + - get diff --git a/backend/config/rbac/zproject_editor_role.yaml b/backend/config/rbac/zproject_editor_role.yaml new file mode 100644 index 0000000..03cfd06 --- /dev/null +++ b/backend/config/rbac/zproject_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zprojects. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zproject-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zproject-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zprojects + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zprojects/status + verbs: + - get diff --git a/backend/config/rbac/zproject_viewer_role.yaml b/backend/config/rbac/zproject_viewer_role.yaml new file mode 100644 index 0000000..dda563d --- /dev/null +++ b/backend/config/rbac/zproject_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zprojects. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zproject-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zproject-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zprojects + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zprojects/status + verbs: + - get diff --git a/backend/config/rbac/zregistry_editor_role.yaml b/backend/config/rbac/zregistry_editor_role.yaml new file mode 100644 index 0000000..d2e72a3 --- /dev/null +++ b/backend/config/rbac/zregistry_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zregistries. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zregistry-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zregistry-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zregistries + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zregistries/status + verbs: + - get diff --git a/backend/config/rbac/zregistry_viewer_role.yaml b/backend/config/rbac/zregistry_viewer_role.yaml new file mode 100644 index 0000000..5aa1e94 --- /dev/null +++ b/backend/config/rbac/zregistry_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zregistries. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zregistry-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zregistry-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zregistries + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zregistries/status + verbs: + - get diff --git a/backend/config/rbac/zruntemplate_editor_role.yaml b/backend/config/rbac/zruntemplate_editor_role.yaml new file mode 100644 index 0000000..892a9d9 --- /dev/null +++ b/backend/config/rbac/zruntemplate_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zruntemplates. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zruntemplate-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zruntemplate-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zruntemplates + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zruntemplates/status + verbs: + - get diff --git a/backend/config/rbac/zruntemplate_viewer_role.yaml b/backend/config/rbac/zruntemplate_viewer_role.yaml new file mode 100644 index 0000000..f16a325 --- /dev/null +++ b/backend/config/rbac/zruntemplate_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zruntemplates. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zruntemplate-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zruntemplate-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zruntemplates + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zruntemplates/status + verbs: + - get diff --git a/backend/config/rbac/zscript_editor_role.yaml b/backend/config/rbac/zscript_editor_role.yaml new file mode 100644 index 0000000..a719c3e --- /dev/null +++ b/backend/config/rbac/zscript_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zscripts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zscript-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zscript-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zscripts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zscripts/status + verbs: + - get diff --git a/backend/config/rbac/zscript_viewer_role.yaml b/backend/config/rbac/zscript_viewer_role.yaml new file mode 100644 index 0000000..03297e1 --- /dev/null +++ b/backend/config/rbac/zscript_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zscripts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zscript-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zscript-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zscripts + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zscripts/status + verbs: + - get diff --git a/backend/config/rbac/zservice_editor_role.yaml b/backend/config/rbac/zservice_editor_role.yaml new file mode 100644 index 0000000..f76fba3 --- /dev/null +++ b/backend/config/rbac/zservice_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zservices. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zservice-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zservice-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zservices + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zservices/status + verbs: + - get diff --git a/backend/config/rbac/zservice_viewer_role.yaml b/backend/config/rbac/zservice_viewer_role.yaml new file mode 100644 index 0000000..503efd7 --- /dev/null +++ b/backend/config/rbac/zservice_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zservices. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zservice-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zservice-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zservices + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zservices/status + verbs: + - get diff --git a/backend/config/rbac/zuser_editor_role.yaml b/backend/config/rbac/zuser_editor_role.yaml new file mode 100644 index 0000000..f174825 --- /dev/null +++ b/backend/config/rbac/zuser_editor_role.yaml @@ -0,0 +1,31 @@ +# permissions for end users to edit zusers. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zuser-editor-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zuser-editor-role +rules: +- apiGroups: + - zelda.io + resources: + - zusers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - zelda.io + resources: + - zusers/status + verbs: + - get diff --git a/backend/config/rbac/zuser_viewer_role.yaml b/backend/config/rbac/zuser_viewer_role.yaml new file mode 100644 index 0000000..35844e5 --- /dev/null +++ b/backend/config/rbac/zuser_viewer_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to view zusers. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: clusterrole + app.kubernetes.io/instance: zuser-viewer-role + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: zelda + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + name: zuser-viewer-role +rules: +- apiGroups: + - zelda.io + resources: + - zusers + verbs: + - get + - list + - watch +- apiGroups: + - zelda.io + resources: + - zusers/status + verbs: + - get diff --git a/backend/config/samples/kustomization.yaml b/backend/config/samples/kustomization.yaml new file mode 100644 index 0000000..c733026 --- /dev/null +++ b/backend/config/samples/kustomization.yaml @@ -0,0 +1,13 @@ +## Append samples of your project ## +resources: +- zelda.io_v1alpha1_zproject.yaml +- zelda.io_v1alpha1_zservice.yaml +- zelda.io_v1alpha1_zuser.yaml +- zelda.io_v1alpha1_zgroup.yaml +- zelda.io_v1alpha1_zregistry.yaml +- zelda.io_v1alpha1_zscript.yaml +- zelda.io_v1alpha1_zbuildtemplate.yaml +- zelda.io_v1alpha1_zruntemplate.yaml +- zelda.io_v1alpha1_zbuilder.yaml +- zelda.io_v1alpha1_zcustomhost.yaml +#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/backend/config/samples/zelda.io_v1alpha1_zbuilder.yaml b/backend/config/samples/zelda.io_v1alpha1_zbuilder.yaml new file mode 100644 index 0000000..466465d --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zbuilder.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZBuilder +metadata: + labels: + app.kubernetes.io/name: zbuilder + app.kubernetes.io/instance: zbuilder-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zbuilder-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zbuildtemplate.yaml b/backend/config/samples/zelda.io_v1alpha1_zbuildtemplate.yaml new file mode 100644 index 0000000..d0cf9b5 --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zbuildtemplate.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZBuildTemplate +metadata: + labels: + app.kubernetes.io/name: zbuildtemplate + app.kubernetes.io/instance: zbuildtemplate-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zbuildtemplate-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zcustomhost.yaml b/backend/config/samples/zelda.io_v1alpha1_zcustomhost.yaml new file mode 100644 index 0000000..762ba36 --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zcustomhost.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZCustomHost +metadata: + labels: + app.kubernetes.io/name: zcustomhost + app.kubernetes.io/instance: zcustomhost-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zcustomhost-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zgroup.yaml b/backend/config/samples/zelda.io_v1alpha1_zgroup.yaml new file mode 100644 index 0000000..521a992 --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zgroup.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZGroup +metadata: + labels: + app.kubernetes.io/name: zgroup + app.kubernetes.io/instance: zgroup-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zgroup-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zproject.yaml b/backend/config/samples/zelda.io_v1alpha1_zproject.yaml new file mode 100644 index 0000000..19fb2eb --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zproject.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZProject +metadata: + labels: + app.kubernetes.io/name: zproject + app.kubernetes.io/instance: zproject-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zproject-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zregistry.yaml b/backend/config/samples/zelda.io_v1alpha1_zregistry.yaml new file mode 100644 index 0000000..dbfe21e --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zregistry.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZRegistry +metadata: + labels: + app.kubernetes.io/name: zregistry + app.kubernetes.io/instance: zregistry-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zregistry-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zruntemplate.yaml b/backend/config/samples/zelda.io_v1alpha1_zruntemplate.yaml new file mode 100644 index 0000000..fda244a --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zruntemplate.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZRunTemplate +metadata: + labels: + app.kubernetes.io/name: zruntemplate + app.kubernetes.io/instance: zruntemplate-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zruntemplate-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zscript.yaml b/backend/config/samples/zelda.io_v1alpha1_zscript.yaml new file mode 100644 index 0000000..73aed8c --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zscript.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZScript +metadata: + labels: + app.kubernetes.io/name: zscript + app.kubernetes.io/instance: zscript-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zscript-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zservice.yaml b/backend/config/samples/zelda.io_v1alpha1_zservice.yaml new file mode 100644 index 0000000..c05455d --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zservice.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZService +metadata: + labels: + app.kubernetes.io/name: zservice + app.kubernetes.io/instance: zservice-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zservice-sample +spec: + # TODO(user): Add fields here diff --git a/backend/config/samples/zelda.io_v1alpha1_zuser.yaml b/backend/config/samples/zelda.io_v1alpha1_zuser.yaml new file mode 100644 index 0000000..6d7df1a --- /dev/null +++ b/backend/config/samples/zelda.io_v1alpha1_zuser.yaml @@ -0,0 +1,12 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZUser +metadata: + labels: + app.kubernetes.io/name: zuser + app.kubernetes.io/instance: zuser-sample + app.kubernetes.io/part-of: zelda + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: zelda + name: zuser-sample +spec: + # TODO(user): Add fields here diff --git a/backend/design/build-template.md b/backend/design/build-template.md new file mode 100644 index 0000000..315990a --- /dev/null +++ b/backend/design/build-template.md @@ -0,0 +1,9 @@ +# Build Template + +编译模板,用于创建编译pod, 与podTemplate相同,创建时会自动添加initial pod,初始化配置 + +```yaml +spec: + steps: + - +``` \ No newline at end of file diff --git a/backend/design/builder.md b/backend/design/builder.md new file mode 100644 index 0000000..f2cc8f3 --- /dev/null +++ b/backend/design/builder.md @@ -0,0 +1,3 @@ +# Zelda Builder + +zelda builder 按照对应配置创建pod,编译并打包项目,部署服务 \ No newline at end of file diff --git a/backend/design/custom-host.md b/backend/design/custom-host.md new file mode 100644 index 0000000..3e3c3b2 --- /dev/null +++ b/backend/design/custom-host.md @@ -0,0 +1,3 @@ +# Zelda Custom Host + +自定义域名解析 \ No newline at end of file diff --git a/backend/design/group.md b/backend/design/group.md new file mode 100644 index 0000000..4fee9ac --- /dev/null +++ b/backend/design/group.md @@ -0,0 +1,3 @@ +# Zelda Group + +用户组管理 \ No newline at end of file diff --git a/backend/design/project.md b/backend/design/project.md new file mode 100644 index 0000000..09f8558 --- /dev/null +++ b/backend/design/project.md @@ -0,0 +1,17 @@ +# project + +CRD 资源,管理项目 + +```yaml +spec: + git: + repo: git@github.com:ycyxuehan/zelda.git + id: 12 + registry: bing89 + imageName: zelda + buildTemplate: go117 +``` + +```yaml +status: +``` \ No newline at end of file diff --git a/backend/design/registry.md b/backend/design/registry.md new file mode 100644 index 0000000..fa9293a --- /dev/null +++ b/backend/design/registry.md @@ -0,0 +1,4 @@ +# Zelda Registry + +镜像仓库配置 + diff --git a/backend/design/run-template.md b/backend/design/run-template.md new file mode 100644 index 0000000..2c2aee6 --- /dev/null +++ b/backend/design/run-template.md @@ -0,0 +1,7 @@ +# Run Template + +运行模板。 项目的默认运行方式,最低运行需求 + +```yaml + +``` \ No newline at end of file diff --git a/backend/design/user.md b/backend/design/user.md new file mode 100644 index 0000000..6b87a1e --- /dev/null +++ b/backend/design/user.md @@ -0,0 +1,3 @@ +# Zelda User + +用户管理 \ No newline at end of file diff --git a/backend/design/zservice.md b/backend/design/zservice.md new file mode 100644 index 0000000..9a47b9d --- /dev/null +++ b/backend/design/zservice.md @@ -0,0 +1,4 @@ +# Zelda Service + +服务,使用指定模板运行一个项目提供服务。 + diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..6f8ad80 --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,100 @@ +module github.com/ycyxuehan/zelda + +go 1.21 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/go-oauth2/oauth2/v4 v4.5.2 + github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/onsi/ginkgo/v2 v2.17.1 + github.com/onsi/gomega v1.32.0 + github.com/pkg/errors v0.9.1 + k8s.io/api v0.29.3 + k8s.io/apimachinery v0.29.3 + k8s.io/client-go v0.29.3 + sigs.k8s.io/controller-runtime v0.17.3 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.8.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 // indirect + github.com/tidwall/buntdb v1.1.2 // indirect + github.com/tidwall/gjson v1.12.1 // indirect + github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e // indirect + github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/term v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.17.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/apiextensions-apiserver v0.29.2 // indirect + k8s.io/component-base v0.29.2 // indirect + k8s.io/klog/v2 v2.110.1 // indirect + k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect + k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..bd74cf4 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,372 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +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/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= +github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-oauth2/oauth2/v4 v4.5.2 h1:CuZhD3lhGuI6aNLyUbRHXsgG2RwGRBOuCBfd4WQKqBQ= +github.com/go-oauth2/oauth2/v4 v4.5.2/go.mod h1:wk/2uLImWIa9VVQDgxz99H2GDbhmfi/9/Xr+GvkSUSQ= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +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 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +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/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E= +github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= +github.com/tidwall/buntdb v1.1.2 h1:noCrqQXL9EKMtcdwJcmuVKSEjqu1ua99RHHgbLTEHRo= +github.com/tidwall/buntdb v1.1.2/go.mod h1:xAzi36Hir4FarpSHyfuZ6JzPJdjRZ8QlLZSntE2mqlI= +github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb h1:5NSYaAdrnblKByzd7XByQEJVT8+9v0W/tIY0Oo4OwrE= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e h1:+NL1GDIUOKxVfbp2KoJQD9cTQ6dyP2co9q4yzmT9FZo= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 h1:Otn9S136ELckZ3KKDyCkxapfufrqDqwmGjcHfAyXRrE= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= +k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= +k8s.io/apiextensions-apiserver v0.29.2 h1:UK3xB5lOWSnhaCk0RFZ0LUacPZz9RY4wi/yt2Iu+btg= +k8s.io/apiextensions-apiserver v0.29.2/go.mod h1:aLfYjpA5p3OwtqNXQFkhJ56TB+spV8Gc4wfMhUA3/b8= +k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= +k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= +k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= +k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= +k8s.io/component-base v0.29.2 h1:lpiLyuvPA9yV1aQwGLENYyK7n/8t6l3nn3zAtFTJYe8= +k8s.io/component-base v0.29.2/go.mod h1:BfB3SLrefbZXiBfbM+2H1dlat21Uewg/5qtKOl8degM= +k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= +k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= +k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/controller-runtime v0.17.3 h1:65QmN7r3FWgTxDMz9fvGnO1kbf2nu+acg9p2R9oYYYk= +sigs.k8s.io/controller-runtime v0.17.3/go.mod h1:N0jpP5Lo7lMTF9aL56Z/B2oWBJjey6StQM0jRbKQXtY= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/backend/hack/boilerplate.go.txt b/backend/hack/boilerplate.go.txt new file mode 100644 index 0000000..1c7a636 --- /dev/null +++ b/backend/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ \ No newline at end of file diff --git a/backend/internal/controller/suite_test.go b/backend/internal/controller/suite_test.go new file mode 100644 index 0000000..7356e69 --- /dev/null +++ b/backend/internal/controller/suite_test.go @@ -0,0 +1,90 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "fmt" + "path/filepath" + "runtime" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + //+kubebuilder:scaffold:imports +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var cfg *rest.Config +var k8sClient client.Client +var testEnv *envtest.Environment + +func TestControllers(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, + ErrorIfCRDPathMissing: true, + + // The BinaryAssetsDirectory is only required if you want to run the tests directly + // without call the makefile target test. If not informed it will look for the + // default path defined in controller-runtime which is /usr/local/kubebuilder/. + // Note that you must have the required binaries setup under the bin directory to perform + // the tests directly. When we run make test it will be setup and used automatically. + BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", + fmt.Sprintf("1.28.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + } + + var err error + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = zeldaiov1alpha1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) diff --git a/backend/internal/controller/zbuilder_controller.go b/backend/internal/controller/zbuilder_controller.go new file mode 100644 index 0000000..29cd6b5 --- /dev/null +++ b/backend/internal/controller/zbuilder_controller.go @@ -0,0 +1,175 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + "github.com/pkg/errors" + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + "github.com/ycyxuehan/zelda/pkg/config" + "github.com/ycyxuehan/zelda/pkg/utils" + watchers "github.com/ycyxuehan/zelda/watcher" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ZBuilderReconciler reconciles a ZBuilder object +type ZBuilderReconciler struct { + client.Client + Scheme *runtime.Scheme + Config config.Config +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zbuilders,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zbuilders/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zbuilders/finalizers,verbs=update +//+kubebuilder:rbac:groups=zelda.io,resources=zservices,verbs=get;list;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zservices/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=*,resources=pods,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=*,resources=pods/status,verbs=get;update;patch + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZBuilder object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile +func (r *ZBuilderReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + zbuilder := zeldaiov1alpha1.ZBuilder{} + err := r.Get(ctx, req.NamespacedName, &zbuilder) + if err != nil { + log.Log.Error(err, "cannot get resource zbuilders.zelda.io/%s/%s", req.Namespace, req.Name) + return ctrl.Result{}, err + } + project := zeldaiov1alpha1.ZProject{} + err = r.Get(ctx, utils.NamespacedNameFromObjectReference(zbuilder.Spec.Project), &project) + if err != nil { + log.Log.Error(err, "cannot get resource zprojects.zelda.io/%s/%s", zbuilder.Spec.Project.Namespace, zbuilder.Spec.Project.Name) + return ctrl.Result{}, err + } + + //非删除 + if zbuilder.GetDeletionTimestamp() == nil || zbuilder.GetDeletionTimestamp().IsZero() { + if zbuilder.Status.Phase == "" { + err = r.DoCreate(ctx, &zbuilder, &project) + if err != nil { + log.Log.Error(err, "do create builder failed") + } + return ctrl.Result{}, err + } + err = r.DoUpdate(ctx, &zbuilder, &project) + if err != nil { + log.Log.Error(err, "update builder failed") + } + } + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZBuilderReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZBuilder{}). + Watches(&corev1.Pod{},&watchers.ZBuilderWatcher{Client: mgr.GetClient(),}). + Complete(r) +} + +//处理update事件 更新状态 +func (r *ZBuilderReconciler) DoUpdate(ctx context.Context, zbuilder *zeldaiov1alpha1.ZBuilder, project *zeldaiov1alpha1.ZProject) error { + switch zbuilder.Status.Phase { + case zeldaiov1alpha1.PhaseCompleted: //已完成 + return nil + case zeldaiov1alpha1.PhaseDeploy: //部署阶段 + return nil + default: //编译打包阶段 + if metav1.Now().Sub(zbuilder.Status.CreatedAt.Time) >= r.Config.Timeout { + pod := corev1.Pod{} + err := r.Get(context.Background(), client.ObjectKeyFromObject(zbuilder), &pod) + if err != nil { + return errors.WithMessage(err, "cannot get pod, maybe it create failed") + } + zbuilder.Status = zeldaiov1alpha1.NewZbuilderStatus(&pod.Status) + } else { //超时 + zbuilder.Status.Phase = zeldaiov1alpha1.PhaseCompleted + zbuilder.Status.Reason = "TimeOut" + now := metav1.Now() + zbuilder.Status.FinishedAt = &now + } + r.Status().Update(context.Background(), zbuilder) + } + return nil +} + +//处理create事件 创建pod,开始编译打包过程。 +func (r *ZBuilderReconciler) DoCreate(ctx context.Context, zbuilder *zeldaiov1alpha1.ZBuilder, project *zeldaiov1alpha1.ZProject) error { + buildTemplate := zeldaiov1alpha1.ZBuildTemplate{} + registry := zeldaiov1alpha1.ZRegistry{} + err := r.Get(context.Background(), utils.NamespacedNameFromObjectReference(project.Spec.Registry), ®istry) + if err != nil { + return errors.WithMessagef(err, "get zregistries.zelda.io/%s/%s failed", project.Spec.Registry.Namespace, project.Spec.Registry.Name) + } + err = r.ProcessRegistrySecret(ctx, ®istry, zbuilder) + if err != nil { + return errors.WithMessagef(err, "process the secret of registry failed") + } + subProject := project.SubProject(zbuilder.Spec.SubProject) + + err = r.Get(context.Background(), utils.NamespacedNameFromObjectReference(subProject.BuildSpec.Template), &buildTemplate) + if err != nil { + return errors.WithMessagef(err, "get zbuildtemplates.zelda.io/%s/%s failed", subProject.BuildSpec.Template.Namespace, subProject.BuildSpec.Template.Name) + } + + pod := zbuilder.Pod(buildTemplate.Spec.DeepCopy(), r.Config.GitImage, project.Spec.Git.Repo, subProject, registry.DeepCopy()) + //先更新状态,再创建pod,避免创建pod触发状态更新导致冲突 + //更新状态 + zbuilder.Status.Phase = zeldaiov1alpha1.PhaseCreating + err = r.Status().Update(context.Background(), zbuilder) + if err != nil { + return errors.WithMessage(err, "update builder status failed") + } + + //创建pod + err = r.Create(context.Background(), &pod, &client.CreateOptions{}) + + return errors.WithMessagef(err, "create pods/%s/%s failed", pod.GetNamespace(), pod.GetName()) +} + +// //UpdateStatus 更新状态 +// func (r *ZBuilderReconciler)UpdateStatus(zbuilder*zeldaiov1alpha1.ZBuilder, pod *corev1.Pod)error{ + +// return nil +// } + +func (r *ZBuilderReconciler) ProcessRegistrySecret(ctx context.Context, zregistry *zeldaiov1alpha1.ZRegistry, zbuilder *zeldaiov1alpha1.ZBuilder) error { + secret := &corev1.Secret{} + err := r.Get(ctx, client.ObjectKey{Namespace: zbuilder.GetNamespace(), Name: zregistry.SecreteName()}, secret) + if err == nil { + return nil + } + secret = zregistry.NamespacedSecret(zbuilder.GetNamespace()) + err = r.Create(ctx, secret, &client.CreateOptions{}) + return err +} diff --git a/backend/internal/controller/zbuildtemplate_controller.go b/backend/internal/controller/zbuildtemplate_controller.go new file mode 100644 index 0000000..5e2444f --- /dev/null +++ b/backend/internal/controller/zbuildtemplate_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" +) + +// ZBuildTemplateReconciler reconciles a ZBuildTemplate object +type ZBuildTemplateReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zbuildtemplates,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zbuildtemplates/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zbuildtemplates/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZBuildTemplate object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.0/pkg/reconcile +func (r *ZBuildTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZBuildTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZBuildTemplate{}). + Complete(r) +} diff --git a/backend/internal/controller/zcustomhost_controller.go b/backend/internal/controller/zcustomhost_controller.go new file mode 100644 index 0000000..0a5b254 --- /dev/null +++ b/backend/internal/controller/zcustomhost_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" +) + +// ZCustomHostReconciler reconciles a ZCustomHost object +type ZCustomHostReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zcustomhosts,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zcustomhosts/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zcustomhosts/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZCustomHost object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.0/pkg/reconcile +func (r *ZCustomHostReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZCustomHostReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZCustomHost{}). + Complete(r) +} diff --git a/backend/internal/controller/zgroup_controller.go b/backend/internal/controller/zgroup_controller.go new file mode 100644 index 0000000..67bd8dd --- /dev/null +++ b/backend/internal/controller/zgroup_controller.go @@ -0,0 +1,135 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" +) + +// ZGroupReconciler reconciles a ZGroup object +type ZGroupReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zgroups,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zgroups/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zgroups/finalizers,verbs=update +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=roles,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=roles/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=roles/finalizers,verbs=update +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=clusterroles,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=clusterroles/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=clusterroles/finalizers,verbs=update + + + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZGroup object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile +func (r *ZGroupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + zgroup := zeldaiov1alpha1.ZGroup{} + err := r.Get(ctx, req.NamespacedName, &zgroup) + if err != nil { + return ctrl.Result{}, err + } + if zgroup.GetDeletionTimestamp() == nil || zgroup.GetDeletionTimestamp().IsZero() { + err = r.Process(ctx, &zgroup) + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZGroupReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZGroup{}). + Complete(r) +} + +//处理zgroup的变更 +//zgroup会根据配置创建对应的 role, cluster role +func (r *ZGroupReconciler) Process(ctx context.Context, zgroup *zeldaiov1alpha1.ZGroup) error { + //空group,暂不处理。group暂时没有status需要处理 + if zgroup.IsEmpty() { + return nil + } + changed, _ := zgroup.IsSpecChanged() + //处理role + err := r.ProcessRole(ctx, zgroup, changed) + if err != nil { + //打印日志,继续处理cluster role + log.Log.Error(err, "process role") + } + err = r.ProcessClusterRole(ctx, zgroup, changed) + return err +} + +//处理Role +func (r *ZGroupReconciler) ProcessRole(ctx context.Context, zgroup *zeldaiov1alpha1.ZGroup, changed bool) error { + if len(zgroup.Spec.Rulers) == 0 { + return nil + } + role := rbacv1.Role{} + err := r.Get(ctx, zgroup.NamespacedNameRole(), &role) + if !changed && err == nil { + return nil + } + role = *zgroup.Role() + if err != nil { + err = r.Create(ctx, &role, &client.CreateOptions{}) + return err + } + err = r.Update(ctx, &role, &client.UpdateOptions{}) + return err +} + +//处理cluster role +func (r *ZGroupReconciler) ProcessClusterRole(ctx context.Context, zgroup *zeldaiov1alpha1.ZGroup, changed bool) error { + if len(zgroup.Spec.Rulers) == 0 { + return nil + } + role := rbacv1.ClusterRole{} + err := r.Get(ctx, zgroup.NamespacedNameRole(), &role) + if !changed && err == nil { + return nil + } + role = *zgroup.ClusterRole() + if err != nil { + err = r.Create(ctx, &role, &client.CreateOptions{}) + return err + } + err = r.Update(ctx, &role, &client.UpdateOptions{}) + return err +} diff --git a/backend/internal/controller/zproject_controller.go b/backend/internal/controller/zproject_controller.go new file mode 100644 index 0000000..807bf12 --- /dev/null +++ b/backend/internal/controller/zproject_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" +) + +// ZProjectReconciler reconciles a ZProject object +type ZProjectReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zprojects,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zprojects/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zprojects/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZProject object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.0/pkg/reconcile +func (r *ZProjectReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZProjectReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZProject{}). + Complete(r) +} diff --git a/backend/internal/controller/zregistry_controller.go b/backend/internal/controller/zregistry_controller.go new file mode 100644 index 0000000..fbc79bf --- /dev/null +++ b/backend/internal/controller/zregistry_controller.go @@ -0,0 +1,94 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +// ZRegistryReconciler reconciles a ZRegistry object +type ZRegistryReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zregistries,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zregistries/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zregistries/finalizers,verbs=update +//+kubebuilder:rbac:groups=*,resources=secrets,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=*,resources=secrets/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=*,resources=secrets/finalizers,verbs=update + + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZRegistry object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile +func (r *ZRegistryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + zregistry := zeldaiov1alpha1.ZRegistry{} + err := r.Get(ctx, req.NamespacedName, &zregistry) + if err != nil { + return ctrl.Result{}, err + } + if zregistry.DeletionTimestamp == nil || zregistry.DeletionTimestamp.IsZero() { + err = r.Process(ctx, &zregistry) + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZRegistryReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZRegistry{}). + Complete(r) +} + +//处理zregistry变更 +//对于需要账号密码登陆的registry, 自动创建secret并保持一致 +func (r *ZRegistryReconciler) Process(ctx context.Context, zregistry *zeldaiov1alpha1.ZRegistry) error { + secret := &corev1.Secret{} + err := r.Get(ctx, zregistry.NamespacedNameSecret(), secret) + changed, _ := zregistry.IsSpecChanged() + if changed || err != nil { + secret = zregistry.Secret() + } + if err != nil { + err = r.Create(ctx, secret, &client.CreateOptions{}) + return err + } + if changed { + err = r.Update(ctx, secret, &client.UpdateOptions{}) + return err + } + return nil +} diff --git a/backend/internal/controller/zruntemplate_controller.go b/backend/internal/controller/zruntemplate_controller.go new file mode 100644 index 0000000..61be9fc --- /dev/null +++ b/backend/internal/controller/zruntemplate_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" +) + +// ZRunTemplateReconciler reconciles a ZRunTemplate object +type ZRunTemplateReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zruntemplates,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zruntemplates/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zruntemplates/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZRunTemplate object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.0/pkg/reconcile +func (r *ZRunTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZRunTemplateReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZRunTemplate{}). + Complete(r) +} diff --git a/backend/internal/controller/zscript_controller.go b/backend/internal/controller/zscript_controller.go new file mode 100644 index 0000000..e85c243 --- /dev/null +++ b/backend/internal/controller/zscript_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" +) + +// ZScriptReconciler reconciles a ZScript object +type ZScriptReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zscripts,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zscripts/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zscripts/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZScript object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.16.0/pkg/reconcile +func (r *ZScriptReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZScriptReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZScript{}). + Complete(r) +} diff --git a/backend/internal/controller/zservice_controller.go b/backend/internal/controller/zservice_controller.go new file mode 100644 index 0000000..f725b8c --- /dev/null +++ b/backend/internal/controller/zservice_controller.go @@ -0,0 +1,187 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + watchers "github.com/ycyxuehan/zelda/watcher" +) + +// ZServiceReconciler reconciles a ZService object +type ZServiceReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zservices,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zservices/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zservices/finalizers,verbs=update +// +kubebuilder:rbac:groups=*,resources=services,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=*,resources=services/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=*,resources=pods,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=*,resources=pods/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=batch,resources=jobs/status,verbs=get;update;patch + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZService object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile +func (r *ZServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + zservice := zeldaiov1alpha1.ZService{} + + err := r.Get(ctx, req.NamespacedName, &zservice) + if err != nil { + log.Log.Error(err, "cannot get resource zservices.zelda.io/%s/%s", req.Namespace, req.Name) + return ctrl.Result{}, err + } + if zservice.DeletionTimestamp == nil || zservice.DeletionTimestamp.IsZero() { + err = r.Process(ctx, &zservice) + if err != nil { + log.Log.Error(err, "create resource zservices.zelda.io/%s/%s failed: %v", req.Namespace, req.Name, err) + } + return ctrl.Result{}, err + } + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZServiceReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZService{}). + Watches(&corev1.Pod{}, &watchers.ZServiceWatcher{ + Client: mgr.GetClient(), + }). + Watches(&appsv1.Deployment{}, + &watchers.ZServiceWatcher{ + Client: mgr.GetClient(), + }). + Watches(&batchv1.Job{}, + + &watchers.ZServiceWatcher{ + Client: mgr.GetClient(), + }). + Complete(r) +} + +//process zservice 负责运行服务。暂时兼容deployment,job,pod三种模式。zservice每次变动都会去检查其子资源是否存在,是否一致 +func (r *ZServiceReconciler) Process(ctx context.Context, zservice *zeldaiov1alpha1.ZService) error { + var managedResource client.Object + switch zservice.Spec.Kind { + case "Deployment": + managedResource = &appsv1.Deployment{} + case "Job": + managedResource = &batchv1.Job{} + case "Pod": + managedResource = &corev1.Pod{} + default: + return fmt.Errorf("unkown kind") + } + changed, err := zservice.IsSpecChanged() + if err != nil { + //日志打印错误 + fmt.Println(err) + } + err = r.Get(context.Background(), zservice.NamespacedNameResource(), managedResource) + if err != nil || changed { //子对象不见了,需要创建, spec有变动,需要更新,这里先创建option + runTemplate := zeldaiov1alpha1.ZRunTemplate{} + err = r.Get(context.Background(), zservice.NamespacedNameRunTemplate(), &runTemplate) + if err != nil { + return err + } + project := zeldaiov1alpha1.ZProject{} + err = r.Get(context.Background(), zservice.NamespacedNameProject(), &project) + if err != nil { + return err + } + registry := zeldaiov1alpha1.ZRegistry{} + err = r.Get(context.Background(), project.NamespacedNameRegistry(), ®istry) + if err != nil { + return err + } + customHost := zeldaiov1alpha1.ZCustomHost{} + err = r.Get(context.Background(), zservice.NamespacedNameCustomHost(), &customHost) + if err != nil { + return err + } + sa := corev1.ServiceAccount{} + err = r.Get(context.Background(), zservice.NamespacedNameUser(), &sa) + if err != nil { + return err + } + secrets := []corev1.LocalObjectReference{} + for _, secret := range sa.Secrets { + if secret.Namespace == zservice.GetNamespace() { + secrets = append(secrets, corev1.LocalObjectReference{Name: secret.Name}) + } + } + option := zeldaiov1alpha1.NewClientObjectOption{ + ZRunTemplateSpec: runTemplate.Spec.DeepCopy(), + Registry: registry.DeepCopy(), + HostAlias: customHost.Spec.HostAlias, + UserSecrets: secrets, + } + managedResource = zservice.ClientObject(&option) + } + + if err != nil { + err = r.Create(context.Background(), managedResource, &client.CreateOptions{}) + return err + } + if changed { + err = r.Update(context.Background(), managedResource, &client.UpdateOptions{}) + return err + } + //////////////////////////////////////// + //这里是处理状态更新 + r.UpdateStatus(ctx, zservice, managedResource) + return nil +} + +//处理状态更新 +func (r *ZServiceReconciler) UpdateStatus(ctx context.Context, zservice *zeldaiov1alpha1.ZService, managedResource client.Object) error { + err := zservice.UpdateStatus(managedResource) + if err != nil { + return err + } + err = r.Status().Update(context.Background(), zservice) + return err +} diff --git a/backend/internal/controller/zuser_controller.go b/backend/internal/controller/zuser_controller.go new file mode 100644 index 0000000..514a451 --- /dev/null +++ b/backend/internal/controller/zuser_controller.go @@ -0,0 +1,172 @@ +/* +Copyright 2023 ycyxuehan. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "fmt" + "strings" + + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + zeldaiov1alpha1 "github.com/ycyxuehan/zelda/api/v1alpha1" + watchers "github.com/ycyxuehan/zelda/watcher" +) + +// ZUserReconciler reconciles a ZUser object +type ZUserReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=zelda.io,resources=zusers,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=zelda.io,resources=zusers/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=zelda.io,resources=zusers/finalizers,verbs=update +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=rolebindings/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=rolebindings/finalizers,verbs=update +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=clusterrolebindings,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=clusterrolebindings/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=rbac.authorization.k8s.io/v1,resources=clusterrolebindings/finalizers,verbs=update +//+kubebuilder:rbac:groups=*,resources=serviceaccounts,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=*,resources=serviceaccounts/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=*,resources=serviceaccounts/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the ZUser object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.10.0/pkg/reconcile +func (r *ZUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + zuser := zeldaiov1alpha1.ZUser{} + err := r.Get(ctx, req.NamespacedName, &zuser) + if err != nil { + return ctrl.Result{}, err + } + if zuser.DeletionTimestamp == nil || zuser.DeletionTimestamp.IsZero() { + err = r.Process(ctx, &zuser) + return ctrl.Result{}, err + } + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *ZUserReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&zeldaiov1alpha1.ZUser{}). + Watches(&corev1.ServiceAccount{}, + &watchers.ZUserWatcher{ + Client: mgr.GetClient(), + }). + Complete(r) +} + +// 处理user变更。 +// user会保持对应的service account,role binding, cluster role binding 与其一致 +// user会定期清理token +func (r *ZUserReconciler) Process(ctx context.Context, zuser *zeldaiov1alpha1.ZUser) error { + zgroup := zeldaiov1alpha1.ZGroup{} + err := r.Get(ctx, zuser.NamespacedNameGroup(), &zgroup) //获取不到组,则无法为账号绑定role + if err != nil { + return err + } + changed, _ := zuser.IsSpecChanged() + err = r.ProcessServiceAccount(ctx, &zgroup, zuser, changed) + if err != nil { //sa处理失败则不用处理角色绑定 + return err + } + err = r.ProcessRoleBinding(ctx, zuser, changed) + if err != nil { + //打印日志 + } + err = r.ProcessClusterRoleBinding(ctx, zuser, changed) + return err +} + +// 处理service account +func (r *ZUserReconciler) ProcessServiceAccount(ctx context.Context, zgroup *zeldaiov1alpha1.ZGroup, zuser *zeldaiov1alpha1.ZUser, changed bool) error { + sa := &corev1.ServiceAccount{} + err := r.Get(ctx, zuser.NamespacedNameServiceAccount(), sa) + if err != nil || changed { + sa = zuser.ServiceAccount(zgroup.Spec.Secrets) + } + if err != nil { //没有获取到,需要创建 + err = r.Create(ctx, sa, &client.CreateOptions{}) + return err + } + if changed { + err = r.Update(ctx, sa, &client.UpdateOptions{}) + return err + } + //zuser 无变化,这里更新状态 + for _, secret := range sa.Secrets { + if strings.Contains(secret.Name, fmt.Sprintf("%s-%s", sa.Name, "token")) { + zuser.Status.Token = secret.Name + err = r.Status().Update(ctx, zuser) + return err + } + } + return nil +} + +// 处理rolebinding +func (r *ZUserReconciler) ProcessRoleBinding(ctx context.Context, zuser *zeldaiov1alpha1.ZUser, changed bool) error { + roleBinding := &rbacv1.RoleBinding{} + err := r.Get(ctx, zuser.NamespacedNameRoleBinding(), roleBinding) + if err != nil || changed { + roleBinding = zuser.RoleBinding() + } + if err != nil { //没有获取到,需要创建 + err = r.Create(ctx, roleBinding, &client.CreateOptions{}) + return err + } + if changed { + err = r.Update(ctx, roleBinding, &client.UpdateOptions{}) + return err + } + return nil +} + +// 处理cluster rolebinding +func (r *ZUserReconciler) ProcessClusterRoleBinding(ctx context.Context, zuser *zeldaiov1alpha1.ZUser, changed bool) error { + roleBinding := &rbacv1.ClusterRoleBinding{} + err := r.Get(ctx, zuser.NamespacedNameClusterRoleBinding(), roleBinding) + if err != nil || changed { + roleBinding = zuser.ClusterRoleBinding() + } + if err != nil { //没有获取到,需要创建 + err = r.Create(ctx, roleBinding, &client.CreateOptions{}) + return err + } + if changed { + err = r.Update(ctx, roleBinding, &client.UpdateOptions{}) + return err + } + return nil +} diff --git a/backend/pkg/config/config.go b/backend/pkg/config/config.go new file mode 100644 index 0000000..67767a2 --- /dev/null +++ b/backend/pkg/config/config.go @@ -0,0 +1,9 @@ +package config + +import "time" + +type Config struct { + GitImage string `json:"gitImage,omitempty"` + Timeout time.Duration `json:"timeout,omitempty"` + AuthSecret string `json:"authSecret"` +} diff --git a/backend/pkg/notifier/api/type.go b/backend/pkg/notifier/api/type.go new file mode 100644 index 0000000..27b587c --- /dev/null +++ b/backend/pkg/notifier/api/type.go @@ -0,0 +1,10 @@ +package api + +type Message struct { + +} + +type Notifier interface { + Run()error + Send(Message)error +} \ No newline at end of file diff --git a/backend/pkg/notifier/dingtalk.go b/backend/pkg/notifier/dingtalk.go new file mode 100644 index 0000000..535b9ed --- /dev/null +++ b/backend/pkg/notifier/dingtalk.go @@ -0,0 +1,26 @@ +package notifier + +import "github.com/ycyxuehan/zelda/pkg/notifier/api" + +type DingTalk struct { + messageChan chan api.Message + accessToken string +} + +func NewDingTalk(token string, queueLength int)*DingTalk{ + if queueLength < 1 { + queueLength = 1 + } + return &DingTalk{ + accessToken: token, + messageChan: make(chan api.Message, queueLength), + } +} + +func (dt *DingTalk)Run()error{ + return nil +} + +func (dt *DingTalk)Send(msg api.Message)error{ + return nil +} diff --git a/backend/pkg/notifier/mail.go b/backend/pkg/notifier/mail.go new file mode 100644 index 0000000..00ef111 --- /dev/null +++ b/backend/pkg/notifier/mail.go @@ -0,0 +1,26 @@ +package notifier + +import "github.com/ycyxuehan/zelda/pkg/notifier/api" + +type Mail struct { + messageChan chan api.Message + accessToken string +} + +func NewMail(token string, queueLength int)*Mail{ + if queueLength < 1 { + queueLength = 1 + } + return &Mail{ + accessToken: token, + messageChan: make(chan api.Message, queueLength), + } +} + +func (dt *Mail)Run()error{ + return nil +} + +func (dt *Mail)Send(msg api.Message)error{ + return nil +} \ No newline at end of file diff --git a/backend/pkg/notifier/wechat.go b/backend/pkg/notifier/wechat.go new file mode 100644 index 0000000..706c46c --- /dev/null +++ b/backend/pkg/notifier/wechat.go @@ -0,0 +1,26 @@ +package notifier + +import "github.com/ycyxuehan/zelda/pkg/notifier/api" + +type WeChat struct { + messageChan chan api.Message + accessToken string +} + +func NewWeChat(token string, queueLength int)*WeChat{ + if queueLength < 1 { + queueLength = 1 + } + return &WeChat{ + accessToken: token, + messageChan: make(chan api.Message, queueLength), + } +} + +func (dt *WeChat)Run()error{ + return nil +} + +func (dt *WeChat)Send(msg api.Message)error{ + return nil +} \ No newline at end of file diff --git a/backend/pkg/utils/corev1.go b/backend/pkg/utils/corev1.go new file mode 100644 index 0000000..a86734f --- /dev/null +++ b/backend/pkg/utils/corev1.go @@ -0,0 +1,95 @@ +package utils + +import ( + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + apitypes "k8s.io/apimachinery/pkg/types" +) + +func MergeEnv(mode MergeMode, envs ...[]v1.EnvVar) []v1.EnvVar { + envMap := make(map[string]v1.EnvVar) + for _, envvars := range envs { + for _, envvar := range envvars { + switch mode { + case MergeOverrideByFirst: + if _, ok := envMap[envvar.Name]; !ok { + envMap[envvar.Name] = envvar + } + case MergeOverrideByLatest: + envMap[envvar.Name] = envvar + case MergeValue: + if old, ok := envMap[envvar.Name]; !ok { + envMap[envvar.Name] = envvar + } else { + envMap[envvar.Name] = v1.EnvVar{ + Name: envvar.Name, + Value: strings.Join([]string{old.Value, envvar.Value}, " "), + } + } + } + } + } + res := []v1.EnvVar{} + for _, v := range envMap { + res = append(res, v) + } + return res +} + +func MergeObjectReferences(mergeMode MergeMode, orList ...[]v1.ObjectReference) ([]v1.ObjectReference, error) { + res := []v1.ObjectReference{} + if mergeMode == MergeValue { + return res, fmt.Errorf("cannot support merge value") + } + resMap := make(map[string]v1.ObjectReference) + for _, ors := range orList { + for _, or := range ors { + key := strings.Join([]string{or.Namespace, or.Name}, ".") + switch mergeMode { + case MergeOverrideByFirst: + if _, ok := resMap[key]; !ok { + resMap[key] = or + } + case MergeOverrideByLatest: + resMap[key] = or + } + } + } + for _, or := range resMap { + res = append(res, or) + } + return res, nil +} + +func MergeLocalObjectReferences(mergeMode MergeMode, orList ...[]v1.LocalObjectReference) ([]v1.LocalObjectReference, error) { + res := []v1.LocalObjectReference{} + if mergeMode == MergeValue { + return res, fmt.Errorf("cannot support merge value") + } + resMap := make(map[string]v1.LocalObjectReference) + for _, ors := range orList { + for _, or := range ors { + switch mergeMode { + case MergeOverrideByFirst: + if _, ok := resMap[or.Name]; !ok { + resMap[or.Name] = or + } + case MergeOverrideByLatest: + resMap[or.Name] = or + } + } + } + for _, or := range resMap { + res = append(res, or) + } + return res, nil +} + +func NamespacedNameFromObjectReference(ref v1.ObjectReference) apitypes.NamespacedName { + return apitypes.NamespacedName{ + Namespace: ref.Namespace, + Name: ref.Name, + } +} diff --git a/backend/pkg/utils/docker.go b/backend/pkg/utils/docker.go new file mode 100644 index 0000000..a92fd65 --- /dev/null +++ b/backend/pkg/utils/docker.go @@ -0,0 +1,22 @@ +package utils + +import ( + "encoding/base64" + "strings" +) + +func NewDockerAuth(user, password string) DockerAuth { + return DockerAuth{ + User: user, + Password: password, + AuthString: base64.StdEncoding.EncodeToString([]byte(strings.Join([]string{user, password}, ":"))), + } +} + +func NewDockerConfig(server, user, password string) DockerConfig { + config := DockerConfig{ + AuthDataMap: make(map[string]DockerAuth), + } + config.AuthDataMap[server] = NewDockerAuth(user, password) + return config +} diff --git a/backend/pkg/utils/types.go b/backend/pkg/utils/types.go new file mode 100644 index 0000000..2b4136c --- /dev/null +++ b/backend/pkg/utils/types.go @@ -0,0 +1,37 @@ +package utils + +import "encoding/json" + +type MergeMode string + +const ( + MergeOverrideByFirst MergeMode = "MergeOverrideByFirst" //覆盖模式,保留第一个 + MergeOverrideByLatest MergeMode = "MergeOverrideByLatest" //覆盖模式,保留最后一个 + MergeValue MergeMode = "MergeValue" //合并值 +) + +type DockerAuth struct { + User string `json:"username"` + Password string `json:"password"` + AuthString string `json:"auth"` +} + +func (da DockerAuth) String() string { + data, err := json.Marshal(&da) + if err != nil { + return "" + } + return string(data) +} + +type DockerConfig struct { + AuthDataMap map[string]DockerAuth `json:"auths"` +} + +func (dc DockerConfig) String() string { + data, err := json.Marshal(&dc) + if err != nil { + return "" + } + return string(data) +} diff --git a/backend/pkg/utils/utils.go b/backend/pkg/utils/utils.go new file mode 100644 index 0000000..d4b585b --- /dev/null +++ b/backend/pkg/utils/utils.go @@ -0,0 +1 @@ +package utils diff --git a/backend/resource/zcustomhost/demo.yaml b/backend/resource/zcustomhost/demo.yaml new file mode 100644 index 0000000..5cfa61b --- /dev/null +++ b/backend/resource/zcustomhost/demo.yaml @@ -0,0 +1,10 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZCustomHost +metadata: + name: demo + namespace: demo +spec: + hostAlias: + - ip: 192.168.0.31 + hostnames: + - "zelda.io" diff --git a/backend/resource/zgroup/demo.yaml b/backend/resource/zgroup/demo.yaml new file mode 100644 index 0000000..c055c58 --- /dev/null +++ b/backend/resource/zgroup/demo.yaml @@ -0,0 +1,54 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZGroup +metadata: + name: demo + namespace: demo +spec: + rulers: + - apiGroups: [""] + resources: ["pods", "secrets", "serviceaccounts", "configmaps", "persistentvolumeclaims", "limitranges", "jobs", "namespaces",] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: [""] + resources: ["pods/log", "pods/status", "events", "pods/events"] + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: ["deployments", "statefulsets"] + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: + - "swallow.intbee.com" + resources: + - "projects" + - "users" + - "groups" + - "builders" + - "apprunners" + - "registries" + - "scriptrunners" + - "hostaliases" + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: + - "tekton.dev" + resources: + - "tasks" + - "taskruns" + - "pipelines" + - "pipelineresources" + - "pipelineruns" + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: + - "triggers.tekton.dev" + resources: + - "triggerbindings" + - "triggertemplates" + verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] + - apiGroups: + - "events.k8s.io" + resources: + - "events" + verbs: ["get", "list", "watch"] + - apiGroups: ["metrics.k8s.io"] + resources: ["pods", "nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["metrics"] + resources: ["pods", "nodes"] + verbs: ["get", "list", "watch"] diff --git a/backend/resource/zregistry/tencent.yaml b/backend/resource/zregistry/tencent.yaml new file mode 100644 index 0000000..fd8de5a --- /dev/null +++ b/backend/resource/zregistry/tencent.yaml @@ -0,0 +1,11 @@ +apiVersion: zelda.io/v1alpha1 +kind: ZRegistry +metadata: + name: tencent + namespace: demo +spec: + server: ccr.ccs.tencentyun.com + namespace: zelda + username: "100004225373" + password: Hello2022 + portal: tcr.tencentcloudapi.com \ No newline at end of file diff --git a/backend/resource/zuser/demo.yaml b/backend/resource/zuser/demo.yaml new file mode 100644 index 0000000..4571593 --- /dev/null +++ b/backend/resource/zuser/demo.yaml @@ -0,0 +1,9 @@ +apiVersion: zelda.io/v1alpha1 +Kind: ZUser +metadata: + namespace: demo + name: demo +spec: + password: aaa + group: demo + notifyMedia: "18818657045" diff --git a/backend/watcher/zbuider.go b/backend/watcher/zbuider.go new file mode 100644 index 0000000..219ec22 --- /dev/null +++ b/backend/watcher/zbuider.go @@ -0,0 +1,44 @@ +package watchers + +import ( + "context" + "time" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +type ZBuilderWatcher struct { + Client client.Client +} + +//监听create事件 +func (zbuilderWatcher *ZBuilderWatcher) Create(ctx context.Context, e event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.Object.GetLabels() + if builderName, ok := labels["zbuilders.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.Object.GetNamespace(), Name: builderName}}, time.Millisecond*50) + } +} + +//监听update事件 +func (zbuilderWatcher *ZBuilderWatcher) Update(ctx context.Context, e event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.ObjectNew.GetLabels() + if builderName, ok := labels["zbuilders.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.ObjectNew.GetNamespace(), Name: builderName}}, time.Millisecond*50) + } +} + +//监听delete事件 +func (zbuilderWatcher *ZBuilderWatcher) Delete(ctx context.Context, e event.DeleteEvent, limitingInerface workqueue.RateLimitingInterface) { + +} + +//监听generic事件 +func (zbuilderWatcher *ZBuilderWatcher) Generic(ctx context.Context, e event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) { + +} diff --git a/backend/watcher/zservice.go b/backend/watcher/zservice.go new file mode 100644 index 0000000..b4689e8 --- /dev/null +++ b/backend/watcher/zservice.go @@ -0,0 +1,48 @@ +package watchers + +import ( + "context" + "time" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +type ZServiceWatcher struct { + Client client.Client +} + +//监听create事件 +func (zserviceWatcher *ZServiceWatcher) Create(ctx context.Context, e event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.Object.GetLabels() + if serviceName, ok := labels["zservices.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.Object.GetNamespace(), Name: serviceName}}, time.Millisecond*50) + } +} + +//监听update事件 +func (zserviceWatcher *ZServiceWatcher) Update(ctx context.Context, e event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.ObjectNew.GetLabels() + if serviceName, ok := labels["zservices.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.ObjectNew.GetNamespace(), Name: serviceName}}, time.Millisecond*50) + } +} + +//监听delete事件 +func (zserviceWatcher *ZServiceWatcher) Delete(ctx context.Context, e event.DeleteEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.Object.GetLabels() + if serviceName, ok := labels["zservices.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.Object.GetNamespace(), Name: serviceName}}, time.Millisecond*50) + } +} + +//监听generic事件 +func (zserviceWatcher *ZServiceWatcher) Generic(ctx context.Context, e event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) { + +} diff --git a/backend/watcher/zuser.go b/backend/watcher/zuser.go new file mode 100644 index 0000000..8fc8003 --- /dev/null +++ b/backend/watcher/zuser.go @@ -0,0 +1,48 @@ +package watchers + +import ( + "context" + "time" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +type ZUserWatcher struct { + Client client.Client +} + +//监听create事件 +func (zserviceWatcher *ZUserWatcher) Create(ctx context.Context, e event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.Object.GetLabels() + if serviceName, ok := labels["zusers.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.Object.GetNamespace(), Name: serviceName}}, time.Millisecond*50) + } +} + +//监听update事件 +func (zserviceWatcher *ZUserWatcher) Update(ctx context.Context, e event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.ObjectNew.GetLabels() + if serviceName, ok := labels["zusers.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.ObjectNew.GetNamespace(), Name: serviceName}}, time.Millisecond*50) + } +} + +//监听delete事件 +func (zserviceWatcher *ZUserWatcher) Delete(ctx context.Context, e event.DeleteEvent, limitingInterface workqueue.RateLimitingInterface) { + labels := e.Object.GetLabels() + if serviceName, ok := labels["zusers.zelda.io"]; ok { + //等待50ms + limitingInterface.AddAfter(&reconcile.Request{NamespacedName: types.NamespacedName{Namespace: e.Object.GetNamespace(), Name: serviceName}}, time.Millisecond*50) + } +} + +//监听generic事件 +func (zserviceWatcher *ZUserWatcher) Generic(ctx context.Context, e event.GenericEvent, limitingInterface workqueue.RateLimitingInterface) { + +} diff --git a/.gitignore b/frontend/.gitignore similarity index 100% rename from .gitignore rename to frontend/.gitignore diff --git a/LICENSE b/frontend/LICENSE similarity index 100% rename from LICENSE rename to frontend/LICENSE diff --git a/README.md b/frontend/README.md similarity index 100% rename from README.md rename to frontend/README.md diff --git a/babel.config.js b/frontend/babel.config.js similarity index 100% rename from babel.config.js rename to frontend/babel.config.js diff --git a/package-lock.json b/frontend/package-lock.json similarity index 100% rename from package-lock.json rename to frontend/package-lock.json diff --git a/package.json b/frontend/package.json similarity index 100% rename from package.json rename to frontend/package.json diff --git a/public/favicon.ico b/frontend/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to frontend/public/favicon.ico diff --git a/public/index.html b/frontend/public/index.html similarity index 100% rename from public/index.html rename to frontend/public/index.html diff --git a/src/App.vue b/frontend/src/App.vue similarity index 100% rename from src/App.vue rename to frontend/src/App.vue diff --git a/src/assets/logo.png b/frontend/src/assets/logo.png similarity index 100% rename from src/assets/logo.png rename to frontend/src/assets/logo.png diff --git a/src/components/HelloWorld.vue b/frontend/src/components/HelloWorld.vue similarity index 100% rename from src/components/HelloWorld.vue rename to frontend/src/components/HelloWorld.vue diff --git a/src/components/Menu.vue b/frontend/src/components/Menu.vue similarity index 100% rename from src/components/Menu.vue rename to frontend/src/components/Menu.vue diff --git a/src/libs/menu.ts b/frontend/src/libs/menu.ts similarity index 100% rename from src/libs/menu.ts rename to frontend/src/libs/menu.ts diff --git a/src/main.ts b/frontend/src/main.ts similarity index 100% rename from src/main.ts rename to frontend/src/main.ts diff --git a/src/router/index.ts b/frontend/src/router/index.ts similarity index 100% rename from src/router/index.ts rename to frontend/src/router/index.ts diff --git a/src/shims-vue.d.ts b/frontend/src/shims-vue.d.ts similarity index 100% rename from src/shims-vue.d.ts rename to frontend/src/shims-vue.d.ts diff --git a/src/store/index.ts b/frontend/src/store/index.ts similarity index 100% rename from src/store/index.ts rename to frontend/src/store/index.ts diff --git a/src/views/About.vue b/frontend/src/views/About.vue similarity index 100% rename from src/views/About.vue rename to frontend/src/views/About.vue diff --git a/src/views/Home.vue b/frontend/src/views/Home.vue similarity index 100% rename from src/views/Home.vue rename to frontend/src/views/Home.vue diff --git a/src/views/Kubernetes.vue b/frontend/src/views/Kubernetes.vue similarity index 100% rename from src/views/Kubernetes.vue rename to frontend/src/views/Kubernetes.vue diff --git a/src/views/Login.vue b/frontend/src/views/Login.vue similarity index 100% rename from src/views/Login.vue rename to frontend/src/views/Login.vue diff --git a/src/views/zelda/ZGroup.vue b/frontend/src/views/zelda/ZGroup.vue similarity index 100% rename from src/views/zelda/ZGroup.vue rename to frontend/src/views/zelda/ZGroup.vue diff --git a/src/views/zelda/ZProject.vue b/frontend/src/views/zelda/ZProject.vue similarity index 100% rename from src/views/zelda/ZProject.vue rename to frontend/src/views/zelda/ZProject.vue diff --git a/src/views/zelda/ZService.vue b/frontend/src/views/zelda/ZService.vue similarity index 100% rename from src/views/zelda/ZService.vue rename to frontend/src/views/zelda/ZService.vue diff --git a/tsconfig.json b/frontend/tsconfig.json similarity index 100% rename from tsconfig.json rename to frontend/tsconfig.json diff --git a/vue.config.js b/frontend/vue.config.js similarity index 100% rename from vue.config.js rename to frontend/vue.config.js