This commit is contained in:
huangkun 2024-11-19 16:57:27 +08:00
parent b253832bd0
commit efbdd13fd0
177 changed files with 18578 additions and 0 deletions

3
backend/.dockerignore Normal file
View File

@ -0,0 +1,3 @@
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
bin/

26
backend/.gitignore vendored Normal file
View File

@ -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
*~

37
backend/Dockerfile Normal file
View File

@ -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"]

174
backend/Makefile Normal file
View File

@ -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<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Development
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object: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=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name 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 -

101
backend/PROJECT Normal file
View File

@ -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"

94
backend/README.md Normal file
View File

@ -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
Youll 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=<some-registry>/zelda:tag
```
3. Deploy the controller to the cluster with the image specified by `IMG`:
```sh
make deploy IMG=<some-registry>/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.

View File

@ -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
)

View File

@ -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
}

View File

@ -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{})
}

View File

@ -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{})
}

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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{})
}

View File

@ -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{})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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())
}

View File

@ -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) {
}

View File

@ -0,0 +1 @@
package zbuilder

View File

@ -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}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -0,0 +1,8 @@
package zuser
import(
kubeclient "sigs.k8s.io/controller-runtime/pkg/client"
)
type ctrl struct {
kubeClient kubeclient.Client
}

View File

@ -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) {
}

View File

@ -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
}

View File

@ -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
}

193
backend/cmd/main.go Normal file
View File

@ -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)
}
}

View File

@ -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: {}

View File

@ -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[''<KEY>'']`,
`metadata.annotations[''<KEY>'']`, 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: {}

View File

@ -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: {}

View File

@ -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: {}

File diff suppressed because it is too large Load Diff

View File

@ -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: {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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: {}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -0,0 +1,10 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: manager

View File

@ -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"

View File

@ -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

View File

@ -0,0 +1,2 @@
resources:
- monitor.yaml

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More