This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
The following commit(s) were added to refs/heads/main by this push:
new 3e223eb Operator first prototype (#419)
3e223eb is described below
commit 3e223eba0da6a5f33578eac5000579068beda7aa
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Tue Jul 19 13:41:44 2022 -0400
Operator first prototype (#419)
---
karavan-operator/.gitignore | 15 +++
karavan-operator/Makefile | 43 ++++++++
karavan-operator/PROJECT | 13 +++
karavan-operator/pom.xml | 80 +++++++++++++++
karavan-operator/resources/deployments-role.yaml | 33 +++++++
karavan-operator/resources/karavan.yaml | 16 +++
.../apache/camel/karavan/AbstractResources.java | 54 ++++++++++
.../java/org/apache/camel/karavan/Constants.java | 23 +++++
.../java/org/apache/camel/karavan/Karavan.java | 12 +++
.../apache/camel/karavan/KaravanController.java | 38 +++++++
.../org/apache/camel/karavan/KaravanResources.java | 109 +++++++++++++++++++++
.../java/org/apache/camel/karavan/KaravanSpec.java | 23 +++++
.../org/apache/camel/karavan/KaravanStatus.java | 46 +++++++++
.../src/main/resources/application.properties | 9 ++
14 files changed, 514 insertions(+)
diff --git a/karavan-operator/.gitignore b/karavan-operator/.gitignore
new file mode 100644
index 0000000..2b14944
--- /dev/null
+++ b/karavan-operator/.gitignore
@@ -0,0 +1,15 @@
+
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+bin
+target
+
+# editor and IDE paraphernalia
+.idea
+*.swp
+*.swo
+*~
diff --git a/karavan-operator/Makefile b/karavan-operator/Makefile
new file mode 100644
index 0000000..584aa45
--- /dev/null
+++ b/karavan-operator/Makefile
@@ -0,0 +1,43 @@
+
+# Image URL to use all building/pushing image targets
+IMG ?= controller:latest
+
+all: docker-build
+
+##@ General
+
+# The help target prints out all targets with their descriptions organized
+# beneath their categories. The categories are represented by '##@' and the
+# target descriptions by '##'. The awk commands is responsible for reading the
+# entire set of makefiles included in this invocation, looking for lines of the
+# file as xyz: ## something, and then pretty-format the target and help. Then,
+# if there's a line with ##@ something, that gets pretty-printed as a category.
+# More info on the usage of ANSI control characters for terminal formatting:
+# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
+# More info on the awk command:
+# http://linuxcommand.org/lc3_adv_awk.php
+
+help: ## Display this help.
+ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make
\033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf "
\033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n",
substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+##@ Build
+
+docker-build: ## Build docker image with the manager.
+ mvn package -Dquarkus.container-image.build=true
-Dquarkus.container-image.image=${IMG}
+
+docker-push: ## Push docker image with the manager.
+ mvn package -Dquarkus.container-image.push=true
-Dquarkus.container-image.image=${IMG}
+
+##@ Deployment
+
+install: ## Install CRDs into the K8s cluster specified in ~/.kube/config.
+ @$(foreach file, $(wildcard target/kubernetes/*-v1.yml), kubectl apply
-f $(file);)
+
+uninstall: ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config.
+ @$(foreach file, $(wildcard target/kubernetes/*-v1.yml), kubectl delete
-f $(file);)
+
+deploy: ## Deploy controller to the K8s cluster specified in ~/.kube/config.
+ kubectl apply -f target/kubernetes/kubernetes.yml
+
+undeploy: ## Undeploy controller from the K8s cluster specified in
~/.kube/config.
+ kubectl delete -f target/kubernetes/kubernetes.yml
diff --git a/karavan-operator/PROJECT b/karavan-operator/PROJECT
new file mode 100644
index 0000000..0a79c8b
--- /dev/null
+++ b/karavan-operator/PROJECT
@@ -0,0 +1,13 @@
+domain: karavan.camel.apache.org
+layout:
+- quarkus.javaoperatorsdk.io/v1-alpha
+projectName: karavan-operator
+resources:
+- api:
+ crdVersion: v1
+ namespaced: true
+ domain: karavan.camel.apache.org
+ group: app
+ kind: Karavan
+ version: v1
+version: "3"
diff --git a/karavan-operator/pom.xml b/karavan-operator/pom.xml
new file mode 100644
index 0000000..86cdf7e
--- /dev/null
+++ b/karavan-operator/pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.camel.karavan</groupId>
+ <artifactId>karavan-operator</artifactId>
+ <name>karavan-operator</name>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <properties>
+ <compiler-plugin.version>3.8.1</compiler-plugin.version>
+ <maven.compiler.parameters>true</maven.compiler.parameters>
+ <maven.compiler.source>11</maven.compiler.source>
+ <maven.compiler.target>11</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <quarkus-sdk.version>2.0.1</quarkus-sdk.version>
+ <quarkus.version>2.7.0.Final</quarkus.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-bom</artifactId>
+ <version>${quarkus.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-arc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.operatorsdk</groupId>
+ <artifactId>quarkus-operator-sdk</artifactId>
+ <version>${quarkus-sdk.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit5</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>native</id>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/karavan-operator/resources/deployments-role.yaml
b/karavan-operator/resources/deployments-role.yaml
new file mode 100644
index 0000000..af8e7e8
--- /dev/null
+++ b/karavan-operator/resources/deployments-role.yaml
@@ -0,0 +1,33 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: karavancontroller-deployment-role
+rules:
+ - apiGroups:
+ - apps
+ - extensions
+ resources:
+ - deployments
+ verbs:
+ - get
+ - list
+ - watch
+ - create
+ - delete
+ - patch
+ - update
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ labels:
+ app.kubernetes.io/name: karavan-operator
+ app.kubernetes.io/version: 0.0.11
+ name: karavan-operator-deployment-controller
+roleRef:
+ kind: Role
+ apiGroup: rbac.authorization.k8s.io
+ name: karavancontroller-deployment-role
+subjects:
+ - kind: ServiceAccount
+ name: karavan-operator
\ No newline at end of file
diff --git a/karavan-operator/resources/karavan.yaml
b/karavan-operator/resources/karavan.yaml
new file mode 100644
index 0000000..61e8af8
--- /dev/null
+++ b/karavan-operator/resources/karavan.yaml
@@ -0,0 +1,16 @@
+apiVersion: camel.apache.org/v1
+kind: Karavan
+metadata:
+ name: karavan
+ annotations:
+ camel.apache.org/support.level: Preview
+ camel.apache.org/version: 0.0.11
+ camel.apache.org/provider: Apache Software Foundation
+spec:
+ instances: 2
+ mode: serverless
+# git:
+# uri: http://gitea:3000/git/karavan.git
+# username: git
+# password: gitgit
+# main: master
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/AbstractResources.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/AbstractResources.java
new file mode 100644
index 0000000..d67a696
--- /dev/null
+++
b/karavan-operator/src/main/java/org/apache/camel/karavan/AbstractResources.java
@@ -0,0 +1,54 @@
+package org.apache.camel.karavan;
+
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import io.fabric8.kubernetes.api.model.OwnerReference;
+import io.fabric8.kubernetes.api.model.OwnerReferenceBuilder;
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.client.KubernetesClient;
+
+public abstract class AbstractResources {
+
+ private Karavan karavan;
+
+ @Inject
+ KubernetesClient client;
+
+ protected Optional<Deployment> checkDeploymentExists(String name){
+ return
Optional.ofNullable(client.apps().deployments().inNamespace(client.getNamespace()).withName(name).get());
+ }
+
+ protected Optional<Service> checkServiceExists(String name) {
+ return
Optional.ofNullable(client.services().inNamespace(client.getNamespace()).withName(name).get());
+ }
+
+ protected void deleteDeployment(String name){
+
client.apps().deployments().inNamespace(client.getNamespace()).withName(name).delete();
+ }
+
+ protected void deleteService(String name){
+
client.services().inNamespace(client.getNamespace()).withName(name).delete();
+ }
+
+ protected OwnerReference createOwnerReference(Karavan resource) {
+ final var metadata = resource.getMetadata();
+ return new OwnerReferenceBuilder()
+ .withUid(metadata.getUid())
+ .withApiVersion(resource.getApiVersion())
+ .withName(metadata.getName())
+ .withKind(resource.getKind())
+ .build();
+ }
+
+ public Karavan getKaravan() {
+ return karavan;
+ }
+
+ public void setKaravan(Karavan karavan) {
+ this.karavan = karavan;
+ }
+
+}
\ No newline at end of file
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/Constants.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/Constants.java
new file mode 100644
index 0000000..a709ebe
--- /dev/null
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/Constants.java
@@ -0,0 +1,23 @@
+package org.apache.camel.karavan;
+
+import java.util.Map;
+
+public final class Constants {
+ public static final String CRD_GROUP = "camel.apache.org";
+ public static final String CRD_VERSION = "v1";
+ public static final String SHORT_NAME = "karavan";
+ public static final String NAME = "karavan";
+ public static final String PLURAL_NAME = "karavans";
+ public static final String MANAGED_BY_LABEL =
"app.kubernetes.io/managed-by";
+ public static final String MANAGED_BY_VALUE = "karavan-operator";
+
+ public static final String KARAVAN_MODE = "KARAVAN_MODE";
+
+ public static final Map<String, String> DEFAULT_LABELS = Map.of(
+ "app.kubernetes.io/name", NAME,
+ "app.kubernetes.io/version", "latest",
+ "app.kubernetes.io/part-of", NAME
+ );
+
+ public static final String KARAVAN_IMAGE =
"ghcr.io/apache/camel-karavan:latest";
+}
\ No newline at end of file
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/Karavan.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/Karavan.java
new file mode 100644
index 0000000..70df643
--- /dev/null
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/Karavan.java
@@ -0,0 +1,12 @@
+package org.apache.camel.karavan;
+
+import io.fabric8.kubernetes.api.model.Namespaced;
+import io.fabric8.kubernetes.client.CustomResource;
+import io.fabric8.kubernetes.model.annotation.*;
+
+@Group(Constants.CRD_GROUP)
+@Version(Constants.CRD_VERSION)
+@ShortNames(Constants.SHORT_NAME)
+@Plural(Constants.PLURAL_NAME)
+public class Karavan extends CustomResource<KaravanSpec, KaravanStatus>
implements Namespaced {}
+
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanController.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanController.java
new file mode 100644
index 0000000..d9f337f
--- /dev/null
+++
b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanController.java
@@ -0,0 +1,38 @@
+package org.apache.camel.karavan;
+
+import javax.inject.Inject;
+
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.javaoperatorsdk.operator.api.Context;
+import io.javaoperatorsdk.operator.api.Controller;
+import io.javaoperatorsdk.operator.api.ResourceController;
+import io.javaoperatorsdk.operator.api.UpdateControl;
+import io.javaoperatorsdk.operator.processing.event.EventSourceManager;
+
+@Controller(namespaces = Controller.WATCH_CURRENT_NAMESPACE)
+public class KaravanController implements ResourceController<Karavan> {
+
+ @Inject
+ KaravanResources karavanResources;
+
+ @Inject
+ KubernetesClient client;
+
+ public KaravanController(KubernetesClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void init(EventSourceManager eventSourceManager) {
+ }
+
+ @Override
+ public UpdateControl<Karavan> createOrUpdateResource(Karavan resource,
Context<Karavan> context) {
+ karavanResources.createResources(resource);
+
+ resource.setStatus(new KaravanStatus());
+
+ return UpdateControl.updateStatusSubResource(resource);
+ }
+}
+
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanResources.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanResources.java
new file mode 100644
index 0000000..f0ae627
--- /dev/null
+++
b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanResources.java
@@ -0,0 +1,109 @@
+package org.apache.camel.karavan;
+
+import java.util.Map;
+import java.util.Optional;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import io.fabric8.kubernetes.api.model.IntOrString;
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.api.model.ServiceBuilder;
+import io.fabric8.kubernetes.api.model.apps.Deployment;
+import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
+
+import static org.apache.camel.karavan.Constants.KARAVAN_IMAGE;
+
+@ApplicationScoped
+public class KaravanResources extends AbstractResources {
+
+
+ public void createResources(Karavan karavan) {
+ this.setKaravan(karavan);
+ createFrontendDeployment(karavan);
+ createFrontendService();
+ }
+
+ private void createFrontendDeployment(Karavan karavan) {
+ Optional<Deployment> potentialDeployment =
checkDeploymentExists(Constants.NAME);
+
+ if (potentialDeployment.isEmpty()) {
+ Deployment deployment1 = new DeploymentBuilder()
+ .withNewMetadata()
+ .withName(Constants.NAME)
+ .withLabels(Constants.DEFAULT_LABELS)
+
.withOwnerReferences(this.createOwnerReference(this.getKaravan()))
+ .endMetadata()
+
+ .withNewSpec()
+ .withReplicas(karavan.getSpec().getInstances())
+ .withNewSelector()
+ .addToMatchLabels(Constants.DEFAULT_LABELS)
+ .endSelector()
+
+ .withNewTemplate()
+ .withNewMetadata()
+ .addToLabels(Constants.DEFAULT_LABELS)
+ .endMetadata()
+
+ .withNewSpec()
+ .addNewContainer()
+ .withName(Constants.NAME)
+ .withImage(KARAVAN_IMAGE)
+ .withImagePullPolicy("Always")
+ .addNewEnv()
+ .withName(Constants.KARAVAN_MODE)
+ .withValue(karavan.getSpec().getMode())
+ .endEnv()
+ .addNewPort()
+ .withContainerPort(8080)
+ .withName(Constants.NAME)
+ .endPort()
+ .endContainer()
+// .withServiceAccount(Constants.NAME)
+ .endSpec()
+ .endTemplate()
+ .endSpec()
+ .build();
+
client.apps().deployments().inNamespace(client.getNamespace()).create(deployment1);
+ } else { //We are maybe dealing with an update
+ //EnvVar envar =
potentialDeployment.get().getSpec().getTemplate().getSpec().getContainers().get(0).
+ client.apps().deployments().inNamespace(client.getNamespace())
+ .withName(Constants.NAME).edit(d -> new
DeploymentBuilder(d)
+ .editSpec()
+ .editTemplate().editSpec()
+ .editFirstContainer()
+ .editFirstEnv()
+ .withValue(karavan.getSpec().getMode())
+ .endEnv()
+ .endContainer()
+ .endSpec()
+ .endTemplate()
+ .endSpec()
+ .build());
+ }
+ }
+
+
+ private void createFrontendService() {
+ if (checkServiceExists(Constants.NAME).isEmpty()) {
+ Service service = new ServiceBuilder()
+ .withNewMetadata()
+ .withName(Constants.NAME)
+ .withLabels(Constants.DEFAULT_LABELS)
+ .endMetadata()
+ .withNewSpec()
+ .withType("NodePort")
+ .addNewPort()
+ .withName(Constants.NAME)
+ .withPort(80)
+ .withTargetPort(new IntOrString(8080))
+ .withNodePort(31171)
+ .withProtocol("TCP")
+ .endPort()
+ .withSelector(Constants.DEFAULT_LABELS)
+ .endSpec()
+ .build();
+
client.services().inNamespace(client.getNamespace()).create(service);
+ }
+ }
+}
\ No newline at end of file
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanSpec.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanSpec.java
new file mode 100644
index 0000000..970aeee
--- /dev/null
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanSpec.java
@@ -0,0 +1,23 @@
+package org.apache.camel.karavan;
+
+public class KaravanSpec {
+
+ private int instances;
+ private String mode;
+
+ public int getInstances() {
+ return instances;
+ }
+
+ public void setInstances(int instances) {
+ this.instances = instances;
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+}
diff --git
a/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanStatus.java
b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanStatus.java
new file mode 100644
index 0000000..e287550
--- /dev/null
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/KaravanStatus.java
@@ -0,0 +1,46 @@
+package org.apache.camel.karavan;
+
+public class KaravanStatus {
+
+ public enum State {
+ READY,
+ ERROR,
+ UNKNOWN
+ }
+
+ private State state = State.UNKNOWN;
+ private boolean error;
+ private String message;
+
+ public State getState() {
+ return state;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ public boolean isError() {
+ return error;
+ }
+
+ public void setError(boolean error) {
+ this.error = error;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public KaravanStatus clone() {
+ var status = new KaravanStatus();
+ status.setMessage(this.message);
+ status.setState(this.state);
+ status.setError(this.error);
+ return status;
+ }
+}
diff --git a/karavan-operator/src/main/resources/application.properties
b/karavan-operator/src/main/resources/application.properties
new file mode 100644
index 0000000..2f80612
--- /dev/null
+++ b/karavan-operator/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+quarkus.container-image.build=true
+# set to true to automatically apply CRDs to the cluster when they get
regenerated
+quarkus.operator-sdk.crd.apply=true
+quarkus.operator-sdk.crd.validate=false
+
+quarkus.container-image.builder=jib
+quarkus.container-image.group=apache
+quarkus.container-image.name=camel-karavan
+quarkus.container-image.tag=latest
\ No newline at end of file