Skip to content

Commit 544c574

Browse files
committed
Kubernetes Operator for Nessie
1 parent 5e17626 commit 544c574

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+4521
-0
lines changed

Diff for: bom/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ dependencies {
4141
api(project(":nessie-jaxrs-tests"))
4242
api(project(":nessie-keycloak-testcontainer"))
4343
api(project(":nessie-nessie-testcontainer"))
44+
api(project(":nessie-operator"))
4445
api(project(":nessie-quarkus-auth"))
4546
api(project(":nessie-quarkus-common"))
4647
api(project(":nessie-quarkus-cli"))

Diff for: gradle/libs.versions.toml

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ quarkus-bom = { module = "io.quarkus.platform:quarkus-bom", version.ref = "quark
146146
quarkus-cassandra-bom = { module = "io.quarkus.platform:quarkus-cassandra-bom", version.ref = "quarkus" }
147147
quarkus-google-cloud-services-bom = { module = "io.quarkus.platform:quarkus-google-cloud-services-bom", version.ref = "quarkus" }
148148
quarkus-logging-sentry = { module = "io.quarkiverse.loggingsentry:quarkus-logging-sentry", version = "2.0.5" }
149+
quarkus-operator-sdk-bom = { module = "io.quarkus.platform:quarkus-operator-sdk-bom", version.ref = "quarkus" }
149150
rest-assured = { module = "io.rest-assured:rest-assured", version = "5.4.0" }
150151
rocksdb-jni = { module = "org.rocksdb:rocksdbjni", version = "8.10.0" }
151152
scala-library-v212 = { module = "org.scala-lang:scala-library", version = { strictly = "[2.12, 2.13[", prefer = "2.12.18" }}

Diff for: gradle/projects.main.properties

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ nessie-jaxrs-testextension=servers/jax-rs-testextension
2121
nessie-jaxrs-tests=servers/jax-rs-tests
2222
nessie-keycloak-testcontainer=testing/keycloak-container
2323
nessie-nessie-testcontainer=testing/nessie-container
24+
nessie-operator=operator
2425
nessie-quarkus-auth=servers/quarkus-auth
2526
nessie-quarkus-cli=servers/quarkus-cli
2627
nessie-quarkus-common=servers/quarkus-common

Diff for: operator/Makefile

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
2+
VERSION ?= $(shell cat ../version.txt | sed -e 's/.*-SNAPSHOT/latest/g')
3+
RELEASE_VERSION ?= $(shell cat ../version.txt | sed -e 's/-SNAPSHOT//g')
4+
5+
# CHANNELS define the bundle channels used in the bundle.
6+
# Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable")
7+
# To re-generate a bundle for other specific channels without changing the standard setup, you can:
8+
# - use the CHANNELS as arg of the bundle target (e.g make bundle CHANNELS=candidate,fast,stable)
9+
# - use environment variables to overwrite this value (e.g export CHANNELS="candidate,fast,stable")
10+
ifneq ($(origin CHANNELS), undefined)
11+
BUNDLE_CHANNELS := --channels=$(CHANNELS)
12+
endif
13+
14+
# DEFAULT_CHANNEL defines the default channel used in the bundle.
15+
# Add a new line here if you would like to change its default config. (E.g DEFAULT_CHANNEL = "stable")
16+
# To re-generate a bundle for any other default channel without changing the default setup, you can:
17+
# - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable)
18+
# - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable")
19+
ifneq ($(origin DEFAULT_CHANNEL), undefined)
20+
BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL)
21+
endif
22+
BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL)
23+
24+
# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images.
25+
# This variable is used to construct full image tags for bundle and catalog images.
26+
IMAGE_TAG_BASE ?= ghcr.io/projectnessie/nessie-operator
27+
28+
# BUNDLE_IMG defines the image:tag used for the bundle.
29+
# You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=<some-registry>/<project-name-bundle>:<tag>)
30+
BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:$(VERSION)
31+
32+
# Image URL to use all building/pushing image targets
33+
IMG ?= $(IMAGE_TAG_BASE):$(VERSION)
34+
35+
PULL_POLICY ?= $(shell [ "$(VERSION)" = "latest" ] && echo "Always" || echo "IfNotPresent")
36+
PLATFORM ?= linux/$(shell arch)
37+
38+
all: docker-build
39+
40+
##@ General
41+
42+
# The help target prints out all targets with their descriptions organized
43+
# beneath their categories. The categories are represented by '##@' and the
44+
# target descriptions by '##'. The awk commands is responsible for reading the
45+
# entire set of makefiles included in this invocation, looking for lines of the
46+
# file as xyz: ## something, and then pretty-format the target and help. Then,
47+
# if there's a line with ##@ something, that gets pretty-printed as a category.
48+
# More info on the usage of ANSI control characters for terminal formatting:
49+
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
50+
# More info on the awk command:
51+
# http://linuxcommand.org/lc3_adv_awk.php
52+
53+
help: ## Display this help.
54+
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
55+
56+
##@ Build
57+
58+
docker-build: ## Build docker image with the manager.
59+
../gradlew --no-build-cache :nessie-operator:spotlessApply :nessie-operator:clean :nessie-operator:build -x check \
60+
-Dquarkus.container-image.image=${IMG} \
61+
-Dquarkus.jib.platforms=${PLATFORM} \
62+
-Dquarkus.kubernetes.image-pull-policy=${PULL_POLICY}
63+
64+
docker-push: ## Build and push docker image with the manager.
65+
../gradlew --no-build-cache :nessie-operator:spotlessApply :nessie-operator:clean :nessie-operator:build -x check \
66+
-Dquarkus.container-image.push=true \
67+
-Dquarkus.container-image.image=${IMG} \
68+
-Dquarkus.jib.platforms=${PLATFORM} \
69+
-Dquarkus.kubernetes.image-pull-policy=${PULL_POLICY}
70+
71+
##@ Deployment
72+
73+
install: ## Install CRDs into the K8s cluster specified in ~/.kube/config.
74+
@$(foreach file, $(wildcard build/kubernetes/*-v1.yml), kubectl apply -f $(file);)
75+
76+
uninstall: ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config.
77+
@$(foreach file, $(wildcard build/kubernetes/*-v1.yml), kubectl delete -f $(file);)
78+
79+
deploy: ## Deploy controller to the K8s cluster specified in ~/.kube/config.
80+
kubectl apply -f build/kubernetes/kubernetes.yml
81+
82+
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config.
83+
kubectl delete -f build/kubernetes/kubernetes.yml
84+
85+
##@ Helm
86+
87+
helm-install: ## Install CRDs and the operator using Helm.
88+
helm install nessie-operator build/helm -n nessie-operator
89+
90+
helm-upgrade: ## Upgrade CRDs and the operator using Helm.
91+
helm upgrade nessie-operator build/helm -n nessie-operator
92+
93+
helm-uninstall: ## Uninstall CRDs and the operator using Helm.
94+
helm uninstall nessie-operator -n nessie-operator
95+
96+
##@ Bundle
97+
98+
.PHONY: bundle
99+
bundle: ## Generate bundle manifests and metadata, then validate generated files.
100+
cat build/kubernetes/* | operator-sdk generate bundle -q --overwrite --version $(RELEASE_VERSION) $(BUNDLE_METADATA_OPTS)
101+
operator-sdk bundle validate ./bundle
102+
# TODO use quarkus
103+
104+
.PHONY: bundle-build
105+
bundle-build: ## Build the bundle image.
106+
docker build -f build/bundle/nessie-operator/bundle.Dockerfile -t $(BUNDLE_IMG) build/bundle/nessie-operator
107+
108+
.PHONY: bundle-push
109+
bundle-push: ## Push the bundle image.
110+
docker push $(BUNDLE_IMG)

Diff for: operator/PROJECT

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Code generated by tool. DO NOT EDIT.
2+
# This file is used to track the info used to scaffold your project
3+
# and allow the plugins properly work.
4+
# More info: https://book.kubebuilder.io/reference/project-config.html
5+
domain: projectnessie.org
6+
layout:
7+
- quarkus.javaoperatorsdk.io/v1-alpha
8+
projectName: nessie-operator
9+
resources:
10+
- api:
11+
crdVersion: v1
12+
namespaced: true
13+
domain: projectnessie.org
14+
group: nessie
15+
kind: Nessie
16+
version: v1alpha1
17+
version: "3"

Diff for: operator/README.md

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Kubernetes Operator for Nessie
2+
3+
## Overview
4+
5+
This module is a Kubernetes Operator for Nessie.
6+
7+
**WARNING: This is a work in progress and is not ready for production use.**
8+
9+
This project was created using [Operator SDK]:
10+
11+
```bash
12+
operator-sdk init --plugins=quarkus --domain=projectnessie.org --project-name=nessie-operator
13+
operator-sdk create api --plugins=quarkus --version=v1alpha1 --kind=Nessie
14+
```
15+
16+
[Operator SDK]:https://sdk.operatorframework.io/docs/cli/operator-sdk/
17+
18+
## Usage
19+
20+
TODO describe typical deployment scenarios.
21+
22+
## Development
23+
24+
### TODOS
25+
26+
- [ ] Features
27+
- [ ] Enable operator remote debugging
28+
- [ ] CRD validation
29+
- [ ] Admission webhook ? https://github.com/operator-framework/josdk-webhooks
30+
- [ ] Operator release
31+
- [ ] Publish operator image as part of release process
32+
- [ ] Publish operator Helm charts
33+
- [ ] Publish manifests + Kustomize?
34+
- [ ] Operator Lifecycle Manager (OLM) support
35+
- [ ] Generate and Validate ClusterServiceVersion (CSV) metadata
36+
- https://olm.operatorframework.io/docs/tasks/creating-operator-manifests/
37+
- https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/building-your-csv.md
38+
- https://k8s-operatorhub.github.io/community-operators/packaging-required-fields/
39+
- [ ] Publish bundle image as part of release process
40+
- [ ] Publish bundle to operatorhub.io:
41+
- How to contribute: https://operatorhub.io/contribute
42+
- Instructions for packaging: https://k8s-operatorhub.github.io/community-operators/packaging-operator/
43+
- Testing the bundle locally: https://k8s-operatorhub.github.io/community-operators/testing-operators/
44+
- [ ] Publish a certified bundle to Openshift OperatorHub?
45+
- https://github.com/redhat-openshift-ecosystem/community-operators-prod
46+
- https://github.com/redhat-openshift-ecosystem/certified-operators
47+
- [ ] Tests
48+
- [ ] Unit tests
49+
- [ ] Smoke test
50+
- [ ] Missing / invalid configs
51+
- [ ] Out-of-cluster tests ?
52+
- [ ] Integration tests:
53+
- [ ] All version stores
54+
- [ ] https://github.com/java-operator-sdk/jenvtest ?
55+
- Examples: https://github.com/operator-framework/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator
56+
- [ ] E2E tests / Adhoc tests
57+
- [ ] Deploy operator in a real cluster (GCP / EKS / AKS / OCP)
58+
- [ ] GC
59+
- [ ] Add a NessieTask CRD ? Reuse Job CRD?
60+
- [ ] Automatically set up a temporary database for Nessie GC
61+
- [ ] Periodic Nessie GC
62+
63+
### Known issues
64+
65+
- [ ] Check generated RBAC rules
66+
67+
### Prerequisites
68+
69+
- Operator SDK: https://sdk.operatorframework.io/docs/installation/
70+
71+
### Building the operator image
72+
73+
```bash
74+
make docker-build
75+
```
76+
77+
### Adhoc testing with Minikube
78+
79+
Install [minikube](https://minikube.sigs.k8s.io/docs/start/).
80+
81+
If you need ingress, install the ingress addon:
82+
83+
```bash
84+
minikube addons enable ingress
85+
minikube tunnel
86+
```
87+
88+
Create the nessie-operator and nessie-ns namespaces (only needed once):
89+
90+
```bash
91+
kubectl create namespace nessie-operator
92+
kubectl create namespace nessie-ns
93+
```
94+
95+
Grant admin rights to the nessie-operator service account (only needed once):
96+
97+
```bash
98+
kubectl apply -f examples/nessie-operator-rbac.yaml
99+
```
100+
101+
Build the operator docker image _inside_ minikube to facilitate testing (doesn't need a registry):
102+
103+
```bash
104+
eval $(minikube docker-env)
105+
make docker-build PULL_POLICY=IfNotPresent
106+
```
107+
108+
Note: the `PULL_POLICY=IfNotPresent` is required to avoid pulling the image from a registry.
109+
110+
Install the CRDs and deploy the operator in the nessie-operator namespace:
111+
112+
```bash
113+
make install deploy
114+
```
115+
116+
Create a Nessie resource in the nessie-ns namespace:
117+
118+
```bash
119+
kubectl apply -n nessie-ns -f examples/nessie-simple.yaml
120+
```
121+
122+
You should see 1 pod, 1 deployment and 1 service running.
123+
124+
### Testing OLM bundles (WIP)
125+
126+
Install OLM in your cluster:
127+
128+
```bash
129+
operator-sdk olm install
130+
```
131+
132+
Manual bundle deployment instructions:
133+
https://docs.quarkiverse.io/quarkus-operator-sdk/dev/index.html#_deployment
134+
135+
Install `opm` (operator package manager): download the binary from:
136+
https://github.com/operator-framework/operator-registry/releases/tag/v1.36.0
137+
138+
MacOS users will need to remove the quarantine attribute from the binary:
139+
140+
```bash
141+
xattr -d com.apple.quarantine ~/bin/opm
142+
```

Diff for: operator/build.gradle.kts

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (C) 2024 Dremio
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/*
18+
* Copyright (C) 2024 Dremio
19+
*
20+
* Licensed under the Apache License, Version 2.0 (the "License");
21+
* you may not use this file except in compliance with the License.
22+
* You may obtain a copy of the License at
23+
*
24+
* http://www.apache.org/licenses/LICENSE-2.0
25+
*
26+
* Unless required by applicable law or agreed to in writing, software
27+
* distributed under the License is distributed on an "AS IS" BASIS,
28+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29+
* See the License for the specific language governing permissions and
30+
* limitations under the License.
31+
*/
32+
import org.apache.tools.ant.filters.ReplaceTokens
33+
34+
plugins {
35+
alias(libs.plugins.quarkus)
36+
id("nessie-conventions-quarkus")
37+
id("nessie-jacoco")
38+
}
39+
40+
extra["maven.name"] = "Nessie - Kubernetes Operator"
41+
42+
dependencies {
43+
implementation(enforcedPlatform(libs.quarkus.bom))
44+
implementation(enforcedPlatform(libs.quarkus.operator.sdk.bom))
45+
46+
implementation("io.quarkiverse.operatorsdk:quarkus-operator-sdk")
47+
implementation("io.quarkiverse.operatorsdk:quarkus-operator-sdk-bundle-generator")
48+
implementation("io.quarkus:quarkus-micrometer-registry-prometheus")
49+
implementation("io.quarkus:quarkus-container-image-jib")
50+
51+
compileOnly("io.sundr:builder-annotations:0.103.0")
52+
compileOnly("io.fabric8:generator-annotations")
53+
54+
annotationProcessor(enforcedPlatform(libs.quarkus.bom))
55+
annotationProcessor("io.sundr:builder-annotations:0.103.0")
56+
// see https://github.com/sundrio/sundrio/issues/104
57+
annotationProcessor("io.fabric8:kubernetes-client")
58+
59+
testImplementation(enforcedPlatform(libs.quarkus.bom))
60+
testImplementation("io.quarkus:quarkus-junit5")
61+
testImplementation("io.quarkus:quarkus-junit5-mockito")
62+
testImplementation("io.quarkus:quarkus-test-kubernetes-client")
63+
testImplementation("org.bouncycastle:bcpkix-jdk18on")
64+
testImplementation(platform(libs.junit.bom))
65+
testImplementation(libs.bundles.junit.testing)
66+
testImplementation(libs.awaitility)
67+
}
68+
69+
listOf("javadoc", "sourcesJar").forEach { name ->
70+
tasks.named(name).configure { dependsOn(tasks.named("compileQuarkusGeneratedSourcesJava")) }
71+
}
72+
73+
listOf("checkstyleTest", "compileTestJava").forEach { name ->
74+
tasks.named(name).configure { dependsOn(tasks.named("compileQuarkusTestGeneratedSourcesJava")) }
75+
}
76+
77+
tasks.named<ProcessResources>("processTestResources").configure {
78+
inputs.property("projectVersion", project.version)
79+
filter(ReplaceTokens::class, mapOf("tokens" to mapOf("projectVersion" to project.version)))
80+
}

Diff for: operator/examples/nessie-autoscaling.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
apiVersion: nessie.projectnessie.org/v1alpha1
2+
kind: Nessie
3+
metadata:
4+
name: nessie-autoscaling
5+
spec:
6+
size: 1
7+
logLevel: INFO
8+
image:
9+
repository: projectnessie/nessie
10+
tag: 0.75.0
11+
versionStore:
12+
type: Jdbc
13+
jdbc:
14+
jdbcUrl: jdbc:h2:mem:nessie
15+
autoscaling:
16+
enabled: true
17+
minReplicas: 1
18+
maxReplicas: 3
19+
targetCpuUtilizationPercentage: 50

0 commit comments

Comments
 (0)