Merge pull request #510 from jenkinsci/operator-sdk-1.3.0
#494 Upgrade to Operator sdk 1.3.0
This commit is contained in:
commit
3dab502234
|
|
@ -0,0 +1,5 @@
|
|||
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
|
||||
# Ignore all files which are not go type
|
||||
!**/*.go
|
||||
!**/*.mod
|
||||
!**/*.sum
|
||||
|
|
@ -23,9 +23,6 @@ jobs:
|
|||
echo "MINIKUBE_WANTUPDATENOTIFICATION=false" >> $GITHUB_ENV
|
||||
echo "MINIKUBE_WANTREPORTERRORPROMPT=false" >> $GITHUB_ENV
|
||||
echo "GO_VERSION=v$(sed -n 's/GO_VERSION=//p' config.base.env)" >> $GITHUB_ENV
|
||||
echo "MINIKUBE_VERSION=v$(sed -n 's/MINIKUBE_VERSION=//p' config.minikube.env)" >> $GITHUB_ENV
|
||||
echo "OPERATOR_SDK_VERSION=v$(sed -n 's/OPERATOR_SDK_VERSION=//p' config.base.env)" >> $GITHUB_ENV
|
||||
echo "MINIKUBE_KUBERNETES_VERSION=$(sed -n 's/MINIKUBE_KUBERNETES_VERSION=//p' config.minikube.env)" >> $GITHUB_ENV
|
||||
echo "HELM_VERSION=v$(sed -n 's/HELM_VERSION=//p' config.base.env)" >> $GITHUB_ENV
|
||||
echo "GOPATH=/home/runner/go" >> $GITHUB_ENV
|
||||
|
||||
|
|
@ -44,17 +41,12 @@ jobs:
|
|||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install socat
|
||||
curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/$MINIKUBE_KUBERNETES_VERSION/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
|
||||
curl -Lo minikube https://storage.googleapis.com/minikube/releases/$MINIKUBE_VERSION/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
|
||||
curl -Lo operator-sdk https://github.com/operator-framework/operator-sdk/releases/download/$OPERATOR_SDK_VERSION/operator-sdk-$OPERATOR_SDK_VERSION-x86_64-linux-gnu && chmod +x operator-sdk && sudo mv operator-sdk /usr/local/bin/
|
||||
curl -Lo helm.tar.gz https://get.helm.sh/helm-$HELM_VERSION-linux-amd64.tar.gz && tar xzfv helm.tar.gz && sudo mv linux-amd64/helm /usr/local/bin/
|
||||
sudo mkdir -p $HOME/.kube $HOME/.minikube
|
||||
touch KUBECONFIG
|
||||
sudo minikube start --vm-driver=none --kubernetes-version=$MINIKUBE_KUBERNETES_VERSION
|
||||
sudo chown -R $USER $HOME/.kube $HOME/.minikube
|
||||
make minikube-start MINIKUBE_DRIVER='docker' CPUS_NUMBER=2
|
||||
|
||||
- name: Jenkins Operator - e2e
|
||||
run: make build e2e
|
||||
run: |
|
||||
make e2e E2E_TEST_ARGS='-ginkgo.v'
|
||||
|
||||
- name: Jenkins Operator Helm Chart - e2e
|
||||
run: make e2e BUILDTAGS=Helm E2E_TEST_SELECTOR='^.*Helm.*$'
|
||||
#TODO Helm e2e test
|
||||
|
|
@ -88,3 +88,6 @@ tags
|
|||
|
||||
### IntelliJ IDEA ###
|
||||
*.iml
|
||||
|
||||
bin
|
||||
testbin/*
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
ARG GO_VERSION
|
||||
|
||||
# Build the manager binary
|
||||
FROM golang:$GO_VERSION as builder
|
||||
ARG CTIMEVAR
|
||||
|
||||
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 api/ api/
|
||||
COPY controllers/ controllers/
|
||||
COPY internal/ internal/
|
||||
COPY pkg/ pkg/
|
||||
COPY version/ version/
|
||||
COPY main.go main.go
|
||||
|
||||
# Build
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -ldflags "-w $CTIMEVAR" -o manager 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"]
|
||||
300
Makefile
300
Makefile
|
|
@ -1,74 +1,4 @@
|
|||
# Set POSIX sh for maximum interoperability
|
||||
SHELL := /bin/sh
|
||||
PATH := $(GOPATH)/bin:$(PATH)
|
||||
|
||||
OSFLAG :=
|
||||
ifeq ($(OS),Windows_NT)
|
||||
OSFLAG = WIN32
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
OSFLAG = LINUX
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
OSFLAG = OSX
|
||||
endif
|
||||
endif
|
||||
|
||||
include config.base.env
|
||||
|
||||
# Import config
|
||||
# You can change the default config with `make config="config_special.env" build`
|
||||
config ?= config.minikube.env
|
||||
include $(config)
|
||||
|
||||
# Set an output prefix, which is the local directory if not specified
|
||||
PREFIX?=$(shell pwd)
|
||||
|
||||
VERSION := $(shell cat VERSION.txt)
|
||||
GITCOMMIT := $(shell git rev-parse --short HEAD)
|
||||
GITBRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
GITUNTRACKEDCHANGES := $(shell git status --porcelain --untracked-files=no)
|
||||
GITIGNOREDBUTTRACKEDCHANGES := $(shell git ls-files -i --exclude-standard)
|
||||
ifneq ($(GITUNTRACKEDCHANGES),)
|
||||
GITCOMMIT := $(GITCOMMIT)-dirty
|
||||
endif
|
||||
ifneq ($(GITIGNOREDBUTTRACKEDCHANGES),)
|
||||
GITCOMMIT := $(GITCOMMIT)-dirty
|
||||
endif
|
||||
|
||||
VERSION_TAG := $(VERSION)
|
||||
LATEST_TAG := latest
|
||||
BUILD_TAG := $(GITBRANCH)-$(GITCOMMIT)
|
||||
|
||||
BUILD_PATH := ./cmd/manager
|
||||
|
||||
# CONTAINER_RUNTIME_COMMAND is Container Runtime - it could be docker or podman
|
||||
CONTAINER_RUNTIME_COMMAND := docker
|
||||
|
||||
# Set any default go build tags
|
||||
BUILDTAGS :=
|
||||
|
||||
# Set the build dir, where built cross-compiled binaries will be output
|
||||
BUILDDIR := ${PREFIX}/cross
|
||||
|
||||
CTIMEVAR=-X $(PKG)/version.GitCommit=$(GITCOMMIT) -X $(PKG)/version.Version=$(VERSION)
|
||||
GO_LDFLAGS=-ldflags "-w $(CTIMEVAR)"
|
||||
GO_LDFLAGS_STATIC=-ldflags "-w $(CTIMEVAR) -extldflags -static"
|
||||
|
||||
# List the GOOS and GOARCH to build
|
||||
GOOSARCHES = linux/amd64
|
||||
|
||||
PACKAGES = $(shell go list -f '{{.ImportPath}}/' ./... | grep -v vendor)
|
||||
PACKAGES_FOR_UNIT_TESTS = $(shell go list -f '{{.ImportPath}}/' ./... | grep -v vendor | grep -v e2e)
|
||||
|
||||
# Run all the e2e tests by default
|
||||
E2E_TEST_SELECTOR ?= .*
|
||||
|
||||
JENKINS_API_HOSTNAME := $(shell $(JENKINS_API_HOSTNAME_COMMAND) 2> /dev/null || echo "" )
|
||||
OPERATOR_ARGS ?= --jenkins-api-hostname=$(JENKINS_API_HOSTNAME) --jenkins-api-port=$(JENKINS_API_PORT) --jenkins-api-use-nodeport=$(JENKINS_API_USE_NODEPORT) --cluster-domain=$(CLUSTER_DOMAIN) $(OPERATOR_EXTRA_ARGS)
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
include variables.mk
|
||||
|
||||
.PHONY: all
|
||||
all: status checkmake clean build verify install container-runtime-build container-runtime-images ## Build the image
|
||||
|
|
@ -121,7 +51,7 @@ build: deepcopy-gen $(NAME) ## Builds a dynamic executable or package
|
|||
.PHONY: $(NAME)
|
||||
$(NAME): $(wildcard *.go) $(wildcard */*.go) VERSION.txt
|
||||
@echo "+ $@"
|
||||
CGO_ENABLED=0 go build -tags "$(BUILDTAGS)" ${GO_LDFLAGS} -o build/_output/bin/jenkins-operator $(BUILD_PATH)
|
||||
CGO_ENABLED=0 go build -tags "$(BUILDTAGS)" ${GO_LDFLAGS} -o bin/manager $(BUILD_PATH)
|
||||
|
||||
.PHONY: static
|
||||
static: ## Builds a static executable
|
||||
|
|
@ -136,22 +66,22 @@ fmt: ## Verifies all files have been `gofmt`ed
|
|||
@go fmt $(PACKAGES)
|
||||
|
||||
.PHONY: lint
|
||||
HAS_GOLINT := $(shell which golangci-lint)
|
||||
HAS_GOLINT := $(shell which $(PROJECT_DIR)/bin/golangci-lint)
|
||||
lint: ## Verifies `golint` passes
|
||||
@echo "+ $@"
|
||||
ifndef HAS_GOLINT
|
||||
go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.26.0
|
||||
$(call go-get-tool,$(PROJECT_DIR)/bin/golangci-lint,github.com/golangci/golangci-lint/cmd/golangci-lint@v1.26.0)
|
||||
endif
|
||||
@golangci-lint run
|
||||
@bin/golangci-lint run
|
||||
|
||||
.PHONY: goimports
|
||||
HAS_GOIMPORTS := $(shell which goimports)
|
||||
HAS_GOIMPORTS := $(shell which $(PROJECT_DIR)/bin/goimports)
|
||||
goimports: ## Verifies `goimports` passes
|
||||
@echo "+ $@"
|
||||
ifndef HAS_GOIMPORTS
|
||||
go get -u golang.org/x/tools/cmd/goimports
|
||||
$(call go-get-tool,$(PROJECT_DIR)/bin/goimports,golang.org/x/tools/cmd/goimports@v0.1.0)
|
||||
endif
|
||||
@goimports -l -e $(shell find . -type f -name '*.go' -not -path "./vendor/*")
|
||||
@bin/goimports -l -e $(shell find . -type f -name '*.go' -not -path "./vendor/*")
|
||||
|
||||
.PHONY: test
|
||||
test: ## Runs the go tests
|
||||
|
|
@ -159,47 +89,10 @@ test: ## Runs the go tests
|
|||
@RUNNING_TESTS=1 go test -tags "$(BUILDTAGS) cgo" $(PACKAGES_FOR_UNIT_TESTS)
|
||||
|
||||
.PHONY: e2e
|
||||
CURRENT_DIRECTORY := $(shell pwd)
|
||||
e2e: container-runtime-build ## Runs e2e tests, you can use EXTRA_ARGS
|
||||
e2e: deepcopy-gen ## Runs e2e tests, you can use EXTRA_ARGS
|
||||
@echo "+ $@"
|
||||
@echo "Docker image: $(DOCKER_REGISTRY):$(GITCOMMIT)"
|
||||
ifeq ($(KUBERNETES_PROVIDER),minikube)
|
||||
kubectl config use-context $(KUBECTL_CONTEXT)
|
||||
endif
|
||||
ifeq ($(KUBERNETES_PROVIDER),crc)
|
||||
oc project $(CRC_OC_PROJECT)
|
||||
endif
|
||||
cp deploy/service_account.yaml deploy/namespace-init.yaml
|
||||
cat deploy/role.yaml >> deploy/namespace-init.yaml
|
||||
cat deploy/role_binding.yaml >> deploy/namespace-init.yaml
|
||||
cat deploy/operator.yaml >> deploy/namespace-init.yaml
|
||||
ifeq ($(OSFLAG), LINUX)
|
||||
ifeq ($(IMAGE_PULL_MODE), remote)
|
||||
sed -i 's|\(image:\).*|\1 $(DOCKER_ORGANIZATION)/$(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml
|
||||
sed -i 's|\(imagePullPolicy\): IfNotPresent|\1: Always|g' deploy/namespace-init.yaml
|
||||
else
|
||||
sed -i 's|\(image:\).*|\1 $(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml
|
||||
endif
|
||||
ifeq ($(KUBERNETES_PROVIDER),minikube)
|
||||
sed -i 's|\(imagePullPolicy\): IfNotPresent|\1: Never|g' deploy/namespace-init.yaml
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OSFLAG), OSX)
|
||||
ifeq ($(IMAGE_PULL_MODE), remote)
|
||||
sed -i '' 's|\(image:\).*|\1 $(DOCKER_ORGANIZATION)/$(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml
|
||||
sed -i '' 's|\(imagePullPolicy\): IfNotPresent|\1: Always|g' deploy/namespace-init.yaml
|
||||
else
|
||||
sed -i '' 's|\(image:\).*|\1 $(DOCKER_REGISTRY):$(GITCOMMIT)|g' deploy/namespace-init.yaml
|
||||
endif
|
||||
ifeq ($(KUBERNETES_PROVIDER),minikube)
|
||||
sed -i '' 's|\(imagePullPolicy\): IfNotPresent|\1: Never|g' deploy/namespace-init.yaml
|
||||
endif
|
||||
endif
|
||||
|
||||
RUNNING_TESTS=1 go test -parallel=1 "./test/e2e/" -tags "$(BUILDTAGS) cgo" -v -timeout 60m -run "$(E2E_TEST_SELECTOR)" \
|
||||
-root=$(CURRENT_DIRECTORY) -kubeconfig=$(HOME)/.kube/config -globalMan deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml \
|
||||
-namespacedMan deploy/namespace-init.yaml $(TEST_ARGS)
|
||||
-jenkins-api-hostname=$(JENKINS_API_HOSTNAME) -jenkins-api-port=$(JENKINS_API_PORT) -jenkins-api-use-nodeport=$(JENKINS_API_USE_NODEPORT) $(E2E_TEST_ARGS)
|
||||
|
||||
.PHONY: vet
|
||||
vet: ## Verifies `go vet` passes
|
||||
|
|
@ -207,17 +100,18 @@ vet: ## Verifies `go vet` passes
|
|||
@go vet $(PACKAGES)
|
||||
|
||||
.PHONY: staticcheck
|
||||
HAS_STATICCHECK := $(shell which staticcheck)
|
||||
PLATFORM = $(shell echo $(UNAME_S) | tr A-Z a-z)
|
||||
HAS_STATICCHECK := $(shell which $(PROJECT_DIR)/bin/staticcheck)
|
||||
staticcheck: ## Verifies `staticcheck` passes
|
||||
@echo "+ $@"
|
||||
ifndef HAS_STATICCHECK
|
||||
wget -O staticcheck_$(PLATFORM)_amd64.tar.gz https://github.com/dominikh/go-tools/releases/download/2020.1.3/staticcheck_$(PLATFORM)_amd64.tar.gz
|
||||
tar zxvf staticcheck_$(PLATFORM)_amd64.tar.gz
|
||||
mkdir -p $(GOPATH)/bin
|
||||
mv staticcheck/staticcheck $(GOPATH)/bin
|
||||
$(eval TMP_DIR := $(shell mktemp -d))
|
||||
wget -O $(TMP_DIR)/staticcheck_$(PLATFORM)_amd64.tar.gz https://github.com/dominikh/go-tools/releases/download/2020.1.3/staticcheck_$(PLATFORM)_amd64.tar.gz
|
||||
tar zxvf $(TMP_DIR)/staticcheck_$(PLATFORM)_amd64.tar.gz -C $(TMP_DIR)
|
||||
mkdir -p $(PROJECT_DIR)/bin
|
||||
mv $(TMP_DIR)/staticcheck/staticcheck $(PROJECT_DIR)/bin
|
||||
rm -rf $(TMP_DIR)
|
||||
endif
|
||||
@staticcheck $(PACKAGES)
|
||||
@$(PROJECT_DIR)/bin/staticcheck $(PACKAGES)
|
||||
|
||||
.PHONY: cover
|
||||
cover: ## Runs go test with coverage
|
||||
|
|
@ -242,7 +136,7 @@ install: ## Installs the executable
|
|||
.PHONY: run
|
||||
run: export WATCH_NAMESPACE = $(NAMESPACE)
|
||||
run: export OPERATOR_NAME = $(NAME)
|
||||
run: build ## Run the executable, you can use EXTRA_ARGS
|
||||
run: fmt vet manifests install-crds build ## Run the executable, you can use EXTRA_ARGS
|
||||
@echo "+ $@"
|
||||
ifeq ($(KUBERNETES_PROVIDER),minikube)
|
||||
kubectl config use-context $(KUBECTL_CONTEXT)
|
||||
|
|
@ -250,10 +144,8 @@ endif
|
|||
ifeq ($(KUBERNETES_PROVIDER),crc)
|
||||
oc project $(CRC_OC_PROJECT)
|
||||
endif
|
||||
kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml
|
||||
kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkinsimage_crd.yaml
|
||||
@echo "Watching '$(WATCH_NAMESPACE)' namespace"
|
||||
build/_output/bin/jenkins-operator $(OPERATOR_ARGS)
|
||||
bin/manager $(OPERATOR_ARGS)
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Cleanup any build binaries or packages
|
||||
|
|
@ -309,13 +201,13 @@ container-runtime-login: ## Log in into the Docker repository
|
|||
@echo "+ $@"
|
||||
|
||||
.PHONY: container-runtime-build
|
||||
container-runtime-build: check-env ## Build the container
|
||||
container-runtime-build: check-env deepcopy-gen ## Build the container
|
||||
@echo "+ $@"
|
||||
$(CONTAINER_RUNTIME_COMMAND) build \
|
||||
--build-arg GO_VERSION=$(GO_VERSION) \
|
||||
--build-arg OPERATOR_SDK_VERSION=$(OPERATOR_SDK_VERSION) \
|
||||
--build-arg CTIMEVAR="$(CTIMEVAR)" \
|
||||
-t $(DOCKER_REGISTRY):$(GITCOMMIT) . \
|
||||
--file build/Dockerfile $(CONTAINER_RUNTIME_EXTRA_ARGS)
|
||||
--file Dockerfile $(CONTAINER_RUNTIME_EXTRA_ARGS)
|
||||
|
||||
.PHONY: container-runtime-images
|
||||
container-runtime-images: ## List all local containers
|
||||
|
|
@ -368,27 +260,18 @@ container-runtime-run: ## Run the container in docker, you can use EXTRA_ARGS
|
|||
.PHONY: minikube-run
|
||||
minikube-run: export WATCH_NAMESPACE = $(NAMESPACE)
|
||||
minikube-run: export OPERATOR_NAME = $(NAME)
|
||||
minikube-run: minikube-start ## Run the operator locally and use minikube as Kubernetes cluster, you can use OPERATOR_ARGS
|
||||
minikube-run: minikube-start run ## Run the operator locally and use minikube as Kubernetes cluster, you can use OPERATOR_ARGS
|
||||
@echo "+ $@"
|
||||
kubectl config use-context minikube
|
||||
kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml
|
||||
@echo "Watching '$(WATCH_NAMESPACE)' namespace"
|
||||
build/_output/bin/jenkins-operator $(OPERATOR_ARGS)
|
||||
|
||||
.PHONY: crc-run
|
||||
crc-run: export WATCH_NAMESPACE = $(NAMESPACE)
|
||||
crc-run: export OPERATOR_NAME = $(NAME)
|
||||
crc-run: crc-start ## Run the operator locally and use CodeReady Containers as Kubernetes cluster, you can use OPERATOR_ARGS
|
||||
crc-run: crc-start run ## Run the operator locally and use CodeReady Containers as Kubernetes cluster, you can use OPERATOR_ARGS
|
||||
@echo "+ $@"
|
||||
oc project $(CRC_OC_PROJECT)
|
||||
kubectl apply -f deploy/crds/jenkins_$(API_VERSION)_jenkins_crd.yaml
|
||||
@echo "Watching '$(WATCH_NAMESPACE)' namespace"
|
||||
build/_output/bin/jenkins-operator $(OPERATOR_ARGS)
|
||||
|
||||
.PHONY: deepcopy-gen
|
||||
deepcopy-gen: ## Generate deepcopy golang code
|
||||
deepcopy-gen: generate ## Generate deepcopy golang code
|
||||
@echo "+ $@"
|
||||
operator-sdk generate k8s
|
||||
|
||||
.PHONY: scheme-doc-gen
|
||||
HAS_GEN_CRD_API_REFERENCE_DOCS := $(shell ls gen-crd-api-reference-docs 2> /dev/null)
|
||||
|
|
@ -400,7 +283,7 @@ ifndef HAS_GEN_CRD_API_REFERENCE_DOCS
|
|||
@tar -C $(GEN_CRD_API) -zxf $(GEN_CRD_API)_linux_amd64.tar.gz
|
||||
@rm $(GEN_CRD_API)_linux_amd64.tar.gz
|
||||
endif
|
||||
$(GEN_CRD_API)/$(GEN_CRD_API) -config gen-crd-api-config.json -api-dir github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/$(API_VERSION) -template-dir $(GEN_CRD_API)/template -out-file documentation/$(VERSION)/jenkins-$(API_VERSION)-scheme.md
|
||||
$(GEN_CRD_API)/$(GEN_CRD_API) -config gen-crd-api-config.json -api-dir $(PKG)/api/$(API_VERSION) -template-dir $(GEN_CRD_API)/template -out-file documentation/$(VERSION)/jenkins-$(API_VERSION)-scheme.md
|
||||
|
||||
.PHONY: check-minikube
|
||||
check-minikube: ## Checks if KUBERNETES_PROVIDER is set to minikube
|
||||
|
|
@ -418,23 +301,41 @@ ifneq ($(KUBERNETES_PROVIDER),crc)
|
|||
$(error KUBERNETES_PROVIDER not set to 'crc')
|
||||
endif
|
||||
|
||||
.PHONY: minikube-start
|
||||
minikube-start: check-minikube ## Start minikube
|
||||
.PHONY: minikube
|
||||
HAS_MINIKUBE := $(shell which $(PROJECT_DIR)/bin/minikube)
|
||||
minikube: ## Download minikube if it's not present
|
||||
@echo "+ $@"
|
||||
@minikube status && exit 0 || \
|
||||
minikube start --kubernetes-version $(MINIKUBE_KUBERNETES_VERSION) --dns-domain=$(CLUSTER_DOMAIN) --extra-config=kubelet.cluster-domain=$(CLUSTER_DOMAIN) --vm-driver=$(MINIKUBE_DRIVER) --memory 4096 --cpus 3
|
||||
ifndef HAS_MINIKUBE
|
||||
mkdir -p $(PROJECT_DIR)/bin
|
||||
wget -O $(PROJECT_DIR)/bin/minikube https://github.com/kubernetes/minikube/releases/download/v$(MINIKUBE_VERSION)/minikube-$(PLATFORM)-amd64
|
||||
chmod +x $(PROJECT_DIR)/bin/minikube
|
||||
endif
|
||||
|
||||
.PHONY: minikube-start
|
||||
minikube-start: minikube check-minikube ## Start minikube
|
||||
@echo "+ $@"
|
||||
bin/minikube status && exit 0 || \
|
||||
bin/minikube start --kubernetes-version $(MINIKUBE_KUBERNETES_VERSION) --dns-domain=$(CLUSTER_DOMAIN) --extra-config=kubelet.cluster-domain=$(CLUSTER_DOMAIN) --driver=$(MINIKUBE_DRIVER) --memory 4096 --cpus $(CPUS_NUMBER)
|
||||
|
||||
.PHONY: crc-start
|
||||
crc-start: check-crc ## Start CodeReady Containers Kubernetes cluster
|
||||
@echo "+ $@"
|
||||
crc start
|
||||
|
||||
.PHONY: sembump
|
||||
HAS_SEMBUMP := $(shell which $(PROJECT_DIR)/bin/sembump)
|
||||
sembump: # Download sembump locally if necessary
|
||||
@echo "+ $@"
|
||||
ifndef HAS_SEMBUMP
|
||||
wget -O $(PROJECT_DIR)/bin/sembump https://github.com/justintout/sembump/releases/download/v0.1.0/sembump-$(PLATFORM)-amd64
|
||||
chmod +x $(PROJECT_DIR)/bin/sembump
|
||||
endif
|
||||
|
||||
.PHONY: bump-version
|
||||
BUMP := patch
|
||||
bump-version: ## Bump the version in the version file. Set BUMP to [ patch | major | minor ]
|
||||
bump-version: sembump ## Bump the version in the version file. Set BUMP to [ patch | major | minor ]
|
||||
@echo "+ $@"
|
||||
#@go get -u github.com/jessfraz/junk/sembump # update sembump tool FIXME
|
||||
$(eval NEW_VERSION=$(shell sembump --kind $(BUMP) $(VERSION)))
|
||||
$(eval NEW_VERSION=$(shell bin/sembump --kind $(BUMP) $(VERSION)))
|
||||
@echo "Bumping VERSION.txt from $(VERSION) to $(NEW_VERSION)"
|
||||
echo $(NEW_VERSION) > VERSION.txt
|
||||
@echo "Updating version from $(VERSION) to $(NEW_VERSION) in README.md"
|
||||
|
|
@ -493,8 +394,101 @@ helm-deploy: helm-package
|
|||
helm repo index chart/ --url https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/chart/jenkins-operator/
|
||||
cd chart/ && mv jenkins-operator-*.tgz jenkins-operator
|
||||
|
||||
# Download hugo locally if necessary
|
||||
HUGO = $(shell pwd)/bin/hugo
|
||||
hugo:
|
||||
$(call go-get-tool,$(HUGO),github.com/gohugoio/hugo@v0.62.2)
|
||||
|
||||
.PHONY: generate-docs
|
||||
generate-docs: ## Re-generate docs directory from the website directory
|
||||
generate-docs: hugo ## Re-generate docs directory from the website directory
|
||||
@echo "+ $@"
|
||||
rm -rf docs || echo "Cannot remove docs dir, ignoring"
|
||||
hugo -s website -d ../docs
|
||||
bin/hugo -s website -d ../docs
|
||||
|
||||
.PHONY: all-in-one-build
|
||||
FILENAME := config/all_in_one_$(API_VERSION).yaml
|
||||
all-in-one-build: ## Re-generate all-in-one yaml
|
||||
@echo "+ $@"
|
||||
> $(FILENAME)
|
||||
cat config/rbac/leader_election_role.yaml >> $(FILENAME)
|
||||
cat config/rbac/leader_election_role_binding.yaml >> $(FILENAME)
|
||||
cat config/rbac/role.yaml >> $(FILENAME)
|
||||
cat config/rbac/role_binding.yaml >> $(FILENAME)
|
||||
cat config/manager/manager.yaml >> $(FILENAME)
|
||||
|
||||
##################### FROM OPERATOR SDK ########################
|
||||
# Install CRDs into a cluster
|
||||
install-crds: manifests kustomize
|
||||
$(KUSTOMIZE) build config/crd | kubectl apply -f -
|
||||
|
||||
# Uninstall CRDs from a cluster
|
||||
uninstall-crds: manifests kustomize
|
||||
$(KUSTOMIZE) build config/crd | kubectl delete -f -
|
||||
|
||||
# Deploy controller in the configured Kubernetes cluster in ~/.kube/config
|
||||
deploy: manifests kustomize
|
||||
cd config/manager && $(KUSTOMIZE) edit set image controller=$(DOCKER_REGISTRY):$(GITCOMMIT)
|
||||
$(KUSTOMIZE) build config/default | kubectl apply -f -
|
||||
|
||||
# UnDeploy controller from the configured Kubernetes cluster in ~/.kube/config
|
||||
undeploy:
|
||||
$(KUSTOMIZE) build config/default | kubectl delete -f -
|
||||
|
||||
# Generate manifests e.g. CRD, RBAC etc.
|
||||
manifests: controller-gen all-in-one-build
|
||||
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
|
||||
|
||||
# Generate code
|
||||
generate: controller-gen
|
||||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
||||
|
||||
# Download controller-gen locally if necessary
|
||||
CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
|
||||
controller-gen:
|
||||
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1)
|
||||
|
||||
# Download kustomize locally if necessary
|
||||
KUSTOMIZE = $(shell pwd)/bin/kustomize
|
||||
kustomize:
|
||||
$(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7)
|
||||
|
||||
# go-get-tool will 'go get' any package $2 and install it to $1.
|
||||
define go-get-tool
|
||||
@[ -f $(1) ] || { \
|
||||
set -e ;\
|
||||
TMP_DIR=$$(mktemp -d) ;\
|
||||
cd $$TMP_DIR ;\
|
||||
go mod init tmp ;\
|
||||
echo "Downloading $(2)" ;\
|
||||
GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\
|
||||
rm -rf $$TMP_DIR ;\
|
||||
}
|
||||
endef
|
||||
|
||||
.PHONY: operator-sdk
|
||||
HAS_OPERATOR_SDK := $(shell which $(PROJECT_DIR)/bin/operator-sdk)
|
||||
operator-sdk: # Download operator-sdk locally if necessary
|
||||
@echo "+ $@"
|
||||
ifndef HAS_OPERATOR_SDK
|
||||
wget -O $(PROJECT_DIR)/bin/operator-sdk https://github.com/operator-framework/operator-sdk/releases/download/v1.3.0/operator-sdk_$(PLATFORM)_amd64
|
||||
chmod +x $(PROJECT_DIR)/bin/operator-sdk
|
||||
endif
|
||||
|
||||
# Generate bundle manifests and metadata, then validate generated files.
|
||||
.PHONY: bundle
|
||||
bundle: manifests operator-sdk kustomize
|
||||
bin/operator-sdk generate kustomize manifests -q
|
||||
cd config/manager && $(KUSTOMIZE) edit set image controller=$(DOCKER_ORGANIZATION)/$(DOCKER_REGISTRY):$(VERSION_TAG)
|
||||
$(KUSTOMIZE) build config/manifests | bin/operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS)
|
||||
bin/operator-sdk bundle validate ./bundle
|
||||
|
||||
# Build the bundle image.
|
||||
.PHONY: bundle-build
|
||||
bundle-build:
|
||||
docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) .
|
||||
|
||||
# Download kubebuilder
|
||||
kubebuilder:
|
||||
mkdir -p ${ENVTEST_ASSETS_DIR}
|
||||
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.7.0/hack/setup-envtest.sh
|
||||
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR);
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
domain: jenkins.io
|
||||
layout: go.kubebuilder.io/v3
|
||||
projectName: jenkins-operator
|
||||
repo: github.com/jenkinsci/kubernetes-operator
|
||||
resources:
|
||||
- crdVersion: v1
|
||||
group: jenkins.io
|
||||
kind: Jenkins
|
||||
version: v1alpha2
|
||||
version: 3-alpha
|
||||
plugins:
|
||||
manifests.sdk.operatorframework.io/v2: {}
|
||||
scorecard.sdk.operatorframework.io/v2: {}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// Package v1alpha2 contains API Schema definitions for the jenkins.io v1alpha2 API group
|
||||
// +k8s:deepcopy-gen=package,register
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=jenkins.io
|
||||
package v1alpha2
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// JenkinsSpec defines the desired state of the Jenkins.
|
||||
// JenkinsSpec defines the desired state of Jenkins
|
||||
// +k8s:openapi-gen=true
|
||||
type JenkinsSpec struct {
|
||||
// Master represents Jenkins master pod properties and Jenkins plugins.
|
||||
|
|
@ -264,14 +264,6 @@ type JenkinsMaster struct {
|
|||
// +optional
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
||||
// Annotations is an unstructured key value map stored with a resource that may be
|
||||
// set by external tools to store and retrieve arbitrary metadata. They are not
|
||||
// queryable and should be preserved when modifying objects.
|
||||
// More info: http://kubernetes.io/docs/user-guide/annotations
|
||||
// Deprecated: will be removed in the future, please use Annotations(annotations)
|
||||
// +optional
|
||||
AnnotationsDeprecated map[string]string `json:"masterAnnotations,omitempty"`
|
||||
|
||||
// Map of string keys and values that can be used to organize and categorize
|
||||
// (scope and select) objects. May match selectors of replication controllers
|
||||
// and services.
|
||||
|
|
@ -489,12 +481,13 @@ type JenkinsStatus struct {
|
|||
AppliedGroovyScripts []AppliedGroovyScript `json:"appliedGroovyScripts,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:subresource:status
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Jenkins is the Schema for the jenkins API
|
||||
// +k8s:openapi-gen=true
|
||||
// +kubebuilder:subresource:status
|
||||
type Jenkins struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
|
@ -506,9 +499,10 @@ type Jenkins struct {
|
|||
Status JenkinsStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// JenkinsList contains a list of Jenkins.
|
||||
// JenkinsList contains a list of Jenkins
|
||||
type JenkinsList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
|
|
@ -15,11 +15,17 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects
|
||||
GroupVersion = schema.GroupVersion{Group: "jenkins.io", Version: "v1alpha2"}
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
SchemeGroupVersion = schema.GroupVersion{Group: "jenkins.io", Version: "v1alpha2"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// GetObjectKind returns Jenkins object kind
|
||||
|
|
@ -47,5 +53,4 @@ func JenkinsTypeMeta() metav1.TypeMeta {
|
|||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Jenkins{}, &JenkinsList{})
|
||||
SchemeBuilder.Register(&JenkinsImage{}, &JenkinsImageList{})
|
||||
}
|
||||
|
|
@ -1,11 +1,27 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
// Code generated by operator-sdk. DO NOT EDIT.
|
||||
/*
|
||||
Copyright 2021.
|
||||
|
||||
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 v1alpha2
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
|
@ -13,7 +29,6 @@ import (
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppliedGroovyScript) DeepCopyInto(out *AppliedGroovyScript) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppliedGroovyScript.
|
||||
|
|
@ -30,7 +45,6 @@ func (in *AppliedGroovyScript) DeepCopy() *AppliedGroovyScript {
|
|||
func (in *Backup) DeepCopyInto(out *Backup) {
|
||||
*out = *in
|
||||
in.Action.DeepCopyInto(&out.Action)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Backup.
|
||||
|
|
@ -46,7 +60,6 @@ func (in *Backup) DeepCopy() *Backup {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConfigMapRef) DeepCopyInto(out *ConfigMapRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapRef.
|
||||
|
|
@ -63,7 +76,6 @@ func (in *ConfigMapRef) DeepCopy() *ConfigMapRef {
|
|||
func (in *ConfigurationAsCode) DeepCopyInto(out *ConfigurationAsCode) {
|
||||
*out = *in
|
||||
in.Customization.DeepCopyInto(&out.Customization)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationAsCode.
|
||||
|
|
@ -92,51 +104,50 @@ func (in *Container) DeepCopyInto(out *Container) {
|
|||
}
|
||||
if in.Ports != nil {
|
||||
in, out := &in.Ports, &out.Ports
|
||||
*out = make([]v1.ContainerPort, len(*in))
|
||||
*out = make([]corev1.ContainerPort, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.EnvFrom != nil {
|
||||
in, out := &in.EnvFrom, &out.EnvFrom
|
||||
*out = make([]v1.EnvFromSource, len(*in))
|
||||
*out = make([]corev1.EnvFromSource, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Env != nil {
|
||||
in, out := &in.Env, &out.Env
|
||||
*out = make([]v1.EnvVar, len(*in))
|
||||
*out = make([]corev1.EnvVar, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.VolumeMounts != nil {
|
||||
in, out := &in.VolumeMounts, &out.VolumeMounts
|
||||
*out = make([]v1.VolumeMount, len(*in))
|
||||
*out = make([]corev1.VolumeMount, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.LivenessProbe != nil {
|
||||
in, out := &in.LivenessProbe, &out.LivenessProbe
|
||||
*out = new(v1.Probe)
|
||||
*out = new(corev1.Probe)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ReadinessProbe != nil {
|
||||
in, out := &in.ReadinessProbe, &out.ReadinessProbe
|
||||
*out = new(v1.Probe)
|
||||
*out = new(corev1.Probe)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Lifecycle != nil {
|
||||
in, out := &in.Lifecycle, &out.Lifecycle
|
||||
*out = new(v1.Lifecycle)
|
||||
*out = new(corev1.Lifecycle)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.SecurityContext != nil {
|
||||
in, out := &in.SecurityContext, &out.SecurityContext
|
||||
*out = new(v1.SecurityContext)
|
||||
*out = new(corev1.SecurityContext)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container.
|
||||
|
|
@ -158,7 +169,6 @@ func (in *Customization) DeepCopyInto(out *Customization) {
|
|||
*out = make([]ConfigMapRef, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Customization.
|
||||
|
|
@ -175,7 +185,6 @@ func (in *Customization) DeepCopy() *Customization {
|
|||
func (in *GroovyScripts) DeepCopyInto(out *GroovyScripts) {
|
||||
*out = *in
|
||||
in.Customization.DeepCopyInto(&out.Customization)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroovyScripts.
|
||||
|
|
@ -193,10 +202,9 @@ func (in *Handler) DeepCopyInto(out *Handler) {
|
|||
*out = *in
|
||||
if in.Exec != nil {
|
||||
in, out := &in.Exec, &out.Exec
|
||||
*out = new(v1.ExecAction)
|
||||
*out = new(corev1.ExecAction)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Handler.
|
||||
|
|
@ -209,22 +217,6 @@ func (in *Handler) DeepCopy() *Handler {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Image) DeepCopyInto(out *Image) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Image.
|
||||
func (in *Image) DeepCopy() *Image {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Image)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Jenkins) DeepCopyInto(out *Jenkins) {
|
||||
*out = *in
|
||||
|
|
@ -232,7 +224,6 @@ func (in *Jenkins) DeepCopyInto(out *Jenkins) {
|
|||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Jenkins.
|
||||
|
|
@ -256,7 +247,6 @@ func (in *Jenkins) DeepCopyObject() runtime.Object {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JenkinsAPISettings) DeepCopyInto(out *JenkinsAPISettings) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsAPISettings.
|
||||
|
|
@ -269,110 +259,6 @@ func (in *JenkinsAPISettings) DeepCopy() *JenkinsAPISettings {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JenkinsImage) DeepCopyInto(out *JenkinsImage) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImage.
|
||||
func (in *JenkinsImage) DeepCopy() *JenkinsImage {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JenkinsImage)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JenkinsImage) 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 *JenkinsImageList) DeepCopyInto(out *JenkinsImageList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]JenkinsImage, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImageList.
|
||||
func (in *JenkinsImageList) DeepCopy() *JenkinsImageList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JenkinsImageList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *JenkinsImageList) 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 *JenkinsImageSpec) DeepCopyInto(out *JenkinsImageSpec) {
|
||||
*out = *in
|
||||
out.BaseImage = in.BaseImage
|
||||
if in.Plugins != nil {
|
||||
in, out := &in.Plugins, &out.Plugins
|
||||
*out = make([]JenkinsPlugin, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImageSpec.
|
||||
func (in *JenkinsImageSpec) DeepCopy() *JenkinsImageSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JenkinsImageSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JenkinsImageStatus) DeepCopyInto(out *JenkinsImageStatus) {
|
||||
*out = *in
|
||||
if in.InstalledPlugins != nil {
|
||||
in, out := &in.InstalledPlugins, &out.InstalledPlugins
|
||||
*out = make([]JenkinsPlugin, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsImageStatus.
|
||||
func (in *JenkinsImageStatus) DeepCopy() *JenkinsImageStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JenkinsImageStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JenkinsList) DeepCopyInto(out *JenkinsList) {
|
||||
*out = *in
|
||||
|
|
@ -385,7 +271,6 @@ func (in *JenkinsList) DeepCopyInto(out *JenkinsList) {
|
|||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsList.
|
||||
|
|
@ -416,13 +301,6 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
|
|||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.AnnotationsDeprecated != nil {
|
||||
in, out := &in.AnnotationsDeprecated, &out.AnnotationsDeprecated
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Labels != nil {
|
||||
in, out := &in.Labels, &out.Labels
|
||||
*out = make(map[string]string, len(*in))
|
||||
|
|
@ -439,7 +317,7 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
|
|||
}
|
||||
if in.SecurityContext != nil {
|
||||
in, out := &in.SecurityContext, &out.SecurityContext
|
||||
*out = new(v1.PodSecurityContext)
|
||||
*out = new(corev1.PodSecurityContext)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Containers != nil {
|
||||
|
|
@ -451,19 +329,19 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
|
|||
}
|
||||
if in.ImagePullSecrets != nil {
|
||||
in, out := &in.ImagePullSecrets, &out.ImagePullSecrets
|
||||
*out = make([]v1.LocalObjectReference, len(*in))
|
||||
*out = make([]corev1.LocalObjectReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Volumes != nil {
|
||||
in, out := &in.Volumes, &out.Volumes
|
||||
*out = make([]v1.Volume, len(*in))
|
||||
*out = make([]corev1.Volume, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Tolerations != nil {
|
||||
in, out := &in.Tolerations, &out.Tolerations
|
||||
*out = make([]v1.Toleration, len(*in))
|
||||
*out = make([]corev1.Toleration, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
|
|
@ -478,7 +356,6 @@ func (in *JenkinsMaster) DeepCopyInto(out *JenkinsMaster) {
|
|||
*out = make([]Plugin, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsMaster.
|
||||
|
|
@ -491,22 +368,6 @@ func (in *JenkinsMaster) DeepCopy() *JenkinsMaster {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JenkinsPlugin) DeepCopyInto(out *JenkinsPlugin) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsPlugin.
|
||||
func (in *JenkinsPlugin) DeepCopy() *JenkinsPlugin {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JenkinsPlugin)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) {
|
||||
*out = *in
|
||||
|
|
@ -536,7 +397,6 @@ func (in *JenkinsSpec) DeepCopyInto(out *JenkinsSpec) {
|
|||
}
|
||||
in.ServiceAccount.DeepCopyInto(&out.ServiceAccount)
|
||||
out.JenkinsAPISettings = in.JenkinsAPISettings
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsSpec.
|
||||
|
|
@ -574,7 +434,6 @@ func (in *JenkinsStatus) DeepCopyInto(out *JenkinsStatus) {
|
|||
*out = make([]AppliedGroovyScript, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JenkinsStatus.
|
||||
|
|
@ -591,7 +450,6 @@ func (in *JenkinsStatus) DeepCopy() *JenkinsStatus {
|
|||
func (in *Mailgun) DeepCopyInto(out *Mailgun) {
|
||||
*out = *in
|
||||
out.APIKeySecretKeySelector = in.APIKeySecretKeySelector
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Mailgun.
|
||||
|
|
@ -608,7 +466,6 @@ func (in *Mailgun) DeepCopy() *Mailgun {
|
|||
func (in *MicrosoftTeams) DeepCopyInto(out *MicrosoftTeams) {
|
||||
*out = *in
|
||||
out.WebHookURLSecretKeySelector = in.WebHookURLSecretKeySelector
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MicrosoftTeams.
|
||||
|
|
@ -644,7 +501,6 @@ func (in *Notification) DeepCopyInto(out *Notification) {
|
|||
*out = new(SMTP)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Notification.
|
||||
|
|
@ -660,7 +516,6 @@ func (in *Notification) DeepCopy() *Notification {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Plugin) DeepCopyInto(out *Plugin) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Plugin.
|
||||
|
|
@ -678,7 +533,6 @@ func (in *Restore) DeepCopyInto(out *Restore) {
|
|||
*out = *in
|
||||
in.Action.DeepCopyInto(&out.Action)
|
||||
in.GetLatestAction.DeepCopyInto(&out.GetLatestAction)
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Restore.
|
||||
|
|
@ -696,7 +550,6 @@ func (in *SMTP) DeepCopyInto(out *SMTP) {
|
|||
*out = *in
|
||||
out.UsernameSecretKeySelector = in.UsernameSecretKeySelector
|
||||
out.PasswordSecretKeySelector = in.PasswordSecretKeySelector
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SMTP.
|
||||
|
|
@ -713,7 +566,6 @@ func (in *SMTP) DeepCopy() *SMTP {
|
|||
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
|
||||
*out = *in
|
||||
out.LocalObjectReference = in.LocalObjectReference
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeySelector.
|
||||
|
|
@ -729,7 +581,6 @@ func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SecretRef) DeepCopyInto(out *SecretRef) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretRef.
|
||||
|
|
@ -745,7 +596,6 @@ func (in *SecretRef) DeepCopy() *SecretRef {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SeedJob) DeepCopyInto(out *SeedJob) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SeedJob.
|
||||
|
|
@ -780,7 +630,6 @@ func (in *Service) DeepCopyInto(out *Service) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Service.
|
||||
|
|
@ -803,7 +652,6 @@ func (in *ServiceAccount) DeepCopyInto(out *ServiceAccount) {
|
|||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccount.
|
||||
|
|
@ -820,7 +668,6 @@ func (in *ServiceAccount) DeepCopy() *ServiceAccount {
|
|||
func (in *Slack) DeepCopyInto(out *Slack) {
|
||||
*out = *in
|
||||
out.WebHookURLSecretKeySelector = in.WebHookURLSecretKeySelector
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Slack.
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
ARG GO_VERSION
|
||||
|
||||
# build stage
|
||||
FROM golang:$GO_VERSION-alpine3.11 AS build-stage
|
||||
ARG OPERATOR_SDK_VERSION
|
||||
ENV GO111MODULE=on
|
||||
RUN apk --no-cache add git curl make \
|
||||
&& curl -L https://github.com/operator-framework/operator-sdk/releases/download/v$OPERATOR_SDK_VERSION/operator-sdk-v$OPERATOR_SDK_VERSION-x86_64-linux-gnu -o /usr/local/bin/operator-sdk \
|
||||
&& chmod +x /usr/local/bin/operator-sdk
|
||||
ADD . /kubernetes-operator
|
||||
|
||||
RUN cd /kubernetes-operator && make build
|
||||
|
||||
# run stage
|
||||
FROM alpine:3.10
|
||||
|
||||
USER nobody
|
||||
|
||||
COPY --from=build-stage /kubernetes-operator/build/_output/bin/jenkins-operator /usr/local/bin/jenkins-operator
|
||||
|
||||
CMD [ "/usr/local/bin/jenkins-operator" ]
|
||||
|
|
@ -1,277 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkinsimage"
|
||||
|
||||
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications"
|
||||
e "github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/version"
|
||||
|
||||
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
|
||||
kubemetrics "github.com/operator-framework/operator-sdk/pkg/kube-metrics"
|
||||
"github.com/operator-framework/operator-sdk/pkg/leader"
|
||||
"github.com/operator-framework/operator-sdk/pkg/log/zap"
|
||||
"github.com/operator-framework/operator-sdk/pkg/metrics"
|
||||
sdkVersion "github.com/operator-framework/operator-sdk/version"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
|
||||
)
|
||||
|
||||
// Change below variables to serve metrics on different host or port.
|
||||
var (
|
||||
metricsHost = "0.0.0.0"
|
||||
metricsPort int32 = 8383
|
||||
operatorMetricsPort int32 = 8686
|
||||
)
|
||||
|
||||
var logger = log.Log.WithName("cmd")
|
||||
|
||||
func printInfo() {
|
||||
logger.Info(fmt.Sprintf("Version: %s", version.Version))
|
||||
logger.Info(fmt.Sprintf("Git commit: %s", version.GitCommit))
|
||||
logger.Info(fmt.Sprintf("Go Version: %s", runtime.Version()))
|
||||
logger.Info(fmt.Sprintf("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH))
|
||||
logger.Info(fmt.Sprintf("operator-sdk Version: %v", sdkVersion.Version))
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Add the zap logger flag set to the CLI. The flag set must
|
||||
// be added before calling pflag.Parse().
|
||||
pflag.CommandLine.AddFlagSet(zap.FlagSet())
|
||||
|
||||
// Add flags registered by imported packages (e.g. glog and
|
||||
// controller-runtime)
|
||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||
|
||||
hostname := pflag.String("jenkins-api-hostname", "", "Hostname or IP of Jenkins API. It can be service name, node IP or localhost.")
|
||||
port := pflag.Int("jenkins-api-port", 0, "The port on which Jenkins API is running. Note: If you want to use nodePort don't set this setting and --jenkins-api-use-nodeport must be true.")
|
||||
useNodePort := pflag.Bool("jenkins-api-use-nodeport", false, "Connect to Jenkins API using the service nodePort instead of service port. If you want to set this as true - don't set --jenkins-api-port.")
|
||||
debug := pflag.Bool("debug", false, "Set log level to debug")
|
||||
kubernetesClusterDomain := pflag.String("cluster-domain", "cluster.local", "Use custom domain name instead of 'cluster.local'.")
|
||||
pflag.Parse()
|
||||
|
||||
log.SetupLogger(*debug)
|
||||
printInfo()
|
||||
|
||||
namespace, err := k8sutil.GetWatchNamespace()
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to get watch namespace"), *debug)
|
||||
}
|
||||
logger.Info(fmt.Sprintf("Watch namespace: %v", namespace))
|
||||
|
||||
// get a config to talk to the apiserver
|
||||
cfg, err := config.GetConfig()
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to get config"), *debug)
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
// Become the leader before proceeding
|
||||
err = leader.Become(ctx, "jenkins-operator-lock")
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to become leader"), *debug)
|
||||
}
|
||||
|
||||
// Create a new Cmd to provide shared dependencies and start components
|
||||
mgr, err := manager.New(cfg, manager.Options{
|
||||
Namespace: namespace,
|
||||
MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
|
||||
})
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to create manager"), *debug)
|
||||
}
|
||||
|
||||
logger.Info("Registering Components.")
|
||||
|
||||
// setup Scheme for all resources
|
||||
if err := apis.AddToScheme(mgr.GetScheme()); err != nil {
|
||||
fatal(errors.Wrap(err, "failed to setup scheme"), *debug)
|
||||
}
|
||||
|
||||
// setup events
|
||||
events, err := event.New(cfg, constants.OperatorName)
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to create manager"), *debug)
|
||||
}
|
||||
|
||||
clientSet, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to create Kubernetes client set"), *debug)
|
||||
}
|
||||
|
||||
if resources.IsRouteAPIAvailable(clientSet) {
|
||||
logger.Info("Route API found: Route creation will be performed")
|
||||
}
|
||||
c := make(chan e.Event)
|
||||
go notifications.Listen(c, events, mgr.GetClient())
|
||||
|
||||
// validate jenkins API connection
|
||||
jenkinsAPIConnectionSettings := client.JenkinsAPIConnectionSettings{Hostname: *hostname, Port: *port, UseNodePort: *useNodePort}
|
||||
if err := jenkinsAPIConnectionSettings.Validate(); err != nil {
|
||||
fatal(errors.Wrap(err, "invalid command line parameters"), *debug)
|
||||
}
|
||||
|
||||
// validate kubernetes cluster domain
|
||||
if *kubernetesClusterDomain == "" {
|
||||
fatal(errors.Wrap(err, "Kubernetes cluster domain can't be empty"), *debug)
|
||||
}
|
||||
|
||||
// setup Jenkins controller
|
||||
if err := jenkins.Add(mgr, jenkinsAPIConnectionSettings, *kubernetesClusterDomain, *clientSet, *cfg, &c); err != nil {
|
||||
fatal(errors.Wrap(err, "failed to setup controllers"), *debug)
|
||||
}
|
||||
// setup JenkinsImage controller
|
||||
if err = jenkinsimage.Add(mgr); err != nil {
|
||||
fatal(errors.Wrap(err, "failed to setup controllers"), *debug)
|
||||
}
|
||||
|
||||
if err = serveCRMetrics(cfg); err != nil {
|
||||
logger.V(log.VWarn).Info("Could not generate and serve custom resource metrics", "error", err.Error())
|
||||
}
|
||||
|
||||
// Add to the below struct any other metrics ports you want to expose.
|
||||
servicePorts := []v1.ServicePort{
|
||||
{Port: metricsPort, Name: metrics.OperatorPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: metricsPort}},
|
||||
{Port: operatorMetricsPort, Name: metrics.CRPortName, Protocol: v1.ProtocolTCP, TargetPort: intstr.IntOrString{Type: intstr.Int, IntVal: operatorMetricsPort}},
|
||||
}
|
||||
// Create Service object to expose the metrics port(s).
|
||||
service, err := metrics.CreateMetricsService(ctx, cfg, servicePorts)
|
||||
if err != nil {
|
||||
logger.V(log.VWarn).Info("Could not create metrics Service", "error", err.Error())
|
||||
}
|
||||
|
||||
// CreateServiceMonitors will automatically create the prometheus-operator ServiceMonitor resources
|
||||
// necessary to configure Prometheus to scrape metrics from this operator.
|
||||
services := []*v1.Service{service}
|
||||
_, err = metrics.CreateServiceMonitors(cfg, namespace, services)
|
||||
if err != nil {
|
||||
logger.V(log.VWarn).Info("Could not create ServiceMonitor object", "error", err.Error())
|
||||
// If this operator is deployed to a cluster without the prometheus-operator running, it will return
|
||||
// ErrServiceMonitorNotPresent, which can be used to safely skip ServiceMonitor creation.
|
||||
if err == metrics.ErrServiceMonitorNotPresent {
|
||||
logger.V(log.VWarn).Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("Starting the Cmd.")
|
||||
|
||||
// start the Cmd
|
||||
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
|
||||
fatal(errors.Wrap(err, "failed to start cmd"), *debug)
|
||||
}
|
||||
}
|
||||
|
||||
// serveCRMetrics gets the Operator/CustomResource GVKs and generates metrics based on those types.
|
||||
// It serves those metrics on "http://metricsHost:operatorMetricsPort".
|
||||
func serveCRMetrics(cfg *rest.Config) error {
|
||||
// Below function returns filtered operator/CustomResource specific GVKs.
|
||||
// For more control override the below GVK list with your own custom logic.
|
||||
gvks, err := k8sutil.GetGVKsFromAddToScheme(apis.AddToScheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// We perform our custom GKV filtering on top of the one performed
|
||||
// by operator-sdk code
|
||||
filteredGVK := filterGKVsFromAddToScheme(gvks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Get the namespace the operator is currently deployed in.
|
||||
operatorNs, err := k8sutil.GetOperatorNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// To generate metrics in other namespaces, add the values below.
|
||||
ns := []string{operatorNs}
|
||||
// Generate and serve custom resource specific metrics.
|
||||
return kubemetrics.GenerateAndServeCRMetrics(cfg, ns, filteredGVK, metricsHost, operatorMetricsPort)
|
||||
}
|
||||
|
||||
func filterGKVsFromAddToScheme(gvks []schema.GroupVersionKind) []schema.GroupVersionKind {
|
||||
// We use gkvFilters to filter from the existing GKVs defined in the used
|
||||
// runtime.Schema for the operator. The reason for that is that
|
||||
// kube-metrics tries to list all of the defined Kinds in the schemas
|
||||
// that are passed, including Kinds that the operator doesn't use and
|
||||
// thus the role used the operator doesn't have them set and we don't want
|
||||
// to set as they are not used by the operator.
|
||||
// For the fields that the filters have we have defined the value '*' to
|
||||
// specify any will be a match (accepted)
|
||||
matchAnyValue := "*"
|
||||
gvkFilters := []schema.GroupVersionKind{
|
||||
// Kubernetes Resources
|
||||
{Kind: "PersistentVolumeClaim", Version: matchAnyValue},
|
||||
{Kind: "ServiceAccount", Version: matchAnyValue},
|
||||
{Kind: "Secret", Version: matchAnyValue},
|
||||
{Kind: "Pod", Version: matchAnyValue},
|
||||
{Kind: "ConfigMap", Version: matchAnyValue},
|
||||
{Kind: "Service", Version: matchAnyValue},
|
||||
{Group: "apps", Kind: "Deployment", Version: matchAnyValue},
|
||||
// Openshift Resources
|
||||
{Group: "route.openshift.io", Kind: "Route", Version: matchAnyValue},
|
||||
{Group: "image.openshift.io", Kind: "ImageStream", Version: matchAnyValue},
|
||||
// Custom Resources
|
||||
{Group: "jenkins.io", Kind: "Jenkins", Version: matchAnyValue},
|
||||
{Group: "jenkins.io", Kind: "JenkinsImage", Version: matchAnyValue},
|
||||
}
|
||||
|
||||
ownGVKs := []schema.GroupVersionKind{}
|
||||
for _, gvk := range gvks {
|
||||
for _, gvkFilter := range gvkFilters {
|
||||
match := true
|
||||
if gvkFilter.Kind == matchAnyValue && gvkFilter.Group == matchAnyValue && gvkFilter.Version == matchAnyValue {
|
||||
logger.V(1).Info("gvkFilter should at least have one of its fields defined. Skipping...")
|
||||
match = false
|
||||
} else {
|
||||
if gvkFilter.Kind != matchAnyValue && gvkFilter.Kind != gvk.Kind {
|
||||
match = false
|
||||
}
|
||||
if gvkFilter.Group != matchAnyValue && gvkFilter.Group != gvk.Group {
|
||||
match = false
|
||||
}
|
||||
if gvkFilter.Version != matchAnyValue && gvkFilter.Version != gvk.Version {
|
||||
match = false
|
||||
}
|
||||
}
|
||||
if match {
|
||||
ownGVKs = append(ownGVKs, gvk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ownGVKs
|
||||
}
|
||||
|
||||
func fatal(err error, debug bool) {
|
||||
if debug {
|
||||
logger.Error(nil, fmt.Sprintf("%+v", err))
|
||||
} else {
|
||||
logger.Error(nil, fmt.Sprintf("%s", err))
|
||||
}
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# Setup variables for the Makefile
|
||||
NAME=kubernetes-operator
|
||||
OPERATOR_SDK_VERSION=0.17.0
|
||||
GO_VERSION=1.14.2
|
||||
OPERATOR_SDK_VERSION=1.3.0
|
||||
GO_VERSION=1.15.6
|
||||
PKG=github.com/jenkinsci/kubernetes-operator
|
||||
DOCKER_ORGANIZATION=virtuslab
|
||||
DOCKER_REGISTRY=jenkins-operator
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ KUBERNETES_PROVIDER=minikube
|
|||
|
||||
MINIKUBE_KUBERNETES_VERSION=v1.17.4
|
||||
MINIKUBE_DRIVER=virtualbox
|
||||
MINIKUBE_VERSION=1.4.0
|
||||
MINIKUBE_VERSION=1.17.1
|
||||
KUBECTL_CONTEXT=minikube
|
||||
|
||||
JENKINS_API_HOSTNAME_COMMAND=minikube ip
|
||||
JENKINS_API_HOSTNAME_COMMAND=bin/minikube ip
|
||||
JENKINS_API_PORT=0
|
||||
JENKINS_API_USE_NODEPORT=true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
---
|
||||
# permissions to do leader election.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: leader-election-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
- configmaps
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: leader-election-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
- configmaps
|
||||
- secrets
|
||||
- serviceaccounts
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- update
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- deployments
|
||||
- daemonsets
|
||||
- replicasets
|
||||
- statefulsets
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- rbac.authorization.k8s.io
|
||||
resources:
|
||||
- roles
|
||||
- rolebindings
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods/portforward
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods/log
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- pods/exec
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- watch
|
||||
- list
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resourceNames:
|
||||
- jenkins-operator
|
||||
resources:
|
||||
- deployments/finalizers
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- jenkins.io
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- persistentvolumeclaims
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- "route.openshift.io"
|
||||
resources:
|
||||
- routes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- apiGroups:
|
||||
- "image.openshift.io"
|
||||
resources:
|
||||
- imagestreams
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- "build.openshift.io"
|
||||
resources:
|
||||
- builds
|
||||
- buildconfigs
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: jenkins-operator
|
||||
namespace: default
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
securityContext:
|
||||
runAsUser: 65532
|
||||
containers:
|
||||
- command:
|
||||
- /manager
|
||||
args:
|
||||
- --leader-elect
|
||||
image: virtuslab/jenkins-operator:v0.5.0
|
||||
name: jenkins-operator
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
env:
|
||||
- name: WATCH_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
terminationGracePeriodSeconds: 10
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# The following manifests contain a self-signed issuer CR and a certificate CR.
|
||||
# More document can be found at https://docs.cert-manager.io
|
||||
# WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Issuer
|
||||
metadata:
|
||||
name: selfsigned-issuer
|
||||
namespace: default
|
||||
spec:
|
||||
selfSigned: {}
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
|
||||
namespace: default
|
||||
spec:
|
||||
# $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize
|
||||
dnsNames:
|
||||
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc
|
||||
- $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local
|
||||
issuerRef:
|
||||
kind: Issuer
|
||||
name: selfsigned-issuer
|
||||
secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
resources:
|
||||
- certificate.yaml
|
||||
|
||||
configurations:
|
||||
- kustomizeconfig.yaml
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# This configuration is for teaching kustomize how to update name ref and var substitution
|
||||
nameReference:
|
||||
- kind: Issuer
|
||||
group: cert-manager.io
|
||||
fieldSpecs:
|
||||
- kind: Certificate
|
||||
group: cert-manager.io
|
||||
path: spec/issuerRef/name
|
||||
|
||||
varReference:
|
||||
- kind: Certificate
|
||||
group: cert-manager.io
|
||||
path: spec/commonName
|
||||
- kind: Certificate
|
||||
group: cert-manager.io
|
||||
path: spec/dnsNames
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,21 @@
|
|||
# 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/jenkins.io_jenkins.yaml
|
||||
# +kubebuilder:scaffold:crdkustomizeresource
|
||||
|
||||
patchesStrategicMerge:
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
|
||||
# patches here are for enabling the conversion webhook for each CRD
|
||||
#- patches/webhook_in_jenkins.yaml
|
||||
# +kubebuilder:scaffold:crdkustomizewebhookpatch
|
||||
|
||||
# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
|
||||
# patches here are for enabling the CA injection for each CRD
|
||||
#- patches/cainjection_in_jenkins.yaml
|
||||
# +kubebuilder:scaffold:crdkustomizecainjectionpatch
|
||||
|
||||
# the following config is for teaching kustomize how to do kustomization for CRDs.
|
||||
configurations:
|
||||
- kustomizeconfig.yaml
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
|
||||
nameReference:
|
||||
- kind: Service
|
||||
version: v1
|
||||
fieldSpecs:
|
||||
- kind: CustomResourceDefinition
|
||||
version: v1
|
||||
group: apiextensions.k8s.io
|
||||
path: spec/conversion/webhook/clientConfig/service/name
|
||||
|
||||
namespace:
|
||||
- kind: CustomResourceDefinition
|
||||
version: v1
|
||||
group: apiextensions.k8s.io
|
||||
path: spec/conversion/webhook/clientConfig/service/namespace
|
||||
create: false
|
||||
|
||||
varReference:
|
||||
- path: metadata/annotations
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# The following patch adds a directive for certmanager to inject CA into the CRD
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
|
||||
name: jenkins.jenkins.io
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# The following patch enables a conversion webhook for the CRD
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: jenkins.jenkins.io
|
||||
spec:
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
service:
|
||||
namespace: default
|
||||
name: webhook-service
|
||||
path: /convert
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# Adds namespace to all resources.
|
||||
namespace: jenkins-operator
|
||||
|
||||
# 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: jenkins-operator-
|
||||
|
||||
# Labels to add to all resources and selectors.
|
||||
#commonLabels:
|
||||
# someName: someValue
|
||||
|
||||
bases:
|
||||
- ../crd
|
||||
- ../rbac
|
||||
- ../manager
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
#- ../webhook
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
|
||||
#- ../certmanager
|
||||
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
|
||||
#- ../prometheus
|
||||
|
||||
patchesStrategicMerge:
|
||||
# Protect the /metrics endpoint by putting it behind auth.
|
||||
# If you want your controller-manager to expose the /metrics
|
||||
# endpoint w/o any authn/z, please comment the following line.
|
||||
- manager_auth_proxy_patch.yaml
|
||||
|
||||
# Mount the controller config file for loading manager configurations
|
||||
# through a ComponentConfig type
|
||||
#- manager_config_patch.yaml
|
||||
|
||||
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
|
||||
# crd/kustomization.yaml
|
||||
#- manager_webhook_patch.yaml
|
||||
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
|
||||
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
|
||||
# 'CERTMANAGER' needs to be enabled to use ca injection
|
||||
#- webhookcainjection_patch.yaml
|
||||
|
||||
# the following config is for teaching kustomize how to do var substitution
|
||||
vars:
|
||||
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
|
||||
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
|
||||
# objref:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# name: serving-cert # this name should match the one in certificate.yaml
|
||||
# fieldref:
|
||||
# fieldpath: metadata.namespace
|
||||
#- name: CERTIFICATE_NAME
|
||||
# objref:
|
||||
# kind: Certificate
|
||||
# group: cert-manager.io
|
||||
# version: v1
|
||||
# name: serving-cert # this name should match the one in certificate.yaml
|
||||
#- name: SERVICE_NAMESPACE # namespace of the service
|
||||
# objref:
|
||||
# kind: Service
|
||||
# version: v1
|
||||
# name: webhook-service
|
||||
# fieldref:
|
||||
# fieldpath: metadata.namespace
|
||||
#- name: SERVICE_NAME
|
||||
# objref:
|
||||
# kind: Service
|
||||
# version: v1
|
||||
# name: webhook-service
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# This patch inject a sidecar container which is a HTTP proxy for the
|
||||
# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: kube-rbac-proxy
|
||||
image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
|
||||
args:
|
||||
- "--secure-listen-address=0.0.0.0:8443"
|
||||
- "--upstream=http://127.0.0.1:8080/"
|
||||
- "--logtostderr=true"
|
||||
- "--v=10"
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
- name: manager
|
||||
args:
|
||||
- "--health-probe-bind-address=:8081"
|
||||
- "--metrics-bind-address=127.0.0.1:8080"
|
||||
- "--leader-elect"
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: controller-manager
|
||||
namespace: default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: manager
|
||||
args:
|
||||
- "--config=controller_manager_config.yaml"
|
||||
volumeMounts:
|
||||
- name: manager-config
|
||||
mountPath: /controller_manager_config.yaml
|
||||
subPath: controller_manager_config.yaml
|
||||
volumes:
|
||||
- name: manager-config
|
||||
configMap:
|
||||
name: manager-config
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
|
||||
kind: ControllerManagerConfig
|
||||
health:
|
||||
healthProbeBindAddress: :8081
|
||||
metrics:
|
||||
bindAddress: 127.0.0.1:8080
|
||||
webhook:
|
||||
port: 9443
|
||||
leaderElection:
|
||||
leaderElect: true
|
||||
resourceName: 9cf053ac.jenkins.io
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
resources:
|
||||
- manager.yaml
|
||||
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
|
||||
configMapGenerator:
|
||||
- files:
|
||||
- controller_manager_config.yaml
|
||||
name: manager-config
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
images:
|
||||
- name: controller
|
||||
newName: controller
|
||||
newTag: latest
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: jenkins-operator
|
||||
namespace: default
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
spec:
|
||||
securityContext:
|
||||
runAsUser: 65532
|
||||
containers:
|
||||
- command:
|
||||
- /manager
|
||||
args:
|
||||
- --leader-elect
|
||||
image: virtuslab/jenkins-operator:v0.5.0
|
||||
name: jenkins-operator
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 30Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 20Mi
|
||||
env:
|
||||
- name: WATCH_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
terminationGracePeriodSeconds: 10
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
resources:
|
||||
- monitor.yaml
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
# Prometheus Monitor Service (Metrics)
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: controller-manager-metrics-monitor
|
||||
namespace: default
|
||||
spec:
|
||||
endpoints:
|
||||
- path: /metrics
|
||||
port: https
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: metrics-reader
|
||||
rules:
|
||||
- nonResourceURLs: ["/metrics"]
|
||||
verbs: ["get"]
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: proxy-role
|
||||
rules:
|
||||
- apiGroups: ["authentication.k8s.io"]
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs: ["create"]
|
||||
- apiGroups: ["authorization.k8s.io"]
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs: ["create"]
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: proxy-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: proxy-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
name: controller-manager-metrics-service
|
||||
namespace: default
|
||||
spec:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
targetPort: https
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# permissions for end users to edit jenkins.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: jenkins-editor-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- jenkins.io
|
||||
resources:
|
||||
- jenkins
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- jenkins.io
|
||||
resources:
|
||||
- jenkins/status
|
||||
verbs:
|
||||
- get
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# permissions for end users to view jenkins.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: jenkins-viewer-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- jenkins.io
|
||||
resources:
|
||||
- jenkins
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- jenkins.io
|
||||
resources:
|
||||
- jenkins/status
|
||||
verbs:
|
||||
- get
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
resources:
|
||||
- role.yaml
|
||||
- role_binding.yaml
|
||||
- leader_election_role.yaml
|
||||
- leader_election_role_binding.yaml
|
||||
# Comment the following 4 lines if you want to disable
|
||||
# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
|
||||
# which protects your /metrics endpoint.
|
||||
- auth_proxy_service.yaml
|
||||
- auth_proxy_role.yaml
|
||||
- auth_proxy_role_binding.yaml
|
||||
- auth_proxy_client_clusterrole.yaml
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
# permissions to do leader election.
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: leader-election-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
- configmaps
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: leader-election-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: leader-election-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: manager-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- services
|
||||
- configmaps
|
||||
- secrets
|
||||
- serviceaccounts
|
||||
verbs:
|
||||
- get
|
||||
- create
|
||||
- update
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- deployments
|
||||
- daemonsets
|
||||
- replicasets
|
||||
- statefulsets
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- rbac.authorization.k8s.io
|
||||
resources:
|
||||
- roles
|
||||
- rolebindings
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods/portforward
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods/log
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- pods/exec
|
||||
verbs:
|
||||
- "*"
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- watch
|
||||
- list
|
||||
- create
|
||||
- patch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resourceNames:
|
||||
- jenkins-operator
|
||||
resources:
|
||||
- deployments/finalizers
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- jenkins.io
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- persistentvolumeclaims
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- "route.openshift.io"
|
||||
resources:
|
||||
- routes
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- apiGroups:
|
||||
- "image.openshift.io"
|
||||
resources:
|
||||
- imagestreams
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- "build.openshift.io"
|
||||
resources:
|
||||
- builds
|
||||
- buildconfigs
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: manager-rolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: manager-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
apiVersion: jenkins.io/v1alpha2
|
||||
kind: Jenkins
|
||||
metadata:
|
||||
name: example
|
||||
namespace: default
|
||||
spec:
|
||||
configurationAsCode:
|
||||
configurations: []
|
||||
secret:
|
||||
name: ""
|
||||
groovyScripts:
|
||||
configurations: []
|
||||
secret:
|
||||
name: ""
|
||||
jenkinsAPISettings:
|
||||
authorizationStrategy: createUser
|
||||
master:
|
||||
disableCSRFProtection: false
|
||||
containers:
|
||||
- name: jenkins-master
|
||||
image: jenkins/jenkins:2.263.3-lts-alpine
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 12
|
||||
httpGet:
|
||||
path: /login
|
||||
port: http
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 100
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 5
|
||||
readinessProbe:
|
||||
failureThreshold: 10
|
||||
httpGet:
|
||||
path: /login
|
||||
port: http
|
||||
scheme: HTTP
|
||||
initialDelaySeconds: 80
|
||||
periodSeconds: 10
|
||||
successThreshold: 1
|
||||
timeoutSeconds: 1
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1500m
|
||||
memory: 3Gi
|
||||
requests:
|
||||
cpu: "1"
|
||||
memory: 500Mi
|
||||
seedJobs:
|
||||
- id: jenkins-operator
|
||||
targets: "cicd/jobs/*.jenkins"
|
||||
description: "Jenkins Operator repository"
|
||||
repositoryBranch: master
|
||||
repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
## Append samples you want in your CSV to this file as resources ##
|
||||
resources:
|
||||
- jenkins.io_v1alpha2_jenkins.yaml
|
||||
# +kubebuilder:scaffold:manifestskustomizesamples
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
apiVersion: scorecard.operatorframework.io/v1alpha3
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: config
|
||||
stages:
|
||||
- parallel: true
|
||||
tests: []
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
resources:
|
||||
- bases/config.yaml
|
||||
patchesJson6902:
|
||||
- path: patches/basic.config.yaml
|
||||
target:
|
||||
group: scorecard.operatorframework.io
|
||||
version: v1alpha3
|
||||
kind: Configuration
|
||||
name: config
|
||||
- path: patches/olm.config.yaml
|
||||
target:
|
||||
group: scorecard.operatorframework.io
|
||||
version: v1alpha3
|
||||
kind: Configuration
|
||||
name: config
|
||||
# +kubebuilder:scaffold:patchesJson6902
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
- op: add
|
||||
path: /stages/0/tests/-
|
||||
value:
|
||||
entrypoint:
|
||||
- scorecard-test
|
||||
- basic-check-spec
|
||||
image: quay.io/operator-framework/scorecard-test:v1.3.0
|
||||
labels:
|
||||
suite: basic
|
||||
test: basic-check-spec-test
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
- op: add
|
||||
path: /stages/0/tests/-
|
||||
value:
|
||||
entrypoint:
|
||||
- scorecard-test
|
||||
- olm-bundle-validation
|
||||
image: quay.io/operator-framework/scorecard-test:v1.3.0
|
||||
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.3.0
|
||||
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.3.0
|
||||
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.3.0
|
||||
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.3.0
|
||||
labels:
|
||||
suite: olm
|
||||
test: olm-status-descriptors-test
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package jenkins
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
|
||||
|
|
@ -20,14 +20,14 @@ import (
|
|||
type enqueueRequestForJenkins struct{}
|
||||
|
||||
func (e *enqueueRequestForJenkins) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
if req := e.getOwnerReconcileRequests(evt.Meta); req != nil {
|
||||
if req := e.getOwnerReconcileRequests(evt.Object); req != nil {
|
||||
q.Add(*req)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *enqueueRequestForJenkins) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
req1 := e.getOwnerReconcileRequests(evt.MetaOld)
|
||||
req2 := e.getOwnerReconcileRequests(evt.MetaNew)
|
||||
req1 := e.getOwnerReconcileRequests(evt.ObjectOld)
|
||||
req2 := e.getOwnerReconcileRequests(evt.ObjectNew)
|
||||
|
||||
if req1 != nil || req2 != nil {
|
||||
jenkinsName := "unknown"
|
||||
|
|
@ -39,7 +39,7 @@ func (e *enqueueRequestForJenkins) Update(evt event.UpdateEvent, q workqueue.Rat
|
|||
}
|
||||
|
||||
log.Log.WithValues("cr", jenkinsName).Info(
|
||||
fmt.Sprintf("%T/%s has been updated", evt.ObjectNew, evt.MetaNew.GetName()))
|
||||
fmt.Sprintf("%T/%s has been updated", evt.ObjectNew, evt.ObjectNew.GetName()))
|
||||
}
|
||||
|
||||
if req1 != nil {
|
||||
|
|
@ -52,13 +52,13 @@ func (e *enqueueRequestForJenkins) Update(evt event.UpdateEvent, q workqueue.Rat
|
|||
}
|
||||
|
||||
func (e *enqueueRequestForJenkins) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
if req := e.getOwnerReconcileRequests(evt.Meta); req != nil {
|
||||
if req := e.getOwnerReconcileRequests(evt.Object); req != nil {
|
||||
q.Add(*req)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *enqueueRequestForJenkins) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
if req := e.getOwnerReconcileRequests(evt.Meta); req != nil {
|
||||
if req := e.getOwnerReconcileRequests(evt.Object); req != nil {
|
||||
q.Add(*req)
|
||||
}
|
||||
}
|
||||
|
|
@ -85,8 +85,8 @@ func (e *jenkinsDecorator) Create(evt event.CreateEvent, q workqueue.RateLimitin
|
|||
|
||||
func (e *jenkinsDecorator) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
if !reflect.DeepEqual(evt.ObjectOld.(*v1alpha2.Jenkins).Spec, evt.ObjectNew.(*v1alpha2.Jenkins).Spec) {
|
||||
log.Log.WithValues("cr", evt.MetaNew.GetName()).Info(
|
||||
fmt.Sprintf("%T/%s has been updated", evt.ObjectNew, evt.MetaNew.GetName()))
|
||||
log.Log.WithValues("cr", evt.ObjectNew.GetName()).Info(
|
||||
fmt.Sprintf("%T/%s has been updated", evt.ObjectNew, evt.ObjectNew.GetName()))
|
||||
}
|
||||
e.handler.Update(evt, q)
|
||||
}
|
||||
|
|
@ -1,4 +1,20 @@
|
|||
package jenkins
|
||||
/*
|
||||
Copyright 2021.
|
||||
|
||||
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 controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
|
@ -7,8 +23,9 @@ import (
|
|||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/user"
|
||||
|
|
@ -17,15 +34,17 @@ import (
|
|||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/plugins"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
|
@ -37,7 +56,6 @@ type reconcileError struct {
|
|||
|
||||
const (
|
||||
APIVersion = "core/v1"
|
||||
PodKind = "Pod"
|
||||
SecretKind = "Secret"
|
||||
ConfigMapKind = "ConfigMap"
|
||||
containerProbeURI = "login"
|
||||
|
|
@ -46,66 +64,59 @@ const (
|
|||
|
||||
var reconcileErrors = map[string]reconcileError{}
|
||||
var logx = log.Log
|
||||
var _ reconcile.Reconciler = &ReconcileJenkins{}
|
||||
|
||||
// Add creates a newReconcilierConfiguration Jenkins Controller and adds it to the Manager. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, kubernetesClusterDomain string, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) error {
|
||||
reconciler := newReconciler(mgr, jenkinsAPIConnectionSettings, kubernetesClusterDomain, clientSet, config, notificationEvents)
|
||||
return add(mgr, reconciler)
|
||||
// JenkinsReconciler reconciles a Jenkins object
|
||||
type JenkinsReconciler struct {
|
||||
Client client.Client
|
||||
Scheme *runtime.Scheme
|
||||
JenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings
|
||||
ClientSet kubernetes.Clientset
|
||||
Config rest.Config
|
||||
NotificationEvents *chan event.Event
|
||||
KubernetesClusterDomain string
|
||||
}
|
||||
|
||||
// add adds a newReconcilierConfiguration Controller to mgr with r as the reconcile.Reconciler.
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a newReconcilierConfiguration controller
|
||||
c, err := controller.New("jenkins-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// Watch for changes to primary resource Jenkins
|
||||
decorator := jenkinsDecorator{handler: &handler.EnqueueRequestForObject{}}
|
||||
err = c.Watch(&source.Kind{Type: &v1alpha2.Jenkins{}}, &decorator)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// Watch for changes to secondary resource Pods and requeue the owner Jenkins
|
||||
|
||||
podResource := &source.Kind{Type: &corev1.Pod{TypeMeta: metav1.TypeMeta{APIVersion: APIVersion, Kind: PodKind}}}
|
||||
err = c.Watch(podResource, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &v1alpha2.Jenkins{},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
secretResource := &source.Kind{Type: &corev1.Secret{TypeMeta: metav1.TypeMeta{APIVersion: APIVersion, Kind: SecretKind}}}
|
||||
err = c.Watch(secretResource, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &v1alpha2.Jenkins{},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// SetupWithManager sets up the controller with the Manager.
|
||||
func (r *JenkinsReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||
jenkinsHandler := &enqueueRequestForJenkins{}
|
||||
err = c.Watch(secretResource, jenkinsHandler)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
configMapResource := &source.Kind{Type: &corev1.ConfigMap{TypeMeta: metav1.TypeMeta{APIVersion: APIVersion, Kind: ConfigMapKind}}}
|
||||
err = c.Watch(configMapResource, jenkinsHandler)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
return nil
|
||||
secretResource := &source.Kind{Type: &corev1.Secret{TypeMeta: metav1.TypeMeta{APIVersion: APIVersion, Kind: SecretKind}}}
|
||||
decorator := jenkinsDecorator{handler: &handler.EnqueueRequestForObject{}}
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&v1alpha2.Jenkins{}).
|
||||
Owns(&corev1.Pod{}).
|
||||
Owns(&corev1.Secret{}).
|
||||
Owns(&corev1.ConfigMap{}).
|
||||
Watches(secretResource, jenkinsHandler).
|
||||
Watches(configMapResource, jenkinsHandler).
|
||||
Watches(&source.Kind{Type: &v1alpha2.Jenkins{}}, &decorator).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
// Reconcile it's a main reconciliation loop which maintain desired state based on Jenkins.Spec.
|
||||
func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
func (r *JenkinsReconciler) newJenkinsReconcilier(jenkins *v1alpha2.Jenkins) configuration.Configuration {
|
||||
config := configuration.Configuration{
|
||||
Client: r.Client,
|
||||
ClientSet: r.ClientSet,
|
||||
Notifications: r.NotificationEvents,
|
||||
Jenkins: jenkins,
|
||||
Scheme: r.Scheme,
|
||||
Config: &r.Config,
|
||||
JenkinsAPIConnectionSettings: r.JenkinsAPIConnectionSettings,
|
||||
KubernetesClusterDomain: r.KubernetesClusterDomain,
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=jenkins.io,resources=jenkins,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=jenkins.io,resources=jenkins/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=jenkins.io,resources=jenkins/finalizers,verbs=update
|
||||
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch
|
||||
// +kubebuilder:rbac:groups=v1,resources=secrets,verbs=get;list;watch
|
||||
|
||||
// For more details, check Reconcile and its Result here:
|
||||
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.7.0/pkg/reconcile
|
||||
func (r *JenkinsReconciler) Reconcile(_ context.Context, request ctrl.Request) (ctrl.Result, error) {
|
||||
reconcileFailLimit := uint64(10)
|
||||
logger := logx.WithValues("cr", request.Name)
|
||||
logger.V(log.VDebug).Info("Reconciling Jenkins")
|
||||
|
|
@ -131,18 +142,18 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul
|
|||
reconcileErrors[request.Name] = lastErrors
|
||||
if lastErrors.counter >= reconcileFailLimit {
|
||||
if log.Debug {
|
||||
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed %d times with the same error, giving up: %+v", reconcileFailLimit, err))
|
||||
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed %d times with the same errors, giving up: %+v", reconcileFailLimit, err))
|
||||
} else {
|
||||
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed %d times with the same error, giving up: %s", reconcileFailLimit, err))
|
||||
logger.V(log.VWarn).Info(fmt.Sprintf("Reconcile loop failed %d times with the same errors, giving up: %s", reconcileFailLimit, err))
|
||||
}
|
||||
|
||||
*r.notificationEvents <- event.Event{
|
||||
*r.NotificationEvents <- event.Event{
|
||||
Jenkins: *jenkins,
|
||||
Phase: event.PhaseBase,
|
||||
Level: v1alpha2.NotificationLevelWarning,
|
||||
Reason: reason.NewReconcileLoopFailed(
|
||||
reason.OperatorSource,
|
||||
[]string{fmt.Sprintf("Reconcile loop failed %d times with the same error, giving up: %s", reconcileFailLimit, err)},
|
||||
[]string{fmt.Sprintf("Reconcile loop failed %d times with the same errors, giving up: %s", reconcileFailLimit, err)},
|
||||
),
|
||||
}
|
||||
return reconcile.Result{Requeue: false}, nil
|
||||
|
|
@ -155,7 +166,7 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul
|
|||
}
|
||||
|
||||
if groovyErr, ok := err.(*jenkinsclient.GroovyScriptExecutionFailed); ok {
|
||||
*r.notificationEvents <- event.Event{
|
||||
*r.NotificationEvents <- event.Event{
|
||||
Jenkins: *jenkins,
|
||||
Phase: event.PhaseBase,
|
||||
Level: v1alpha2.NotificationLevelWarning,
|
||||
|
|
@ -175,12 +186,12 @@ func (r *ReconcileJenkins) Reconcile(request reconcile.Request) (reconcile.Resul
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Result, *v1alpha2.Jenkins, error) {
|
||||
func (r *JenkinsReconciler) reconcile(request reconcile.Request) (reconcile.Result, *v1alpha2.Jenkins, error) {
|
||||
logger := logx.WithValues("cr", request.Name)
|
||||
// Fetch the Jenkins instance
|
||||
jenkins := &v1alpha2.Jenkins{}
|
||||
var err error
|
||||
err = r.client.Get(context.TODO(), request.NamespacedName, jenkins)
|
||||
err = r.Client.Get(context.TODO(), request.NamespacedName, jenkins)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
// Request object not found, could have been deleted after reconcile request.
|
||||
|
|
@ -200,17 +211,9 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Resul
|
|||
return reconcile.Result{Requeue: true}, jenkins, nil
|
||||
}
|
||||
|
||||
requeue, err = r.handleDeprecatedData(jenkins)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, jenkins, err
|
||||
}
|
||||
if requeue {
|
||||
return reconcile.Result{Requeue: true}, jenkins, nil
|
||||
}
|
||||
|
||||
config := r.newReconcilierConfiguration(jenkins)
|
||||
config := r.newJenkinsReconcilier(jenkins)
|
||||
// Reconcile base configuration
|
||||
baseConfiguration := base.New(config, r.jenkinsAPIConnectionSettings)
|
||||
baseConfiguration := base.New(config, r.JenkinsAPIConnectionSettings)
|
||||
|
||||
var baseMessages []string
|
||||
baseMessages, err = baseConfiguration.Validate(jenkins)
|
||||
|
|
@ -219,7 +222,7 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Resul
|
|||
}
|
||||
if len(baseMessages) > 0 {
|
||||
message := "Validation of base configuration failed, please correct Jenkins CR."
|
||||
*r.notificationEvents <- event.Event{
|
||||
*r.NotificationEvents <- event.Event{
|
||||
Jenkins: *jenkins,
|
||||
Phase: event.PhaseBase,
|
||||
Level: v1alpha2.NotificationLevelWarning,
|
||||
|
|
@ -248,14 +251,14 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Resul
|
|||
if jenkins.Status.BaseConfigurationCompletedTime == nil {
|
||||
now := metav1.Now()
|
||||
jenkins.Status.BaseConfigurationCompletedTime = &now
|
||||
err = r.client.Update(context.TODO(), jenkins)
|
||||
err = r.Client.Status().Update(context.TODO(), jenkins)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, jenkins, errors.WithStack(err)
|
||||
}
|
||||
|
||||
message := fmt.Sprintf("Base configuration phase is complete, took %s",
|
||||
jenkins.Status.BaseConfigurationCompletedTime.Sub(jenkins.Status.ProvisionStartTime.Time))
|
||||
*r.notificationEvents <- event.Event{
|
||||
*r.NotificationEvents <- event.Event{
|
||||
Jenkins: *jenkins,
|
||||
Phase: event.PhaseBase,
|
||||
Level: v1alpha2.NotificationLevelInfo,
|
||||
|
|
@ -274,7 +277,7 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Resul
|
|||
}
|
||||
if len(messages) > 0 {
|
||||
message := "Validation of user configuration failed, please correct Jenkins CR"
|
||||
*r.notificationEvents <- event.Event{
|
||||
*r.NotificationEvents <- event.Event{
|
||||
Jenkins: *jenkins,
|
||||
Phase: event.PhaseUser,
|
||||
Level: v1alpha2.NotificationLevelWarning,
|
||||
|
|
@ -309,13 +312,13 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Resul
|
|||
if jenkins.Status.UserConfigurationCompletedTime == nil {
|
||||
now := metav1.Now()
|
||||
jenkins.Status.UserConfigurationCompletedTime = &now
|
||||
err = r.client.Update(context.TODO(), jenkins)
|
||||
err = r.Client.Status().Update(context.TODO(), jenkins)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, jenkins, errors.WithStack(err)
|
||||
}
|
||||
message := fmt.Sprintf("User configuration phase is complete, took %s",
|
||||
jenkins.Status.UserConfigurationCompletedTime.Sub(jenkins.Status.ProvisionStartTime.Time))
|
||||
*r.notificationEvents <- event.Event{
|
||||
*r.NotificationEvents <- event.Event{
|
||||
Jenkins: *jenkins,
|
||||
Phase: event.PhaseUser,
|
||||
Level: v1alpha2.NotificationLevelInfo,
|
||||
|
|
@ -326,7 +329,7 @@ func (r *ReconcileJenkins) reconcile(request reconcile.Request) (reconcile.Resul
|
|||
return reconcile.Result{}, jenkins, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha2.Jenkins) (requeue bool, err error) {
|
||||
func (r *JenkinsReconciler) setDefaults(jenkins *v1alpha2.Jenkins) (requeue bool, err error) {
|
||||
changed := false
|
||||
logger := logx.WithValues("cr", jenkins.Name)
|
||||
|
||||
|
|
@ -356,7 +359,7 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha2.Jenkins) (requeue bool,
|
|||
if jenkinsContainer.ReadinessProbe == nil {
|
||||
logger.Info("Setting default Jenkins readinessProbe")
|
||||
changed = true
|
||||
jenkinsContainer.ReadinessProbe = resources.NewSimpleProbe(containerProbeURI, containerProbePortName, corev1.URISchemeHTTP, 30)
|
||||
jenkinsContainer.ReadinessProbe = resources.NewProbe(containerProbeURI, containerProbePortName, corev1.URISchemeHTTP, 60, 1, 10)
|
||||
}
|
||||
if jenkinsContainer.LivenessProbe == nil {
|
||||
logger.Info("Setting default Jenkins livenessProbe")
|
||||
|
|
@ -390,7 +393,7 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha2.Jenkins) (requeue bool,
|
|||
logger.Info("Setting default Jenkins master service")
|
||||
changed = true
|
||||
var serviceType = corev1.ServiceTypeClusterIP
|
||||
if r.jenkinsAPIConnectionSettings.UseNodePort {
|
||||
if r.JenkinsAPIConnectionSettings.UseNodePort {
|
||||
serviceType = corev1.ServiceTypeNodePort
|
||||
}
|
||||
jenkins.Spec.Service = v1alpha2.Service{
|
||||
|
|
@ -441,7 +444,7 @@ func (r *ReconcileJenkins) setDefaults(jenkins *v1alpha2.Jenkins) (requeue bool,
|
|||
}
|
||||
|
||||
if changed {
|
||||
return changed, errors.WithStack(r.client.Update(context.TODO(), jenkins))
|
||||
return changed, errors.WithStack(r.Client.Update(context.TODO(), jenkins))
|
||||
}
|
||||
return changed, nil
|
||||
}
|
||||
|
|
@ -455,7 +458,7 @@ func isJavaOpsVariableNotSet(container v1alpha2.Container) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkins) setDefaultsForContainer(jenkins *v1alpha2.Jenkins, containerName string, containerIndex int) bool {
|
||||
func (r *JenkinsReconciler) setDefaultsForContainer(jenkins *v1alpha2.Jenkins, containerName string, containerIndex int) bool {
|
||||
changed := false
|
||||
logger := logx.WithValues("cr", jenkins.Name, "container", containerName)
|
||||
|
||||
|
|
@ -482,18 +485,3 @@ func basePlugins() (result []v1alpha2.Plugin) {
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkins) handleDeprecatedData(jenkins *v1alpha2.Jenkins) (requeue bool, err error) {
|
||||
changed := false
|
||||
logger := logx.WithValues("cr", jenkins.Name)
|
||||
if len(jenkins.Spec.Master.AnnotationsDeprecated) > 0 {
|
||||
changed = true
|
||||
jenkins.Spec.Master.Annotations = jenkins.Spec.Master.AnnotationsDeprecated
|
||||
jenkins.Spec.Master.AnnotationsDeprecated = map[string]string{}
|
||||
logger.V(log.VWarn).Info("spec.master.masterAnnotations is deprecated, the annotations have been moved to spec.master.annotations")
|
||||
}
|
||||
if changed {
|
||||
return changed, errors.WithStack(r.client.Update(context.TODO(), jenkins))
|
||||
}
|
||||
return changed, nil
|
||||
}
|
||||
82
go.mod
82
go.mod
|
|
@ -1,75 +1,29 @@
|
|||
module github.com/jenkinsci/kubernetes-operator
|
||||
|
||||
go 1.13
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/bndr/gojenkins v0.0.0-20181125150310-de43c03cf849
|
||||
github.com/bndr/gojenkins v1.0.1
|
||||
github.com/docker/distribution v2.7.1+incompatible
|
||||
github.com/elazarl/goproxy v0.0.0-20190711103511-473e67f1d7d2 // indirect
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 // indirect
|
||||
github.com/emersion/go-sasl v0.0.0-20190817083125-240c8404624e // indirect
|
||||
github.com/emersion/go-smtp v0.11.2
|
||||
github.com/go-logr/logr v0.1.0
|
||||
github.com/go-logr/zapr v0.1.1
|
||||
github.com/go-openapi/spec v0.19.4
|
||||
github.com/golang/mock v1.3.1
|
||||
github.com/golangci/golangci-lint v1.26.0 // indirect
|
||||
github.com/mailgun/mailgun-go/v3 v3.6.0
|
||||
github.com/openshift/api v3.9.1-0.20190924102528-32369d4db2ad+incompatible
|
||||
github.com/operator-framework/operator-sdk v0.17.0
|
||||
github.com/go-logr/logr v0.3.0
|
||||
github.com/go-logr/zapr v0.2.0
|
||||
github.com/golang/mock v1.4.1
|
||||
github.com/mailgun/mailgun-go/v3 v3.6.4
|
||||
github.com/onsi/ginkgo v1.14.1
|
||||
github.com/onsi/gomega v1.10.2
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/openshift/api v3.9.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/robfig/cron v1.2.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.5.1
|
||||
go.uber.org/zap v1.14.1
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8 // indirect
|
||||
github.com/stretchr/testify v1.6.1
|
||||
go.uber.org/zap v1.15.0
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
k8s.io/api v0.17.4
|
||||
k8s.io/apimachinery v0.17.4
|
||||
k8s.io/cli-runtime v0.17.4
|
||||
k8s.io/client-go v12.0.0+incompatible
|
||||
k8s.io/code-generator v0.17.4
|
||||
k8s.io/gengo v0.0.0-20191010091904-7fa3014cb28f
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a
|
||||
k8s.io/utils v0.0.0-20190801114015-581e00157fb1
|
||||
sigs.k8s.io/controller-runtime v0.5.2
|
||||
sigs.k8s.io/controller-tools v0.2.8
|
||||
)
|
||||
|
||||
// Pinned to kubernetes-1.16.2
|
||||
replace (
|
||||
github.com/Azure/go-autorest => github.com/Azure/go-autorest v12.2.0+incompatible
|
||||
k8s.io/api => k8s.io/api v0.0.0-20191016110408-35e52d86657a
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.0.0-20191016113550-5357c4baaf65
|
||||
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20191004115801-a2eda9f80ab8
|
||||
k8s.io/apiserver => k8s.io/apiserver v0.0.0-20191016112112-5190913f932d
|
||||
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20191016114015-74ad18325ed5
|
||||
k8s.io/client-go => k8s.io/client-go v0.0.0-20191016111102-bec269661e48
|
||||
k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20191016115326-20453efc2458
|
||||
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.0.0-20191016115129-c07a134afb42
|
||||
k8s.io/component-base => k8s.io/component-base v0.0.0-20191016111319-039242c015a9
|
||||
k8s.io/cri-api => k8s.io/cri-api v0.0.0-20190828162817-608eb1dad4ac
|
||||
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.0.0-20191016115521-756ffa5af0bd
|
||||
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.0.0-20191016112429-9587704a8ad4
|
||||
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.0.0-20191016114939-2b2b218dc1df
|
||||
k8s.io/kube-proxy => k8s.io/kube-proxy v0.0.0-20191016114407-2e83b6f20229
|
||||
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.0.0-20191016114748-65049c67a58b
|
||||
k8s.io/kubectl => k8s.io/kubectl v0.0.0-20191016120415-2ed914427d51
|
||||
k8s.io/kubelet => k8s.io/kubelet v0.0.0-20191016114556-7841ed97f1b2
|
||||
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.0.0-20191016115753-cf0698c3a16b
|
||||
k8s.io/metrics => k8s.io/metrics v0.0.0-20191016113814-3b1a734dba6e
|
||||
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.0.0-20191016112829-06bb3c9d77c9
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/coreos/prometheus-operator => github.com/coreos/prometheus-operator v0.35.1
|
||||
github.com/docker/docker => github.com/moby/moby v0.7.3-0.20190826074503-38ab9da00309
|
||||
github.com/operator-framework/operator-sdk => github.com/operator-framework/operator-sdk v0.17.0
|
||||
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20181117043124-c2090bec4d9b
|
||||
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20180711000925-0cf8f7e6ed1d
|
||||
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.4.0
|
||||
sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde
|
||||
k8s.io/api v0.20.2
|
||||
k8s.io/apimachinery v0.20.2
|
||||
k8s.io/cli-runtime v0.20.2
|
||||
k8s.io/client-go v0.20.2
|
||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
|
||||
sigs.k8s.io/controller-runtime v0.7.0
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
Copyright 2021.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
Copyright 2021.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
r "runtime"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/controllers"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications"
|
||||
e "github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/version"
|
||||
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
|
||||
// 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"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
var (
|
||||
metricsHost = "0.0.0.0"
|
||||
metricsPort int32 = 8383
|
||||
scheme = runtime.NewScheme()
|
||||
logger = logf.Log.WithName("cmd")
|
||||
)
|
||||
|
||||
func printInfo() {
|
||||
logger.Info(fmt.Sprintf("Version: %s", version.Version))
|
||||
logger.Info(fmt.Sprintf("Git commit: %s", version.GitCommit))
|
||||
logger.Info(fmt.Sprintf("Go Version: %s", r.Version()))
|
||||
logger.Info(fmt.Sprintf("Go OS/Arch: %s/%s", r.GOOS, r.GOARCH))
|
||||
}
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
utilruntime.Must(v1alpha2.AddToScheme(scheme))
|
||||
utilruntime.Must(routev1.AddToScheme(scheme))
|
||||
utilruntime.Must(corev1.AddToScheme(scheme))
|
||||
// +kubebuilder:scaffold:scheme
|
||||
}
|
||||
|
||||
func main() {
|
||||
var metricsAddr string
|
||||
var enableLeaderElection bool
|
||||
var probeAddr string
|
||||
|
||||
isRunningInCluster, err := resources.IsRunningInCluster()
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to get watch namespace"), true)
|
||||
}
|
||||
|
||||
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
|
||||
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
|
||||
flag.BoolVar(&enableLeaderElection, "leader-elect", isRunningInCluster, "Enable leader election for controller manager. "+
|
||||
"Enabling this will ensure there is only one active controller manager.")
|
||||
hostname := flag.String("jenkins-api-hostname", "", "Hostname or IP of Jenkins API. It can be service name, node IP or localhost.")
|
||||
port := flag.Int("jenkins-api-port", 0, "The port on which Jenkins API is running. Note: If you want to use nodePort don't set this setting and --jenkins-api-use-nodeport must be true.")
|
||||
useNodePort := flag.Bool("jenkins-api-use-nodeport", false, "Connect to Jenkins API using the service nodePort instead of service port. If you want to set this as true - don't set --jenkins-api-port.")
|
||||
kubernetesClusterDomain := flag.String("cluster-domain", "cluster.local", "Use custom domain name instead of 'cluster.local'.")
|
||||
opts := zap.Options{
|
||||
Development: true,
|
||||
}
|
||||
opts.BindFlags(flag.CommandLine)
|
||||
flag.Parse()
|
||||
|
||||
debug := &opts.Development
|
||||
log.Debug = *debug
|
||||
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
|
||||
printInfo()
|
||||
|
||||
namespace, found := os.LookupEnv("WATCH_NAMESPACE")
|
||||
if !found {
|
||||
fatal(errors.New("failed to get watch namespace, please set up WATCH_NAMESPACE environment variable"), *debug)
|
||||
}
|
||||
logger.Info(fmt.Sprintf("Watch namespace: %v", namespace))
|
||||
|
||||
// get a config to talk to the API server
|
||||
cfg, err := config.GetConfig()
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to get config"), *debug)
|
||||
}
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
Scheme: scheme,
|
||||
MetricsBindAddress: fmt.Sprintf("%s:%d", metricsHost, metricsPort),
|
||||
Port: 9443,
|
||||
HealthProbeBindAddress: probeAddr,
|
||||
LeaderElection: enableLeaderElection,
|
||||
LeaderElectionID: "c674355f.jenkins.io",
|
||||
})
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "unable to start manager"), *debug)
|
||||
}
|
||||
|
||||
// setup events
|
||||
events, err := event.New(cfg, constants.OperatorName)
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to setup events"), *debug)
|
||||
}
|
||||
|
||||
//Setup controller
|
||||
clientSet, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
fatal(errors.Wrap(err, "failed to create Kubernetes client set"), *debug)
|
||||
}
|
||||
|
||||
if resources.IsRouteAPIAvailable(clientSet) {
|
||||
logger.Info("Route API found: Route creation will be performed")
|
||||
}
|
||||
notificationEvents := make(chan e.Event)
|
||||
go notifications.Listen(notificationEvents, events, mgr.GetClient())
|
||||
|
||||
// validate jenkins API connection
|
||||
jenkinsAPIConnectionSettings := client.JenkinsAPIConnectionSettings{Hostname: *hostname, Port: *port, UseNodePort: *useNodePort}
|
||||
if err := jenkinsAPIConnectionSettings.Validate(); err != nil {
|
||||
fatal(errors.Wrap(err, "invalid command line parameters"), *debug)
|
||||
}
|
||||
|
||||
// validate kubernetes cluster domain
|
||||
if *kubernetesClusterDomain == "" {
|
||||
fatal(errors.Wrap(err, "Kubernetes cluster domain can't be empty"), *debug)
|
||||
}
|
||||
|
||||
if err = (&controllers.JenkinsReconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
JenkinsAPIConnectionSettings: jenkinsAPIConnectionSettings,
|
||||
ClientSet: *clientSet,
|
||||
Config: *cfg,
|
||||
NotificationEvents: ¬ificationEvents,
|
||||
KubernetesClusterDomain: *kubernetesClusterDomain,
|
||||
}).SetupWithManager(mgr); err != nil {
|
||||
fatal(errors.Wrap(err, "unable to create Jenkins controller"), *debug)
|
||||
}
|
||||
|
||||
// +kubebuilder:scaffold:builder
|
||||
|
||||
if err := mgr.AddHealthzCheck("health", healthz.Ping); err != nil {
|
||||
fatal(errors.Wrap(err, "unable to set up health check"), *debug)
|
||||
}
|
||||
if err := mgr.AddReadyzCheck("check", healthz.Ping); err != nil {
|
||||
fatal(errors.Wrap(err, "unable to set up ready check"), *debug)
|
||||
}
|
||||
|
||||
logger.Info("starting manager")
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
fatal(errors.Wrap(err, "problem running manager"), *debug)
|
||||
}
|
||||
}
|
||||
|
||||
func fatal(err error, debug bool) {
|
||||
if debug {
|
||||
logger.Error(nil, fmt.Sprintf("%+v", err))
|
||||
} else {
|
||||
logger.Error(nil, fmt.Sprintf("%s", err))
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package apis
|
||||
|
||||
import (
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// AddToSchemes may be used to add all resources defined in the project to a Scheme.
|
||||
var AddToSchemes runtime.SchemeBuilder
|
||||
|
||||
// AddToScheme adds all Resources to the Scheme.
|
||||
func AddToScheme(s *runtime.Scheme) error {
|
||||
return AddToSchemes.AddToScheme(s)
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
|
||||
AddToSchemes = append(AddToSchemes, v1alpha2.SchemeBuilder.AddToScheme)
|
||||
AddToSchemes = append(AddToSchemes, routev1.Install)
|
||||
AddToSchemes = append(AddToSchemes, appsv1.AddToScheme)
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package v1alpha2
|
||||
|
||||
import (
|
||||
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.
|
||||
|
||||
// JenkinsImageSpec defines the desired state of JenkinsImage
|
||||
type JenkinsImageSpec struct {
|
||||
BaseImage Image `json:"image"`
|
||||
Plugins []JenkinsPlugin `json:"plugins"` // Plugins list
|
||||
}
|
||||
|
||||
// Defines Jenkins Plugin structure
|
||||
type JenkinsPlugin struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// Defines Jenkins Plugin structure
|
||||
type Image struct {
|
||||
Name string `json:"name"`
|
||||
Tag string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// JenkinsImageStatus defines the observed state of JenkinsImage
|
||||
type JenkinsImageStatus struct {
|
||||
Image string `json:"image,omitempty"`
|
||||
MD5Sum string `json:"md5sum,omitempty"`
|
||||
InstalledPlugins []JenkinsPlugin `json:"installedPlugins,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// JenkinsImage is the Schema for the jenkinsimages API
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:resource:path=jenkinsimages,scope=Namespaced
|
||||
type JenkinsImage struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
Spec JenkinsImageSpec `json:"spec,omitempty"`
|
||||
Status JenkinsImageStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// JenkinsImageList contains a list of JenkinsImage
|
||||
type JenkinsImageList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []JenkinsImage `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&JenkinsImage{}, &JenkinsImageList{})
|
||||
}
|
||||
|
|
@ -1,275 +0,0 @@
|
|||
// +build !ignore_autogenerated
|
||||
|
||||
// This file was autogenerated by openapi-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
spec "github.com/go-openapi/spec"
|
||||
common "k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
|
||||
return map[string]common.OpenAPIDefinition{
|
||||
"github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Jenkins": schema_pkg_apis_jenkins_v1alpha2_Jenkins(ref),
|
||||
"github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsSpec": schema_pkg_apis_jenkins_v1alpha2_JenkinsSpec(ref),
|
||||
"github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsStatus": schema_pkg_apis_jenkins_v1alpha2_JenkinsStatus(ref),
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_jenkins_v1alpha2_Jenkins(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Jenkins is the Schema for the jenkins API",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
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{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
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{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Spec defines the desired state of the Jenkins",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Status defines the observed state of Jenkins",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsSpec", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_jenkins_v1alpha2_JenkinsSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "JenkinsSpec defines the desired state of the Jenkins",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"master": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Master represents Jenkins master pod properties and Jenkins plugins. Every single change here requires a pod restart.",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsMaster"),
|
||||
},
|
||||
},
|
||||
"seedJobs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "SeedJobs defines list of Jenkins Seed Job configurations More info: https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-seed-jobs-and-pipelines",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.SeedJob"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"notifications": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Notifications defines list of a services which are used to inform about Jenkins status Can be used to integrate chat services like Slack, Microsoft Teams or Mailgun",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Notification"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"service": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Service is Kubernetes service of Jenkins master HTTP pod Defaults to : port: 8080 type: ClusterIP",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Service"),
|
||||
},
|
||||
},
|
||||
"slaveService": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Service is Kubernetes service of Jenkins slave pods Defaults to : port: 50000 type: ClusterIP",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Service"),
|
||||
},
|
||||
},
|
||||
"backup": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Backup defines configuration of Jenkins backup More info: https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-backup-and-restore",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Backup"),
|
||||
},
|
||||
},
|
||||
"restore": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Backup defines configuration of Jenkins backup restore More info: https://github.com/jenkinsci/kubernetes-operator/blob/master/docs/getting-started.md#configure-backup-and-restore",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Restore"),
|
||||
},
|
||||
},
|
||||
"groovyScripts": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "GroovyScripts defines configuration of Jenkins customization via groovy scripts",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.GroovyScripts"),
|
||||
},
|
||||
},
|
||||
"configurationAsCode": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ConfigurationAsCode defines configuration of Jenkins customization via Configuration as Code Jenkins plugin",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.ConfigurationAsCode"),
|
||||
},
|
||||
},
|
||||
"roles": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Roles defines list of extra RBAC roles for the Jenkins Master pod service account",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("k8s.io/api/rbac/v1.RoleRef"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"serviceAccount": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ServiceAccount defines Jenkins master service account attributes",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.ServiceAccount"),
|
||||
},
|
||||
},
|
||||
"jenkinsAPISettings": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "JenkinsAPISettings defines configuration used by the operator to gain admin access to the Jenkins API",
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsAPISettings"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"master", "jenkinsAPISettings"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Backup", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.ConfigurationAsCode", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.GroovyScripts", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsAPISettings", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.JenkinsMaster", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Notification", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Restore", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.SeedJob", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Service", "github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.ServiceAccount", "k8s.io/api/rbac/v1.RoleRef"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_jenkins_v1alpha2_JenkinsStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "JenkinsStatus defines the observed state of Jenkins",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"operatorVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "OperatorVersion is the operator version which manages this CR",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"provisionStartTime": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ProvisionStartTime is a time when Jenkins master pod has been created",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"baseConfigurationCompletedTime": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "BaseConfigurationCompletedTime is a time when Jenkins base configuration phase has been completed",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"userConfigurationCompletedTime": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UserConfigurationCompletedTime is a time when Jenkins user configuration phase has been completed",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"restoredBackup": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "RestoredBackup is the restored backup number after Jenkins master pod restart",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"lastBackup": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "LastBackup is the latest backup number",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"pendingBackup": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "PendingBackup is the pending backup number",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"backupDoneBeforePodDeletion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "BackupDoneBeforePodDeletion tells if backup before pod deletion has been made",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"userAndPasswordHash": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "UserAndPasswordHash is a SHA256 hash made from user and password",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"createdSeedJobs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "CreatedSeedJobs contains list of seed job id already created in Jenkins",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"appliedGroovyScripts": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "AppliedGroovyScripts is a list with all applied groovy scripts in Jenkins by the operator",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.AppliedGroovyScript"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"github.com/kubernetes-operator/pkg/apis/jenkins/v1alpha2.AppliedGroovyScript", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
|
@ -132,7 +132,7 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error
|
|||
bar.logger.V(log.VDebug).Info("Skipping restore backup")
|
||||
if jenkins.Status.PendingBackup == 0 {
|
||||
jenkins.Status.PendingBackup = 1
|
||||
return bar.Client.Update(context.TODO(), jenkins)
|
||||
return bar.Client.Status().Update(context.TODO(), jenkins)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error
|
|||
bar.logger.V(log.VDebug).Info("Skipping restore backup, get latest action returned -1")
|
||||
jenkins.Status.LastBackup = 0
|
||||
jenkins.Status.PendingBackup = 1
|
||||
return bar.Client.Update(context.TODO(), jenkins)
|
||||
return bar.Client.Status().Update(context.TODO(), jenkins)
|
||||
}
|
||||
|
||||
backupNumber, err = strconv.ParseUint(backupNumberString, 10, 64)
|
||||
|
|
@ -180,11 +180,25 @@ func (bar *BackupAndRestore) Restore(jenkinsClient jenkinsclient.Jenkins) error
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//TODO fix me because we're doing two saves unatomically
|
||||
jenkins.Spec.Restore.RecoveryOnce = 0
|
||||
err = bar.Client.Update(context.TODO(), jenkins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := types.NamespacedName{
|
||||
Namespace: jenkins.Namespace,
|
||||
Name: jenkins.Name,
|
||||
}
|
||||
err = bar.Client.Get(context.TODO(), key, jenkins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bar.Configuration.Jenkins = jenkins
|
||||
|
||||
jenkins.Status.RestoredBackup = backupNumber
|
||||
jenkins.Status.PendingBackup = backupNumber + 1
|
||||
return bar.Client.Update(context.TODO(), jenkins)
|
||||
return bar.Client.Status().Update(context.TODO(), jenkins)
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -216,7 +230,7 @@ func (bar *BackupAndRestore) Backup(setBackupDoneBeforePodDeletion bool) error {
|
|||
jenkins.Status.LastBackup = backupNumber
|
||||
jenkins.Status.PendingBackup = backupNumber
|
||||
jenkins.Status.BackupDoneBeforePodDeletion = setBackupDoneBeforePodDeletion
|
||||
return bar.Client.Update(context.TODO(), jenkins)
|
||||
return bar.Client.Status().Update(context.TODO(), jenkins)
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
@ -234,7 +248,7 @@ func triggerBackup(ticker *time.Ticker, k8sClient k8s.Client, logger logr.Logger
|
|||
}
|
||||
if jenkins.Status.LastBackup == jenkins.Status.PendingBackup {
|
||||
jenkins.Status.PendingBackup++
|
||||
err = k8sClient.Update(context.TODO(), jenkins)
|
||||
err = k8sClient.Status().Update(context.TODO(), jenkins)
|
||||
if err != nil {
|
||||
logger.V(log.VWarn).Info(fmt.Sprintf("backup trigger, error when updating CR: %s", err))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createScriptsConfigMap(meta metav1.ObjectMeta) error {
|
||||
configMap, err := resources.NewScriptsConfigMap(meta, r.Configuration.Jenkins)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -15,7 +15,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createScriptsConfigMap(meta metav1.O
|
|||
return stackerr.WithStack(r.CreateOrUpdateResource(configMap))
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createInitConfigurationConfigMap(meta metav1.ObjectMeta) error {
|
||||
configMap, err := resources.NewInitConfigurationConfigMap(meta, r.Configuration.Jenkins)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -23,7 +23,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createInitConfigurationConfigMap(met
|
|||
return stackerr.WithStack(r.CreateOrUpdateResource(configMap))
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createBaseConfigurationConfigMap(meta metav1.ObjectMeta) error {
|
||||
configMap, err := resources.NewBaseConfigurationConfigMap(meta, r.Configuration.Jenkins, r.KubernetesClusterDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) compareContainers(expected corev1.Container, actual corev1.Container) (messages []string, verbose []string) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) compareContainers(expected corev1.Container, actual corev1.Container) (messages []string, verbose []string) {
|
||||
if !reflect.DeepEqual(expected.Args, actual.Args) {
|
||||
messages = append(messages, "Arguments have changed")
|
||||
verbose = append(verbose, fmt.Sprintf("Arguments have changed to '%+v' in container '%s'", expected.Args, expected.Name))
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason"
|
||||
|
|
@ -16,7 +16,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsDeployment(meta metav1.ObjectMeta) (reconcile.Result, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsDeployment(meta metav1.ObjectMeta) (reconcile.Result, error) {
|
||||
userAndPasswordHash, err := r.calculateUserAndPasswordHash()
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package base
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
||||
stackerr "github.com/pkg/errors"
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) addLabelForWatchesResources(customization v1alpha2.Customization) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) addLabelForWatchesResources(customization v1alpha2.Customization) error {
|
||||
labelsForWatchedResources := resources.BuildLabelsForWatchedResources(*r.Configuration.Jenkins)
|
||||
|
||||
if len(customization.Secret.Name) > 0 {
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@ package base
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/plugins"
|
||||
|
||||
"github.com/bndr/gojenkins"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/plugins"
|
||||
stackerr "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) verifyPlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) verifyPlugins(jenkinsClient jenkinsclient.Jenkins) (bool, error) {
|
||||
allPluginsInJenkins, err := jenkinsClient.GetPlugins(fetchAllPlugins)
|
||||
if err != nil {
|
||||
return false, stackerr.WithStack(err)
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/backuprestore"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason"
|
||||
"github.com/jenkinsci/kubernetes-operator/version"
|
||||
|
|
@ -20,7 +19,7 @@ import (
|
|||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) checkForPodRecreation(currentJenkinsMasterPod corev1.Pod, userAndPasswordHash string) reason.Reason {
|
||||
func (r *JenkinsBaseConfigurationReconciler) checkForPodRecreation(currentJenkinsMasterPod corev1.Pod, userAndPasswordHash string) reason.Reason {
|
||||
var messages []string
|
||||
var verbose []string
|
||||
|
||||
|
|
@ -52,7 +51,14 @@ func (r *ReconcileJenkinsBaseConfiguration) checkForPodRecreation(currentJenkins
|
|||
r.Configuration.Jenkins.Status.OperatorVersion, version.Version))
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(r.Configuration.Jenkins.Spec.Master.SecurityContext, currentJenkinsMasterPod.Spec.SecurityContext) {
|
||||
//FIXME too hacky
|
||||
var jenkinsSecurityContext *corev1.PodSecurityContext
|
||||
if r.Configuration.Jenkins.Spec.Master.SecurityContext == nil {
|
||||
jenkinsSecurityContext = &corev1.PodSecurityContext{}
|
||||
} else {
|
||||
jenkinsSecurityContext = r.Configuration.Jenkins.Spec.Master.SecurityContext
|
||||
}
|
||||
if !reflect.DeepEqual(jenkinsSecurityContext, currentJenkinsMasterPod.Spec.SecurityContext) {
|
||||
messages = append(messages, "Jenkins pod security context has changed")
|
||||
verbose = append(verbose, fmt.Sprintf("Jenkins pod security context has changed, actual '%+v' required '%+v'",
|
||||
currentJenkinsMasterPod.Spec.SecurityContext, r.Configuration.Jenkins.Spec.Master.SecurityContext))
|
||||
|
|
@ -140,7 +146,7 @@ func (r *ReconcileJenkinsBaseConfiguration) checkForPodRecreation(currentJenkins
|
|||
return reason.NewPodRestart(reason.OperatorSource, messages, verbose...)
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.ObjectMeta) (reconcile.Result, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) ensureJenkinsMasterPod(meta metav1.ObjectMeta) (reconcile.Result, error) {
|
||||
userAndPasswordHash, err := r.calculateUserAndPasswordHash()
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
|
|
@ -162,13 +168,6 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.O
|
|||
return reconcile.Result{}, stackerr.WithStack(err)
|
||||
}
|
||||
|
||||
currentJenkinsMasterPod, err := r.waitUntilCreateJenkinsMasterPod()
|
||||
if err == nil {
|
||||
r.handleAdmissionControllerChanges(currentJenkinsMasterPod)
|
||||
} else {
|
||||
r.logger.V(log.VWarn).Info(fmt.Sprintf("waitUntilCreateJenkinsMasterPod has failed: %s", err))
|
||||
}
|
||||
|
||||
now := metav1.Now()
|
||||
r.Configuration.Jenkins.Status = v1alpha2.JenkinsStatus{
|
||||
OperatorVersion: version.Version,
|
||||
|
|
@ -177,7 +176,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureJenkinsMasterPod(meta metav1.O
|
|||
PendingBackup: r.Configuration.Jenkins.Status.LastBackup,
|
||||
UserAndPasswordHash: userAndPasswordHash,
|
||||
}
|
||||
return reconcile.Result{Requeue: true}, r.Client.Update(context.TODO(), r.Configuration.Jenkins)
|
||||
return reconcile.Result{Requeue: true}, r.Client.Status().Update(context.TODO(), r.Configuration.Jenkins)
|
||||
} else if err != nil && !apierrors.IsNotFound(err) {
|
||||
return reconcile.Result{}, stackerr.WithStack(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ import (
|
|||
|
||||
stackerr "github.com/pkg/errors"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createRBAC(meta metav1.ObjectMeta) error {
|
||||
err := r.createServiceAccount(meta)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -38,13 +39,16 @@ func (r *ReconcileJenkinsBaseConfiguration) createRBAC(meta metav1.ObjectMeta) e
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) ensureExtraRBAC(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) ensureExtraRBAC(meta metav1.ObjectMeta) error {
|
||||
var err error
|
||||
var name string
|
||||
for _, roleRef := range r.Configuration.Jenkins.Spec.Roles {
|
||||
name = getExtraRoleBindingName(meta.Name, roleRef)
|
||||
roleBinding := resources.NewRoleBinding(name, meta.Namespace, meta.Name, roleRef)
|
||||
err = r.CreateOrUpdateResource(roleBinding)
|
||||
err := r.Client.Create(context.TODO(), roleBinding)
|
||||
if err != nil && errors.IsAlreadyExists(err) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return stackerr.WithStack(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/bndr/gojenkins"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
|
||||
"github.com/bndr/gojenkins"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
|
@ -161,12 +162,12 @@ func TestCompareVolumes(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
||||
func TestJenkinsBaseConfigurationReconciler_verifyPlugins(t *testing.T) {
|
||||
log.SetupLogger(true)
|
||||
|
||||
t.Run("happy, empty base and user plugins", func(t *testing.T) {
|
||||
jenkins := &v1alpha2.Jenkins{}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -194,7 +195,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -238,7 +239,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -275,7 +276,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -312,7 +313,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -349,7 +350,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -386,7 +387,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -415,7 +416,7 @@ func TestReconcileJenkinsBaseConfiguration_verifyPlugins(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
r := ReconcileJenkinsBaseConfiguration{
|
||||
r := JenkinsBaseConfigurationReconciler{
|
||||
logger: log.Log,
|
||||
Configuration: configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -618,7 +619,7 @@ func TestEnsureExtraRBAC(t *testing.T) {
|
|||
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
// given
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -654,7 +655,7 @@ func TestEnsureExtraRBAC(t *testing.T) {
|
|||
clusterRoleKind := "ClusterRole"
|
||||
t.Run("one extra", func(t *testing.T) {
|
||||
// given
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -695,7 +696,7 @@ func TestEnsureExtraRBAC(t *testing.T) {
|
|||
})
|
||||
t.Run("two extra", func(t *testing.T) {
|
||||
// given
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -743,7 +744,7 @@ func TestEnsureExtraRBAC(t *testing.T) {
|
|||
})
|
||||
t.Run("delete one extra", func(t *testing.T) {
|
||||
// given
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -801,8 +802,8 @@ func TestEnsureExtraRBAC(t *testing.T) {
|
|||
roleBindings, err := fetchAllRoleBindings(fakeClient)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(roleBindings.Items))
|
||||
assert.Equal(t, metaObject.Name, roleBindings.Items[1].Name)
|
||||
assert.Equal(t, jenkins.Spec.Roles[0], roleBindings.Items[2].RoleRef)
|
||||
assert.Equal(t, metaObject.Name, roleBindings.Items[0].Name)
|
||||
assert.Equal(t, jenkins.Spec.Roles[0], roleBindings.Items[1].RoleRef)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
|
@ -33,15 +33,15 @@ const (
|
|||
)
|
||||
|
||||
// ReconcileJenkinsBaseConfiguration defines values required for Jenkins base configuration.
|
||||
type ReconcileJenkinsBaseConfiguration struct {
|
||||
type JenkinsBaseConfigurationReconciler struct {
|
||||
configuration.Configuration
|
||||
logger logr.Logger
|
||||
jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings
|
||||
}
|
||||
|
||||
// New create structure which takes care of base configuration
|
||||
func New(config configuration.Configuration, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings) *ReconcileJenkinsBaseConfiguration {
|
||||
return &ReconcileJenkinsBaseConfiguration{
|
||||
func New(config configuration.Configuration, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings) *JenkinsBaseConfigurationReconciler {
|
||||
return &JenkinsBaseConfigurationReconciler{
|
||||
Configuration: config,
|
||||
logger: log.Log.WithValues("cr", config.Jenkins.Name),
|
||||
jenkinsAPIConnectionSettings: jenkinsAPIConnectionSettings,
|
||||
|
|
@ -49,7 +49,7 @@ func New(config configuration.Configuration, jenkinsAPIConnectionSettings jenkin
|
|||
}
|
||||
|
||||
// Reconcile takes care of base configuration.
|
||||
func (r *ReconcileJenkinsBaseConfiguration) Reconcile() (reconcile.Result, jenkinsclient.Jenkins, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) Reconcile() (reconcile.Result, jenkinsclient.Jenkins, error) {
|
||||
metaObject := resources.NewResourceObjectMeta(r.Configuration.Jenkins)
|
||||
|
||||
// Create Necessary Resources
|
||||
|
|
@ -134,7 +134,7 @@ func useDeploymentForJenkinsMaster(jenkins *v1alpha2.Jenkins) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod(metaObject metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) ensureResourcesRequiredForJenkinsPod(metaObject metav1.ObjectMeta) error {
|
||||
if err := r.createOperatorCredentialsSecret(metaObject); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -197,7 +197,7 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureResourcesRequiredForJenkinsPod
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createOperatorCredentialsSecret(meta metav1.ObjectMeta) error {
|
||||
found := &corev1.Secret{}
|
||||
err := r.Configuration.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, found)
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ func (r *ReconcileJenkinsBaseConfiguration) createOperatorCredentialsSecret(meta
|
|||
return stackerr.WithStack(r.UpdateResource(resources.NewOperatorCredentialsSecret(meta, r.Configuration.Jenkins)))
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) calculateUserAndPasswordHash() (string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) calculateUserAndPasswordHash() (string, error) {
|
||||
credentialsSecret := &corev1.Secret{}
|
||||
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: resources.GetOperatorCredentialsSecretName(r.Configuration.Jenkins), Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, credentialsSecret)
|
||||
if err != nil {
|
||||
|
|
@ -222,8 +222,14 @@ func (r *ReconcileJenkinsBaseConfiguration) calculateUserAndPasswordHash() (stri
|
|||
}
|
||||
|
||||
hash := sha256.New()
|
||||
hash.Write(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey])
|
||||
hash.Write(credentialsSecret.Data[resources.OperatorCredentialsSecretPasswordKey])
|
||||
_, err = hash.Write(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey])
|
||||
if err != nil {
|
||||
return "", stackerr.WithStack(err)
|
||||
}
|
||||
_, err = hash.Write(credentialsSecret.Data[resources.OperatorCredentialsSecretPasswordKey])
|
||||
if err != nil {
|
||||
return "", stackerr.WithStack(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
|
|
@ -282,7 +288,7 @@ func CompareContainerVolumeMounts(expected corev1.Container, actual corev1.Conta
|
|||
}
|
||||
|
||||
// compareVolumes returns true if Jenkins pod and Jenkins CR volumes are the same
|
||||
func (r *ReconcileJenkinsBaseConfiguration) compareVolumes(actualPod corev1.Pod) bool {
|
||||
func (r *JenkinsBaseConfigurationReconciler) compareVolumes(actualPod corev1.Pod) bool {
|
||||
var withoutServiceAccount []corev1.Volume
|
||||
for _, volume := range actualPod.Spec.Volumes {
|
||||
if !strings.HasPrefix(volume.Name, actualPod.Spec.ServiceAccountName) {
|
||||
|
|
@ -296,7 +302,7 @@ func (r *ReconcileJenkinsBaseConfiguration) compareVolumes(actualPod corev1.Pod)
|
|||
)
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) detectJenkinsMasterPodStartingIssues() (stopReconcileLoop bool, err error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) detectJenkinsMasterPodStartingIssues() (stopReconcileLoop bool, err error) {
|
||||
jenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod()
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
|
@ -330,7 +336,7 @@ func (r *ReconcileJenkinsBaseConfiguration) detectJenkinsMasterPodStartingIssues
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) filterEvents(source corev1.EventList, jenkinsMasterPod corev1.Pod) []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) filterEvents(source corev1.EventList, jenkinsMasterPod corev1.Pod) []string {
|
||||
events := []string{}
|
||||
for _, eventItem := range source.Items {
|
||||
if r.Configuration.Jenkins.Status.ProvisionStartTime.UTC().After(eventItem.LastTimestamp.UTC()) {
|
||||
|
|
@ -347,7 +353,7 @@ func (r *ReconcileJenkinsBaseConfiguration) filterEvents(source corev1.EventList
|
|||
return events
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) waitForJenkins() (reconcile.Result, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) waitForJenkins() (reconcile.Result, error) {
|
||||
jenkinsMasterPod, err := r.Configuration.GetJenkinsMasterPod()
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
|
|
@ -388,7 +394,7 @@ func (r *ReconcileJenkinsBaseConfiguration) waitForJenkins() (reconcile.Result,
|
|||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClient jenkinsclient.Jenkins) (reconcile.Result, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) ensureBaseConfiguration(jenkinsClient jenkinsclient.Jenkins) (reconcile.Result, error) {
|
||||
customization := v1alpha2.GroovyScripts{
|
||||
Customization: v1alpha2.Customization{
|
||||
Secret: v1alpha2.SecretRef{Name: ""},
|
||||
|
|
@ -403,30 +409,3 @@ func (r *ReconcileJenkinsBaseConfiguration) ensureBaseConfiguration(jenkinsClien
|
|||
})
|
||||
return reconcile.Result{Requeue: requeue}, err
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) waitUntilCreateJenkinsMasterPod() (currentJenkinsMasterPod *corev1.Pod, err error) {
|
||||
currentJenkinsMasterPod, err = r.Configuration.GetJenkinsMasterPod()
|
||||
for {
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
return nil, stackerr.WithStack(err)
|
||||
} else if err == nil {
|
||||
break
|
||||
}
|
||||
currentJenkinsMasterPod, err = r.Configuration.GetJenkinsMasterPod()
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) handleAdmissionControllerChanges(currentJenkinsMasterPod *corev1.Pod) {
|
||||
if !reflect.DeepEqual(r.Configuration.Jenkins.Spec.Master.SecurityContext, currentJenkinsMasterPod.Spec.SecurityContext) {
|
||||
r.Configuration.Jenkins.Spec.Master.SecurityContext = currentJenkinsMasterPod.Spec.SecurityContext
|
||||
r.logger.Info(fmt.Sprintf("The Admission controller has changed the Jenkins master pod spec.securityContext, changing the Jenkinc CR spec.master.securityContext to '%+v'", currentJenkinsMasterPod.Spec.SecurityContext))
|
||||
}
|
||||
for i, container := range r.Configuration.Jenkins.Spec.Master.Containers {
|
||||
if !reflect.DeepEqual(container.SecurityContext, currentJenkinsMasterPod.Spec.Containers[i].SecurityContext) {
|
||||
r.Configuration.Jenkins.Spec.Master.Containers[i].SecurityContext = currentJenkinsMasterPod.Spec.Containers[i].SecurityContext
|
||||
r.logger.Info(fmt.Sprintf("The Admission controller has changed the securityContext, changing the Jenkins CR spec.master.containers[%s].securityContext to '+%v'", container.Name, currentJenkinsMasterPod.Spec.Containers[i].SecurityContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package resources
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -1,128 +0,0 @@
|
|||
package resources
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
jenkinsv1alpha2 "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
NameWithSuffixFormat = "%s-%s"
|
||||
PluginDefinitionFormat = "%s:%s"
|
||||
BuilderDockerfileArg = "--dockerfile=/workspace/dockerfile/Dockerfile"
|
||||
BuilderContextDirArg = "--context=dir://workspace/"
|
||||
BuilderPushArg = "--no-push"
|
||||
BuilderDigestFileArg = "--digest-file=/dev/termination-log"
|
||||
BuilderSuffix = "builder"
|
||||
DockerfileStorageSuffix = "dockerfile-storage"
|
||||
DockerfileNameSuffix = "dockerfile"
|
||||
JenkinsImageBuilderImage = "gcr.io/kaniko-project/executor:latest"
|
||||
JenkinsImageBuilderName = "jenkins-image-builder"
|
||||
JenkinsImageDefaultBaseImage = "jenkins/jenkins:lts"
|
||||
DockerfileName = "Dockerfile"
|
||||
DockerfileTemplate = `FROM %s
|
||||
RUN curl -o /tmp/install-plugins.sh https://raw.githubusercontent.com/jenkinsci/docker/master/install-plugins.sh
|
||||
RUN chmod +x /tmp/install-plugins.sh
|
||||
RUN install-plugins.sh %s `
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller_jenkinsimage")
|
||||
|
||||
// NewBuilderPod returns a busybox pod with the same name/namespace as the cr.
|
||||
func NewBuilderPod(cr *jenkinsv1alpha2.JenkinsImage) *corev1.Pod {
|
||||
name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, BuilderSuffix)
|
||||
args := []string{BuilderDockerfileArg, BuilderContextDirArg, BuilderPushArg, BuilderDigestFileArg}
|
||||
volumes := getVolumes(cr)
|
||||
volumeMounts := getVolumesMounts(cr)
|
||||
p := &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: cr.Namespace,
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
RestartPolicy: corev1.RestartPolicyNever,
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: JenkinsImageBuilderName,
|
||||
Image: JenkinsImageBuilderImage,
|
||||
Args: args,
|
||||
VolumeMounts: volumeMounts,
|
||||
},
|
||||
},
|
||||
Volumes: volumes,
|
||||
},
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// NewDockerfileConfigMap returns a busybox pod with the same name/namespace as the cr.
|
||||
func NewDockerfileConfigMap(cr *jenkinsv1alpha2.JenkinsImage) *corev1.ConfigMap {
|
||||
dockerfileContent := fmt.Sprintf(DockerfileTemplate, getDefaultedBaseImage(cr), getPluginsList(cr))
|
||||
name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileNameSuffix)
|
||||
data := map[string]string{DockerfileName: dockerfileContent}
|
||||
dockerfile := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: cr.Namespace,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
return dockerfile
|
||||
}
|
||||
|
||||
func getPluginsList(cr *jenkinsv1alpha2.JenkinsImage) string {
|
||||
logger := log.WithName("jenkinsimage_getPluginsList")
|
||||
plugins := ""
|
||||
for _, v := range cr.Spec.Plugins {
|
||||
plugins += fmt.Sprintf(PluginDefinitionFormat, v.Name, v.Version) + " "
|
||||
logger.Info(fmt.Sprintf("Adding plugin %s:%s ", v.Name, v.Version))
|
||||
}
|
||||
return plugins
|
||||
}
|
||||
|
||||
func getDefaultedBaseImage(cr *jenkinsv1alpha2.JenkinsImage) string {
|
||||
if len(cr.Spec.BaseImage.Name) != 0 {
|
||||
return cr.Spec.BaseImage.Name
|
||||
}
|
||||
return JenkinsImageDefaultBaseImage
|
||||
}
|
||||
|
||||
func getVolumes(cr *jenkinsv1alpha2.JenkinsImage) []corev1.Volume {
|
||||
name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileStorageSuffix)
|
||||
storage := corev1.Volume{
|
||||
Name: name,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
||||
},
|
||||
}
|
||||
|
||||
name = fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileNameSuffix)
|
||||
config := corev1.Volume{
|
||||
Name: name,
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: corev1.LocalObjectReference{Name: name},
|
||||
},
|
||||
},
|
||||
}
|
||||
volumes := []corev1.Volume{storage, config}
|
||||
return volumes
|
||||
}
|
||||
|
||||
func getVolumesMounts(cr *jenkinsv1alpha2.JenkinsImage) []corev1.VolumeMount {
|
||||
name := fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileStorageSuffix)
|
||||
storage := corev1.VolumeMount{
|
||||
Name: name,
|
||||
MountPath: "/workspace",
|
||||
}
|
||||
name = fmt.Sprintf(NameWithSuffixFormat, cr.Name, DockerfileNameSuffix)
|
||||
config := corev1.VolumeMount{
|
||||
Name: name,
|
||||
MountPath: "/workspace/dockerfile",
|
||||
}
|
||||
volumeMounts := []corev1.VolumeMount{storage, config}
|
||||
return volumeMounts
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package resources
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import (
|
|||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/internal/render"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package resources
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package resources
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ package resources
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func NewSimpleProbe(uri string, port string, scheme corev1.URIScheme, initialDelaySeconds int32) *corev1.Probe {
|
||||
func NewProbe(uri string, port string, scheme corev1.URIScheme, initialDelaySeconds, timeoutSeconds, failureThreshold int32) *corev1.Probe {
|
||||
return &corev1.Probe{
|
||||
Handler: corev1.Handler{
|
||||
HTTPGet: &corev1.HTTPGetAction{
|
||||
|
|
@ -15,12 +15,9 @@ func NewSimpleProbe(uri string, port string, scheme corev1.URIScheme, initialDel
|
|||
},
|
||||
},
|
||||
InitialDelaySeconds: initialDelaySeconds,
|
||||
TimeoutSeconds: timeoutSeconds,
|
||||
FailureThreshold: failureThreshold,
|
||||
SuccessThreshold: int32(1),
|
||||
PeriodSeconds: int32(1),
|
||||
}
|
||||
}
|
||||
|
||||
func NewProbe(uri string, port string, scheme corev1.URIScheme, initialDelaySeconds, timeoutSeconds, failureThreshold int32) *corev1.Probe {
|
||||
p := NewSimpleProbe(uri, port, scheme, initialDelaySeconds)
|
||||
p.TimeoutSeconds = timeoutSeconds
|
||||
p.FailureThreshold = failureThreshold
|
||||
return p
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package resources
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
package resources
|
||||
|
||||
import (
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
//RouteKind the kind name for route
|
||||
const RouteKind = "Route"
|
||||
|
||||
var isRouteAPIAvailable = false
|
||||
var routeAPIChecked = false
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import (
|
|||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/internal/render"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -2,17 +2,16 @@ package resources
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
"github.com/operator-framework/operator-sdk/pkg/k8sutil"
|
||||
stackerr "github.com/pkg/errors"
|
||||
|
||||
stackerr "github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//ServiceKind the kind name for Service
|
||||
|
|
@ -71,7 +70,7 @@ func GetJenkinsSlavesServiceFQDN(jenkins *v1alpha2.Jenkins, kubernetesClusterDom
|
|||
|
||||
// GetClusterDomain returns Kubernetes cluster domain, default to "cluster.local"
|
||||
func getClusterDomain(kubernetesClusterDomain string) (string, error) {
|
||||
isRunningInCluster, err := isRunningInCluster()
|
||||
isRunningInCluster, err := IsRunningInCluster()
|
||||
if !isRunningInCluster {
|
||||
return kubernetesClusterDomain, nil
|
||||
}
|
||||
|
|
@ -93,13 +92,13 @@ func getClusterDomain(kubernetesClusterDomain string) (string, error) {
|
|||
return kubernetesClusterDomain, nil
|
||||
}
|
||||
|
||||
func isRunningInCluster() (bool, error) {
|
||||
_, err := k8sutil.GetOperatorNamespace()
|
||||
if err != nil {
|
||||
if err == k8sutil.ErrNoNamespace || err == k8sutil.ErrRunLocal {
|
||||
return false, nil
|
||||
}
|
||||
return false, stackerr.WithStack(err)
|
||||
func IsRunningInCluster() (bool, error) {
|
||||
const inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
|
||||
_, err := os.Stat(inClusterNamespacePath)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
} else if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
return true, nil
|
||||
return false, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
||||
routev1 "github.com/openshift/api/route/v1"
|
||||
stackerr "github.com/pkg/errors"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// createRoute takes the ServiceName and Creates the Route based on it
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createRoute(meta metav1.ObjectMeta, serviceName string, config *v1alpha2.Jenkins) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createRoute(meta metav1.ObjectMeta, serviceName string, config *v1alpha2.Jenkins) error {
|
||||
route := routev1.Route{}
|
||||
name := fmt.Sprintf("jenkins-%s", config.ObjectMeta.Name)
|
||||
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: meta.Namespace}, &route)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package base
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
||||
stackerr "github.com/pkg/errors"
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createService(meta metav1.ObjectMeta, name string, config v1alpha2.Service, targetPort int32) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createService(meta metav1.ObjectMeta, name string, config v1alpha2.Service, targetPort int32) error {
|
||||
service := corev1.Service{}
|
||||
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: name, Namespace: meta.Namespace}, &service)
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) createServiceAccount(meta metav1.ObjectMeta) error {
|
||||
func (r *JenkinsBaseConfigurationReconciler) createServiceAccount(meta metav1.ObjectMeta) error {
|
||||
serviceAccount := &corev1.ServiceAccount{}
|
||||
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: meta.Name, Namespace: meta.Namespace}, serviceAccount)
|
||||
annotations := r.Configuration.Jenkins.Spec.ServiceAccount.Annotations
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/constants"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/plugins"
|
||||
|
|
@ -23,7 +23,7 @@ var (
|
|||
)
|
||||
|
||||
// Validate validates Jenkins CR Spec.master section
|
||||
func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha2.Jenkins) ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) Validate(jenkins *v1alpha2.Jenkins) ([]string, error) {
|
||||
var messages []string
|
||||
|
||||
if msg := r.validateReservedVolumes(); len(msg) > 0 {
|
||||
|
|
@ -70,7 +70,7 @@ func (r *ReconcileJenkinsBaseConfiguration) Validate(jenkins *v1alpha2.Jenkins)
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterContainerCommand() []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateJenkinsMasterContainerCommand() []string {
|
||||
masterContainer := r.Configuration.GetJenkinsMasterContainer()
|
||||
if masterContainer == nil {
|
||||
return []string{}
|
||||
|
|
@ -102,7 +102,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterContainerComman
|
|||
return []string{}
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecrets() ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateImagePullSecrets() ([]string, error) {
|
||||
var messages []string
|
||||
for _, sr := range r.Configuration.Jenkins.Spec.Master.ImagePullSecrets {
|
||||
msg, err := r.validateImagePullSecret(sr.Name)
|
||||
|
|
@ -116,7 +116,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecrets() ([]string
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecret(secretName string) ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateImagePullSecret(secretName string) ([]string, error) {
|
||||
var messages []string
|
||||
secret := &corev1.Secret{}
|
||||
err := r.Client.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: r.Configuration.Jenkins.ObjectMeta.Namespace}, secret)
|
||||
|
|
@ -142,7 +142,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateImagePullSecret(secretName s
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateVolumes() ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateVolumes() ([]string, error) {
|
||||
var messages []string
|
||||
for _, volume := range r.Configuration.Jenkins.Spec.Master.Volumes {
|
||||
switch {
|
||||
|
|
@ -170,7 +170,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateVolumes() ([]string, error)
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validatePersistentVolumeClaim(volume corev1.Volume) ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validatePersistentVolumeClaim(volume corev1.Volume) ([]string, error) {
|
||||
var messages []string
|
||||
|
||||
pvc := &corev1.PersistentVolumeClaim{}
|
||||
|
|
@ -184,7 +184,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validatePersistentVolumeClaim(volume
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateConfigMapVolume(volume corev1.Volume) ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateConfigMapVolume(volume corev1.Volume) ([]string, error) {
|
||||
var messages []string
|
||||
if volume.ConfigMap.Optional != nil && *volume.ConfigMap.Optional {
|
||||
return nil, nil
|
||||
|
|
@ -201,7 +201,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateConfigMapVolume(volume corev
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateSecretVolume(volume corev1.Volume) ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateSecretVolume(volume corev1.Volume) ([]string, error) {
|
||||
var messages []string
|
||||
if volume.Secret.Optional != nil && *volume.Secret.Optional {
|
||||
return nil, nil
|
||||
|
|
@ -218,7 +218,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateSecretVolume(volume corev1.V
|
|||
return messages, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateReservedVolumes() []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateReservedVolumes() []string {
|
||||
var messages []string
|
||||
|
||||
for _, baseVolume := range resources.GetJenkinsMasterPodBaseVolumes(r.Configuration.Jenkins) {
|
||||
|
|
@ -232,7 +232,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateReservedVolumes() []string {
|
|||
return messages
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateContainer(container v1alpha2.Container) []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateContainer(container v1alpha2.Container) []string {
|
||||
var messages []string
|
||||
if container.Image == "" {
|
||||
messages = append(messages, "Image not set")
|
||||
|
|
@ -253,7 +253,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateContainer(container v1alpha2
|
|||
return messages
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateContainerVolumeMounts(container v1alpha2.Container) []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateContainerVolumeMounts(container v1alpha2.Container) []string {
|
||||
var messages []string
|
||||
allVolumes := append(resources.GetJenkinsMasterPodBaseVolumes(r.Configuration.Jenkins), r.Configuration.Jenkins.Spec.Master.Volumes...)
|
||||
|
||||
|
|
@ -277,7 +277,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateContainerVolumeMounts(contai
|
|||
return messages
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterPodEnvs() []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateJenkinsMasterPodEnvs() []string {
|
||||
var messages []string
|
||||
baseEnvs := resources.GetJenkinsMasterContainerBaseEnvs(r.Configuration.Jenkins)
|
||||
baseEnvNames := map[string]string{}
|
||||
|
|
@ -316,7 +316,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validateJenkinsMasterPodEnvs() []str
|
|||
return messages
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validatePlugins(requiredBasePlugins []plugins.Plugin, basePlugins, userPlugins []v1alpha2.Plugin) []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validatePlugins(requiredBasePlugins []plugins.Plugin, basePlugins, userPlugins []v1alpha2.Plugin) []string {
|
||||
var messages []string
|
||||
allPlugins := map[plugins.Plugin][]plugins.Plugin{}
|
||||
|
||||
|
|
@ -353,7 +353,7 @@ func (r *ReconcileJenkinsBaseConfiguration) validatePlugins(requiredBasePlugins
|
|||
return messages
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) verifyBasePlugins(requiredBasePlugins []plugins.Plugin, basePlugins []v1alpha2.Plugin) []string {
|
||||
func (r *JenkinsBaseConfigurationReconciler) verifyBasePlugins(requiredBasePlugins []plugins.Plugin, basePlugins []v1alpha2.Plugin) []string {
|
||||
var messages []string
|
||||
|
||||
for _, requiredBasePlugin := range requiredBasePlugins {
|
||||
|
|
@ -372,7 +372,7 @@ func (r *ReconcileJenkinsBaseConfiguration) verifyBasePlugins(requiredBasePlugin
|
|||
return messages
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkinsBaseConfiguration) validateCustomization(customization v1alpha2.Customization, name string) ([]string, error) {
|
||||
func (r *JenkinsBaseConfigurationReconciler) validateCustomization(customization v1alpha2.Customization, name string) ([]string, error) {
|
||||
var messages []string
|
||||
if len(customization.Secret.Name) == 0 && len(customization.Configurations) == 0 {
|
||||
return nil, nil
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
|
@ -161,7 +161,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -221,7 +221,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -293,7 +293,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ func TestReconcileJenkinsBaseConfiguration_validateImagePullSecrets(t *testing.T
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -569,7 +569,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Name: "example"}},
|
||||
|
|
@ -596,7 +596,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), &configMap)
|
||||
assert.NoError(t, err)
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
|
|
@ -624,7 +624,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -634,7 +634,7 @@ func TestValidateConfigMapVolume(t *testing.T) {
|
|||
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, got, []string{"ConfigMap 'configmap-name' not found for volume '{volume-name {nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil &ConfigMapVolumeSource{LocalObjectReference:LocalObjectReference{Name:configmap-name,},Items:[]KeyToPath{},DefaultMode:nil,Optional:*false,} nil nil nil nil nil nil nil nil nil}}'"})
|
||||
assert.Equal(t, got, []string{"ConfigMap 'configmap-name' not found for volume '{volume-name {nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil &ConfigMapVolumeSource{LocalObjectReference:LocalObjectReference{Name:configmap-name,},Items:[]KeyToPath{},DefaultMode:nil,Optional:*false,} nil nil nil nil nil nil nil nil nil nil}}'"})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -649,7 +649,7 @@ func TestValidateSecretVolume(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: &v1alpha2.Jenkins{ObjectMeta: metav1.ObjectMeta{Name: "example"}},
|
||||
Client: fakeClient,
|
||||
|
|
@ -673,7 +673,7 @@ func TestValidateSecretVolume(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), &secret)
|
||||
assert.NoError(t, err)
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
|
|
@ -699,7 +699,7 @@ func TestValidateSecretVolume(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
Jenkins: jenkins,
|
||||
|
|
@ -708,7 +708,7 @@ func TestValidateSecretVolume(t *testing.T) {
|
|||
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, got, []string{"Secret 'secret-name' not found for volume '{volume-name {nil nil nil nil nil &SecretVolumeSource{SecretName:secret-name,Items:[]KeyToPath{},DefaultMode:nil,Optional:*false,} nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil}}'"})
|
||||
assert.Equal(t, got, []string{"Secret 'secret-name' not found for volume '{volume-name {nil nil nil nil nil &SecretVolumeSource{SecretName:secret-name,Items:[]KeyToPath{},DefaultMode:nil,Optional:*false,} nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil}}'"})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -722,7 +722,7 @@ func TestValidateCustomization(t *testing.T) {
|
|||
}
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
customization := v1alpha2.Customization{}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
Client: fakeClient,
|
||||
|
|
@ -744,7 +744,7 @@ func TestValidateCustomization(t *testing.T) {
|
|||
Namespace: defaultNamespace,
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
Client: fakeClient,
|
||||
|
|
@ -775,7 +775,7 @@ func TestValidateCustomization(t *testing.T) {
|
|||
Namespace: defaultNamespace,
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
Client: fakeClient,
|
||||
|
|
@ -802,7 +802,7 @@ func TestValidateCustomization(t *testing.T) {
|
|||
Namespace: defaultNamespace,
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
Client: fakeClient,
|
||||
|
|
@ -827,7 +827,7 @@ func TestValidateCustomization(t *testing.T) {
|
|||
Namespace: defaultNamespace,
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
baseReconcileLoop := New(configuration.Configuration{
|
||||
Jenkins: jenkins,
|
||||
Client: fakeClient,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ package configuration
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
|
|
@ -89,7 +88,7 @@ func (c *Configuration) IsJenkinsTerminating(pod corev1.Pod) bool {
|
|||
|
||||
// CreateResource is creating kubernetes resource and references it to Jenkins CR
|
||||
func (c *Configuration) CreateResource(obj metav1.Object) error {
|
||||
runtimeObj, ok := obj.(runtime.Object)
|
||||
clientObj, ok := obj.(client.Object)
|
||||
if !ok {
|
||||
return stackerr.Errorf("is not a %T a runtime.Object", obj)
|
||||
}
|
||||
|
|
@ -99,25 +98,25 @@ func (c *Configuration) CreateResource(obj metav1.Object) error {
|
|||
return stackerr.WithStack(err)
|
||||
}
|
||||
|
||||
return c.Client.Create(context.TODO(), runtimeObj) // don't wrap error
|
||||
return c.Client.Create(context.TODO(), clientObj) // don't wrap error
|
||||
}
|
||||
|
||||
// UpdateResource is updating kubernetes resource and references it to Jenkins CR.
|
||||
func (c *Configuration) UpdateResource(obj metav1.Object) error {
|
||||
runtimeObj, ok := obj.(runtime.Object)
|
||||
clientObj, ok := obj.(client.Object)
|
||||
if !ok {
|
||||
return stackerr.Errorf("is not a %T a runtime.Object", obj)
|
||||
}
|
||||
|
||||
// set Jenkins instance as the owner and controller, don't check error(can be already set)
|
||||
// set Jenkins instance as the owner and controller, don't check errors(can be already set)
|
||||
_ = controllerutil.SetControllerReference(c.Jenkins, obj, c.Scheme)
|
||||
|
||||
return c.Client.Update(context.TODO(), runtimeObj) // don't wrap error
|
||||
return c.Client.Update(context.TODO(), clientObj) // don't wrap error
|
||||
}
|
||||
|
||||
// CreateOrUpdateResource is creating or updating kubernetes resource and references it to Jenkins CR.
|
||||
func (c *Configuration) CreateOrUpdateResource(obj metav1.Object) error {
|
||||
runtimeObj, ok := obj.(runtime.Object)
|
||||
clientObj, ok := obj.(client.Object)
|
||||
if !ok {
|
||||
return stackerr.Errorf("is not a %T a runtime.Object", obj)
|
||||
}
|
||||
|
|
@ -125,7 +124,7 @@ func (c *Configuration) CreateOrUpdateResource(obj metav1.Object) error {
|
|||
// set Jenkins instance as the owner and controller, don't check error(can be already set)
|
||||
_ = controllerutil.SetControllerReference(c.Jenkins, obj, c.Scheme)
|
||||
|
||||
err := c.Client.Create(context.TODO(), runtimeObj)
|
||||
err := c.Client.Create(context.TODO(), clientObj)
|
||||
if err != nil && errors.IsAlreadyExists(err) {
|
||||
return c.UpdateResource(obj)
|
||||
} else if err != nil && !errors.IsAlreadyExists(err) {
|
||||
|
|
@ -202,7 +201,7 @@ func (c *Configuration) getJenkinsAPIUrl() (string, error) {
|
|||
return "", err
|
||||
}
|
||||
jenkinsURL := c.JenkinsAPIConnectionSettings.BuildJenkinsAPIUrl(service.Name, service.Namespace, service.Spec.Ports[0].Port, service.Spec.Ports[0].NodePort)
|
||||
if prefix, ok := GetJenkinsOpts(*c.Jenkins)["prefix"]; ok {
|
||||
if prefix, ok := resources.GetJenkinsOpts(*c.Jenkins)["prefix"]; ok {
|
||||
jenkinsURL += prefix
|
||||
}
|
||||
return jenkinsURL, nil
|
||||
|
|
@ -278,29 +277,3 @@ func (c *Configuration) GetJenkinsClientFromSecret() (jenkinsclient.Jenkins, err
|
|||
string(credentialsSecret.Data[resources.OperatorCredentialsSecretUserNameKey]),
|
||||
string(credentialsSecret.Data[resources.OperatorCredentialsSecretTokenKey]))
|
||||
}
|
||||
|
||||
// GetJenkinsOpts gets JENKINS_OPTS env parameter, parses it's values and returns it as a map`
|
||||
func GetJenkinsOpts(jenkins v1alpha2.Jenkins) map[string]string {
|
||||
envs := jenkins.Spec.Master.Containers[0].Env
|
||||
jenkinsOpts := make(map[string]string)
|
||||
|
||||
for key, value := range envs {
|
||||
if value.Name == "JENKINS_OPTS" {
|
||||
jenkinsOptsEnv := envs[key]
|
||||
jenkinsOptsWithDashes := jenkinsOptsEnv.Value
|
||||
if len(jenkinsOptsWithDashes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
jenkinsOptsWithEqOperators := strings.Split(jenkinsOptsWithDashes, " ")
|
||||
|
||||
for _, vx := range jenkinsOptsWithEqOperators {
|
||||
opt := strings.Split(vx, "=")
|
||||
jenkinsOpts[strings.ReplaceAll(opt[0], "--", "")] = opt[1]
|
||||
}
|
||||
|
||||
return jenkinsOpts
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/groovy"
|
||||
|
|
@ -31,7 +31,7 @@ func New(jenkinsClient jenkinsclient.Jenkins, k8sClient k8s.Client, jenkins *v1a
|
|||
}
|
||||
|
||||
// Ensure configures Jenkins with help Configuration as a code plugin
|
||||
func (c *configurationAsCode) Ensure(jenkins *v1alpha2.Jenkins) (requeue bool, err error) {
|
||||
func (c *configurationAsCode) Ensure(_ *v1alpha2.Jenkins) (requeue bool, err error) {
|
||||
requeue, err = c.groovyClient.WaitForSecretSynchronization(resources.ConfigurationAsCodeSecretVolumePath)
|
||||
if err != nil || requeue {
|
||||
return requeue, err
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ package user
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/backuprestore"
|
||||
|
|
@ -14,6 +12,8 @@ import (
|
|||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/user/seedjobs"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/groovy"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ import (
|
|||
"reflect"
|
||||
"text/template"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/internal/render"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
|
@ -18,6 +17,8 @@ import (
|
|||
"github.com/jenkinsci/kubernetes-operator/pkg/groovy"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
stackerr "github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
@ -228,7 +229,7 @@ func (s *seedJobs) EnsureSeedJobs(jenkins *v1alpha2.Jenkins) (done bool, err err
|
|||
seedJobIDs := s.getAllSeedJobIDs(*jenkins)
|
||||
if !reflect.DeepEqual(seedJobIDs, jenkins.Status.CreatedSeedJobs) {
|
||||
jenkins.Status.CreatedSeedJobs = seedJobIDs
|
||||
return false, stackerr.WithStack(s.Client.Update(context.TODO(), jenkins))
|
||||
return false, stackerr.WithStack(s.Client.Status().Update(context.TODO(), jenkins))
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
|
@ -267,8 +268,15 @@ func (s *seedJobs) createJobs(jenkins *v1alpha2.Jenkins) (requeue bool, err erro
|
|||
}
|
||||
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(groovyScript))
|
||||
hash.Write([]byte(credentialValue))
|
||||
_, err = hash.Write([]byte(groovyScript))
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
_, err = hash.Write([]byte(credentialValue))
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
requeue, err := groovyClient.EnsureSingle(seedJob.ID, fmt.Sprintf("%s.groovy", seedJob.ID), base64.URLEncoding.EncodeToString(hash.Sum(nil)), groovyScript)
|
||||
if err != nil {
|
||||
return true, err
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
|
@ -16,6 +14,7 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
|
@ -74,7 +73,7 @@ func TestEnsureSeedJobs(t *testing.T) {
|
|||
defer ctrl.Finish()
|
||||
|
||||
jenkinsClient := jenkinsclient.NewMockJenkins(ctrl)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -126,7 +125,7 @@ func TestEnsureSeedJobs(t *testing.T) {
|
|||
jenkins.Spec.SeedJobs = []v1alpha2.SeedJob{}
|
||||
|
||||
jenkinsClient := jenkinsclient.NewMockJenkins(ctrl)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -174,7 +173,7 @@ func TestCreateAgent(t *testing.T) {
|
|||
jenkins := jenkinsCustomResource()
|
||||
|
||||
jenkinsClient := jenkinsclient.NewMockJenkins(ctrl)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
|
||||
stackerr "github.com/pkg/errors"
|
||||
"github.com/robfig/cron"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -57,6 +57,10 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
Name: "deploy-keys",
|
||||
Namespace: "default",
|
||||
}
|
||||
jenkinsObjectMeta := metav1.ObjectMeta{
|
||||
Name: "cr",
|
||||
Namespace: "default",
|
||||
}
|
||||
t.Run("Valid with public repository and without private key", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
|
|
@ -73,7 +77,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -102,7 +106,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -120,6 +124,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Valid with private key and secret", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -141,7 +146,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PrivateKeySecretKey: []byte(fakePrivateKey),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -160,6 +165,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Invalid private key in secret", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -181,7 +187,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PrivateKeySecretKey: []byte(fakeInvalidPrivateKey),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -201,6 +207,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Invalid with PrivateKey and empty Secret data", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -222,7 +229,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PrivateKeySecretKey: []byte(""),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -256,7 +263,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -286,7 +293,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -316,7 +323,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -346,7 +353,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -364,6 +371,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Valid with username and password", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -385,7 +393,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PasswordSecretKey: []byte("some-password"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -404,6 +412,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Invalid with empty username", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -425,7 +434,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PasswordSecretKey: []byte("some-password"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -445,6 +454,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Invalid with empty password", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -466,7 +476,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PasswordSecretKey: []byte(""),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -486,6 +496,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Invalid without username", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -506,7 +517,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
PasswordSecretKey: []byte("some-password"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -526,6 +537,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
})
|
||||
t.Run("Invalid without password", func(t *testing.T) {
|
||||
jenkins := v1alpha2.Jenkins{
|
||||
ObjectMeta: jenkinsObjectMeta,
|
||||
Spec: v1alpha2.JenkinsSpec{
|
||||
SeedJobs: []v1alpha2.SeedJob{
|
||||
{
|
||||
|
|
@ -546,7 +558,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
UsernameSecretKey: []byte("some-username"),
|
||||
},
|
||||
}
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err := fakeClient.Create(context.TODO(), secret)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
|
@ -581,7 +593,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -615,7 +627,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -647,7 +659,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -685,7 +697,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -717,7 +729,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
@ -755,7 +767,7 @@ func TestValidateSeedJobs(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
|
||||
config := configuration.Configuration{
|
||||
Client: fakeClient,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/backuprestore"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/user/seedjobs"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
package jenkins
|
||||
|
||||
import (
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
// ReconcileJenkins reconciles a Jenkins object.
|
||||
type ReconcileJenkins struct {
|
||||
client client.Client
|
||||
scheme *runtime.Scheme
|
||||
jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings
|
||||
clientSet kubernetes.Clientset
|
||||
config rest.Config
|
||||
notificationEvents *chan event.Event
|
||||
KubernetesClusterDomain string
|
||||
}
|
||||
|
||||
func (r *ReconcileJenkins) newReconcilierConfiguration(jenkins *v1alpha2.Jenkins) configuration.Configuration {
|
||||
config := configuration.Configuration{
|
||||
Client: r.client,
|
||||
ClientSet: r.clientSet,
|
||||
Notifications: r.notificationEvents,
|
||||
Jenkins: jenkins,
|
||||
Scheme: r.scheme,
|
||||
Config: &r.config,
|
||||
JenkinsAPIConnectionSettings: r.jenkinsAPIConnectionSettings,
|
||||
KubernetesClusterDomain: r.KubernetesClusterDomain,
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// newReconciler returns a newReconcilierConfiguration reconcile.Reconciler.
|
||||
func newReconciler(mgr manager.Manager, jenkinsAPIConnectionSettings jenkinsclient.JenkinsAPIConnectionSettings, kubernetesClusterDomain string, clientSet kubernetes.Clientset, config rest.Config, notificationEvents *chan event.Event) reconcile.Reconciler {
|
||||
return &ReconcileJenkins{
|
||||
client: mgr.GetClient(),
|
||||
scheme: mgr.GetScheme(),
|
||||
jenkinsAPIConnectionSettings: jenkinsAPIConnectionSettings,
|
||||
clientSet: clientSet,
|
||||
config: config,
|
||||
notificationEvents: notificationEvents,
|
||||
KubernetesClusterDomain: kubernetesClusterDomain,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
package jenkinsimage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
jenkinsv1alpha2 "github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/configuration/base/resources"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller_jenkinsimage")
|
||||
|
||||
// Add creates a new JenkinsImage Controller and adds it to the Manager. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
r := &ReconcileJenkinsImage{client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
return add(mgr, r)
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("jenkinsimage-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to primary resource JenkinsImage
|
||||
eventHandlerForObject := &handler.EnqueueRequestForObject{}
|
||||
src := &source.Kind{Type: &jenkinsv1alpha2.JenkinsImage{}}
|
||||
err = c.Watch(src, eventHandlerForObject)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
// Watch for changes to secondary resource Pods and requeue the owner JenkinsImage
|
||||
eventHandlerForOwner := &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &jenkinsv1alpha2.JenkinsImage{},
|
||||
}
|
||||
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, eventHandlerForOwner)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
// Watch for changes to secondary ConfigMap and requeue the owner JenkinsImage
|
||||
err = c.Watch(&source.Kind{Type: &corev1.ConfigMap{}}, eventHandlerForOwner)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// blank assignment to verify that ReconcileJenkinsImage implements reconcile.Reconciler
|
||||
var _ reconcile.Reconciler = &ReconcileJenkinsImage{}
|
||||
|
||||
// ReconcileJenkinsImage reconciles a JenkinsImage object
|
||||
type ReconcileJenkinsImage struct {
|
||||
// This client, initialized using mgr.Client() above, is a split client
|
||||
// that reads objects from the cache and writes to the apiserver
|
||||
client client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a JenkinsImage object and makes changes based on the state read
|
||||
// and what is in the JenkinsImage.Spec
|
||||
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
|
||||
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
|
||||
func (r *ReconcileJenkinsImage) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
|
||||
reqLogger.Info("Reconciling JenkinsImage")
|
||||
|
||||
// Fetch the JenkinsImage instance
|
||||
instance := &jenkinsv1alpha2.JenkinsImage{}
|
||||
err := r.client.Get(context.TODO(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
// Request object not found, could have been deleted after reconcile request.
|
||||
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
|
||||
// Return and don't requeue
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Define a new ConfigMap containing the Dockerfile used to build the image
|
||||
dockerfile := resources.NewDockerfileConfigMap(instance)
|
||||
// Set JenkinsImage instance as the owner and controller
|
||||
if err := controllerutil.SetControllerReference(instance, dockerfile, r.scheme); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Check if this ConfigMap already exists
|
||||
foundConfigMap := &corev1.ConfigMap{}
|
||||
err = r.client.Get(context.TODO(), types.NamespacedName{Name: dockerfile.Name, Namespace: dockerfile.Namespace}, foundConfigMap)
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
reqLogger.Info("Creating a new ConfigMap", "ConfigMap.Namespace", dockerfile.Namespace, "ConfigMap.Name", dockerfile.Name)
|
||||
err = r.client.Create(context.TODO(), dockerfile)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
// ConfigMap created successfully - don't requeue
|
||||
return reconcile.Result{}, nil
|
||||
} else if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
// ConfigMap already exists - don't requeue
|
||||
reqLogger.Info("Skip reconcile: ConfigMap already exists", "ConfigMap.Namespace", foundConfigMap.Namespace, "ConfigMap.Name", foundConfigMap.Name)
|
||||
|
||||
// Define a new Pod object
|
||||
pod := resources.NewBuilderPod(instance)
|
||||
// Set JenkinsImage instance as the owner and controller
|
||||
if err := controllerutil.SetControllerReference(instance, pod, r.scheme); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Check if this Pod already exists
|
||||
foundPod := &corev1.Pod{}
|
||||
err = r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, foundPod)
|
||||
if err != nil && apierrors.IsNotFound(err) {
|
||||
reqLogger.Info("Creating a new Pod", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name)
|
||||
err = r.client.Create(context.TODO(), pod)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// Pod created successfully - don't requeue
|
||||
return reconcile.Result{}, nil
|
||||
} else if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
// Pod already exists - don't requeue
|
||||
reqLogger.Info("Skip reconcile: Pod already exists", "Pod.Namespace", foundPod.Namespace, "Pod.Name", foundPod.Name)
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
|
@ -54,7 +54,6 @@ func initializeEventRecorder(config *rest.Config, component string) (record.Even
|
|||
return nil, errors.WithStack(err)
|
||||
}
|
||||
eventBroadcaster := record.NewBroadcaster()
|
||||
//eventBroadcaster.StartLogging(glog.Infof) TODO integrate with proper logger
|
||||
eventBroadcaster.StartRecordingToSink(
|
||||
&typedcorev1.EventSinkImpl{
|
||||
Interface: client.CoreV1().Events("")})
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ func (g *Groovy) EnsureSingle(source, name, hash, groovyScript string) (requeue
|
|||
|
||||
g.jenkins.Status.AppliedGroovyScripts = appliedGroovyScripts
|
||||
|
||||
return true, g.k8sClient.Update(context.TODO(), g.jenkins)
|
||||
return true, g.k8sClient.Status().Update(context.TODO(), g.jenkins)
|
||||
}
|
||||
|
||||
// WaitForSecretSynchronization runs groovy script which waits to synchronize secrets in pod by k8s
|
||||
|
|
@ -96,7 +96,10 @@ func (g *Groovy) WaitForSecretSynchronization(secretsPath string) (requeue bool,
|
|||
for secretKey, secretValue := range secret.Data {
|
||||
toCalculate[secretKey] = string(secretValue)
|
||||
}
|
||||
hash := g.calculateHash(toCalculate)
|
||||
hash, err := g.calculateHash(toCalculate)
|
||||
if err != nil {
|
||||
return true, errors.WithStack(err)
|
||||
}
|
||||
|
||||
name := "synchronizing-secret.groovy"
|
||||
if g.isGroovyScriptAlreadyApplied(g.customization.Secret.Name, name, hash) {
|
||||
|
|
@ -137,7 +140,10 @@ func (g *Groovy) Ensure(filter func(name string) bool, updateGroovyScript func(g
|
|||
continue
|
||||
}
|
||||
|
||||
hash := g.calculateCustomizationHash(*secret, name, groovyScript)
|
||||
hash, err := g.calculateCustomizationHash(*secret, name, groovyScript)
|
||||
if err != nil {
|
||||
return true, errors.WithStack(err)
|
||||
}
|
||||
if g.isGroovyScriptAlreadyApplied(configMap.Name, name, hash) {
|
||||
continue
|
||||
}
|
||||
|
|
@ -153,7 +159,7 @@ func (g *Groovy) Ensure(filter func(name string) bool, updateGroovyScript func(g
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (g *Groovy) calculateCustomizationHash(secret corev1.Secret, key, groovyScript string) string {
|
||||
func (g *Groovy) calculateCustomizationHash(secret corev1.Secret, key, groovyScript string) (string, error) {
|
||||
toCalculate := map[string]string{}
|
||||
for secretKey, secretValue := range secret.Data {
|
||||
toCalculate[secretKey] = string(secretValue)
|
||||
|
|
@ -173,7 +179,7 @@ func (g *Groovy) isGroovyScriptAlreadyApplied(source, name, hash string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (g *Groovy) calculateHash(data map[string]string) string {
|
||||
func (g *Groovy) calculateHash(data map[string]string) (string, error) {
|
||||
hash := sha256.New()
|
||||
|
||||
var keys []string
|
||||
|
|
@ -182,10 +188,16 @@ func (g *Groovy) calculateHash(data map[string]string) string {
|
|||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
hash.Write([]byte(key))
|
||||
hash.Write([]byte(data[key]))
|
||||
_, err := hash.Write([]byte(key))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = hash.Write([]byte(data[key]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(hash.Sum(nil))
|
||||
return base64.StdEncoding.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// AddSecretsLoaderToGroovyScript modify groovy scripts to load Kubernetes secrets into groovy map
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
jenkinsclient "github.com/jenkinsci/kubernetes-operator/pkg/client"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/log"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
@ -43,7 +43,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -197,7 +197,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -257,7 +257,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ func TestGroovy_EnsureSingle(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
@ -392,7 +392,7 @@ func TestGroovy_Ensure(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
err = fakeClient.Create(ctx, configMap)
|
||||
|
|
@ -452,7 +452,7 @@ func TestGroovy_Ensure(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
err = fakeClient.Create(ctx, configMap)
|
||||
|
|
@ -511,7 +511,7 @@ func TestGroovy_Ensure(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
err = fakeClient.Create(ctx, configMap)
|
||||
|
|
@ -577,7 +577,7 @@ func TestGroovy_Ensure(t *testing.T) {
|
|||
}
|
||||
err := v1alpha2.SchemeBuilder.AddToScheme(scheme.Scheme)
|
||||
require.NoError(t, err)
|
||||
fakeClient := fake.NewFakeClient()
|
||||
fakeClient := fake.NewClientBuilder().Build()
|
||||
err = fakeClient.Create(ctx, jenkins)
|
||||
require.NoError(t, err)
|
||||
err = fakeClient.Create(ctx, secret)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/reason"
|
||||
)
|
||||
|
||||
|
|
@ -28,7 +28,4 @@ const (
|
|||
|
||||
// PhaseUser is user-defined configuration of Jenkins
|
||||
PhaseUser Phase = "user"
|
||||
|
||||
// PhaseUnknown is untraceable type of configuration
|
||||
PhaseUnknown Phase = "unknown"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/api/v1alpha2"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/event"
|
||||
"github.com/jenkinsci/kubernetes-operator/pkg/notifications/provider"
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue