You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/08/19 15:58:18 UTC

[camel-karavan] branch main updated: Fix #866

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 880fed58 Fix #866
880fed58 is described below

commit 880fed5864b1e0531bb84cdf0a98c44ae136231f
Author: Marat Gubaidullin <ma...@Marats-MacBook-Pro.local>
AuthorDate: Sat Aug 19 11:54:51 2023 -0400

    Fix #866
---
 .../camel/karavan/docker/DockerEventListener.java  |  21 ++--
 .../apache/camel/karavan/docker/DockerService.java | 111 +++++++++++++++++++--
 .../camel/karavan/docker/GiteaCheckCallback.java   |  53 ++++++++++
 .../camel/karavan/docker/LoggerCallback.java       |  21 ++++
 .../apache/camel/karavan/service/EventService.java |  21 +++-
 .../apache/camel/karavan/service/GitService.java   |  12 +--
 .../apache/camel/karavan/service/GiteaService.java | 101 +++++++++++++++++++
 .../camel/karavan/service/KaravanService.java      |  20 +++-
 .../camel/karavan/service/ProjectService.java      |   4 +-
 .../org/apache/camel/karavan/shared/Constants.java |   2 +
 .../org/apache/camel/karavan/shared/EventType.java |   2 +
 .../src/main/resources/application.properties      |  20 ++--
 .../karavan-app/src/main/webui/package.json        |   2 +-
 .../karavan/infinispan/InfinispanService.java      |   8 +-
 .../camel/karavan/infinispan/model/GitConfig.java  |   1 -
 .../src/main/resources/application.properties      |   6 +-
 16 files changed, 347 insertions(+), 58 deletions(-)

diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
index 2508aa96..5c36fb4d 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
@@ -59,19 +59,18 @@ public class DockerEventListener implements ResultCallback<Event> {
     }
 
     public void onContainerEvent(Event event, Container container) {
+        String status = event.getStatus();
+        if (status.startsWith("health_status:") && container.getNames()[0].equals("/gitea")) {
+            dockerService.installGitea();
+        }
         if (infinispanService.isReady()) {
-//             if (Arrays.asList("create", "start", "unpause", "stop", "pause").contains(event.getStatus())) {
-//                onExistingContainer(container);
-//            } else {
-                String status = event.getStatus();
-                if (status.startsWith("health_status:")) {
-                    if (container.getNames()[0].equals("/infinispan")) {
-                        onInfinispanHealthEvent(container, event);
-                    } else if (inDevMode(container)) {
-                        onDevModeHealthEvent(container, event);
-                    }
+            if (status.startsWith("health_status:")) {
+                if (container.getNames()[0].equals("/infinispan")) {
+                    onInfinispanHealthEvent(container, event);
+                } else if (inDevMode(container)) {
+                    onDevModeHealthEvent(container, event);
                 }
-//            }
+            }
         }
     }
 
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
index 103c04c3..4bf53751 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
@@ -18,10 +18,7 @@ package org.apache.camel.karavan.docker;
 
 import com.github.dockerjava.api.DockerClient;
 import com.github.dockerjava.api.async.ResultCallback;
-import com.github.dockerjava.api.command.CreateContainerCmd;
-import com.github.dockerjava.api.command.CreateContainerResponse;
-import com.github.dockerjava.api.command.CreateNetworkResponse;
-import com.github.dockerjava.api.command.HealthState;
+import com.github.dockerjava.api.command.*;
 import com.github.dockerjava.api.model.*;
 import com.github.dockerjava.core.DefaultDockerClientConfig;
 import com.github.dockerjava.core.DockerClientConfig;
@@ -32,11 +29,15 @@ import com.github.dockerjava.zerodep.ZerodepDockerHttpClient;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.docker.model.DevService;
 import org.apache.camel.karavan.infinispan.model.ContainerStatus;
+import org.apache.camel.karavan.infinispan.model.GitConfig;
+import org.apache.camel.karavan.service.GitService;
+import org.apache.camel.karavan.service.GiteaService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+
 import java.io.IOException;
 import java.time.Instant;
 import java.util.*;
@@ -51,11 +52,13 @@ public class DockerService extends DockerServiceUtils {
     private static final Logger LOGGER = Logger.getLogger(DockerService.class.getName());
 
     protected static final String INFINISPAN_CONTAINER_NAME = "infinispan";
+    protected static final String GITEA_CONTAINER_NAME = "gitea";
     protected static final String KARAVAN_CONTAINER_NAME = "karavan-headless";
 
     protected static final String NETWORK_NAME = "karavan";
 
     private static final List<String> infinispanHealthCheckCMD = List.of("CMD", "curl", "-f", "http://localhost:11222/rest/v2/cache-managers/default/health/status");
+    private static final List<String> giteaHealthCheckCMD = List.of("CMD", "curl", "-fss", "127.0.0.1:3000/api/healthz");
 
     @ConfigProperty(name = "karavan.environment")
     String environment;
@@ -66,18 +69,27 @@ public class DockerService extends DockerServiceUtils {
     @ConfigProperty(name = "karavan.headless.image")
     String headlessImage;
 
-    @ConfigProperty(name = "infinispan.image")
+    @ConfigProperty(name = "karavan.infinispan.image")
     String infinispanImage;
-    @ConfigProperty(name = "infinispan.port")
+    @ConfigProperty(name = "karavan.infinispan.port")
     String infinispanPort;
-    @ConfigProperty(name = "infinispan.username")
+    @ConfigProperty(name = "karavan.infinispan.username")
     String infinispanUsername;
-    @ConfigProperty(name = "infinispan.password")
+    @ConfigProperty(name = "karavan.infinispan.password")
     String infinispanPassword;
 
+    @ConfigProperty(name = "karavan.gitea.image")
+    String giteaImage;
+
     @Inject
     DockerEventListener dockerEventListener;
 
+    @Inject
+    GitService gitService;
+
+    @Inject
+    GiteaService giteaService;
+
     @Inject
     EventBus eventBus;
 
@@ -369,4 +381,87 @@ public class DockerService extends DockerServiceUtils {
         }
         return dockerClient;
     }
+
+    public void startGitea() {
+        try {
+            LOGGER.info("Gitea container is starting...");
+
+            HealthCheck healthCheck = new HealthCheck().withTest(giteaHealthCheckCMD)
+                    .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30);
+
+            createContainer(GITEA_CONTAINER_NAME, giteaImage,
+                    List.of(), "3000:3000", false, List.of("3000"), healthCheck,
+                    Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name()));
+
+            runContainer(GITEA_CONTAINER_NAME);
+
+            LOGGER.info("Gitea container is started");
+        } catch (Exception e) {
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    protected void createGiteaInstance() {
+        try {
+            LOGGER.info("Creating Gitea Instance");
+            Container gitea = getContainerByName(GITEA_CONTAINER_NAME);
+            ExecCreateCmdResponse instance = dockerClient.execCreateCmd(gitea.getId())
+                    .withAttachStdout(true).withAttachStderr(true)
+                    .withCmd("curl", "-X", "POST", "localhost:3000", "-d",
+                            "db_type=sqlite3&db_host=localhost%3A3306&db_user=root&db_passwd=&db_name=gitea" +
+                                    "&ssl_mode=disable&db_schema=&db_path=%2Fvar%2Flib%2Fgitea%2Fdata%2Fgitea.db&app_name=Gitea%3A+Git+with+a+cup+of+tea" +
+                                    "&repo_root_path=%2Fvar%2Flib%2Fgitea%2Fgit%2Frepositories&lfs_root_path=%2Fvar%2Flib%2Fgitea%2Fgit%2Flfs&run_user=git" +
+                                    "&domain=localhost&ssh_port=2222&http_port=3000&app_url=http%3A%2F%2Flocalhost%3A3000%2F&log_root_path=%2Fvar%2Flib%2Fgitea%2Fdata%2Flog" +
+                                    "&smtp_addr=&smtp_port=&smtp_from=&smtp_user=&smtp_passwd=&enable_federated_avatar=on&enable_open_id_sign_in=on" +
+                                    "&enable_open_id_sign_up=on&default_allow_create_organization=on&default_enable_timetracking=on" +
+                                    "&no_reply_address=noreply.localhost&password_algorithm=pbkdf2&admin_name=&admin_email=&admin_passwd=&admin_confirm_passwd=",
+                            "-H", "'Content-Type: application/x-www-form-urlencoded'")
+                    .exec();
+
+            dockerClient.execStartCmd(instance.getId()).start().awaitCompletion();
+            LOGGER.info("Created Gitea Instance");
+        } catch (Exception e) {
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    protected void createGiteaUser() {
+        try {
+            LOGGER.info("Creating Gitea User");
+            GitConfig config = gitService.getGitConfig();
+            Container gitea = getContainerByName(GITEA_CONTAINER_NAME);
+            ExecCreateCmdResponse user = dockerClient.execCreateCmd(gitea.getId())
+                    .withAttachStdout(true).withAttachStderr(true)
+                    .withCmd("/app/gitea/gitea", "admin", "user", "create",
+                            "--config", "/etc/gitea/app.ini",
+                            "--username", config.getUsername(),
+                            "--password", config.getPassword(),
+                            "--email", config.getUsername() + "@karavan.space",
+                            "--admin")
+                    .exec();
+            dockerClient.execStartCmd(user.getId()).exec(new LoggerCallback()).awaitCompletion();
+            LOGGER.info("Created Gitea User");
+            giteaService.createRepository();
+        } catch (Exception e) {
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    protected void checkGiteaInstance() {
+        try {
+            Container gitea = getContainerByName(GITEA_CONTAINER_NAME);
+            ExecCreateCmdResponse user = dockerClient.execCreateCmd(gitea.getId())
+                    .withAttachStdout(true).withAttachStderr(true)
+                    .withCmd("curl", "-Is", "localhost:3000/user/login").exec();
+
+            dockerClient.execStartCmd(user.getId()).exec(new GiteaCheckCallback(o -> createGiteaUser(), o -> checkGiteaInstance()));
+        } catch (Exception e) {
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    public void installGitea() {
+        createGiteaInstance();
+        checkGiteaInstance();
+    }
 }
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/GiteaCheckCallback.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/GiteaCheckCallback.java
new file mode 100644
index 00000000..0db0978e
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/GiteaCheckCallback.java
@@ -0,0 +1,53 @@
+package org.apache.camel.karavan.docker;
+
+import com.github.dockerjava.api.async.ResultCallback;
+import com.github.dockerjava.api.model.Frame;
+
+import java.io.Closeable;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+
+public class GiteaCheckCallback extends ResultCallback.Adapter<Frame> {
+
+    private static final AtomicBoolean giteaStarted = new AtomicBoolean(false);
+    private static final AtomicInteger giteaCheck = new AtomicInteger(0);
+
+
+    private final Consumer createGiteaUser;
+    private final Consumer checkGiteaInstance;
+
+    public GiteaCheckCallback(Consumer createGiteaUser, Consumer checkGiteaInstance) {
+        this.createGiteaUser = createGiteaUser;
+        this.checkGiteaInstance = checkGiteaInstance;
+    }
+
+    @Override
+    public void onStart(Closeable stream) {
+    }
+
+    @Override
+    public void onNext(Frame object) {
+        if (!giteaStarted.get()) {
+            String line = new String(object.getPayload());
+            if (line.startsWith("HTTP/1.1 200")) {
+                giteaStarted.set(true);
+                createGiteaUser.accept(null);
+            }
+        }
+    }
+
+    @Override
+    public void onError(Throwable throwable) {
+
+    }
+
+    @Override
+    public void onComplete() {
+        giteaCheck.incrementAndGet();
+        if (!giteaStarted.get() && giteaCheck.get() < 1000) {
+            checkGiteaInstance.accept(null);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LoggerCallback.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LoggerCallback.java
new file mode 100644
index 00000000..054148f5
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LoggerCallback.java
@@ -0,0 +1,21 @@
+package org.apache.camel.karavan.docker;
+
+import com.github.dockerjava.api.async.ResultCallback;
+import com.github.dockerjava.api.model.Frame;
+import org.jboss.logging.Logger;
+
+public class LoggerCallback extends ResultCallback.Adapter<Frame> {
+
+    private static final Logger LOGGER = Logger.getLogger(LoggerCallback.class.getName());
+
+    @Override
+    public void onNext(Frame frame) {
+        LOGGER.info(new String(frame.getPayload()));
+    }
+
+
+    @Override
+    public void onError(Throwable throwable) {
+        LOGGER.error(throwable.getMessage());
+    }
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
index 03da9dce..1eef3b1e 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
@@ -10,6 +10,7 @@ import org.apache.camel.karavan.infinispan.model.CamelStatus;
 import org.apache.camel.karavan.infinispan.model.ContainerStatus;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
 import org.apache.camel.karavan.shared.ConfigService;
+import org.apache.camel.karavan.shared.Constants;
 import org.apache.camel.karavan.shared.EventType;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
@@ -49,9 +50,15 @@ public class EventService {
     @Inject
     EventBus eventBus;
 
+    @ConsumeEvent(value = START_INFINISPAN_IN_DOCKER, blocking = true, ordered = true)
+    void startInfinispan1(String data) {
+        dockerService.startInfinispan();
+        dockerService.checkInfinispanHealth();
+    }
+
     @ConsumeEvent(value = INFINISPAN_STARTED, blocking = true, ordered = true)
-    void startServices(String infinispanHealth) {
-        if (infinispanHealth.equals(InfinispanService.HEALTHY_STATUS)) {
+    void startServices1(String infinispanHealth) {
+        if (infinispanHealth.equals(Constants.HEALTHY_STATUS)) {
             infinispanService.start(false);
             infinispanService.clearAllStatuses();
             if (!ConfigService.inKubernetes()) {
@@ -63,6 +70,16 @@ public class EventService {
         }
     }
 
+    @ConsumeEvent(value = GITEA_STARTED, blocking = true, ordered = true)
+    void startServices2(String giteaHealth) {
+        eventBus.publish(EventType.START_INFINISPAN_IN_DOCKER, null);
+    }
+
+    void startServices(String infinispanHealth) {
+        eventBus.publish(EventType.IMPORT_PROJECTS, "");
+        eventBus.publish(EventType.START_INFRASTRUCTURE_LISTENERS, "");
+    }
+
     @ConsumeEvent(value = START_INFRASTRUCTURE_LISTENERS, blocking = true, ordered = true)
     void startInfrastructureListeners(String data) {
         LOGGER.info("Start Infrastructure Listeners");
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
index 2ce35d23..16feebf9 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
@@ -54,17 +54,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GiteaService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GiteaService.java
new file mode 100644
index 00000000..b62d268d
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/GiteaService.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.karavan.service;
+
+import io.vertx.core.eventbus.EventBus;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.Vertx;
+import io.vertx.mutiny.core.buffer.Buffer;
+import io.vertx.mutiny.ext.web.client.HttpResponse;
+import io.vertx.mutiny.ext.web.client.WebClient;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import org.apache.camel.karavan.infinispan.model.GitConfig;
+import org.apache.camel.karavan.shared.EventType;
+import org.jboss.logging.Logger;
+
+import java.util.List;
+import java.util.Map;
+
+@ApplicationScoped
+public class GiteaService {
+
+    private static final Logger LOGGER = Logger.getLogger(GiteaService.class.getName());
+
+    @Inject
+    Vertx vertx;
+
+    @Inject
+    EventBus eventBus;
+
+    @Inject
+    GitService gitService;
+
+    WebClient webClient;
+
+    private WebClient getWebClient() {
+        if (webClient == null) {
+            webClient = WebClient.create(vertx);
+        }
+        return webClient;
+    }
+
+    public void createRepository() {
+        try {
+            LOGGER.info("Creating Gitea Repository");
+            String token = generateToken();
+            HttpResponse<Buffer> result = getWebClient().postAbs("http://localhost:3000/api/v1/user/repos").timeout(500)
+                    .putHeader("Content-Type", "application/json")
+                    .bearerTokenAuthentication(token)
+                    .sendJsonObject(new JsonObject(Map.of(
+                            "auto_init", true,
+                            "default_branch", "main",
+                            "description", "karavan",
+                            "name", "karavan",
+                            "private", true
+                    )))
+                    .subscribeAsCompletionStage().toCompletableFuture().get();
+            if (result.statusCode() == 201) {
+                JsonObject res = result.bodyAsJsonObject();
+                eventBus.publish(EventType.START_INFINISPAN_IN_DOCKER, null);
+            }
+            LOGGER.info("Created Gitea Repository");
+        } catch (Exception e) {
+            LOGGER.info(e.getMessage());
+        }
+    }
+
+    private String generateToken() {
+        try {
+            LOGGER.info("Creating Gitea User Token");
+            GitConfig config = gitService.getGitConfig();
+            HttpResponse<Buffer> result = getWebClient().postAbs("http://localhost:3000/api/v1/users/" + config.getUsername() + "/tokens").timeout(500)
+                    .putHeader("Content-Type", "application/json")
+                    .putHeader("accept", "application/json")
+                    .basicAuthentication(config.getUsername(), config.getPassword())
+                    .sendJsonObject(new JsonObject(Map.of("name", "karavan", "scopes", List.of("write:repository", "write:user"))))
+                    .subscribeAsCompletionStage().toCompletableFuture().get();
+            if (result.statusCode() == 201) {
+                JsonObject res = result.bodyAsJsonObject();
+                return res.getString("sha1");
+            }
+        } catch (Exception e) {
+            LOGGER.info(e.getMessage());
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index b2d3b57f..bdd5b900 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -21,10 +21,11 @@ import io.quarkus.runtime.ShutdownEvent;
 import io.quarkus.runtime.StartupEvent;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.docker.DockerService;
-import org.apache.camel.karavan.infinispan.InfinispanService;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
 import org.apache.camel.karavan.shared.ConfigService;
+import org.apache.camel.karavan.shared.Constants;
 import org.apache.camel.karavan.shared.EventType;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import jakarta.enterprise.context.ApplicationScoped;
@@ -37,6 +38,9 @@ public class KaravanService {
 
     private static final Logger LOGGER = Logger.getLogger(KaravanService.class.getName());
 
+    @ConfigProperty(name = "karavan.git-install-gitea")
+    boolean giteaInstall;
+
     @Inject
     KubernetesService kubernetesService;
 
@@ -44,7 +48,10 @@ public class KaravanService {
     DockerService dockerService;
 
     @Inject
-    EventBus bus;
+    GitService gitService;
+
+    @Inject
+    EventBus eventBus;
 
     void onStart(@Observes StartupEvent ev) {
         LOGGER.info("Starting Karavan");
@@ -58,13 +65,16 @@ public class KaravanService {
                 } else {
                     dockerService.createNetwork();
                     dockerService.startListeners();
-                    dockerService.startInfinispan();
-                    dockerService.checkInfinispanHealth();
+                    if (giteaInstall) {
+                        dockerService.startGitea();
+                    } else {
+                        eventBus.publish(EventType.START_INFINISPAN_IN_DOCKER, null);
+                    }
                 }
             }
         } else {
             LOGGER.info("Starting Karavan in " + (kubernetesService.isOpenshift() ? "OpenShift" : "Kubernetes"));
-            bus.publish(EventType.INFINISPAN_STARTED, InfinispanService.HEALTHY_STATUS);
+            eventBus.publish(EventType.INFINISPAN_STARTED, Constants.HEALTHY_STATUS);
         }
     }
 
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index 8d042d71..7dd01ca1 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -105,6 +105,7 @@ public class ProjectService implements HealthCheck{
         if (infinispanService.getProjects().isEmpty()) {
             importAllProjects();
         }
+        addKameletsProject();
         addTemplatesProject();
         addServicesProject();
         if (!Objects.equals("disabled", gitPullInterval.toLowerCase()) && !Objects.equals("off", gitPullInterval.toLowerCase())) {
@@ -137,7 +138,6 @@ public class ProjectService implements HealthCheck{
                     infinispanService.saveProjectFile(file);
                 });
             });
-            addKameletsProject();
         } catch (Exception e) {
             LOGGER.error("Error during project import", e);
         }
@@ -237,7 +237,7 @@ public class ProjectService implements HealthCheck{
                     ProjectFile file = new ProjectFile(name, value, Project.Type.services.name(), Instant.now().toEpochMilli());
                     infinispanService.saveProjectFile(file);
                 });
-                commitAndPushProject(Project.Type.templates.name(), "Add services");
+                commitAndPushProject(Project.Type.services.name(), "Add services");
             }
         } catch (Exception e) {
             LOGGER.error("Error during services project creation", e);
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
index 1d7467fc..0d6871bd 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Constants.java
@@ -24,4 +24,6 @@ public class Constants {
     public static final String LABEL_PROJECT_ID = "org.apache.camel.karavan/projectId";
 
     public static final String RELOAD_TRY_COUNT = "reloadTryCount";
+
+    public static final String HEALTHY_STATUS = "healthy";
 }
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java
index 112cea18..edcaa284 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/EventType.java
@@ -24,7 +24,9 @@ public class EventType {
     //    Import projects from Git repository
     public static final String IMPORT_PROJECTS = "IMPORT_PROJECTS";
 
+    public static final String START_INFINISPAN_IN_DOCKER = "START_INFINISPAN_IN_DOCKER";
     public static final String INFINISPAN_STARTED = "INFINISPAN_STARTED";
+    public static final String GITEA_STARTED = "GITEA_STARTED";
 
     public static final String CONTAINER_STATUS = "CONTAINER_STATUS";
     public static final String DEVMODE_CONTAINER_READY = "DEVMODE_STATUS";
diff --git a/karavan-web/karavan-app/src/main/resources/application.properties b/karavan-web/karavan-app/src/main/resources/application.properties
index 6f42cd08..80c50b65 100644
--- a/karavan-web/karavan-app/src/main/resources/application.properties
+++ b/karavan-web/karavan-app/src/main/resources/application.properties
@@ -10,19 +10,21 @@ karavan.devmode.image=ghcr.io/apache/camel-karavan-devmode:4.0.0-RC2
 karavan.headless.image=entropy1/karavan-headless:4.0.0-RC2
 
 # Git repository Configuration
-karavan.git-repository=${GIT_REPOSITORY}
-karavan.git-username=${GIT_USERNAME}
-karavan.git-password=${GIT_TOKEN}
+karavan.git-repository=http://localhost:3000/karavan/karavan.git
+karavan.git-username=karavan
+karavan.git-password=karavan
 karavan.git-branch=main
+karavan.git-install-gitea=true
 karavan.git-pull-interval=disabled
+karavan.gitea.image=gitea/gitea:1.20.2-rootless
 
 # Infinispan container config in Docker
-infinispan.image=quay.io/infinispan/server:14.0.6.Final
-infinispan.port=11222:11222
+karavan.infinispan.image=quay.io/infinispan/server:14.0.6.Final
+karavan.infinispan.port=11222:11222
 # Infinispan connection config
-infinispan.username=admin
-infinispan.password=karavan
-infinispan.hosts=localhost:11222
+karavan.infinispan.username=admin
+karavan.infinispan.password=karavan
+karavan.infinispan.hosts=localhost:11222
 
 quarkus.infinispan-client.devservices.enabled=false
 quarkus.infinispan-client.client-intelligence=BASIC
@@ -109,5 +111,5 @@ quarkus.kubernetes-client.devservices.enabled=false
 quarkus.quinoa.frozen-lockfile=false
 quarkus.quinoa.package-manager-install=false
 quarkus.quinoa.package-manager-install.node-version=18.12.1
-quarkus.quinoa.dev-server.port=3000
+quarkus.quinoa.dev-server.port=3003
 quarkus.quinoa.dev-server.check-timeout=60000
diff --git a/karavan-web/karavan-app/src/main/webui/package.json b/karavan-web/karavan-app/src/main/webui/package.json
index d8192567..8361a5cb 100644
--- a/karavan-web/karavan-app/src/main/webui/package.json
+++ b/karavan-web/karavan-app/src/main/webui/package.json
@@ -4,7 +4,7 @@
   "private": true,
   "scripts": {
     "copy-designer": "cp -r ../../../../../karavan-designer/src/designer src && cp -r ../../../../../karavan-designer/src/knowledgebase src",
-    "start": "npm run copy-designer && react-scripts start",
+    "start": "export PORT=3003 && npm run copy-designer && react-scripts start",
     "build": "CI=false && npm run copy-designer && DISABLE_ESLINT_PLUGIN=true react-scripts build"
   },
   "proxy": "http://127.0.0.1:8080/",
diff --git a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
index e03e9c12..36301239 100644
--- a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
+++ b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
@@ -51,13 +51,11 @@ import static org.infinispan.query.remote.client.ProtobufMetadataManagerConstant
 @ApplicationScoped
 public class InfinispanService {
 
-    public static final String HEALTHY_STATUS = "healthy";
-
-    @ConfigProperty(name ="infinispan.hosts")
+    @ConfigProperty(name ="karavan.infinispan.hosts")
     String infinispanHosts;
-    @ConfigProperty(name ="infinispan.username")
+    @ConfigProperty(name ="karavan.infinispan.username")
     String infinispanUsername;
-    @ConfigProperty(name ="infinispan.password")
+    @ConfigProperty(name ="karavan.infinispan.password")
     String infinispanPassword;
 
     @Inject
diff --git a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/GitConfig.java b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/GitConfig.java
index 285c8017..580ee799 100644
--- a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/GitConfig.java
+++ b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/model/GitConfig.java
@@ -44,5 +44,4 @@ public class GitConfig {
     public void setBranch(String branch) {
         this.branch = branch;
     }
-
 }
diff --git a/karavan-web/karavan-infinispan/src/main/resources/application.properties b/karavan-web/karavan-infinispan/src/main/resources/application.properties
index 81c48214..b708de8f 100644
--- a/karavan-web/karavan-infinispan/src/main/resources/application.properties
+++ b/karavan-web/karavan-infinispan/src/main/resources/application.properties
@@ -1,6 +1,6 @@
-infinispan.username=admin
-infinispan.password=password
-infinispan.hosts=localhost:11222
+karavan.infinispan.username=admin
+karavan.infinispan.password=password
+karavan.infinispan.hosts=localhost:11222
 
 quarkus.infinispan-client.devservices.enabled=true
 quarkus.infinispan-client.devservices.service-name=infinispan