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

Reply via email to