chore: remove all files related to the freeleaps-gitops-initializer project

This commit deletes the entire freeleaps-gitops-initializer directory, including configuration files, source code, and documentation, as part of a project cleanup.

Signed-off-by: zhenyus <zhenyus@mathmast.com>
This commit is contained in:
zhenyus 2025-07-14 10:40:23 +08:00
parent e3bce5dddb
commit 32a40173da
68 changed files with 0 additions and 6208 deletions

View File

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

View File

@ -1,27 +0,0 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/*
Dockerfile.cross
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Go workspace file
go.work
# Kubernetes Generated files - skip generated files, except for vendored files
!vendor/**/zz_generated.*
# editor and IDE paraphernalia
.idea
.vscode
*.swp
*.swo
*~

View File

@ -1,47 +0,0 @@
run:
timeout: 5m
allow-parallel-runners: true
issues:
# don't skip warning about doc comments
# don't exclude the default set of lint
exclude-use-default: false
# restore some of the defaults
# (fill in the rest as needed)
exclude-rules:
- path: "api/*"
linters:
- lll
- path: "internal/*"
linters:
- dupl
- lll
linters:
disable-all: true
enable:
- dupl
- errcheck
- exportloopref
- ginkgolinter
- goconst
- gocyclo
- gofmt
- goimports
- gosimple
- govet
- ineffassign
- lll
- misspell
- nakedret
- prealloc
- revive
- staticcheck
- typecheck
- unconvert
- unparam
- unused
linters-settings:
revive:
rules:
- name: comment-spacings

View File

@ -1,33 +0,0 @@
# Build the manager binary
FROM golang:1.22 AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
# Copy the go source
COPY cmd/main.go cmd/main.go
COPY api/ api/
COPY internal/controller/ internal/controller/
# 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"]

View File

@ -1,324 +0,0 @@
# VERSION defines the project version for the bundle.
# Update this value when you upgrade the version of your project.
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.0.1
# CHANNELS define the bundle channels used in the bundle.
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
# To re-generate a bundle for other specific channels without changing the standard setup, you can:
# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable)
# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable")
ifneq ($(origin CHANNELS), undefined)
BUNDLE_CHANNELS := --channels=$(CHANNELS)
endif
# DEFAULT_CHANNEL defines the default channel used in the bundle.
# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable")
# To re-generate a bundle for any other default channel without changing the default setup, you can:
# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable)
# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable")
ifneq ($(origin DEFAULT_CHANNEL), undefined)
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
endif
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images.
# This variable is used to construct full image tags for bundle and catalog images.
#
# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both
# freeleaps.com/freeleaps-gitops-initializer-bundle:$VERSION and freeleaps.com/freeleaps-gitops-initializer-catalog:$VERSION.
IMAGE_TAG_BASE ?= freeleaps.com/freeleaps-gitops-initializer
# BUNDLE_IMG defines the image:tag used for the bundle.
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:v$(VERSION)
# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command
BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests
# You can enable this value if you would like to use SHA Based Digests
# To enable set flag to true
USE_IMAGE_DIGESTS ?= false
ifeq ($(USE_IMAGE_DIGESTS), true)
BUNDLE_GEN_FLAGS += --use-image-digests
endif
# Set the Operator SDK version to use. By default, what is installed on the system is used.
# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit.
OPERATOR_SDK_VERSION ?= v1.39.1
# Image URL to use all building/pushing image targets
IMG ?= controller:latest
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.31.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 $$(go list ./... | grep -v /e2e) -coverprofile cover.out
# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v
.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter
$(GOLANGCI_LINT) run
.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
$(GOLANGCI_LINT) run --fix
##@ 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 freeleaps-gitops-initializer-builder
$(CONTAINER_TOOL) buildx use freeleaps-gitops-initializer-builder
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- $(CONTAINER_TOOL) buildx rm freeleaps-gitops-initializer-builder
rm Dockerfile.cross
.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > dist/install.yaml
##@ Deployment
ifndef ignore-not-found
ignore-not-found = false
endif
.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(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: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -
##@ Dependencies
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
KUBECTL ?= kubectl
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
## Tool Versions
KUSTOMIZE_VERSION ?= v5.4.3
CONTROLLER_TOOLS_VERSION ?= v0.16.1
ENVTEST_VERSION ?= release-0.19
GOLANGCI_LINT_VERSION ?= v1.59.1
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))
.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))
.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f "$(1)-$(3)" ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
rm -f $(1) || true ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv $(1) $(1)-$(3) ;\
} ;\
ln -sf $(1)-$(3) $(1)
endef
.PHONY: operator-sdk
OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk
operator-sdk: ## Download operator-sdk locally if necessary.
ifeq (,$(wildcard $(OPERATOR_SDK)))
ifeq (, $(shell which operator-sdk 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPERATOR_SDK)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\
chmod +x $(OPERATOR_SDK) ;\
}
else
OPERATOR_SDK = $(shell which operator-sdk)
endif
endif
.PHONY: bundle
bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files.
$(OPERATOR_SDK) generate kustomize manifests -q
cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG)
$(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS)
$(OPERATOR_SDK) bundle validate ./bundle
.PHONY: bundle-build
bundle-build: ## Build the bundle image.
docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .
.PHONY: bundle-push
bundle-push: ## Push the bundle image.
$(MAKE) docker-push IMG=$(BUNDLE_IMG)
.PHONY: opm
OPM = $(LOCALBIN)/opm
opm: ## Download opm locally if necessary.
ifeq (,$(wildcard $(OPM)))
ifeq (,$(shell which opm 2>/dev/null))
@{ \
set -e ;\
mkdir -p $(dir $(OPM)) ;\
OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \
curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.23.0/$${OS}-$${ARCH}-opm ;\
chmod +x $(OPM) ;\
}
else
OPM = $(shell which opm)
endif
endif
# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0).
# These images MUST exist in a registry and be pull-able.
BUNDLE_IMGS ?= $(BUNDLE_IMG)
# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0).
CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION)
# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image.
ifneq ($(origin CATALOG_BASE_IMG), undefined)
FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG)
endif
# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'.
# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see:
# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator
.PHONY: catalog-build
catalog-build: opm ## Build a catalog image.
$(OPM) index add --container-tool docker --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT)
# Push the catalog image.
.PHONY: catalog-push
catalog-push: ## Push a catalog image.
$(MAKE) docker-push IMG=$(CATALOG_IMG)

View File

@ -1,23 +0,0 @@
# 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: freeleaps.com
layout:
- go.kubebuilder.io/v4
plugins:
manifests.sdk.operatorframework.io/v2: {}
scorecard.sdk.operatorframework.io/v2: {}
projectName: freeleaps-gitops-initializer
repo: freeleaps.com/gitops/initializer
resources:
- api:
crdVersion: v1
namespaced: true
controller: true
domain: freeleaps.com
group: gitops
kind: ProjectInitialize
path: freeleaps.com/gitops/initializer/api/v1alpha1
version: v1alpha1
version: "3"

View File

@ -1,114 +0,0 @@
# freeleaps-gitops-initializer
// TODO(user): Add simple overview of use/purpose
## Description
// TODO(user): An in-depth paragraph about your project and overview of use
## Getting Started
### Prerequisites
- go version v1.22.0+
- docker version 17.03+.
- kubectl version v1.11.3+.
- Access to a Kubernetes v1.11.3+ cluster.
### To Deploy on the cluster
**Build and push your image to the location specified by `IMG`:**
```sh
make docker-build docker-push IMG=<some-registry>/freeleaps-gitops-initializer:tag
```
**NOTE:** This image ought to be published in the personal registry you specified.
And it is required to have access to pull the image from the working environment.
Make sure you have the proper permission to the registry if the above commands dont work.
**Install the CRDs into the cluster:**
```sh
make install
```
**Deploy the Manager to the cluster with the image specified by `IMG`:**
```sh
make deploy IMG=<some-registry>/freeleaps-gitops-initializer:tag
```
> **NOTE**: If you encounter RBAC errors, you may need to grant yourself cluster-admin
privileges or be logged in as admin.
**Create instances of your solution**
You can apply the samples (examples) from the config/sample:
```sh
kubectl apply -k config/samples/
```
>**NOTE**: Ensure that the samples has default values to test it out.
### To Uninstall
**Delete the instances (CRs) from the cluster:**
```sh
kubectl delete -k config/samples/
```
**Delete the APIs(CRDs) from the cluster:**
```sh
make uninstall
```
**UnDeploy the controller from the cluster:**
```sh
make undeploy
```
## Project Distribution
Following are the steps to build the installer and distribute this project to users.
1. Build the installer for the image built and published in the registry:
```sh
make build-installer IMG=<some-registry>/freeleaps-gitops-initializer:tag
```
NOTE: The makefile target mentioned above generates an 'install.yaml'
file in the dist directory. This file contains all the resources built
with Kustomize, which are necessary to install this project without
its dependencies.
2. Using the installer
Users can just run kubectl apply -f <URL for YAML BUNDLE> to install the project, i.e.:
```sh
kubectl apply -f https://raw.githubusercontent.com/<org>/freeleaps-gitops-initializer/<tag or branch>/dist/install.yaml
```
## Contributing
// TODO(user): Add detailed information on how you would like others to contribute to this project
**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 2025.
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

@ -1,36 +0,0 @@
/*
Copyright 2025.
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 gitops v1alpha1 API group
// +kubebuilder:object:generate=true
// +groupName=gitops.freeleaps.com
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: "gitops.freeleaps.com", 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

@ -1,478 +0,0 @@
/*
Copyright 2025.
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 (
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
corev1 "k8s.io/api/core/v1"
netowrkingv1 "k8s.io/api/networking/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.
// ArgoSyncPolicySpec defines the desired state of sync policy settings of Argo Application
type ArgoSyncPolicySpec struct {
// Automated enables the auto sync of Argo Application
Automated bool `json:"automated,omitempty"`
// Prune enables the auto pruning of Argo Application
Prune bool `json:"prune,omitempty"`
// SelfHeal enables the auto self healing of Argo Application
SelfHeal bool `json:"selfHeal,omitempty"`
}
// ArgoSpec defines the desired state of Argo Project and Argo Application.
type ArgoSpec struct {
// Name of the Argo Application
Name string `json:"name,omitempty"`
// Name of the Argo Project
Project string `json:"project,omitempty"`
// Namespace of the Argo Application to deploy
Namespace string `json:"namespace,omitempty"`
// Branch defines the Git branch of this Argo Application
Branch string `json:"branch,omitempty"`
// SyncPolicy defines the sync policy settings of Argo Application
SyncPolicy ArgoSyncPolicySpec `json:"syncPolicy,omitempty"`
}
// RepositoryType defines the type of the Git repository
type RepositoryType string
const (
// Monorepo defines the Git repository type as monorepo
Monorepo RepositoryType = "monorepo"
// Separated defines the Git repository type as separated
Separated RepositoryType = "separated"
)
// RepositoryHookEventConfigSpec defines the desired state of project's Git repository hook event configuration
type RepositoryHookEventConfigSpec struct {
// TriggerGroups defines the groups that trigger the Git repository hook event
TriggerGroups string `json:"triggerGroups,omitempty"`
// ReviewersIncludesGroups defines the groups that includes the reviewers of the Git repository hook event
ReviewersIncludesGroups string `json:"reviewersIncludesGroups,omitempty"`
}
// RepositoryHookEventSpec defines the desired state of project's Git repository hook event
type RepositoryHookEventSpec struct {
Event string `json:"event,omitempty"`
// Config defines the Git repository hook event configuration
Config RepositoryHookEventConfigSpec `json:"config,omitempty"`
}
// RepositoryHookRegisterSpec defines the desired state of project's Git repository hook registration
type RepositoryHookRegisterSpec struct {
// Enabled defines the existence of the Git repository hook registration, set to false to skip the Git repository hook registration.
Enabled bool `json:"enabled,omitempty"`
// Events defines the Git repository hook events
Events []RepositoryHookEventSpec `json:"events,omitempty"`
}
const (
// RepositoryPluginAzureDevOps defines the Git repository plugin as Azure DevOps
RepositoryPluginAzureDevOps = "azure-devops"
)
// RepositorySpec defines the desired state of project's Git repository
type RepositorySpec struct {
// Plugin defines the Git repository plugin
Plugin string `json:"plugin,omitempty"`
// PluginConfig defines the Git repository plugin configuration
PluginConfig map[string]string `json:"pluginConfig,omitempty"`
// RegisterToArgo defines the existence of the Git repository registration to Argo, set to false to skip the Git repository registration to Argo.
RegisterToArgo bool `json:"registerToArgo,omitempty"`
// Project defines the project of the Git repository
Project string `json:"project,omitempty"`
// Name defines the name of the Git repository
Name string `json:"name,omitempty"`
// Type defines the type of the Git repository
Type RepositoryType `json:"type,omitempty"`
// Branch defines the branch of the Git repository
Branch string `json:"branch,omitempty"`
// HookRegister defines the Git repository hook registration
HookRegister RepositoryHookRegisterSpec `json:"hookRegister,omitempty"`
}
// CIExecuteModeTypes defines the type of the CI execute mode
type CIExecuteModeTypes string
const (
// Fully defines the CI execute mode as fully
Fully CIExecuteModeTypes = "fully"
// OnDemand defines the CI execute mode as on-demand
OnDemand CIExecuteModeTypes = "on-demand"
)
// CIComponentLanguage defines the type of the CI component language
type CIComponentLanguage string
const (
// Python defines the CI component language as Python
Python CIComponentLanguage = "python"
// JS defines the CI component language as JavaScript
JS CIComponentLanguage = "javascript"
)
// CIDependenciesManager defines the type of the CI dependencies manager
type CIDependenciesManager string
const (
// PIP defines the CI dependencies manager as pip
PIP CIDependenciesManager = "pip"
// NPM defines the CI dependencies manager as npm
NPM CIDependenciesManager = "npm"
// Yarn defines the CI dependencies manager as yarn
Yarn CIDependenciesManager = "yarn"
)
// ImageBuilderType defines the type of the image builder
type ImageBuilderType string
const (
// DockerInDocker defines the image builder type as Docker-in-Docker
DockerInDocker ImageBuilderType = "dind"
// Kaniko defines the image builder type as Kaniko
Kaniko ImageBuilderType = "kaniko"
)
// ImageRegistryCredentialType defines the type of the image registry credential
type ImageRegistryCredentialSpec struct {
// Username defines the username of the image registry credential
Username string `json:"username,omitempty"`
// Password defines the password of the image registry credential
Password string `json:"password,omitempty"`
}
type ImageRegistrySpec struct {
// URL defines the URL of the image registry
URL string `json:"url,omitempty"`
// Credentials defines the credentials of the image registry
Credentials ImageRegistryCredentialSpec `json:"credentials,omitempty"`
}
// ImageBuilderSpec defines the desired state of the image builder
type ImageBuilderSpec struct {
// Type defines the type of the image builder
Type ImageBuilderType `json:"type,omitempty"`
// Registry defines the image registry of the image builder
Registry ImageRegistrySpec `json:"registry,omitempty"`
// Repository defines the repository of the image builder
Repository string `json:"repository,omitempty"`
// Name defines the name of the image builder
Name string `json:"name,omitempty"`
// Dockerfile defines the Dockerfile path of the image builder
Dockerfile string `json:"dockerfile,omitempty"`
// BuildContextRoot defines the build context root of the image builder
BuildContextRoot string `json:"buildContextRoot,omitempty"`
// ReleaseArchitectures defines the release architectures of the image builder
ReleaseArchitectures []string `json:"releaseArchitectures,omitempty"`
}
// CIComponentSpec defines the desired state of CI component
type CIComponentSpec struct {
// Name defines the name of the CI component
Name string `json:"name,omitempty"`
// Root defines the root path of the CI component
Root string `json:"root,omitempty"`
// Language defines the language of the CI component
Language CIComponentLanguage `json:"language,omitempty"`
// SemanticReleaseEnabled defines the existence of the semantic release, set to false to skip the semantic release.
SemanticReleaseEnabled bool `json:"semanticReleaseEnabled,omitempty"`
// DependenciesManager defines the dependencies manager of the CI component
DependenciesManager CIDependenciesManager `json:"dependenciesManager,omitempty"`
// NPMPackageJsonFile defines the path of the npm package.json file
NPMPackageJsonFile string `json:"npmPackageJsonFile,omitempty"`
// BuildCacheEnabled defines the existence of the build cache, set to false to skip the build caching.
BuildCacheEnabled bool `json:"buildCacheEnabled,omitempty"`
// BuildCommand defines the build command of the CI component
BuildCommand string `json:"buildCommand,omitempty"`
// BuildAgentImage defines the build agent image of the CI component
BuildAgentImage string `json:"buildAgentImage,omitempty"`
// BuildArtifacts defines the build artifacts of the CI component
BuildArtifacts []string `json:"buildArtifacts,omitempty"`
// ImageBuilder defines the image builder of the CI component
ImageBuilder ImageBuilderSpec `json:"imageBuilder,omitempty"`
}
// ContinuousIntegrationSpec defines the desired state of Continuous Integration (CI)
type ContinuousIntegrationSpec struct {
// ExecuteMode defines the CI execute mode
ExecuteMode CIExecuteModeTypes `json:"executeMode,omitempty"`
// CommitMessageLintEnabled defines the existence of the commit message lint, set to false to skip the commit message lint.
CommitMessageLintEnabled bool `json:"commitMessageLintEnabled,omitempty"`
// Components defines the CI components
Components []CIComponentSpec `json:"components,omitempty"`
}
// HelmMetadataSpec defines the desired state of Helm metadata
type HelmMetadataSpec struct {
// Name defines the name of the Helm chart
Name string `json:"name,omitempty"`
// Description defines the description of the Helm chart
Description string `json:"description,omitempty"`
}
// HelmGlobalValuesSpec defines the desired state of Helm global values
type HelmGlobalValuesSpec struct {
// Registry defines the image registry of the Helm global values
Registry string `json:"registry,omitempty"`
// Repository defines the repository of the Helm global values
Repository string `json:"repository,omitempty"`
// NodeSelector defines the node selector of the Helm global values
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
}
// HelmComponentImageSpec defines the desired state of Helm component image
type HelmComponentImageSpec struct {
// Registry defines the image registry of the Helm component image
Registry string `json:"registry,omitempty"`
// Repository defines the repository of the Helm component image
Repository string `json:"repository,omitempty"`
// Name defines the name of the Helm component image
Name string `json:"name,omitempty"`
// Tag defines the tag of the Helm component image
Tag string `json:"tag,omitempty"`
// PullPolicy defines the pull policy of the Helm component image
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
}
// HelmComponentProbeType defines the type of the Helm component probe
type HelmComponentProbeType string
const (
// HTTPGet defines the Helm component probe type as HTTP GET
HTTPGet HelmComponentProbeType = "httpGet"
)
type HelmComponentProbeConfigSpec struct {
// Path defines the path of the Helm component probe
Path string `json:"path,omitempty"`
// Port defines the port of the Helm component probe
Port uint32 `json:"port,omitempty"`
// InitialDelaySeconds defines the initial delay seconds of the Helm component probe
InitialDelaySeconds int32 `json:"initialDelaySeconds,omitempty"`
// TimeoutSeconds defines the timeout seconds of the Helm component probe
TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"`
// PeriodSeconds defines the period seconds of the Helm component probe
PeriodSeconds int32 `json:"periodSeconds,omitempty"`
// SuccessThreshold defines the success threshold of the Helm component probe
SuccessThreshold int32 `json:"successThreshold,omitempty"`
// FailureThreshold defines the failure threshold of the Helm component probe
FailureThreshold int32 `json:"failureThreshold,omitempty"`
// TerminationGracePeriodSeconds defines the termination grace period seconds of the Helm component probe
TerminationGracePeriodSeconds int64 `json:"terminationGracePeriodSeconds,omitempty"`
}
// HelmComponentProbeConfigSpec defines the desired state of Helm component probe configuration
type HelmComponentProbeSpec struct {
// Type defines the type of the Helm component probe
Type HelmComponentProbeType `json:"type,omitempty"`
// Config defines the configuration of the Helm component probe
Config HelmComponentProbeConfigSpec `json:"config,omitempty"`
}
// HelmComponentProbesSpec defines the desired state of Helm component probes
type HelmComponentProbesSpec struct {
// Liveness defines the liveness probe of the Helm component
Liveness HelmComponentProbeSpec `json:"liveness,omitempty"`
// Readiness defines the readiness probe of the Helm component
Readiness HelmComponentProbeSpec `json:"readiness,omitempty"`
}
// HelmComponentServiceSpec defines the desired state of Helm component service
type HelmComponentServiceSpec struct {
// Name defines the name of the Helm component service
Name string `json:"name,omitempty"`
// Type defines the type of the Helm component service
Type corev1.ServiceType `json:"type,omitempty"`
// Port defines the port of the Helm component service
Port uint32 `json:"port,omitempty"`
// TargetPort defines the target port of the Helm component service
TargetPort uint32 `json:"targetPort,omitempty"`
}
// HelmComponentIngressTLSSpec defines the desired state of Helm component ingress TLS
type HelmComponentIngressTLSSpec struct {
// Exists defines the existence of the Helm component ingress TLS, set to false to skip the Helm component ingress TLS auto creation.
Exists bool `json:"exists,omitempty"`
// Name defines the name of the Helm component ingress TLS
Name string `json:"name,omitempty"`
// SecretRef defines the secret reference of the Helm component ingress TLS
SecretRef *corev1.SecretReference `json:"secretRef,omitempty"`
// IssuerRef defines the issuer reference of the Helm component ingress TLS
IssuerRef *cmmeta.ObjectReference `json:"issuerRef,omitempty"`
}
// HelmComponentIngressSpec defines the desired state of Helm component ingress
type HelmComponentIngressSpec struct {
// Name defines the name of the Helm component ingress
Name string `json:"name,omitempty"`
// Class defines the ingress class of the Helm component ingress
Class string `json:"class,omitempty"`
// Host defines the host of the Helm component ingress
Host string `json:"host,omitempty"`
// Rules defines the route rules of the Helm component ingress
Rules []netowrkingv1.HTTPIngressPath `json:"rules,omitempty"`
// TLS defines the TLS of the Helm component ingress
TLS HelmComponentIngressTLSSpec `json:"tls,omitempty"`
}
// HelmComponentConfigType defines the type of the Helm component configuration
type HelmComponentConfigType string
const (
// EnvironmentSecret defines the Helm component configuration type as environment secret
EnvironmentSecret HelmComponentConfigType = "environment-secret"
)
// HelmComponentConfigSpec defines the desired state of Helm component configuration
type HelmComponentConfigSpec struct {
// Name defines the name of the Helm component configuration
Name string `json:"name,omitempty"`
// Type defines the type of the Helm component configuration
Type HelmComponentConfigType `json:"type,omitempty"`
// Data defines the data of the Helm component configuration
Data []corev1.EnvVar `json:"data,omitempty"`
}
// HelmComponentResourceSettingSpec defines the desired state of Helm component resource setting
type HelmComponentResourceSettingSpec struct {
// CPU defines the CPU of the Helm component resource setting
CPU string `json:"cpu,omitempty"`
// Memory defines the memory of the Helm component resource setting
Memory string `json:"memory,omitempty"`
}
// HelmComponentResourceRequirementsSpec defines the desired state of Helm component resource requirements
type HelmComponentResourceRequirementsSpec struct {
// Limits defines the limits of the Helm component resource requirements
Limits HelmComponentResourceSettingSpec `json:"limits,omitempty"`
// Requests defines the requests of the Helm component resource requirements
Requests HelmComponentResourceSettingSpec `json:"requests,omitempty"`
}
// HelmComponentSpec defines the desired state of Helm component
type HelmComponentSpec struct {
// Name defines the name of the Helm component
Name string `json:"name,omitempty"`
// Chart defines the chart of the Helm component
Ports []corev1.ContainerPort `json:"ports,omitempty"`
// Replica defines the replica of the Helm component
Replicas uint32 `json:"replicas,omitempty"`
// Resources defines the resources of the Helm component
Resources HelmComponentResourceRequirementsSpec `json:"resources,omitempty"`
// Image defines the image of the Helm component
Image HelmComponentImageSpec `json:"image,omitempty"`
// Probes defines the probes of the Helm component
Probes HelmComponentProbesSpec `json:"probes,omitempty"`
// Services defines the services of the Helm component
Services []HelmComponentServiceSpec `json:"services,omitempty"`
// Ingresses defines the ingresses of the Helm component
Ingresses []HelmComponentIngressSpec `json:"ingresses,omitempty"`
// Configs defines the configurations of the Helm component
Configs []HelmComponentConfigSpec `json:"configs,omitempty"`
}
// HelmSpec defines the desired state of Helm generation
type HelmSpec struct {
// Generate defines the existence of the Helm generation, set to false to skip the Helm generation.
Generate bool `json:"generate,omitempty"`
// Metadata defines the Helm metadata
Metadata HelmMetadataSpec `json:"metadata,omitempty"`
// GlobalValues defines the Helm global values
Global HelmGlobalValuesSpec `json:"global,omitempty"`
// Components defines the Helm components
Components []HelmComponentSpec `json:"components,omitempty"`
}
// ProjectInitializeSpec defines the desired state of ProjectInitialize
type ProjectInitializeSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Argo defines the desired state of Argo Project and Argo Application
Argo *ArgoSpec `json:"argo,omitempty"`
// Repository defines the desired state of project's Git repository
Repository *RepositorySpec `json:"repository,omitempty"`
// ContinuousIntegration defines the desired state of Continuous Integration (CI)
ContinuousIntegration *ContinuousIntegrationSpec `json:"ci,omitempty"`
// Helm defines the desired state of Helm generation
Helm *HelmSpec `json:"helm,omitempty"`
}
const (
// OperatorDegraded defines the ProjectInitialize condition type as OperatorDegraded
ConditionOperatorDegraded = "OperatorDegraded"
// RepositoryCreated defines the ProjectInitialize condition type as RepositoryCreated
ConditionHelmPackageGenerated = "HelmPackageGenerated"
// JenkinsfileGenerated defines the ProjectInitialize condition type as JenkinsfileGenerated
ConditionJenkinsfileGenerated = "JenkinsfileGenerated"
// JenkinsProjectCreated defines the ProjectInitialize condition type as JenkinsProjectCreated
ConditionJenkinsProjectCreated = "JenkinsProjectCreated"
// RepositoryHookConfigured defines the ProjectInitialize condition type as RepositoryHookConfigured
ConditionRepositoryHookConfigured = "RepositoryHookConfigured"
// ArgoProjectConfigured defines the ProjectInitialize condition type as ArgoProjectConfigured
ConditionArgoProjectConfigured = "ArgoProjectConfigured"
// ArgoApplicationConfigured defines the ProjectInitialize condition type as ArgoApplicationConfigured
ConditionArgoApplicationConfigured = "ArgoApplicationConfigured"
)
const (
// ReasonCustomResourceNotAvailable defines the reason of the ProjectInitialize condition as CustomResourceNotAvailable
ReasonCustomResourceNotAvailable = "CustomResourceNotAvailable"
// ReasonRepositoryCreateFailed defines the reason of the ProjectInitialize condition as RepositoryCreateFailed
ReasonHelmPackageGenerateFailed = "HelmPackageGenerateFailed"
// ReasonJenkinsfileGenerateFailed defines the reason of the ProjectInitialize condition as JenkinsfileGenerateFailed
ReasonHelmPackageGenerated = "HelmPackageGenerated"
)
// ProjectInitializeStatus defines the observed state of ProjectInitialize
type ProjectInitializeStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
// Conditions defines the observed conditions of the ProjectInitialize
Conditions []metav1.Condition `json:"conditions,omitempty"`
// Ready defines the readiness of the ProjectInitialize
Ready bool `json:"ready,omitempty"`
}
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// ProjectInitialize is the Schema for the projectinitializes API
type ProjectInitialize struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ProjectInitializeSpec `json:"spec,omitempty"`
Status ProjectInitializeStatus `json:"status,omitempty"`
}
// +kubebuilder:object:root=true
// ProjectInitializeList contains a list of ProjectInitialize
type ProjectInitializeList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ProjectInitialize `json:"items"`
}
func init() {
SchemeBuilder.Register(&ProjectInitialize{}, &ProjectInitializeList{})
}

View File

@ -1,628 +0,0 @@
//go:build !ignore_autogenerated
/*
Copyright 2025.
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 (
metav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
"k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
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 *ArgoSpec) DeepCopyInto(out *ArgoSpec) {
*out = *in
out.SyncPolicy = in.SyncPolicy
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoSpec.
func (in *ArgoSpec) DeepCopy() *ArgoSpec {
if in == nil {
return nil
}
out := new(ArgoSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArgoSyncPolicySpec) DeepCopyInto(out *ArgoSyncPolicySpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoSyncPolicySpec.
func (in *ArgoSyncPolicySpec) DeepCopy() *ArgoSyncPolicySpec {
if in == nil {
return nil
}
out := new(ArgoSyncPolicySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CIComponentSpec) DeepCopyInto(out *CIComponentSpec) {
*out = *in
if in.BuildArtifacts != nil {
in, out := &in.BuildArtifacts, &out.BuildArtifacts
*out = make([]string, len(*in))
copy(*out, *in)
}
in.ImageBuilder.DeepCopyInto(&out.ImageBuilder)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CIComponentSpec.
func (in *CIComponentSpec) DeepCopy() *CIComponentSpec {
if in == nil {
return nil
}
out := new(CIComponentSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ContinuousIntegrationSpec) DeepCopyInto(out *ContinuousIntegrationSpec) {
*out = *in
if in.Components != nil {
in, out := &in.Components, &out.Components
*out = make([]CIComponentSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContinuousIntegrationSpec.
func (in *ContinuousIntegrationSpec) DeepCopy() *ContinuousIntegrationSpec {
if in == nil {
return nil
}
out := new(ContinuousIntegrationSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentConfigSpec) DeepCopyInto(out *HelmComponentConfigSpec) {
*out = *in
if in.Data != nil {
in, out := &in.Data, &out.Data
*out = make([]v1.EnvVar, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentConfigSpec.
func (in *HelmComponentConfigSpec) DeepCopy() *HelmComponentConfigSpec {
if in == nil {
return nil
}
out := new(HelmComponentConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentImageSpec) DeepCopyInto(out *HelmComponentImageSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentImageSpec.
func (in *HelmComponentImageSpec) DeepCopy() *HelmComponentImageSpec {
if in == nil {
return nil
}
out := new(HelmComponentImageSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentIngressSpec) DeepCopyInto(out *HelmComponentIngressSpec) {
*out = *in
if in.Rules != nil {
in, out := &in.Rules, &out.Rules
*out = make([]networkingv1.HTTPIngressPath, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.TLS.DeepCopyInto(&out.TLS)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentIngressSpec.
func (in *HelmComponentIngressSpec) DeepCopy() *HelmComponentIngressSpec {
if in == nil {
return nil
}
out := new(HelmComponentIngressSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentIngressTLSSpec) DeepCopyInto(out *HelmComponentIngressTLSSpec) {
*out = *in
if in.SecretRef != nil {
in, out := &in.SecretRef, &out.SecretRef
*out = new(v1.SecretReference)
**out = **in
}
if in.IssuerRef != nil {
in, out := &in.IssuerRef, &out.IssuerRef
*out = new(metav1.ObjectReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentIngressTLSSpec.
func (in *HelmComponentIngressTLSSpec) DeepCopy() *HelmComponentIngressTLSSpec {
if in == nil {
return nil
}
out := new(HelmComponentIngressTLSSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentProbeConfigSpec) DeepCopyInto(out *HelmComponentProbeConfigSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentProbeConfigSpec.
func (in *HelmComponentProbeConfigSpec) DeepCopy() *HelmComponentProbeConfigSpec {
if in == nil {
return nil
}
out := new(HelmComponentProbeConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentProbeSpec) DeepCopyInto(out *HelmComponentProbeSpec) {
*out = *in
out.Config = in.Config
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentProbeSpec.
func (in *HelmComponentProbeSpec) DeepCopy() *HelmComponentProbeSpec {
if in == nil {
return nil
}
out := new(HelmComponentProbeSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentProbesSpec) DeepCopyInto(out *HelmComponentProbesSpec) {
*out = *in
out.Liveness = in.Liveness
out.Readiness = in.Readiness
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentProbesSpec.
func (in *HelmComponentProbesSpec) DeepCopy() *HelmComponentProbesSpec {
if in == nil {
return nil
}
out := new(HelmComponentProbesSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentResourceRequirementsSpec) DeepCopyInto(out *HelmComponentResourceRequirementsSpec) {
*out = *in
out.Limits = in.Limits
out.Requests = in.Requests
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentResourceRequirementsSpec.
func (in *HelmComponentResourceRequirementsSpec) DeepCopy() *HelmComponentResourceRequirementsSpec {
if in == nil {
return nil
}
out := new(HelmComponentResourceRequirementsSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentResourceSettingSpec) DeepCopyInto(out *HelmComponentResourceSettingSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentResourceSettingSpec.
func (in *HelmComponentResourceSettingSpec) DeepCopy() *HelmComponentResourceSettingSpec {
if in == nil {
return nil
}
out := new(HelmComponentResourceSettingSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentServiceSpec) DeepCopyInto(out *HelmComponentServiceSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentServiceSpec.
func (in *HelmComponentServiceSpec) DeepCopy() *HelmComponentServiceSpec {
if in == nil {
return nil
}
out := new(HelmComponentServiceSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmComponentSpec) DeepCopyInto(out *HelmComponentSpec) {
*out = *in
if in.Ports != nil {
in, out := &in.Ports, &out.Ports
*out = make([]v1.ContainerPort, len(*in))
copy(*out, *in)
}
out.Resources = in.Resources
out.Image = in.Image
out.Probes = in.Probes
if in.Services != nil {
in, out := &in.Services, &out.Services
*out = make([]HelmComponentServiceSpec, len(*in))
copy(*out, *in)
}
if in.Ingresses != nil {
in, out := &in.Ingresses, &out.Ingresses
*out = make([]HelmComponentIngressSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Configs != nil {
in, out := &in.Configs, &out.Configs
*out = make([]HelmComponentConfigSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmComponentSpec.
func (in *HelmComponentSpec) DeepCopy() *HelmComponentSpec {
if in == nil {
return nil
}
out := new(HelmComponentSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmGlobalValuesSpec) DeepCopyInto(out *HelmGlobalValuesSpec) {
*out = *in
if in.NodeSelector != nil {
in, out := &in.NodeSelector, &out.NodeSelector
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmGlobalValuesSpec.
func (in *HelmGlobalValuesSpec) DeepCopy() *HelmGlobalValuesSpec {
if in == nil {
return nil
}
out := new(HelmGlobalValuesSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmMetadataSpec) DeepCopyInto(out *HelmMetadataSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmMetadataSpec.
func (in *HelmMetadataSpec) DeepCopy() *HelmMetadataSpec {
if in == nil {
return nil
}
out := new(HelmMetadataSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HelmSpec) DeepCopyInto(out *HelmSpec) {
*out = *in
out.Metadata = in.Metadata
in.Global.DeepCopyInto(&out.Global)
if in.Components != nil {
in, out := &in.Components, &out.Components
*out = make([]HelmComponentSpec, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmSpec.
func (in *HelmSpec) DeepCopy() *HelmSpec {
if in == nil {
return nil
}
out := new(HelmSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageBuilderSpec) DeepCopyInto(out *ImageBuilderSpec) {
*out = *in
out.Registry = in.Registry
if in.ReleaseArchitectures != nil {
in, out := &in.ReleaseArchitectures, &out.ReleaseArchitectures
*out = make([]string, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageBuilderSpec.
func (in *ImageBuilderSpec) DeepCopy() *ImageBuilderSpec {
if in == nil {
return nil
}
out := new(ImageBuilderSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageRegistryCredentialSpec) DeepCopyInto(out *ImageRegistryCredentialSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageRegistryCredentialSpec.
func (in *ImageRegistryCredentialSpec) DeepCopy() *ImageRegistryCredentialSpec {
if in == nil {
return nil
}
out := new(ImageRegistryCredentialSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImageRegistrySpec) DeepCopyInto(out *ImageRegistrySpec) {
*out = *in
out.Credentials = in.Credentials
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageRegistrySpec.
func (in *ImageRegistrySpec) DeepCopy() *ImageRegistrySpec {
if in == nil {
return nil
}
out := new(ImageRegistrySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProjectInitialize) DeepCopyInto(out *ProjectInitialize) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectInitialize.
func (in *ProjectInitialize) DeepCopy() *ProjectInitialize {
if in == nil {
return nil
}
out := new(ProjectInitialize)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ProjectInitialize) 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 *ProjectInitializeList) DeepCopyInto(out *ProjectInitializeList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]ProjectInitialize, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectInitializeList.
func (in *ProjectInitializeList) DeepCopy() *ProjectInitializeList {
if in == nil {
return nil
}
out := new(ProjectInitializeList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *ProjectInitializeList) 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 *ProjectInitializeSpec) DeepCopyInto(out *ProjectInitializeSpec) {
*out = *in
if in.Argo != nil {
in, out := &in.Argo, &out.Argo
*out = new(ArgoSpec)
**out = **in
}
if in.Repository != nil {
in, out := &in.Repository, &out.Repository
*out = new(RepositorySpec)
(*in).DeepCopyInto(*out)
}
if in.ContinuousIntegration != nil {
in, out := &in.ContinuousIntegration, &out.ContinuousIntegration
*out = new(ContinuousIntegrationSpec)
(*in).DeepCopyInto(*out)
}
if in.Helm != nil {
in, out := &in.Helm, &out.Helm
*out = new(HelmSpec)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectInitializeSpec.
func (in *ProjectInitializeSpec) DeepCopy() *ProjectInitializeSpec {
if in == nil {
return nil
}
out := new(ProjectInitializeSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProjectInitializeStatus) DeepCopyInto(out *ProjectInitializeStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]apismetav1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectInitializeStatus.
func (in *ProjectInitializeStatus) DeepCopy() *ProjectInitializeStatus {
if in == nil {
return nil
}
out := new(ProjectInitializeStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RepositoryHookEventConfigSpec) DeepCopyInto(out *RepositoryHookEventConfigSpec) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryHookEventConfigSpec.
func (in *RepositoryHookEventConfigSpec) DeepCopy() *RepositoryHookEventConfigSpec {
if in == nil {
return nil
}
out := new(RepositoryHookEventConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RepositoryHookEventSpec) DeepCopyInto(out *RepositoryHookEventSpec) {
*out = *in
out.Config = in.Config
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryHookEventSpec.
func (in *RepositoryHookEventSpec) DeepCopy() *RepositoryHookEventSpec {
if in == nil {
return nil
}
out := new(RepositoryHookEventSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RepositoryHookRegisterSpec) DeepCopyInto(out *RepositoryHookRegisterSpec) {
*out = *in
if in.Events != nil {
in, out := &in.Events, &out.Events
*out = make([]RepositoryHookEventSpec, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryHookRegisterSpec.
func (in *RepositoryHookRegisterSpec) DeepCopy() *RepositoryHookRegisterSpec {
if in == nil {
return nil
}
out := new(RepositoryHookRegisterSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RepositorySpec) DeepCopyInto(out *RepositorySpec) {
*out = *in
if in.PluginConfig != nil {
in, out := &in.PluginConfig, &out.PluginConfig
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
in.HookRegister.DeepCopyInto(&out.HookRegister)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositorySpec.
func (in *RepositorySpec) DeepCopy() *RepositorySpec {
if in == nil {
return nil
}
out := new(RepositorySpec)
in.DeepCopyInto(out)
return out
}

View File

@ -1,212 +0,0 @@
/*
Copyright 2025.
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 (
"context"
"crypto/tls"
"flag"
"os"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
"sigs.k8s.io/controller-runtime/pkg/webhook"
gitopsv1alpha1 "freeleaps.com/gitops/initializer/api/v1alpha1"
"freeleaps.com/gitops/initializer/internal/controller"
"freeleaps.com/gitops/initializer/internal/repo"
// +kubebuilder:scaffold:imports
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(gitopsv1alpha1.AddToScheme(scheme))
// +kubebuilder:scaffold:scheme
}
func main() {
var metricsAddr string
var enableLeaderElection bool
var probeAddr string
var secureMetrics bool
var enableHTTP2 bool
var tlsOpts []func(*tls.Config)
flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.BoolVar(&secureMetrics, "metrics-secure", true,
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
flag.BoolVar(&enableHTTP2, "enable-http2", false,
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
opts := zap.Options{
Development: true,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
// if the enable-http2 flag is false (the default), http/2 should be disabled
// due to its vulnerabilities. More specifically, disabling http/2 will
// prevent from being vulnerable to the HTTP/2 Stream Cancellation and
// Rapid Reset CVEs. For more information see:
// - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
// - https://github.com/advisories/GHSA-4374-p667-p6c8
disableHTTP2 := func(c *tls.Config) {
setupLog.Info("disabling http/2")
c.NextProtos = []string{"http/1.1"}
}
if !enableHTTP2 {
tlsOpts = append(tlsOpts, disableHTTP2)
}
webhookServer := webhook.NewServer(webhook.Options{
TLSOpts: tlsOpts,
})
// Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
// More info:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/server
// - https://book.kubebuilder.io/reference/metrics.html
metricsServerOptions := metricsserver.Options{
BindAddress: metricsAddr,
SecureServing: secureMetrics,
// TODO(user): TLSOpts is used to allow configuring the TLS config used for the server. If certificates are
// not provided, self-signed certificates will be generated by default. This option is not recommended for
// production environments as self-signed certificates do not offer the same level of trust and security
// as certificates issued by a trusted Certificate Authority (CA). The primary risk is potentially allowing
// unauthorized access to sensitive metrics data. Consider replacing with CertDir, CertName, and KeyName
// to provide certificates, ensuring the server communicates using trusted and secure certificates.
TLSOpts: tlsOpts,
}
if secureMetrics {
// FilterProvider is used to protect the metrics endpoint with authn/authz.
// These configurations ensure that only authorized users and service accounts
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
// https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/metrics/filters#WithAuthenticationAndAuthorization
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
Metrics: metricsServerOptions,
WebhookServer: webhookServer,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "509da9b1.freeleaps.com",
// 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)
}
// read configurations from the environment
gitopsRepoName := os.Getenv("FREELEAPS_GITOPS_REPO_NAME")
gitopsProjectName := os.Getenv("FREELEAPS_GITOPS_PROJECT_NAME")
gitopsBranchName := os.Getenv("FREELEAPS_GITOPS_BRANCH_NAME")
gitopsRepoPAT := os.Getenv("FREELEAPS_GITOPS_REPO_PAT")
gitopsOrganizationUrl := os.Getenv("FREELEAPS_GITOPS_ORGANIZATION_URL")
if gitopsRepoName == "" || gitopsProjectName == "" || gitopsBranchName == "" || gitopsRepoPAT == "" || gitopsOrganizationUrl == "" {
setupLog.Error(nil, "missing environment variables")
os.Exit(1)
}
// create repo manager
repoMgr, ok := repo.GetPlugin("azure-devops")
if !ok {
setupLog.Error(nil, "repo plugin not found")
os.Exit(1)
}
// create plugin config
pluginConfig := repo.NewPluginConfig()
pluginConfig.Set("pat", gitopsRepoPAT)
pluginConfig.Set("organizationUrl", gitopsOrganizationUrl)
// initialize repo manager
err = repoMgr.Initialize(context.Background(),
repo.WithProject(gitopsProjectName),
repo.WithName(gitopsRepoName),
repo.WithBranch(gitopsBranchName),
repo.WithAuthor("freeleaps-gitops-bot", "gitops@mathmast.com"),
repo.WithPluginConfig(pluginConfig),
)
if err != nil {
setupLog.Error(err, "failed to initialize repo manager")
os.Exit(1)
}
if err = (&controller.ProjectInitializeReconciler{
Log: ctrl.Log.WithName("controllers").WithName("ProjectInitialize"),
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
GitOpsRepoManager: repoMgr,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ProjectInitialize")
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 manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}

View File

@ -1,911 +0,0 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.1
name: projectinitializes.gitops.freeleaps.com
spec:
group: gitops.freeleaps.com
names:
kind: ProjectInitialize
listKind: ProjectInitializeList
plural: projectinitializes
singular: projectinitialize
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: ProjectInitialize is the Schema for the projectinitializes 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: ProjectInitializeSpec defines the desired state of ProjectInitialize
properties:
argo:
description: Argo defines the desired state of Argo Project and Argo
Application
properties:
branch:
description: Branch defines the Git branch of this Argo Application
type: string
name:
description: Name of the Argo Application
type: string
namespace:
description: Namespace of the Argo Application to deploy
type: string
project:
description: Name of the Argo Project
type: string
syncPolicy:
description: SyncPolicy defines the sync policy settings of Argo
Application
properties:
automated:
description: Automated enables the auto sync of Argo Application
type: boolean
prune:
description: Prune enables the auto pruning of Argo Application
type: boolean
selfHeal:
description: SelfHeal enables the auto self healing of Argo
Application
type: boolean
type: object
type: object
ci:
description: ContinuousIntegration defines the desired state of Continuous
Integration (CI)
properties:
commitMessageLintEnabled:
description: CommitMessageLintEnabled defines the existence of
the commit message lint, set to false to skip the commit message
lint.
type: boolean
components:
description: Components defines the CI components
items:
description: CIComponentSpec defines the desired state of CI
component
properties:
buildAgentImage:
description: BuildAgentImage defines the build agent image
of the CI component
type: string
buildArtifacts:
description: BuildArtifacts defines the build artifacts
of the CI component
items:
type: string
type: array
buildCacheEnabled:
description: BuildCacheEnabled defines the existence of
the build cache, set to false to skip the build caching.
type: boolean
buildCommand:
description: BuildCommand defines the build command of the
CI component
type: string
dependenciesManager:
description: DependenciesManager defines the dependencies
manager of the CI component
type: string
imageBuilder:
description: ImageBuilder defines the image builder of the
CI component
properties:
buildContextRoot:
description: BuildContextRoot defines the build context
root of the image builder
type: string
dockerfile:
description: Dockerfile defines the Dockerfile path
of the image builder
type: string
name:
description: Name defines the name of the image builder
type: string
registry:
description: Registry defines the image registry of
the image builder
properties:
credentials:
description: Credentials defines the credentials
of the image registry
properties:
password:
description: Password defines the password of
the image registry credential
type: string
username:
description: Username defines the username of
the image registry credential
type: string
type: object
url:
description: URL defines the URL of the image registry
type: string
type: object
releaseArchitectures:
description: ReleaseArchitectures defines the release
architectures of the image builder
items:
type: string
type: array
repository:
description: Repository defines the repository of the
image builder
type: string
type:
description: Type defines the type of the image builder
type: string
type: object
language:
description: Language defines the language of the CI component
type: string
name:
description: Name defines the name of the CI component
type: string
npmPackageJsonFile:
description: NPMPackageJsonFile defines the path of the
npm package.json file
type: string
root:
description: Root defines the root path of the CI component
type: string
semanticReleaseEnabled:
description: SemanticReleaseEnabled defines the existence
of the semantic release, set to false to skip the semantic
release.
type: boolean
type: object
type: array
executeMode:
description: ExecuteMode defines the CI execute mode
type: string
type: object
helm:
description: Helm defines the desired state of Helm generation
properties:
components:
description: Components defines the Helm components
items:
description: HelmComponentSpec defines the desired state of
Helm component
properties:
configs:
description: Configs defines the configurations of the Helm
component
items:
description: HelmComponentConfigSpec defines the desired
state of Helm component configuration
properties:
data:
description: Data defines the data of the Helm component
configuration
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:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the ConfigMap
or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
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:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
optional:
description: Specify whether the Secret
or its key must be defined
type: boolean
required:
- key
type: object
x-kubernetes-map-type: atomic
type: object
required:
- name
type: object
type: array
name:
description: Name defines the name of the Helm component
configuration
type: string
type:
description: Type defines the type of the Helm component
configuration
type: string
type: object
type: array
image:
description: Image defines the image of the Helm component
properties:
imagePullPolicy:
description: PullPolicy defines the pull policy of the
Helm component image
type: string
name:
description: Name defines the name of the Helm component
image
type: string
registry:
description: Registry defines the image registry of
the Helm component image
type: string
repository:
description: Repository defines the repository of the
Helm component image
type: string
tag:
description: Tag defines the tag of the Helm component
image
type: string
type: object
ingresses:
description: Ingresses defines the ingresses of the Helm
component
items:
description: HelmComponentIngressSpec defines the desired
state of Helm component ingress
properties:
class:
description: Class defines the ingress class of the
Helm component ingress
type: string
host:
description: Host defines the host of the Helm component
ingress
type: string
name:
description: Name defines the name of the Helm component
ingress
type: string
rules:
description: Rules defines the route rules of the
Helm component ingress
items:
description: |-
HTTPIngressPath associates a path with a backend. Incoming urls matching the
path are forwarded to the backend.
properties:
backend:
description: |-
backend defines the referenced service endpoint to which the traffic
will be forwarded to.
properties:
resource:
description: |-
resource is an ObjectRef to another Kubernetes resource in the namespace
of the Ingress object. If resource is specified, a service.Name and
service.Port must not be specified.
This is a mutually exclusive setting with "Service".
properties:
apiGroup:
description: |-
APIGroup is the group for the resource being referenced.
If APIGroup is not specified, the specified Kind must be in the core API group.
For any other third-party types, APIGroup is required.
type: string
kind:
description: Kind is the type of resource
being referenced
type: string
name:
description: Name is the name of resource
being referenced
type: string
required:
- kind
- name
type: object
x-kubernetes-map-type: atomic
service:
description: |-
service references a service as a backend.
This is a mutually exclusive setting with "Resource".
properties:
name:
description: |-
name is the referenced service. The service must exist in
the same namespace as the Ingress object.
type: string
port:
description: |-
port of the referenced service. A port name or port number
is required for a IngressServiceBackend.
properties:
name:
description: |-
name is the name of the port on the Service.
This is a mutually exclusive setting with "Number".
type: string
number:
description: |-
number is the numerical port number (e.g. 80) on the Service.
This is a mutually exclusive setting with "Name".
format: int32
type: integer
type: object
x-kubernetes-map-type: atomic
required:
- name
type: object
type: object
path:
description: |-
path is matched against the path of an incoming request. Currently it can
contain characters disallowed from the conventional "path" part of a URL
as defined by RFC 3986. Paths must begin with a '/' and must be present
when using PathType with value "Exact" or "Prefix".
type: string
pathType:
description: |-
pathType determines the interpretation of the path matching. PathType can
be one of the following values:
* Exact: Matches the URL path exactly.
* Prefix: Matches based on a URL path prefix split by '/'. Matching is
done on a path element by element basis. A path element refers is the
list of labels in the path split by the '/' separator. A request is a
match for path p if every p is an element-wise prefix of p of the
request path. Note that if the last element of the path is a substring
of the last element in request path, it is not a match (e.g. /foo/bar
matches /foo/bar/baz, but does not match /foo/barbaz).
* ImplementationSpecific: Interpretation of the Path matching is up to
the IngressClass. Implementations can treat this as a separate PathType
or treat it identically to Prefix or Exact path types.
Implementations are required to support all path types.
type: string
required:
- backend
- pathType
type: object
type: array
tls:
description: TLS defines the TLS of the Helm component
ingress
properties:
exists:
description: Exists defines the existence of the
Helm component ingress TLS, set to false to
skip the Helm component ingress TLS auto creation.
type: boolean
issuerRef:
description: IssuerRef defines the issuer reference
of the Helm component ingress TLS
properties:
group:
description: Group of the resource being referred
to.
type: string
kind:
description: Kind of the resource being referred
to.
type: string
name:
description: Name of the resource being referred
to.
type: string
required:
- name
type: object
name:
description: Name defines the name of the Helm
component ingress TLS
type: string
secretRef:
description: SecretRef defines the secret reference
of the Helm component ingress TLS
properties:
name:
description: name is unique within a namespace
to reference a secret resource.
type: string
namespace:
description: namespace defines the space within
which the secret name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
type: object
type: object
type: array
name:
description: Name defines the name of the Helm component
type: string
ports:
description: Chart defines the chart of the Helm component
items:
description: ContainerPort represents a network port in
a single container.
properties:
containerPort:
description: |-
Number of port to expose on the pod's IP address.
This must be a valid port number, 0 < x < 65536.
format: int32
type: integer
hostIP:
description: What host IP to bind the external port
to.
type: string
hostPort:
description: |-
Number of port to expose on the host.
If specified, this must be a valid port number, 0 < x < 65536.
If HostNetwork is specified, this must match ContainerPort.
Most containers do not need this.
format: int32
type: integer
name:
description: |-
If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
named port in a pod must have a unique name. Name for the port that can be
referred to by services.
type: string
protocol:
default: TCP
description: |-
Protocol for port. Must be UDP, TCP, or SCTP.
Defaults to "TCP".
type: string
required:
- containerPort
type: object
type: array
probes:
description: Probes defines the probes of the Helm component
properties:
liveness:
description: Liveness defines the liveness probe of
the Helm component
properties:
config:
description: Config defines the configuration of
the Helm component probe
properties:
failureThreshold:
description: FailureThreshold defines the failure
threshold of the Helm component probe
format: int32
type: integer
initialDelaySeconds:
description: InitialDelaySeconds defines the
initial delay seconds of the Helm component
probe
format: int32
type: integer
path:
description: Path defines the path of the Helm
component probe
type: string
periodSeconds:
description: PeriodSeconds defines the period
seconds of the Helm component probe
format: int32
type: integer
port:
description: Port defines the port of the Helm
component probe
format: int32
type: integer
successThreshold:
description: SuccessThreshold defines the success
threshold of the Helm component probe
format: int32
type: integer
terminationGracePeriodSeconds:
description: TerminationGracePeriodSeconds defines
the termination grace period seconds of the
Helm component probe
format: int64
type: integer
timeoutSeconds:
description: TimeoutSeconds defines the timeout
seconds of the Helm component probe
format: int32
type: integer
type: object
type:
description: Type defines the type of the Helm component
probe
type: string
type: object
readiness:
description: Readiness defines the readiness probe of
the Helm component
properties:
config:
description: Config defines the configuration of
the Helm component probe
properties:
failureThreshold:
description: FailureThreshold defines the failure
threshold of the Helm component probe
format: int32
type: integer
initialDelaySeconds:
description: InitialDelaySeconds defines the
initial delay seconds of the Helm component
probe
format: int32
type: integer
path:
description: Path defines the path of the Helm
component probe
type: string
periodSeconds:
description: PeriodSeconds defines the period
seconds of the Helm component probe
format: int32
type: integer
port:
description: Port defines the port of the Helm
component probe
format: int32
type: integer
successThreshold:
description: SuccessThreshold defines the success
threshold of the Helm component probe
format: int32
type: integer
terminationGracePeriodSeconds:
description: TerminationGracePeriodSeconds defines
the termination grace period seconds of the
Helm component probe
format: int64
type: integer
timeoutSeconds:
description: TimeoutSeconds defines the timeout
seconds of the Helm component probe
format: int32
type: integer
type: object
type:
description: Type defines the type of the Helm component
probe
type: string
type: object
type: object
replicas:
description: Replica defines the replica of the Helm component
format: int32
type: integer
resources:
description: Resources defines the resources of the Helm
component
properties:
limits:
description: Limits defines the limits of the Helm component
resource requirements
properties:
cpu:
description: CPU defines the CPU of the Helm component
resource setting
type: string
memory:
description: Memory defines the memory of the Helm
component resource setting
type: string
type: object
requests:
description: Requests defines the requests of the Helm
component resource requirements
properties:
cpu:
description: CPU defines the CPU of the Helm component
resource setting
type: string
memory:
description: Memory defines the memory of the Helm
component resource setting
type: string
type: object
type: object
services:
description: Services defines the services of the Helm component
items:
description: HelmComponentServiceSpec defines the desired
state of Helm component service
properties:
name:
description: Name defines the name of the Helm component
service
type: string
port:
description: Port defines the port of the Helm component
service
format: int32
type: integer
targetPort:
description: TargetPort defines the target port of
the Helm component service
format: int32
type: integer
type:
description: Type defines the type of the Helm component
service
type: string
type: object
type: array
type: object
type: array
generate:
description: Generate defines the existence of the Helm generation,
set to false to skip the Helm generation.
type: boolean
global:
description: GlobalValues defines the Helm global values
properties:
nodeSelector:
additionalProperties:
type: string
description: NodeSelector defines the node selector of the
Helm global values
type: object
registry:
description: Registry defines the image registry of the Helm
global values
type: string
repository:
description: Repository defines the repository of the Helm
global values
type: string
type: object
metadata:
description: Metadata defines the Helm metadata
properties:
description:
description: Description defines the description of the Helm
chart
type: string
name:
description: Name defines the name of the Helm chart
type: string
type: object
type: object
repository:
description: Repository defines the desired state of project's Git
repository
properties:
hookRegister:
description: HookRegister defines the Git repository hook registration
properties:
enabled:
description: Enabled defines the existence of the Git repository
hook registration, set to false to skip the Git repository
hook registration.
type: boolean
events:
description: Events defines the Git repository hook events
items:
description: RepositoryHookEventSpec defines the desired
state of project's Git repository hook event
properties:
config:
description: Config defines the Git repository hook
event configuration
properties:
reviewersIncludesGroups:
description: ReviewersIncludesGroups defines the
groups that includes the reviewers of the Git
repository hook event
type: string
triggerGroups:
description: TriggerGroups defines the groups that
trigger the Git repository hook event
type: string
type: object
event:
type: string
type: object
type: array
type: object
name:
description: Name defines the name of the Git repository
type: string
plugin:
description: Plugin defines the Git repository plugin
type: string
pluginConfig:
additionalProperties:
type: string
description: PluginConfig defines the Git repository plugin configuration
type: object
project:
description: Project defines the project of the Git repository
type: string
registerToArgo:
description: RegisterToArgo defines the existence of the Git repository
registration to Argo, set to false to skip the Git repository
registration to Argo.
type: boolean
type:
description: Type defines the type of the Git repository
type: string
type: object
type: object
status:
description: ProjectInitializeStatus defines the observed state of ProjectInitialize
properties:
conditions:
description: Conditions defines the observed conditions of the ProjectInitialize
items:
description: Condition contains details for one aspect of the current
state of this API Resource.
properties:
lastTransitionTime:
description: |-
lastTransitionTime is the last time the condition transitioned from one status to another.
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
format: date-time
type: string
message:
description: |-
message is a human readable message indicating details about the transition.
This may be an empty string.
maxLength: 32768
type: string
observedGeneration:
description: |-
observedGeneration represents the .metadata.generation that the condition was set based upon.
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
with respect to the current state of the instance.
format: int64
minimum: 0
type: integer
reason:
description: |-
reason contains a programmatic identifier indicating the reason for the condition's last transition.
Producers of specific condition types may define expected values and meanings for this field,
and whether the values are considered a guaranteed API.
The value should be a CamelCase string.
This field may not be empty.
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
type: string
status:
description: status of the condition, one of True, False, Unknown.
enum:
- "True"
- "False"
- Unknown
type: string
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase.
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
type: string
required:
- lastTransitionTime
- message
- reason
- status
- type
type: object
type: array
ready:
description: Ready defines the readiness of the ProjectInitialize
type: boolean
type: object
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -1,22 +0,0 @@
# 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/gitops.freeleaps.com_projectinitializes.yaml
# +kubebuilder:scaffold:crdkustomizeresource
patches:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
# +kubebuilder:scaffold:crdkustomizewebhookpatch
# [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_projectinitializes.yaml
# +kubebuilder:scaffold:crdkustomizecainjectionpatch
# [WEBHOOK] To enable webhook, uncomment the following section
# the following config is for teaching kustomize how to do kustomization for CRDs.
#configurations:
#- kustomizeconfig.yaml

View File

@ -1,19 +0,0 @@
# 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

@ -1,151 +0,0 @@
# Adds namespace to all resources.
namespace: freeleaps-gitops-initializer-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: freeleaps-gitops-initializer-
# Labels to add to all resources and selectors.
#labels:
#- includeSelectors: true
# pairs:
# someName: someValue
resources:
- ../crd
- ../rbac
- ../manager
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
#- ../certmanager
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
#- ../prometheus
# [METRICS] Expose the controller manager metrics service.
- metrics_service.yaml
# [NETWORK POLICY] Protect the /metrics endpoint and Webhook Server with NetworkPolicy.
# Only Pod(s) running a namespace labeled with 'metrics: enabled' will be able to gather the metrics.
# Only CR(s) which requires webhooks and are applied on namespaces labeled with 'webhooks: enabled' will
# be able to communicate with the Webhook Server.
#- ../network-policy
# Uncomment the patches line if you enable Metrics, and/or are using webhooks and cert-manager
patches:
# [METRICS] The following patch will enable the metrics endpoint using HTTPS and the port :8443.
# More info: https://book.kubebuilder.io/reference/metrics
- path: manager_metrics_patch.yaml
target:
kind: Deployment
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- path: 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
#- path: 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

@ -1,4 +0,0 @@
# This patch adds the args to allow exposing the metrics endpoint using HTTPS
- op: add
path: /spec/template/spec/containers/0/args/0
value: --metrics-bind-address=:8443

View File

@ -1,17 +0,0 @@
apiVersion: v1
kind: Service
metadata:
labels:
control-plane: controller-manager
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: controller-manager-metrics-service
namespace: system
spec:
ports:
- name: https
port: 8443
protocol: TCP
targetPort: 8443
selector:
control-plane: controller-manager

View File

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

View File

@ -1,95 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
labels:
control-plane: controller-manager
app.kubernetes.io/name: freeleaps-gitops-initializer
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: freeleaps-gitops-initializer
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
- --health-probe-bind-address=:8081
image: controller:latest
name: manager
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

View File

@ -1,28 +0,0 @@
# These resources constitute the fully configured set of manifests
# used to generate the 'manifests/' directory in a bundle.
resources:
- bases/freeleaps-gitops-initializer.clusterserviceversion.yaml
- ../default
- ../samples
- ../scorecard
# [WEBHOOK] To enable webhooks, uncomment all the sections with [WEBHOOK] prefix.
# Do NOT uncomment sections with prefix [CERTMANAGER], as OLM does not support cert-manager.
# These patches remove the unnecessary "cert" volume and its manager container volumeMount.
#patches:
#- target:
# group: apps
# version: v1
# kind: Deployment
# name: controller-manager
# namespace: system
# patch: |-
# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs.
# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment.
# - op: remove
# path: /spec/template/spec/containers/0/volumeMounts/0
# # Remove the "cert" volume, since OLM will create and mount a set of certs.
# # Update the indices in this path if adding or removing volumes in the manager's Deployment.
# - op: remove
# path: /spec/template/spec/volumes/0

View File

@ -1,26 +0,0 @@
# This NetworkPolicy allows ingress traffic
# with Pods running on namespaces labeled with 'metrics: enabled'. Only Pods on those
# namespaces are able to gathering data from the metrics endpoint.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: allow-metrics-traffic
namespace: system
spec:
podSelector:
matchLabels:
control-plane: controller-manager
policyTypes:
- Ingress
ingress:
# This allows ingress traffic from any namespace with the label metrics: enabled
- from:
- namespaceSelector:
matchLabels:
metrics: enabled # Only from namespaces with this label
ports:
- port: 8443
protocol: TCP

View File

@ -1,2 +0,0 @@
resources:
- allow-metrics-traffic.yaml

View File

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

View File

@ -1,30 +0,0 @@
# Prometheus Monitor Service (Metrics)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
control-plane: controller-manager
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: controller-manager-metrics-monitor
namespace: system
spec:
endpoints:
- path: /metrics
port: https # Ensure this is the name of the port that exposes HTTPS metrics
scheme: https
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
tlsConfig:
# TODO(user): The option insecureSkipVerify: true is not recommended for production since it disables
# certificate verification. This poses a significant security risk by making the system vulnerable to
# man-in-the-middle attacks, where an attacker could intercept and manipulate the communication between
# Prometheus and the monitored services. This could lead to unauthorized access to sensitive metrics data,
# compromising the integrity and confidentiality of the information.
# Please use the following options for secure configurations:
# caFile: /etc/metrics-certs/ca.crt
# certFile: /etc/metrics-certs/tls.crt
# keyFile: /etc/metrics-certs/tls.key
insecureSkipVerify: true
selector:
matchLabels:
control-plane: controller-manager

View File

@ -1,27 +0,0 @@
resources:
# All RBAC will be applied under this service account in
# the deployment namespace. You may comment out this resource
# if your manager will use a service account that exists at
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
# subjects if changing service account names.
- service_account.yaml
- role.yaml
- role_binding.yaml
- leader_election_role.yaml
- leader_election_role_binding.yaml
# The following RBAC configurations are used to protect
# the metrics endpoint with authn/authz. These configurations
# ensure that only authorized users and service accounts
# can access the metrics endpoint. Comment the following
# permissions if you want to disable this protection.
# More info: https://book.kubebuilder.io/reference/metrics.html
- metrics_auth_role.yaml
- metrics_auth_role_binding.yaml
- metrics_reader_role.yaml
# For each CRD, "Editor" and "Viewer" roles are scaffolded by
# default, aiding admins in cluster management. Those roles are
# not used by the Project itself. You can comment the following lines
# if you do not want those helpers be installed with your Project.
- projectinitialize_editor_role.yaml
- projectinitialize_viewer_role.yaml

View File

@ -1,40 +0,0 @@
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
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

@ -1,15 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
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

@ -1,17 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metrics-auth-role
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create

View File

@ -1,12 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metrics-auth-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metrics-auth-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system

View File

@ -1,9 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metrics-reader
rules:
- nonResourceURLs:
- "/metrics"
verbs:
- get

View File

@ -1,27 +0,0 @@
# permissions for end users to edit projectinitializes.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: projectinitialize-editor-role
rules:
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes/status
verbs:
- get

View File

@ -1,23 +0,0 @@
# permissions for end users to view projectinitializes.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: projectinitialize-viewer-role
rules:
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes
verbs:
- get
- list
- watch
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes/status
verbs:
- get

View File

@ -1,59 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: manager-role
rules:
- apiGroups:
- apps
resources:
- deployments
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes/finalizers
verbs:
- update
- apiGroups:
- gitops.freeleaps.com
resources:
- projectinitializes/status
verbs:
- get
- patch
- update

View File

@ -1,15 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
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

@ -1,8 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: controller-manager
namespace: system

View File

@ -1,222 +0,0 @@
apiVersion: gitops.freeleaps.com/v1alpha1
kind: ProjectInitialize
metadata:
labels:
app.kubernetes.io/name: freeleaps-gitops-initializer
app.kubernetes.io/managed-by: kustomize
name: magicleaps-alpha
annotations:
gitops.freeleaps.com/environment: alpha
spec:
argo:
name: magicleaps-alpha
project: magicleaps
namespace: magicleaps-alpha
syncPolicy:
automated: true
prune: true
selfHeal: true
repo:
plugins: azure-devops
project: magicleaps
name: magicleaps
branch: develop
pluginConfig:
organizationUrl: https://dev.azure.com/freeleaps
pat: 3E9J1v0si6HRvyc1RSRgT791W9ZvMi4kBmrznfcIXB8mq6Trj9VkJQQJ99BBACAAAAArj0WRAAASAZDO32n4
registerToArgo: true
type: monorepo
hookRegister:
enabled: true
events:
- event: code-pushed
config:
triggerGroups: any
- event: pr-attempted
config:
triggerGroups: any
reviewersIncludesGroup: any
ci:
executeMode: on-demand
commitMessageLintEnabled: true
components:
- name: frontend
root: frontend
language: javascript
semanticReleaseEnabled: true
dependenciesManager: npm
npmPackageJsonFile: package.json
buildCacheEnabled: true
buildCommand: npm run build
buildAgentImage: "node:lts"
buildArtifacts:
- dist
lintEnabled: false
imageBuilder:
type: dind
registry:
url: docker.io
credentials:
username: sunzhenyucn
password: "]wRJ**YEZp8nFq=E8WowMADf"
repository: sunzhenyucn
name: magicleaps-frontend
dockerfile: Dockerfile
buildContextRoot: "."
releaseArchitectures:
- linux/amd64
- linux/arm64
- name: backend
root: backend
language: python
semanticReleaseEnabled: true
dependenciesManager: pip
buildCacheEnabled: true
buildAgentImage: "python:3.8-slim-buster"
lintEnabled: false
imageBuilder:
type: dint
registry:
url: docker.io
credentials:
username: sunzhenyucn
password: "]wRJ**YEZp8nFq=E8WowMADf"
repository: sunzhenyucn
name: magicleaps-backend
dockerfile: Dockerfile
buildContextRoot: "."
releaseArchitectures:
- linux/amd64
- linux/arm64
helm:
generate: true
metadata:
name: magicleaps
description: A Helm chart for Magic Leaps application.
global:
registry: docker.io
repository: magicleaps
nodeSelector:
beta.kubernetes.io/os: linux
components:
- name: frontend
replica: 1
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
image:
registry: docker.io
repository: magicleaps-frontend
tag: "1.0.0"
imagePullPolicy: IfNotPresent
probes:
liveness:
type: httpGet
config:
path: /
port: 80
readiness:
type: httpGet
config:
path: /
port: 80
services:
- name: frontend
type: ClusterIP
port: 80
targetPort: 80
ingresses:
- name: frontend
class: nginx
host: alpha.magicleaps.mathmast.com
rules:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
tls:
exists: false
secretRef:
name: alpha.magicleaps.mathmast.com-cert
issuerRef:
name: mathmast-dot-com
kind: ClusterIssuer
name: alpha.magicleaps.mathmast.com-cert
configs:
- name: frontend-env
type: environment-secret
data:
- key: TZ
value: America/Los_Angeles
- name: backend
replica: 1
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 200m
memory: 512Mi
image:
registry: docker.io
repository: magicleaps-backend
tag: "1.0.0"
imagePullPolicy: IfNotPresent
probes:
liveness:
type: httpGet
config:
path: /api/_/probe/liveness
port: 8081
readiness:
type: httpGet
config:
path: /api/_/probe/readiness
port: 8081
services:
- name: backend
type: ClusterIP
port: 8081
targetPort: 8081
ingresses:
- name: backend
class: nginx
host: alpha.api.magicleaps.com
tls:
exists: false
secretRef:
name: alpha.api.magicleaps.mathmast.com-cert
key: tls.crt
issuerRef:
name: mathmast-dot-com
kind: ClusterIssuer
name: alpha.api.magicleaps.mathmast.com-cert
configs:
- name: backend-env
type: environment-secret
data:
- key: TZ
value: America/Los_Angeles
- key: MONGO_HOST
value: mongo-mongodb.magicleaps-alpha.svc.cluster.local
- key: MONGO_PORT
value: "27017"
- key: EMAIL_USER
value: your@freeleaps.com
- key: EMAIL_PASSWORD
value: your-password
- key: SUPER_ADMIN
value: your@freeleaps.com
- key: TWILIO_ACCOUNT_SID
value: ""
- key: TWILIO_AUTH_TOKEN
value: ""
- key: LOG_LEVEL
value: INFO

View File

@ -1,4 +0,0 @@
## Append samples of your project ##
resources:
- gitops_v1alpha1_projectinitialize.yaml
# +kubebuilder:scaffold:manifestskustomizesamples

View File

@ -1,7 +0,0 @@
apiVersion: scorecard.operatorframework.io/v1alpha3
kind: Configuration
metadata:
name: config
stages:
- parallel: true
tests: []

View File

@ -1,18 +0,0 @@
resources:
- bases/config.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
patches:
- path: patches/basic.config.yaml
target:
group: scorecard.operatorframework.io
kind: Configuration
name: config
version: v1alpha3
- path: patches/olm.config.yaml
target:
group: scorecard.operatorframework.io
kind: Configuration
name: config
version: v1alpha3
# +kubebuilder:scaffold:patches

View File

@ -1,10 +0,0 @@
- op: add
path: /stages/0/tests/-
value:
entrypoint:
- scorecard-test
- basic-check-spec
image: quay.io/operator-framework/scorecard-test:v1.39.1
labels:
suite: basic
test: basic-check-spec-test

View File

@ -1,50 +0,0 @@
- op: add
path: /stages/0/tests/-
value:
entrypoint:
- scorecard-test
- olm-bundle-validation
image: quay.io/operator-framework/scorecard-test:v1.39.1
labels:
suite: olm
test: olm-bundle-validation-test
- op: add
path: /stages/0/tests/-
value:
entrypoint:
- scorecard-test
- olm-crds-have-validation
image: quay.io/operator-framework/scorecard-test:v1.39.1
labels:
suite: olm
test: olm-crds-have-validation-test
- op: add
path: /stages/0/tests/-
value:
entrypoint:
- scorecard-test
- olm-crds-have-resources
image: quay.io/operator-framework/scorecard-test:v1.39.1
labels:
suite: olm
test: olm-crds-have-resources-test
- op: add
path: /stages/0/tests/-
value:
entrypoint:
- scorecard-test
- olm-spec-descriptors
image: quay.io/operator-framework/scorecard-test:v1.39.1
labels:
suite: olm
test: olm-spec-descriptors-test
- op: add
path: /stages/0/tests/-
value:
entrypoint:
- scorecard-test
- olm-status-descriptors
image: quay.io/operator-framework/scorecard-test:v1.39.1
labels:
suite: olm
test: olm-status-descriptors-test

View File

@ -1,103 +0,0 @@
module freeleaps.com/gitops/initializer
go 1.23.0
toolchain go1.24.0
require (
github.com/cert-manager/cert-manager v1.17.1
github.com/go-logr/logr v1.4.2
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
github.com/onsi/ginkgo/v2 v2.22.2
github.com/onsi/gomega v1.36.2
github.com/prometheus/client_golang v1.20.5
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.32.1
k8s.io/apimachinery v0.32.1
k8s.io/client-go v0.32.1
sigs.k8s.io/controller-runtime v0.19.4
)
require (
cel.dev/expr v0.19.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/cel-go v0.22.1 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.61.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel v1.33.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.8.0 // indirect
golang.org/x/tools v0.29.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/apiextensions-apiserver v0.32.1 // indirect
k8s.io/apiserver v0.32.1 // indirect
k8s.io/component-base v0.32.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.1 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

View File

@ -1,252 +0,0 @@
cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4=
cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cert-manager/cert-manager v1.17.1 h1:Aig+lWMoLsmpGd9TOlTvO4t0Ah3D+/vGB37x/f+ZKt0=
github.com/cert-manager/cert-manager v1.17.1/go.mod h1:zeG4D+AdzqA7hFMNpYCJgcQ2VOfFNBa+Jzm3kAwiDU4=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls=
github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 h1:YH424zrwLTlyHSH/GzLMJeu5zhYVZSx5RQxGKm1h96s=
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw=
go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA=
go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ=
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM=
go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb h1:B7GIB7sr443wZ/EAEl7VZjmh1V6qzkt5V+RYcUYtS1U=
google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb h1:3oy2tynMOP1QbTC0MsNNAV+Se8M2Bd0A5+x1QHyw+pI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.32.1 h1:f562zw9cy+GvXzXf0CKlVQ7yHJVYzLfL6JAS4kOAaOc=
k8s.io/api v0.32.1/go.mod h1:/Yi/BqkuueW1BgpoePYBRdDYfjPF5sgTr5+YqDZra5k=
k8s.io/apiextensions-apiserver v0.32.1 h1:hjkALhRUeCariC8DiVmb5jj0VjIc1N0DREP32+6UXZw=
k8s.io/apiextensions-apiserver v0.32.1/go.mod h1:sxWIGuGiYov7Io1fAS2X06NjMIk5CbRHc2StSmbaQto=
k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs=
k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/apiserver v0.32.1 h1:oo0OozRos66WFq87Zc5tclUX2r0mymoVHRq8JmR7Aak=
k8s.io/apiserver v0.32.1/go.mod h1:UcB9tWjBY7aryeI5zAgzVJB/6k7E97bkr1RgqDz0jPw=
k8s.io/client-go v0.32.1 h1:otM0AxdhdBIaQh7l1Q0jQpmo7WOFIk5FFa4bg6YMdUU=
k8s.io/client-go v0.32.1/go.mod h1:aTTKZY7MdxUaJ/KiUs8D+GssR9zJZi77ZqtzcGXIiDg=
k8s.io/component-base v0.32.1 h1:/5IfJ0dHIKBWysGV0yKTFfacZ5yNV1sulPh3ilJjRZk=
k8s.io/component-base v0.32.1/go.mod h1:j1iMMHi/sqAHeG5z+O9BFNCF698a1u0186zkjMZQ28w=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg=
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.1 h1:uOuSLOMBWkJH0TWa9X6l+mj5nZdm6Ay6Bli8HL8rNfk=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.1/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/controller-runtime v0.19.4 h1:SUmheabttt0nx8uJtoII4oIP27BVVvAKFvdvGFwV/Qo=
sigs.k8s.io/controller-runtime v0.19.4/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk=
sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -1,15 +0,0 @@
/*
Copyright 2025.
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

@ -1,179 +0,0 @@
/*
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"fmt"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
gitopsv1alpha1 "freeleaps.com/gitops/initializer/api/v1alpha1"
"freeleaps.com/gitops/initializer/internal/helm"
"freeleaps.com/gitops/initializer/internal/metrics"
"freeleaps.com/gitops/initializer/internal/repo"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
)
// ProjectInitializeReconciler reconciles a ProjectInitialize object
type ProjectInitializeReconciler struct {
client.Client
Scheme *runtime.Scheme
Log logr.Logger
GitOpsRepoManager repo.RepoManager
}
// +kubebuilder:rbac:groups=gitops.freeleaps.com,resources=projectinitializes,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=gitops.freeleaps.com,resources=projectinitializes/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=gitops.freeleaps.com,resources=projectinitializes/finalizers,verbs=update
// +kubebuilder:rbac:groups=core,resources=events,verbs=create;patch
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the ProjectInitialize object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile
func (r *ProjectInitializeReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
metrics.ReconcilesTotal.Inc()
log := r.Log.WithValues("projectinitialize", req.NamespacedName)
// fetch the ProjectInitialize instance
cr := &gitopsv1alpha1.ProjectInitialize{}
err := r.Get(ctx, req.NamespacedName, cr)
if err != nil {
if errors.IsNotFound(err) {
log.Info("ProjectInitialize resource not found. Ignoring since object must be deleted")
return ctrl.Result{}, nil
} else {
meta.SetStatusCondition(&cr.Status.Conditions, metav1.Condition{
Type: gitopsv1alpha1.ConditionOperatorDegraded,
Status: metav1.ConditionTrue,
Reason: gitopsv1alpha1.ReasonCustomResourceNotAvailable,
LastTransitionTime: metav1.Now(),
Message: fmt.Sprintf("Unable to get ProjectInitialize instance: %s", err.Error()),
})
log.Error(err, "Failed to get ProjectInitialize")
return ctrl.Result{}, utilerrors.NewAggregate([]error{err, r.Status().Update(ctx, cr)})
}
}
// reconcile helm package for the ProjectInitialize instance
if err := r.reconcileHelmPackage(logr.NewContext(ctx, log), cr); err != nil {
meta.SetStatusCondition(&cr.Status.Conditions, metav1.Condition{
Type: gitopsv1alpha1.ConditionOperatorDegraded,
Status: metav1.ConditionTrue,
Reason: gitopsv1alpha1.ReasonHelmPackageGenerateFailed,
LastTransitionTime: metav1.Now(),
Message: fmt.Sprintf("Failed to reconcile Helm package: %s", err.Error()),
})
log.Error(err, "Failed to reconcile Helm package")
return ctrl.Result{}, utilerrors.NewAggregate([]error{err, r.Status().Update(ctx, cr)})
} else {
meta.SetStatusCondition(&cr.Status.Conditions, metav1.Condition{
Type: gitopsv1alpha1.ConditionHelmPackageGenerated,
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: gitopsv1alpha1.ReasonHelmPackageGenerated,
Message: "The Helm package successful generated",
})
if err := r.Status().Update(ctx, cr); err != nil {
log.Error(err, "Failed to update ProjectInitialize status")
return ctrl.Result{}, err
}
}
// reconcile Jenkinsfile for the ProjectInitialize instance
return ctrl.Result{}, nil
}
func (r *ProjectInitializeReconciler) reconcileHelmPackage(ctx context.Context, cr *gitopsv1alpha1.ProjectInitialize) error {
// retrieve logger
log, err := logr.FromContext(ctx)
if err != nil {
return err
}
// check if already generated
generated := meta.IsStatusConditionPresentAndEqual(cr.Status.Conditions, gitopsv1alpha1.ConditionHelmPackageGenerated, metav1.ConditionTrue)
if generated {
log.Info("Helm package already generated, skip reconcile for Helm package")
return nil
}
if cr.Spec.Helm == nil {
return fmt.Errorf("helm spec is missing")
}
// create helm package generator
generator := helm.HelmGenerator{
Instance: cr,
}
defer generator.Close()
// generate helm package files into local tmp dir
if err := generator.Generate(); err != nil {
return err
}
requests := make([]repo.ChangeRequest, 0)
// commit generated files to gitops repo
err = generator.Walk(func(f *helm.HelmGeneratedFile) error {
if blob, err := f.ReadAll(); err != nil {
return err
} else {
req := repo.ChangeRequest{
Path: fmt.Sprintf("%s/helm-pkg/%s", cr.ObjectMeta.GetName(), f.QualifiedPath),
Content: blob,
Operation: repo.OpCreate,
}
requests = append(requests, req)
}
return nil
})
if err != nil {
return err
}
// apply changes to gitops repo
if err := r.GitOpsRepoManager.ApplyChanges(ctx, requests, "chore(freeleaps-gitios-initializer): commit generated helm package"); err != nil {
return err
}
return nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *ProjectInitializeReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&gitopsv1alpha1.ProjectInitialize{}).
Complete(r)
}

View File

@ -1,84 +0,0 @@
/*
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gitopsv1alpha1 "freeleaps.com/gitops/initializer/api/v1alpha1"
)
var _ = Describe("ProjectInitialize Controller", func() {
Context("When reconciling a resource", func() {
const resourceName = "test-resource"
ctx := context.Background()
typeNamespacedName := types.NamespacedName{
Name: resourceName,
Namespace: "default", // TODO(user):Modify as needed
}
projectinitialize := &gitopsv1alpha1.ProjectInitialize{}
BeforeEach(func() {
By("creating the custom resource for the Kind ProjectInitialize")
err := k8sClient.Get(ctx, typeNamespacedName, projectinitialize)
if err != nil && errors.IsNotFound(err) {
resource := &gitopsv1alpha1.ProjectInitialize{
ObjectMeta: metav1.ObjectMeta{
Name: resourceName,
Namespace: "default",
},
// TODO(user): Specify other spec details if needed.
}
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
}
})
AfterEach(func() {
// TODO(user): Cleanup logic after each test, like removing the resource instance.
resource := &gitopsv1alpha1.ProjectInitialize{}
err := k8sClient.Get(ctx, typeNamespacedName, resource)
Expect(err).NotTo(HaveOccurred())
By("Cleanup the specific resource instance ProjectInitialize")
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
})
It("should successfully reconcile the resource", func() {
By("Reconciling the created resource")
controllerReconciler := &ProjectInitializeReconciler{
Client: k8sClient,
Scheme: k8sClient.Scheme(),
}
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: typeNamespacedName,
})
Expect(err).NotTo(HaveOccurred())
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
// Example: If you expect a certain status condition after reconciliation, verify it here.
})
})
})

View File

@ -1,96 +0,0 @@
/*
Copyright 2025.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"context"
"fmt"
"path/filepath"
"runtime"
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
gitopsv1alpha1 "freeleaps.com/gitops/initializer/api/v1alpha1"
// +kubebuilder:scaffold:imports
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
var ctx context.Context
var cancel context.CancelFunc
func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
ctx, cancel = context.WithCancel(context.TODO())
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
// The BinaryAssetsDirectory is only required if you want to run the tests directly
// without call the makefile target test. If not informed it will look for the
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
// Note that you must have the required binaries setup under the bin directory to perform
// the tests directly. When we run make test it will be setup and used automatically.
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
}
var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
err = gitopsv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
// +kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
})
var _ = AfterSuite(func() {
By("tearing down the test environment")
cancel()
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})

View File

@ -1,67 +0,0 @@
package helm
import (
"bytes"
"encoding/base64"
"strings"
"text/template"
"gopkg.in/yaml.v3"
)
var funcMap template.FuncMap
func init() {
funcMap = template.FuncMap{
"camelCase": camelCase,
"toYaml": toYaml,
"nindent": nindent,
"title": strings.Title,
"lower": strings.ToLower,
"join": strings.Join,
"split": split,
"quote": quote,
"b64enc": b64enc,
}
funcMap["include"] = include
}
func b64enc(s string) string {
return base64.StdEncoding.EncodeToString([]byte(s))
}
func quote(s string) string {
return `"` + s + `"`
}
func include(name string, data interface{}) (string, error) {
buf := &bytes.Buffer{}
err := template.Must(template.New("").Funcs(funcMap).Parse("{{define \"tmp\"}}{{template \""+name+"\" .}}{{end}}")).
ExecuteTemplate(buf, "tmp", data)
return buf.String(), err
}
func camelCase(s string) string {
parts := strings.Split(s, "_")
for i := 1; i < len(parts); i++ {
parts[i] = strings.Title(strings.ToLower(parts[i]))
}
return strings.ToLower(parts[0]) + strings.Join(parts[1:], "")
}
func toYaml(v interface{}) string {
marshaled, err := yaml.Marshal(v)
if err != nil {
panic(err)
}
return string(marshaled)
}
func nindent(n int, s string) string {
prefix := strings.Repeat(" ", n)
return prefix + strings.ReplaceAll(s, "\n", "\n"+prefix)
}
func split(sep, s string) []string {
return strings.Split(s, sep)
}

View File

@ -1,245 +0,0 @@
package helm
import (
"embed"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"text/template"
"freeleaps.com/gitops/initializer/api/v1alpha1"
)
//go:embed templates/*
var embeddedTemplates embed.FS
type HelmGenerator struct {
io.Closer
Instance *v1alpha1.ProjectInitialize
workingDir string
generated bool
}
const leftDelim = "[["
const rightDelim = "]]"
func (hg *HelmGenerator) prepareWorkingDir() error {
path, err := os.MkdirTemp("", fmt.Sprintf("helm-gen-%s-*", hg.Instance.Name))
if err != nil {
return fmt.Errorf("failed to create helm generator temp dir: %w", err)
}
hg.workingDir = path
return nil
}
func (hg *HelmGenerator) readTemplate(name string) (*template.Template, error) {
tpl := template.New(name)
templateBytes, err := embeddedTemplates.ReadFile(name)
if err != nil {
return nil, fmt.Errorf("failed to read template %s: %w", name, err)
}
tpl, err = tpl.
Delims(leftDelim, rightDelim).
Funcs(funcMap).
Parse(string(templateBytes))
if err != nil {
return nil, fmt.Errorf("failed to parse template %s: %w", name, err)
}
return tpl, nil
}
func (hg *HelmGenerator) createMetaFiles() error {
// create Chart.yaml
tpl, err := hg.readTemplate("templates/metadata/Chart.yaml.tpl")
if err != nil {
return err
}
chartYamlFd, err := os.Create(hg.workingDir + "/Chart.yaml")
if err != nil {
return fmt.Errorf("failed to create Chart.yaml file: %w", err)
}
defer chartYamlFd.Close()
if err := tpl.Execute(chartYamlFd, hg.Instance.Spec.Helm); err != nil {
return fmt.Errorf("failed to rendering Chart.yaml with template: %w", err)
}
// create values.yaml
tpl, err = hg.readTemplate("templates/metadata/values.yaml.tpl")
if err != nil {
return err
}
valuesYamlFd, err := os.Create(hg.workingDir + "/values.yaml")
if err != nil {
return fmt.Errorf("failed to create values.yaml file: %w", err)
}
defer valuesYamlFd.Close()
if err := tpl.Execute(valuesYamlFd, hg.Instance.Spec.Helm); err != nil {
return fmt.Errorf("failed to rendering values.yaml with template: %w", err)
}
return nil
}
func (hg *HelmGenerator) createComponentManifests(component v1alpha1.HelmComponentSpec) error {
workRoot := hg.workingDir + "/templates/" + component.Name
if err := os.MkdirAll(workRoot, 0755); err != nil {
return fmt.Errorf("failed to create component directory: %w", err)
}
// create deployment.yaml
tpl, err := hg.readTemplate("templates/deployment/deployment.yaml.tpl")
if err != nil {
return err
}
deploymentYamlFd, err := os.Create(workRoot + "/deployment.yaml")
if err != nil {
return fmt.Errorf("failed to create deployment.yaml file: %w", err)
}
defer deploymentYamlFd.Close()
if err := tpl.Execute(deploymentYamlFd, component); err != nil {
return fmt.Errorf("failed to rendering deployment.yaml with template: %w", err)
}
// create service.yaml if there has services
if len(component.Services) > 0 {
tpl, err = hg.readTemplate("templates/service/service.yaml.tpl")
if err != nil {
return err
}
serviceYamlFd, err := os.Create(workRoot + "/service.yaml")
if err != nil {
return fmt.Errorf("failed to create service.yaml file: %w", err)
}
defer serviceYamlFd.Close()
if err := tpl.Execute(serviceYamlFd, component); err != nil {
return fmt.Errorf("failed to rendering service.yaml with template: %w", err)
}
}
// create ingress.yaml if there has ingress
if len(component.Ingresses) > 0 {
tpl, err = hg.readTemplate("templates/ingress/ingress.yaml.tpl")
if err != nil {
return err
}
ingressYamlFd, err := os.Create(workRoot + "/ingress.yaml")
if err != nil {
return fmt.Errorf("failed to create ingress.yaml file: %w", err)
}
defer ingressYamlFd.Close()
if err := tpl.Execute(ingressYamlFd, component); err != nil {
return fmt.Errorf("failed to rendering ingress.yaml with template: %w", err)
}
}
// create secret.yaml if there has configs
if len(component.Configs) > 0 {
for _, config := range component.Configs {
tpl, err = hg.readTemplate("templates/secret/secret.yaml.tpl")
if err != nil {
return err
}
secretYamlFd, err := os.Create(workRoot + "/" + config.Name + ".yaml")
if err != nil {
return fmt.Errorf("failed to create secret.yaml file: %w", err)
}
defer secretYamlFd.Close()
if err := tpl.Execute(secretYamlFd, struct {
ComponentName string
Config v1alpha1.HelmComponentConfigSpec
}{
ComponentName: component.Name,
Config: config,
}); err != nil {
return fmt.Errorf("failed to rendering secret.yaml with template: %w", err)
}
}
}
// create certificate if ingress need to sign with tls
if len(component.Ingresses) > 0 {
needSign := false
for _, ingress := range component.Ingresses {
if !ingress.TLS.Exists {
needSign = true
break
}
}
if needSign {
tpl, err = hg.readTemplate("templates/certificate/certificate.yaml.tpl")
if err != nil {
return err
}
certificateYamlFd, err := os.Create(workRoot + "/certificate.yaml")
if err != nil {
return fmt.Errorf("failed to create certificate.yaml file: %w", err)
}
defer certificateYamlFd.Close()
if err := tpl.Execute(certificateYamlFd, component); err != nil {
return fmt.Errorf("failed to rendering certificate.yaml with template: %w", err)
}
}
}
return nil
}
func (hg *HelmGenerator) Generate() error {
if hg.Instance == nil {
return errors.New("instance is nil")
}
// create temp working dir
if err := hg.prepareWorkingDir(); err != nil {
return err
}
// create meta files (Chart.yaml, values.yaml, .helmignore)
if err := hg.createMetaFiles(); err != nil {
return err
}
// create manifests for each component
for _, componentSpec := range hg.Instance.Spec.Helm.Components {
if err := hg.createComponentManifests(componentSpec); err != nil {
return err
}
}
hg.generated = true
return nil
}
type HelmGeneratedFile struct {
QualifiedPath string
}
func (hgf *HelmGeneratedFile) ReadAll() ([]byte, error) {
return os.ReadFile(hgf.QualifiedPath)
}
type HelmGeneratedFileCallback func(f *HelmGeneratedFile) error
func (hg *HelmGenerator) Walk(cb HelmGeneratedFileCallback) error {
if !hg.generated {
return errors.New("helm package not generated")
}
return filepath.Walk(hg.workingDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
return cb(&HelmGeneratedFile{QualifiedPath: path})
}
return nil
})
}
func (hg *HelmGenerator) Close() error {
if hg.workingDir != "" {
return os.RemoveAll(hg.workingDir)
}
return nil
}

View File

@ -1,261 +0,0 @@
package helm
import (
"testing"
"freeleaps.com/gitops/initializer/api/v1alpha1"
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var pathType = networkingv1.PathTypeImplementationSpecific
var testCase = v1alpha1.ProjectInitialize{
ObjectMeta: metav1.ObjectMeta{
Name: "magicleaps-alpha",
},
Spec: v1alpha1.ProjectInitializeSpec{
Repository: &v1alpha1.RepositorySpec{
Plugin: "azure-devops",
PluginConfig: map[string]string{
"pat": "3E9J1v0si6HRvyc1RSRgT791W9ZvMi4kBmrznfcIXB8mq6Trj9VkJQQJ99BBACAAAAArj0WRAAASAZDO32n4",
"organizationUrl": "https://dev.azure.com/freeleaps",
},
RegisterToArgo: true,
Project: "magicleaps",
Name: "magicleaps",
Type: v1alpha1.Monorepo,
Branch: "develop",
},
Helm: &v1alpha1.HelmSpec{
Generate: true,
Metadata: v1alpha1.HelmMetadataSpec{
Name: "magicleaps",
Description: "A Helm Chart of magicleaps, powered by Freeleaps.",
},
Global: v1alpha1.HelmGlobalValuesSpec{
Registry: "docker.io",
Repository: "sunzhenyucn",
},
Components: []v1alpha1.HelmComponentSpec{
{
Name: "frontend",
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 8080,
Protocol: corev1.ProtocolTCP,
},
},
Replicas: 1,
Resources: v1alpha1.HelmComponentResourceRequirementsSpec{
Limits: v1alpha1.HelmComponentResourceSettingSpec{
CPU: "100m",
Memory: "256Mi",
},
Requests: v1alpha1.HelmComponentResourceSettingSpec{
CPU: "50m",
Memory: "128Mi",
},
},
Image: v1alpha1.HelmComponentImageSpec{
Repository: "sunzhenyucn",
Name: "magicleaps-frontend",
Tag: "1.0.0",
ImagePullPolicy: corev1.PullIfNotPresent,
},
Probes: v1alpha1.HelmComponentProbesSpec{
Liveness: v1alpha1.HelmComponentProbeSpec{
Type: v1alpha1.HTTPGet,
Config: v1alpha1.HelmComponentProbeConfigSpec{
Path: "/",
Port: 8080,
},
},
Readiness: v1alpha1.HelmComponentProbeSpec{
Type: v1alpha1.HTTPGet,
Config: v1alpha1.HelmComponentProbeConfigSpec{
Path: "/",
Port: 8080,
},
},
},
Services: []v1alpha1.HelmComponentServiceSpec{
{
Name: "magicleaps-frontend-service",
Type: corev1.ServiceTypeClusterIP,
Port: 80,
TargetPort: 8080,
},
},
Ingresses: []v1alpha1.HelmComponentIngressSpec{
{
Name: "magicleaps-frontend-ingress",
Class: "nginx",
Host: "alpha.magicleaps.mathmast.com",
Rules: []networkingv1.HTTPIngressPath{
{
Path: "/*",
PathType: &pathType,
Backend: networkingv1.IngressBackend{
Service: &networkingv1.IngressServiceBackend{
Name: "magicleaps-frontend-service",
Port: networkingv1.ServiceBackendPort{
Number: 80,
},
},
},
},
},
TLS: v1alpha1.HelmComponentIngressTLSSpec{
Exists: false,
Name: "magicleaps-alpha-frontend-ingress-tls",
IssuerRef: &cmmeta.ObjectReference{
Name: "mathmast-dot-com",
Kind: "ClusterIssuer",
Group: "cert-manager.io",
},
},
},
},
Configs: []v1alpha1.HelmComponentConfigSpec{
{
Name: "magicleaps-frontend-config",
Type: v1alpha1.EnvironmentSecret,
Data: []corev1.EnvVar{
{
Name: "TZ",
Value: "America/Settle",
},
},
},
},
},
{
Name: "backend",
Ports: []corev1.ContainerPort{
{
Name: "http",
ContainerPort: 8081,
Protocol: corev1.ProtocolTCP,
},
},
Replicas: 1,
Resources: v1alpha1.HelmComponentResourceRequirementsSpec{
Limits: v1alpha1.HelmComponentResourceSettingSpec{
CPU: "200m",
Memory: "512Mi",
},
Requests: v1alpha1.HelmComponentResourceSettingSpec{
CPU: "100m",
Memory: "256Mi",
},
},
Image: v1alpha1.HelmComponentImageSpec{
Repository: "sunzhenyucn",
Name: "magicleaps-backend",
Tag: "1.0.0",
ImagePullPolicy: corev1.PullIfNotPresent,
},
Probes: v1alpha1.HelmComponentProbesSpec{
Liveness: v1alpha1.HelmComponentProbeSpec{
Type: v1alpha1.HTTPGet,
Config: v1alpha1.HelmComponentProbeConfigSpec{
Path: "/api/_/probe/liveness",
Port: 8081,
},
},
Readiness: v1alpha1.HelmComponentProbeSpec{
Type: v1alpha1.HTTPGet,
Config: v1alpha1.HelmComponentProbeConfigSpec{
Path: "/api/_/probe/readiness",
Port: 8081,
},
},
},
Services: []v1alpha1.HelmComponentServiceSpec{
{
Name: "magicleaps-backend-service",
Type: corev1.ServiceTypeClusterIP,
Port: 8081,
TargetPort: 8081,
},
},
Ingresses: []v1alpha1.HelmComponentIngressSpec{},
Configs: []v1alpha1.HelmComponentConfigSpec{
{
Name: "magicleaps-backend-config",
Type: v1alpha1.EnvironmentSecret,
Data: []corev1.EnvVar{
{
Name: "TZ",
Value: "America/Settle",
},
{
Name: "MONGODB_HOST",
Value: "localhost",
},
{
Name: "MONGODB_PORT",
Value: "27017",
},
{
Name: "MONGODB_NAME",
Value: "interview",
},
{
Name: "EMAIL_USER",
Value: "your@freeleaps.com",
},
{
Name: "EMAIL_PASSWORD",
Value: "your-password",
},
{
Name: "SUPER_ADMIN",
Value: "your@email.com",
},
{
Name: "TWILIO_ACCOUNT_SID",
Value: "",
},
{
Name: "TWILIO_AUTH_TOKEN",
Value: "",
},
{
Name: "EVELUATION_TASK_FOLDER_BASE",
Value: "temp/interview/eveluation_task/",
},
{
Name: "LOG_DIR",
Value: "logs",
},
{
Name: "APP_LOG_FILE",
Value: "app.log",
},
{
Name: "APP_LOG_LEVEL",
Value: "INFO",
},
},
},
},
},
},
},
},
}
func TestGenerate(t *testing.T) {
gen := &HelmGenerator{
Instance: &testCase,
}
if err := gen.Generate(); err != nil {
t.Error(err)
}
}

View File

@ -1,27 +0,0 @@
{{ $namespace := .Release.Namespace }}
{{ $appVersion := .Chart.AppVersion | quote }}
{{ $releaseCertificate := .Release.Certificate }}
{{ $releaseName := .Release.Name }}
{{- range $ingress := .Values.[[ .Name ]].ingresses }}
{{- if not $ingress.tls.exists }}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: {{ $ingress.name }}
namespace: {{ $namespace }}
labels:
app.kubernetes.io/version: {{ $appVersion }}
app.kubernetes.io/name: {{ $ingress.name | quote }}
app.kubernetes.io/managed-by: {{ $releaseCertificate }}
app.kubernetes.io/instance: {{ $releaseName }}
spec:
commonName: {{ $ingress.host }}
dnsNames:
- {{ $ingress.host }}
issuerRef:
name: {{ $ingress.tls.issuerRef.name }}
kind: {{ $ingress.tls.issuerRef.kind }}
secretName: {{ $ingress.tls.name }}
{{- end }}
{{- end }}

View File

@ -1,101 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/name: [[ .Name | quote ]]
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
name: [[ .Name | quote ]]
namespace: {{ .Release.Namespace | quote }}
spec:
selector:
matchLabels:
app.kubernetes.io/name: [[ .Name | quote ]]
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
replicas: {{ .Values.[[ .Name ]].replicas }}
template:
metadata:
labels:
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/name: [[ .Name | quote ]]
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: [[ .Name | quote]]
image: "{{ coalesce .Values.[[ .Name ]].image.registry .Values.global.registry "docker.io"}}/{{ coalesce .Values.[[ .Name ]].image.repository .Values.global.repository }}/{{ .Values.[[ .Name ]].image.name }}:{{ .Values.[[ .Name ]].image.tag | default "latest" }}"
imagePullPolicy: {{ .Values.[[ .Name ]].image.imagePullPolicy | default "IfNotPresent" }}
ports:
{{- range $port := .Values.[[ .Name ]].ports }}
- containerPort: {{ $port.containerPort }}
name: {{ $port.name }}
protocol: {{ $port.protocol }}
{{- end }}
{{- if .Values.[[ .Name ]].resources }}
resources:
{{- toYaml .Values.[[ .Name ]].resources | nindent 12 }}
{{- end }}
{{- if .Values.[[ .Name ]].probes }}
{{- if and (.Values.[[ .Name ]].probes.liveness) (eq .Values.[[ .Name ]].probes.liveness.type "httpGet") }}
livenessProbe:
httpGet:
path: {{ .Values.[[ .Name ]].probes.liveness.config.path }}
port: {{ .Values.[[ .Name ]].probes.liveness.config.port }}
{{- if .Values.[[ .Name ]].probes.liveness.config.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.[[ .Name ]].probes.liveness.config.initialDelaySeconds }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.liveness.config.periodSeconds }}
periodSeconds: {{ .Values.[[ .Name ]].probes.liveness.config.periodSeconds }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.liveness.config.timeoutSeconds }}
timeoutSeconds: {{ .Values.[[ .Name ]].probes.liveness.config.timeoutSeconds }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.liveness.config.successThreshold }}
successThreshold: {{ .Values.[[ .Name ]].probes.liveness.config.successThreshold }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.liveness.config.failureThreshold }}
failureThreshold: {{ .Values.[[ .Name ]].probes.liveness.config.failureThreshold }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.liveness.config.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.[[ .Name ]].probes.liveness.config.terminationGracePeriodSeconds }}
{{- end }}
{{- end }}
{{- if and (.Values.[[ .Name ]].probes.readiness) (eq .Values.[[ .Name ]].probes.readiness.type "httpGet") }}
readinessProbe:
httpGet:
path: {{ .Values.[[ .Name ]].probes.readiness.config.path }}
port: {{ .Values.[[ .Name ]].probes.readiness.config.port }}
{{- if .Values.[[ .Name ]].probes.readiness.config.initialDelaySeconds }}
initialDelaySeconds: {{ .Values.[[ .Name ]].probes.readiness.config.initialDelaySeconds }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.readiness.config.periodSeconds }}
periodSeconds: {{ .Values.[[ .Name ]].probes.readiness.config.periodSeconds }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.readiness.config.timeoutSeconds }}
timeoutSeconds: {{ .Values.[[ .Name ]].probes.readiness.config.timeoutSeconds }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.readiness.config.successThreshold }}
successThreshold: {{ .Values.[[ .Name ]].probes.readiness.config.successThreshold }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.readiness.config.failureThreshold }}
failureThreshold: {{ .Values.[[ .Name ]].probes.readiness.config.failureThreshold }}
{{- end }}
{{- if .Values.[[ .Name ]].probes.readiness.config.terminationGracePeriodSeconds }}
terminationGracePeriodSeconds: {{ .Values.[[ .Name ]].probes.readiness.config.terminationGracePeriodSeconds }}
{{- end }}
{{- end }}
{{- end}}
env:
[[- $componentName := .Name ]]
[[- range $config := .Configs ]]
{{- range $key, $value := .Values.[[ $componentName ]].configs }}
- name: {{ $key | snakecase | upper }}
valueFrom:
secretKeyRef:
name: [[ $config.Name ]]
key: {{ $key | snakecase | upper }}
{{- end }}
[[- end ]]

View File

@ -1,38 +0,0 @@
{{ $namespace := .Release.Namespace }}
{{ $appVersion := .Chart.AppVersion | quote }}
{{ $releaseIngress := .Release.Ingress }}
{{ $releaseName := .Release.Name }}
{{- range $ingress := .Values.[[ .Name ]].ingresses }}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ $ingress.name }}
namespace: {{ $namespace }}
labels:
app.kubernetes.io/version: {{ $appVersion }}
app.kubernetes.io/name: {{ $ingress.name | quote }}
app.kubernetes.io/managed-by: {{ $releaseIngress }}
app.kubernetes.io/instance: {{ $releaseName }}
spec:
{{- if $ingress.class }}
ingressClassName: {{ $ingress.class }}
{{- end }}
{{- if $ingress.tls }}
tls:
- hosts:
- {{ $ingress.host }}
{{- if $ingress.tls.exists }}
secretName: {{ $ingress.tls.secretRef.name }}
{{- else }}
secretName: {{ $ingress.tls.name }}
{{- end }}
{{- end }}
rules:
- host: {{ $ingress.host }}
http:
paths:
{{- range $path := $ingress.rules }}
{{ toYaml $path | indent 10 }}
{{- end }}
{{- end }}

View File

@ -1,6 +0,0 @@
apiVersion: v2
name: [[ .Metadata.Name ]]
description: [[ .Metadata.Description ]]
type: application
version: 0.0.1
appVersion: "0.0.1"

View File

@ -1,103 +0,0 @@
[[- define "camelCase" -]]
[[- $input := . -]]
[[- $parts := split "_" $input -]]
[[- $camel := "" -]]
[[- range $index, $part := $parts -]]
[[- if eq $index 0 -]]
[[- $camel = lower $part -]]
[[- else -]]
[[- $camel = printf "%s%s" $camel (title (lower $part)) -]]
[[- end -]]
[[- end -]]
[[- $camel -]]
[[- end -]]
[[- if .Generate ]]
global:
registry: [[ .Global.Registry ]]
repository: [[ .Global.Repository ]]
[[- if .Global.NodeSelector ]]
nodeSelector:
[[- range $key, $value := .Global.NodeSelector ]]
[[ $key ]]: [[ $value ]]
[[- end ]]
[[- else ]]
nodeSelector: {}
[[- end ]]
[[- range $component := .Components ]]
[[ $component.Name ]]:
replicas: [[ $component.Replicas ]]
image:
registry: [[ $component.Image.Registry ]]
repository: [[ $component.Image.Repository ]]
name: [[ $component.Image.Name ]]
tag: [[ $component.Image.Tag ]]
imagePullPolicy: [[ $component.Image.ImagePullPolicy ]]
[[- if $component.Ports]]
ports:
[[- range $port := $component.Ports ]]
- name: [[ $port.Name ]]
containerPort: [[ $port.ContainerPort ]]
protocol: [[ $port.Protocol ]]
[[- end ]]
[[- end]]
resources:
requests:
cpu: "[[ $component.Resources.Requests.CPU ]]"
memory: "[[ $component.Resources.Requests.Memory ]]"
limits:
cpu: "[[ $component.Resources.Limits.CPU ]]"
memory: "[[ $component.Resources.Limits.Memory ]]"
probes:
liveness:
type: [[ $component.Probes.Liveness.Type ]]
config:
path: [[ $component.Probes.Liveness.Config.Path ]]
port: [[ $component.Probes.Liveness.Config.Port ]]
readiness:
type: [[ $component.Probes.Readiness.Type ]]
config:
path: [[ $component.Probes.Readiness.Config.Path ]]
port: [[ $component.Probes.Readiness.Config.Port ]]
services:
[[- range $service := $component.Services ]]
- name: [[ $service.Name ]]
type: [[ $service.Type ]]
port: [[ $service.Port ]]
targetPort: [[ $service.TargetPort ]]
[[- end ]]
ingresses:
[[- range $ingress := $component.Ingresses ]]
- name: [[ $ingress.Name ]]
host: [[ $ingress.Host ]]
class: [[ $ingress.Class ]]
rules:
[[- range $rule := $ingress.Rules ]]
- path: [[ $rule.Path ]]
pathType: [[ $rule.PathType ]]
backend:
service:
name: [[ $rule.Backend.Service.Name ]]
port:
number: [[ $rule.Backend.Service.Port.Number ]]
[[- end ]]
tls:
exists: [[ $ingress.TLS.Exists ]]
[[- if $ingress.TLS.IssuerRef ]]
issuerRef:
name: [[ $ingress.TLS.IssuerRef.Name ]]
kind: [[ $ingress.TLS.IssuerRef.Kind ]]
[[- end ]]
name: [[ $ingress.TLS.Name ]]
[[- end ]]
configs:
[[- range $config := $component.Configs ]]
[[- if eq $config.Type "environment-secret" ]]
[[- range $data := $config.Data ]]
[[ $data.Name | camelCase ]]: [[ $data.Value | quote ]]
[[- end ]]
[[- end ]]
[[- end ]]
[[- end ]]
[[- end ]]

View File

@ -1,11 +0,0 @@
[[ $componentName := .ComponentName ]]
apiVersion: v1
kind: Secret
metadata:
name: [[ .Config.Name ]]
namespace: {{ .Release.Namespace }}
type: Opaque
data:
[[ range $data := .Config.Data ]]
[[- $data.Name ]]: {{ .Values.[[ $componentName ]].configs.[[ $data.Name | camelCase ]] | b64enc | quote }}
[[ end ]]

View File

@ -1,26 +0,0 @@
{{ $namespace := .Release.Namespace }}
{{ $appVersion := .Chart.AppVersion | quote }}
{{ $releaseService := .Release.Service }}
{{ $releaseName := .Release.Name }}
{{- range $service := .Values.[[ .Name ]].services }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ $service.name }}
namespace: {{ $namespace }}
labels:
app.kubernetes.io/version: {{ $appVersion }}
app.kubernetes.io/name: {{ $service.name | quote }}
app.kubernetes.io/managed-by: {{ $releaseService }}
app.kubernetes.io/instance: {{ $releaseName }}
spec:
ports:
- port: {{ $service.port }}
targetPort: {{ $service.targetPort }}
selector:
app.kubernetes.io/version: {{ $appVersion }}
app.kubernetes.io/name: [[ .Name | quote ]]
app.kubernetes.io/managed-by: {{ $releaseService }}
app.kubernetes.io/instance: {{ $releaseName }}
{{- end }}

View File

@ -1,96 +0,0 @@
package jenkins
import (
"embed"
"fmt"
"html/template"
"io"
"os"
"freeleaps.com/gitops/initializer/api/v1alpha1"
)
//go:embed templates/*
var embeddedTemplates embed.FS
type JenkinsfileGenerator struct {
io.Closer
Instance *v1alpha1.ProjectInitialize
workingDir string
generated bool
}
const leftDelim = "[["
const rightDelim = "]]"
func (jg *JenkinsfileGenerator) prepareWorkingDir() error {
path, err := os.MkdirTemp("", fmt.Sprintf("jenkinsfile-gen-%s-*", jg.Instance.Name))
if err != nil {
return fmt.Errorf("failed to create jenkinsfile generator temp dir: %w", err)
}
jg.workingDir = path
return nil
}
func (jg *JenkinsfileGenerator) readTemplate(name string) (*template.Template, error) {
tpl := template.New(name)
templateBytes, err := embeddedTemplates.ReadFile(name)
if err != nil {
return nil, fmt.Errorf("failed to read template %s: %w", name, err)
}
tpl, err = tpl.
Delims(leftDelim, rightDelim).
Parse(string(templateBytes))
if err != nil {
return nil, fmt.Errorf("failed to parse template %s: %w", name, err)
}
return tpl, nil
}
func (jg *JenkinsfileGenerator) Generate() error {
if jg.Instance == nil {
return fmt.Errorf("instance is nil")
}
if err := jg.prepareWorkingDir(); err != nil {
return err
}
tpl, err := jg.readTemplate("templates/Jenkinsfile.tpl")
if err != nil {
return err
}
jenkinsfileFd, err := os.Create(jg.workingDir + "/Jenkinsfile")
if err != nil {
return fmt.Errorf("failed to create Jenkinsfile: %w", err)
}
defer jenkinsfileFd.Close()
if err := tpl.Execute(jenkinsfileFd, jg.Instance.Spec); err != nil {
return fmt.Errorf("failed to render Jenkinsfile with template: %w", err)
}
jg.generated = true
return nil
}
func (jg *JenkinsfileGenerator) Close() error {
if jg.workingDir != "" {
return os.RemoveAll(jg.workingDir)
}
return nil
}
func (jg *JenkinsfileGenerator) ReadGeneratedJenkinsfile() ([]byte, error) {
if !jg.generated {
return nil, fmt.Errorf("jenkinsfile not generated")
}
jenkinsfileBytes, err := os.ReadFile(jg.workingDir + "/Jenkinsfile")
if err != nil {
return nil, fmt.Errorf("failed to read generated Jenkinsfile: %w", err)
}
return jenkinsfileBytes, nil
}

View File

@ -1,28 +0,0 @@
library 'first-class-pipeline'
executeFreeleapsPipeline {
serviceName = [[ .ServiceName | quote ]]
environmentSlug = [[ .EnvironmentSlug | quote ]]
serviceGitBranch = [[ .Spec.Repository.Branch | quote ]]
serviceGitRepo = [[ .GitRepoURL | quote ]]
serviceGitRepoType = [[ .Spec.Repository.Type | quote ]]
serviceGitCredentialsId = [[ .JenkinsGitCredentialsId | quote ]]
executeMode = [[ .Spec.ContinuousIntegrationSpec.ExecuteMode | quote ]]
commitMessageLintEnabled = [[ .Spec.ContinuousIntegrationSpec.CommitMessageLintEnabled ]]
components = [
[[- range $component := .Spec.ContinuousIntegrationSpec.Components ]]
[
name: [[ $component.Name | quote ]],
root: [[ $component.Root | quote ]],
language: [[ $component.Language | quote ]],
dependenciesManager: [[ $component.DependenciesManager | quote ]],
[[- if and (eq $component.DependenciesManager "npm") ($component.NPMPackageJsonFile) ]]
npmPackageJsonFile: [[ $component.NPMPackageJsonFile | quote ]],
[[- end ]]
[[- if $component.BuildCacheEnabled ]]
buildCacheEnabled: [[ $component.BuildCacheEnabled ]],
[[- end ]]
]
[[- end ]]
]
}

View File

@ -1,19 +0,0 @@
package metrics
import (
"github.com/prometheus/client_golang/prometheus"
"sigs.k8s.io/controller-runtime/pkg/metrics"
)
var (
ReconcilesTotal = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "reconciles_total",
Help: "Number of total reconciliation attempts",
},
)
)
func init() {
metrics.Registry.MustRegister(ReconcilesTotal)
}

View File

@ -1,27 +0,0 @@
package repo
import "context"
const (
DefaultAuthorName = "freeleaps-gitops-bot"
DefaultAuthorEmail = "gitops@mathmast.com"
)
type FileOperation string
const (
OpCreate FileOperation = "create"
OpUpdate FileOperation = "update"
OpDelete FileOperation = "delete"
)
type ChangeRequest struct {
Path string
Content []byte // nil for delete
Operation FileOperation
}
type RepoManager interface {
Initialize(context context.Context, opts ...Option) error
ApplyChanges(context context.Context, changes []ChangeRequest, message string) error
}

View File

@ -1,50 +0,0 @@
package repo
type Option func(*Options)
type Options struct {
URL string
Project string
Name string
Branch string
AuthorName string
AuthorEmail string
PluginConfig PluginConfig
}
func WithProject(project string) Option {
return func(o *Options) {
o.Project = project
}
}
func WithName(name string) Option {
return func(o *Options) {
o.Name = name
}
}
func WithURL(url string) Option {
return func(o *Options) {
o.URL = url
}
}
func WithBranch(branch string) Option {
return func(o *Options) {
o.Branch = branch
}
}
func WithAuthor(name, email string) Option {
return func(o *Options) {
o.AuthorName = name
o.AuthorEmail = email
}
}
func WithPluginConfig(config PluginConfig) Option {
return func(o *Options) {
o.PluginConfig = config
}
}

View File

@ -1,63 +0,0 @@
package repo
import (
"fmt"
"sync"
)
var (
pluginsMu sync.RWMutex
plugins = make(map[string]PluginCreateFunc)
)
type PluginCreateFunc func() RepoManager
type PluginConfig interface {
Get(key string) (any, error)
Set(key string, value any)
}
type pluginConfig struct {
config map[string]any
}
func (c *pluginConfig) Get(key string) (any, error) {
val, exists := c.config[key]
if !exists {
return "", fmt.Errorf("key %s not found", key)
}
return val, nil
}
func (c *pluginConfig) Set(key string, value any) {
c.config[key] = value
}
func NewPluginConfig() PluginConfig {
return &pluginConfig{
config: make(map[string]any),
}
}
func RegisterPlugin(name string, fun PluginCreateFunc) {
pluginsMu.Lock()
defer pluginsMu.Unlock()
if fun == nil {
panic("plugin create func cannot be nil")
}
if old, exists := plugins[name]; exists {
fmt.Printf("WARNING: plugin '%s' already registered (%T), overwriting\n", name, old)
}
plugins[name] = fun
}
func GetPlugin(name string) (RepoManager, bool) {
pluginsMu.RLock()
defer pluginsMu.RUnlock()
fun, exists := plugins[name]
return fun(), exists
}

View File

@ -1,179 +0,0 @@
package azure
import (
"context"
"encoding/base64"
"errors"
"fmt"
"freeleaps.com/gitops/initializer/internal/repo"
"github.com/microsoft/azure-devops-go-api/azuredevops"
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
)
type AzureDevOpsRepoManager struct {
options *repo.Options
client git.Client
}
var _ repo.RepoManager = &AzureDevOpsRepoManager{}
func init() {
repo.RegisterPlugin("azure-devops", func() repo.RepoManager {
return &AzureDevOpsRepoManager{}
})
}
// Initialize implements repo.RepoManager.
func (a *AzureDevOpsRepoManager) Initialize(context context.Context, opts ...repo.Option) error {
options := &repo.Options{}
for _, opt := range opts {
opt(options)
}
if options.Project == "" {
return errors.New("missing project name")
}
if options.Name == "" {
return errors.New("missing repository name")
}
if options.Branch == "" {
options.Branch = "master"
}
if options.AuthorName == "" {
options.AuthorName = repo.DefaultAuthorName
}
if options.AuthorEmail == "" {
options.AuthorEmail = repo.DefaultAuthorEmail
}
if options.PluginConfig == nil {
return errors.New("missing plugin config")
}
config := options.PluginConfig
pat, err := config.Get("pat")
if err != nil {
return errors.New("missing PAT")
}
organization, err := config.Get("organizationUrl")
if err != nil {
return errors.New("missing organization URL")
}
conn := azuredevops.NewPatConnection(organization.(string), pat.(string))
a.client, err = git.NewClient(context, conn)
if err != nil {
return fmt.Errorf("failed to create git client: %w", err)
}
a.options = options
return nil
}
func (a *AzureDevOpsRepoManager) getBranchHeadCommit() (string, error) {
filter := "heads/"
filterContains := a.options.Branch
refs, err := a.client.GetRefs(context.Background(), git.GetRefsArgs{
RepositoryId: &a.options.Name,
Project: &a.options.Project,
Filter: &filter,
FilterContains: &filterContains,
})
if err != nil {
return "", fmt.Errorf("failed to get branch ref: %v", err)
}
if len(refs.Value) == 0 || (refs.Value)[0].ObjectId == nil {
return "", fmt.Errorf("branch '%s' not found", a.options.Branch)
}
return *refs.Value[0].ObjectId, nil
}
// ApplyChanges implements repo.RepoManager.
func (a *AzureDevOpsRepoManager) ApplyChanges(context context.Context, changes []repo.ChangeRequest, message string) error {
targetRepo, err := a.client.GetRepository(context, git.GetRepositoryArgs{
RepositoryId: &a.options.Name,
Project: &a.options.Project,
})
if err != nil {
return fmt.Errorf("failed to get repository: %w", err)
}
// convert changes to git changes
gitChanges := make([]interface{}, 0, len(changes))
for _, change := range changes {
gitChange := git.GitChange{
ChangeType: toAzureGitChangeType(change.Operation),
Item: &git.GitItem{
Path: &change.Path,
},
}
if change.Operation != repo.OpDelete {
contentBase64 := base64.StdEncoding.EncodeToString(change.Content)
gitChange.NewContent = &git.ItemContent{
Content: &contentBase64,
ContentType: &git.ItemContentTypeValues.Base64Encoded,
}
}
gitChanges = append(gitChanges, gitChange)
}
// get head commit id
baseCommitId, err := a.getBranchHeadCommit()
if err != nil {
return err
}
// generate ref name
refName := "refs/heads/" + a.options.Branch
// create push
_, err = a.client.CreatePush(context, git.CreatePushArgs{
RepositoryId: &a.options.Name,
Project: targetRepo.Project.Name,
Push: &git.GitPush{
RefUpdates: &[]git.GitRefUpdate{
{
Name: &refName,
OldObjectId: &baseCommitId,
},
},
Commits: &[]git.GitCommitRef{
{
Comment: &message,
Changes: &gitChanges,
Author: &git.GitUserDate{
Name: &a.options.AuthorName,
Email: &a.options.AuthorEmail,
},
},
},
},
})
return err
}
func toAzureGitChangeType(op repo.FileOperation) *git.VersionControlChangeType {
switch op {
case repo.OpCreate:
return &git.VersionControlChangeTypeValues.Add
case repo.OpDelete:
return &git.VersionControlChangeTypeValues.Delete
case repo.OpUpdate:
return &git.VersionControlChangeTypeValues.Edit
default:
panic("unreachable")
}
}

View File

@ -1,41 +0,0 @@
package azure_test
import (
"context"
"testing"
"freeleaps.com/gitops/initializer/internal/repo"
)
func TestApplyChanges(t *testing.T) {
mgr, ok := repo.GetPlugin("azure-devops")
if !ok {
t.Fatal("plugin not found")
}
pluginConfig := repo.NewPluginConfig()
// pluginConfig.Set("pat", "3E9J1v0si6HRvyc1RSRgT791W9ZvMi4kBmrznfcIXB8mq6Trj9VkJQQJ99BBACAAAAArj0WRAAASAZDO32n4")
pluginConfig.Set("pat", "6MM9azUlikBWsFDqnCpbmDaUrdHz3Cufer9KwWFl67ohoWVrVJ8DJQQJ99BBACAAAAArj0WRAAASAZDOj9V2")
pluginConfig.Set("organizationUrl", "https://dev.azure.com/zhenyus")
err := mgr.Initialize(context.Background(),
repo.WithProject("gitops-repo"),
repo.WithName("gitops-repo"),
repo.WithBranch("master"),
repo.WithAuthor("gitops-bot", "zhenyus@mathmast.com"),
repo.WithPluginConfig(pluginConfig))
if err != nil {
t.Fatal(err)
}
err = mgr.ApplyChanges(context.Background(), []repo.ChangeRequest{
{
Path: "test.txt",
Content: []byte("hello from operator"),
Operation: repo.OpCreate,
},
}, "chore(test): test commit from operator")
if err != nil {
t.Fatal(err)
}
}

View File

@ -1,32 +0,0 @@
/*
Copyright 2025.
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 e2e
import (
"fmt"
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// Run e2e tests using the Ginkgo runner.
func TestE2E(t *testing.T) {
RegisterFailHandler(Fail)
_, _ = fmt.Fprintf(GinkgoWriter, "Starting freeleaps-gitops-initializer suite\n")
RunSpecs(t, "e2e suite")
}

View File

@ -1,122 +0,0 @@
/*
Copyright 2025.
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 e2e
import (
"fmt"
"os/exec"
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"freeleaps.com/gitops/initializer/test/utils"
)
const namespace = "freeleaps-gitops-initializer-system"
var _ = Describe("controller", Ordered, func() {
BeforeAll(func() {
By("installing prometheus operator")
Expect(utils.InstallPrometheusOperator()).To(Succeed())
By("installing the cert-manager")
Expect(utils.InstallCertManager()).To(Succeed())
By("creating manager namespace")
cmd := exec.Command("kubectl", "create", "ns", namespace)
_, _ = utils.Run(cmd)
})
AfterAll(func() {
By("uninstalling the Prometheus manager bundle")
utils.UninstallPrometheusOperator()
By("uninstalling the cert-manager bundle")
utils.UninstallCertManager()
By("removing manager namespace")
cmd := exec.Command("kubectl", "delete", "ns", namespace)
_, _ = utils.Run(cmd)
})
Context("Operator", func() {
It("should run successfully", func() {
var controllerPodName string
var err error
// projectimage stores the name of the image used in the example
var projectimage = "example.com/freeleaps-gitops-initializer:v0.0.1"
By("building the manager(Operator) image")
cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("loading the the manager(Operator) image on Kind")
err = utils.LoadImageToKindClusterWithName(projectimage)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("installing CRDs")
cmd = exec.Command("make", "install")
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("deploying the controller-manager")
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage))
_, err = utils.Run(cmd)
ExpectWithOffset(1, err).NotTo(HaveOccurred())
By("validating that the controller-manager pod is running as expected")
verifyControllerUp := func() error {
// Get pod name
cmd = exec.Command("kubectl", "get",
"pods", "-l", "control-plane=controller-manager",
"-o", "go-template={{ range .items }}"+
"{{ if not .metadata.deletionTimestamp }}"+
"{{ .metadata.name }}"+
"{{ \"\\n\" }}{{ end }}{{ end }}",
"-n", namespace,
)
podOutput, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
podNames := utils.GetNonEmptyLines(string(podOutput))
if len(podNames) != 1 {
return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames))
}
controllerPodName = podNames[0]
ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager"))
// Validate pod status
cmd = exec.Command("kubectl", "get",
"pods", controllerPodName, "-o", "jsonpath={.status.phase}",
"-n", namespace,
)
status, err := utils.Run(cmd)
ExpectWithOffset(2, err).NotTo(HaveOccurred())
if string(status) != "Running" {
return fmt.Errorf("controller pod in %s status", status)
}
return nil
}
EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed())
})
})
})

View File

@ -1,140 +0,0 @@
/*
Copyright 2025.
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 utils
import (
"fmt"
"os"
"os/exec"
"strings"
. "github.com/onsi/ginkgo/v2" //nolint:golint,revive
)
const (
prometheusOperatorVersion = "v0.72.0"
prometheusOperatorURL = "https://github.com/prometheus-operator/prometheus-operator/" +
"releases/download/%s/bundle.yaml"
certmanagerVersion = "v1.14.4"
certmanagerURLTmpl = "https://github.com/jetstack/cert-manager/releases/download/%s/cert-manager.yaml"
)
func warnError(err error) {
_, _ = fmt.Fprintf(GinkgoWriter, "warning: %v\n", err)
}
// InstallPrometheusOperator installs the prometheus Operator to be used to export the enabled metrics.
func InstallPrometheusOperator() error {
url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion)
cmd := exec.Command("kubectl", "create", "-f", url)
_, err := Run(cmd)
return err
}
// Run executes the provided command within this context
func Run(cmd *exec.Cmd) ([]byte, error) {
dir, _ := GetProjectDir()
cmd.Dir = dir
if err := os.Chdir(cmd.Dir); err != nil {
_, _ = fmt.Fprintf(GinkgoWriter, "chdir dir: %s\n", err)
}
cmd.Env = append(os.Environ(), "GO111MODULE=on")
command := strings.Join(cmd.Args, " ")
_, _ = fmt.Fprintf(GinkgoWriter, "running: %s\n", command)
output, err := cmd.CombinedOutput()
if err != nil {
return output, fmt.Errorf("%s failed with error: (%v) %s", command, err, string(output))
}
return output, nil
}
// UninstallPrometheusOperator uninstalls the prometheus
func UninstallPrometheusOperator() {
url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion)
cmd := exec.Command("kubectl", "delete", "-f", url)
if _, err := Run(cmd); err != nil {
warnError(err)
}
}
// UninstallCertManager uninstalls the cert manager
func UninstallCertManager() {
url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion)
cmd := exec.Command("kubectl", "delete", "-f", url)
if _, err := Run(cmd); err != nil {
warnError(err)
}
}
// InstallCertManager installs the cert manager bundle.
func InstallCertManager() error {
url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion)
cmd := exec.Command("kubectl", "apply", "-f", url)
if _, err := Run(cmd); err != nil {
return err
}
// Wait for cert-manager-webhook to be ready, which can take time if cert-manager
// was re-installed after uninstalling on a cluster.
cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook",
"--for", "condition=Available",
"--namespace", "cert-manager",
"--timeout", "5m",
)
_, err := Run(cmd)
return err
}
// LoadImageToKindClusterWithName loads a local docker image to the kind cluster
func LoadImageToKindClusterWithName(name string) error {
cluster := "kind"
if v, ok := os.LookupEnv("KIND_CLUSTER"); ok {
cluster = v
}
kindOptions := []string{"load", "docker-image", name, "--name", cluster}
cmd := exec.Command("kind", kindOptions...)
_, err := Run(cmd)
return err
}
// GetNonEmptyLines converts given command output string into individual objects
// according to line breakers, and ignores the empty elements in it.
func GetNonEmptyLines(output string) []string {
var res []string
elements := strings.Split(output, "\n")
for _, element := range elements {
if element != "" {
res = append(res, element)
}
}
return res
}
// GetProjectDir will return the directory where the project is
func GetProjectDir() (string, error) {
wd, err := os.Getwd()
if err != nil {
return wd, err
}
wd = strings.Replace(wd, "/test/e2e", "", -1)
return wd, nil
}