Skip to content

Commit

Permalink
Merge branch 'release/v0.1.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
robertauer authored and cesmarvin committed Sep 5, 2023
2 parents af04eb1 + f28e93b commit 2dd6cc9
Show file tree
Hide file tree
Showing 74 changed files with 6,973 additions and 4 deletions.
11 changes: 11 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Usage:
# 1. Copy this file as `.env` into your project
# 2. Adapt the information below with the your personal data.
# 3. INFO: escape special characters like # with \
#
# The file `.env` is ignored by git. Note: DO NOT COMMIT your personal data.

# It is necessary to set the stage to `development` when developing locally (optional)
#export STAGE=development
export LOG_LEVEL=debug
export NAMESPACE=$(shell kubectl config view --minify -o jsonpath='{..namespace}')
4 changes: 4 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
inpackage: True
testonly: True
with-expecter: True
keeptree: False
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# k8s-backup-operator Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [v0.1.0] - 2023-09-05

Initial release

45 changes: 45 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Build the manager binary
FROM golang:1.21 AS builder

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 main.go main.go
COPY pkg/ pkg/

# Copy .git files as the build process builds the current commit id into the binary via ldflags.
# We removed this entry as changes in the repository makes all cached layers invalid leading to rebuilding all layers.
# TODO resolve COMMIT_ID
#COPY .git .git

# Copy build files
COPY build build
COPY Makefile Makefile

# Build
RUN go mod vendor
RUN make compile-generic

# 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
LABEL maintainer="[email protected]" \
NAME="k8s-backup-operator" \
VERSION="0.1.0"

WORKDIR /
COPY --from=builder /workspace/target/k8s-backup-operator .

# the linter has a problem with the valid colon-syntax
# dockerfile_lint - ignore
USER 65532:65532

ENTRYPOINT ["/k8s-backup-operator"]
157 changes: 154 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
#!groovy

@Library(['github.com/cloudogu/[email protected]', 'github.com/cloudogu/ces-build-lib@1.56.0'])
@Library('github.com/cloudogu/ces-build-lib@1.66.1')
import com.cloudogu.ces.cesbuildlib.*
import com.cloudogu.ces.dogubuildlib.*

// Creating necessary git objects
git = new Git(this, "cesmarvin")
git.committerName = 'cesmarvin'
git.committerEmail = '[email protected]'
gitflow = new GitFlow(this, git)
github = new GitHub(this, git)
changelog = new Changelog(this)
Docker docker = new Docker(this)
gpg = new Gpg(this, docker)
goVersion = "1.21"
Makefile makefile = new Makefile(this)

// Configuration of repository
repositoryOwner = "cloudogu"
repositoryName = "k8s-backup-operator"
project = "github.com/${repositoryOwner}/${repositoryName}"
registry = "registry.cloudogu.com"
registry_namespace = "k8s"

// Configuration of branches
productionReleaseBranch = "main"
Expand All @@ -27,6 +34,10 @@ node('docker') {
make 'clean'
}

stage('Lint') {
lintDockerfile()
}

new Docker(this)
.image("golang:${goVersion}")
.mountJenkinsUser()
Expand All @@ -41,14 +52,74 @@ node('docker') {
junit allowEmptyResults: true, testResults: 'target/unit-tests/*-tests.xml'
}

stage('k8s-Integration-Test') {
make 'k8s-integration-test'
}

stage("Review dog analysis") {
stageStaticAnalysisReviewDog()
}

stage('Generate k8s Resources') {
make 'k8s-create-temporary-resource'
archiveArtifacts 'target/*.yaml'
}
}

stage("Lint k8s Resources") {
stageLintK8SResources(makefile)
}

stage('SonarQube') {
stageStaticAnalysisSonarQube()
}

K3d k3d = new K3d(this, "${WORKSPACE}", "${WORKSPACE}/k3d", env.PATH)

try {
String controllerVersion = makefile.getVersion()

stage('Set up k3d cluster') {
k3d.startK3d()
}

def imageName
stage('Build & Push Image') {
imageName = k3d.buildAndPushToLocalRegistry("cloudogu/${repositoryName}", controllerVersion)
}

GString sourceDeploymentYaml = "target/${repositoryName}_${controllerVersion}.yaml"
stage('Update development resources') {
docker.image('mikefarah/yq:4.22.1')
.mountJenkinsUser()
.inside("--volume ${WORKSPACE}:/workdir -w /workdir") {
sh "yq -i '(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.name == \"manager\")).image=\"${imageName}\"' ${sourceDeploymentYaml}"
}
}

stage('Deploy etcd') {
k3d.kubectl("apply -f https://raw.githubusercontent.com/cloudogu/k8s-etcd/develop/manifests/etcd.yaml")
}

stage('Wait for etcd to be ready') {
sleep(time: 5, unit: "SECONDS")
k3d.kubectl("wait --for=condition=ready pod -l statefulset.kubernetes.io/pod-name=etcd-0 --timeout=300s")
}

stage('Deploy Manager') {
k3d.kubectl("apply -f ${sourceDeploymentYaml}")
}

stage('Wait for Ready Rollout') {
k3d.kubectl("--namespace default wait --for=condition=Ready pods --all")
}

stageAutomaticRelease(makefile)
} finally {
stage('Remove k3d cluster') {
k3d.deleteK3d()
}
}
}
}

Expand All @@ -61,6 +132,18 @@ void gitWithCredentials(String command) {
}
}

void stageLintK8SResources(Makefile makefile) {
String kubevalImage = "cytopia/kubeval:0.13"
String controllerVersion = makefile.getVersion()

docker
.image(kubevalImage)
.inside("-v ${WORKSPACE}/target:/data -t --entrypoint=")
{
sh "kubeval /data/${repositoryName}_${controllerVersion}.yaml --ignore-missing-schemas"
}
}

void stageStaticAnalysisReviewDog() {
def commitSha = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()

Expand Down Expand Up @@ -102,6 +185,74 @@ void stageStaticAnalysisSonarQube() {
}
}

void stageAutomaticRelease(Makefile makefile) {
if (gitflow.isReleaseBranch()) {
String releaseVersion = git.getSimpleBranchName()
String dockerReleaseVersion = releaseVersion.split("v")[1]
String controllerVersion = makefile.getVersion()

stage('Build & Push Image') {
withCredentials([usernamePassword(credentialsId: 'cesmarvin',
passwordVariable: 'CES_MARVIN_PASSWORD',
usernameVariable: 'CES_MARVIN_USERNAME')]) {
// .netrc is necessary to access private repos
sh "echo \"machine github.com\n" +
"login ${CES_MARVIN_USERNAME}\n" +
"password ${CES_MARVIN_PASSWORD}\" >> ~/.netrc"
}
def dockerImage = docker.build("cloudogu/${repositoryName}:${dockerReleaseVersion}")
sh "rm ~/.netrc"
docker.withRegistry('https://registry.hub.docker.com/', 'dockerHubCredentials') {
dockerImage.push("${dockerReleaseVersion}")
}
}

stage('Finish Release') {
gitflow.finishRelease(releaseVersion, productionReleaseBranch)
}

stage('Sign after Release') {
gpg.createSignature()
}

stage('Regenerate resources for release') {
new Docker(this)
.image("golang:${goVersion}")
.mountJenkinsUser()
.inside("--volume ${WORKSPACE}:/go/src/${project} -w /go/src/${project}")
{
make 'k8s-create-temporary-resource'
}
}

stage('Push to Registry') {
GString targetOperatorResourceYaml = "target/${repositoryName}_${controllerVersion}.yaml"

DoguRegistry registry = new DoguRegistry(this)
registry.pushK8sYaml(targetOperatorResourceYaml, repositoryName, "k8s", "${controllerVersion}")
}

stage('Push Helm chart to Harbor') {
new Docker(this)
.image("golang:${goVersion}")
.mountJenkinsUser()
.inside("--volume ${WORKSPACE}:/go/src/${project} -w /go/src/${project}")
{
make 'k8s-helm-package-release'

withCredentials([usernamePassword(credentialsId: 'harborhelmchartpush', usernameVariable: 'HARBOR_USERNAME', passwordVariable: 'HARBOR_PASSWORD')]) {
sh ".bin/helm registry login ${registry} --username '${HARBOR_USERNAME}' --password '${HARBOR_PASSWORD}'"
sh ".bin/helm push target/helm/${repositoryName}-${controllerVersion}.tgz oci://${registry}/${registry_namespace}/"
}
}
}

stage('Add Github-Release') {
releaseId = github.createReleaseWithChangelog(releaseVersion, changelog, productionReleaseBranch)
}
}
}

void make(String makeArgs) {
sh "make ${makeArgs}"
}
}
58 changes: 58 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,63 @@ include build/make/clean.mk
include build/make/digital-signature.mk
include build/make/mocks.mk

PRE_COMPILE=generate
K8S_RESOURCE_TEMP_FOLDER ?= $(TARGET_DIR)
K8S_PRE_GENERATE_TARGETS=k8s-create-temporary-resource template-dev-only-image-pull-policy

include build/make/k8s-controller.mk

.PHONY: build-boot
build-boot: image-import k8s-apply kill-operator-pod ## Builds a new version of the operator and deploys it into the K8s-EcoSystem.

##@ Controller specific targets

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
@echo "Generate manifests..."
@$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
@cp config/crd/bases/k8s.cloudogu.com_backups.yaml pkg/api/v1/
@cp config/crd/bases/k8s.cloudogu.com_restores.yaml pkg/api/v1/

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
@echo "Auto-generate deepcopy functions..."
@$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

##@ Deployment

.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | kubectl apply -f -

.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
@$(KUSTOMIZE) build config/crd | kubectl delete --wait=false --ignore-not-found=true -f -
@kubectl patch crd/backups.k8s.cloudogu.com -p '{"metadata":{"finalizers":[]}}' --type=merge || true

.PHONY: template-stage
template-stage:
@echo "Setting STAGE env in deployment to ${STAGE}!"
@$(BINARY_YQ) -i e "(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.image == \"*$(ARTIFACT_ID)*\").env[]|select(.name==\"STAGE\").value)=\"${STAGE}\"" $(K8S_RESOURCE_TEMP_YAML)

.PHONY: template-log-level
template-log-level:
@echo "Setting LOG_LEVEL env in deployment to ${LOG_LEVEL}!"
@$(BINARY_YQ) -i e "(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.image == \"*$(ARTIFACT_ID)*\").env[]|select(.name==\"LOG_LEVEL\").value)=\"${LOG_LEVEL}\"" $(K8S_RESOURCE_TEMP_YAML)

.PHONY: template-dev-only-image-pull-policy
template-dev-only-image-pull-policy: $(BINARY_YQ)
@echo "Setting pull policy to always!"
@$(BINARY_YQ) -i e "(select(.kind == \"Deployment\").spec.template.spec.containers[]|select(.image == \"*$(ARTIFACT_ID)*\").imagePullPolicy)=\"Always\"" $(K8S_RESOURCE_TEMP_YAML)

.PHONY: kill-operator-pod
kill-operator-pod:
@echo "Restarting k8s-backup-operator!"
@kubectl -n ${NAMESPACE} delete pods -l 'app.kubernetes.io/name=k8s-backup-operator'

##@ Debug

.PHONY: print-debug-info
print-debug-info: ## Generates indo and the list of environment variables required to start the operator in debug mode.
@echo "The target generates a list of env variables required to start the operator in debug mode. These can be pasted directly into the 'go build' run configuration in IntelliJ to run and debug the operator on-demand."
@echo "STAGE=$(STAGE);LOG_LEVEL=$(LOG_LEVEL);KUBECONFIG=$(KUBECONFIG);NAMESPACE=$(NAMESPACE);DOGU_REGISTRY_ENDPOINT=$(DOGU_REGISTRY_ENDPOINT);DOGU_REGISTRY_USERNAME=$(DOGU_REGISTRY_USERNAME);DOGU_REGISTRY_PASSWORD=$(DOGU_REGISTRY_PASSWORD);DOCKER_REGISTRY={\"auths\":{\"$(docker_registry_server)\":{\"username\":\"$(docker_registry_username)\",\"password\":\"$(docker_registry_password)\",\"email\":\"[email protected]\",\"auth\":\"ignoreMe\"}}}"
29 changes: 29 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Code generated by tool. DO NOT EDIT.
# This file is used to track the info used to scaffold your project
# and allow the plugins properly work.
# More info: https://book.kubebuilder.io/reference/project-config.html
domain: cloudogu.com
layout:
- go.kubebuilder.io/v4
projectName: k8s-backup-operator
repo: github.com/cloudogu/k8s-backup-operator
resources:
- api:
crdVersion: v1
namespaced: true
controller: true
domain: cloudogu.com
group: k8s
kind: Restore
path: github.com/cloudogu/k8s-backup-operator/pkg/api/v1
version: v1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: cloudogu.com
group: k8s
kind: Backup
path: github.com/cloudogu/k8s-backup-operator/pkg/api/v1
version: v1
version: "3"
Loading

0 comments on commit 2dd6cc9

Please sign in to comment.