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
commit c8a13f22531c1fa0521b8517bcca623824f12312 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Thu Aug 31 10:48:45 2023 -0400 Unifying Docker deployment for #817 --- .../camel/karavan/api/InfrastructureResource.java | 10 +- .../camel/karavan/docker/DockerForGitea.java | 46 ++------- .../camel/karavan/docker/DockerForInfinispan.java | 24 +---- .../camel/karavan/docker/DockerForKaravan.java | 23 ++--- .../apache/camel/karavan/docker/DockerService.java | 105 +++++++++++++++++++-- .../camel/karavan/docker/DockerServiceUtils.java | 77 +++++++++------ .../{DevService.java => DockerComposeService.java} | 6 +- .../src/main/resources/application.properties | 1 - .../karavan-app/src/main/resources/gitea/app.ini | 94 ++++++++++++++++++ .../src/main/resources/services/internal.yaml | 31 ++++++ 10 files changed, 299 insertions(+), 118 deletions(-) diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java index 17f4c526..5c5f9fae 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java @@ -22,7 +22,7 @@ import io.vertx.mutiny.core.eventbus.EventBus; import io.vertx.mutiny.core.eventbus.Message; import org.apache.camel.karavan.docker.DockerForKaravan; import org.apache.camel.karavan.docker.DockerService; -import org.apache.camel.karavan.docker.model.DevService; +import org.apache.camel.karavan.docker.model.DockerComposeService; import org.apache.camel.karavan.infinispan.InfinispanService; import org.apache.camel.karavan.infinispan.model.ContainerStatus; import org.apache.camel.karavan.infinispan.model.DeploymentStatus; @@ -195,10 +195,10 @@ public class InfrastructureResource { if (command.getString("command").equalsIgnoreCase("run")) { if (Objects.equals(type, ContainerStatus.ContainerType.devservice.name())) { String code = projectService.getDevServiceCode(); - DevService devService = dockerService.getDevService(code, name); - if (devService != null) { - dockerForKaravan.createDevserviceContainer(devService); - dockerService.runContainer(devService.getContainer_name()); + DockerComposeService dockerComposeService = dockerService.convertToDockerComposeService(code, name); + if (dockerComposeService != null) { + dockerForKaravan.createDevserviceContainer(dockerComposeService); + dockerService.runContainer(dockerComposeService.getContainer_name()); } } else if (Objects.equals(type, ContainerStatus.ContainerType.devmode.name())) { dockerForKaravan.createDevmodeContainer(name, ""); diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java index 9e5d6c6e..8cde9667 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java @@ -18,21 +18,14 @@ package org.apache.camel.karavan.docker; import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.model.Container; -import com.github.dockerjava.api.model.HealthCheck; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; 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 java.util.List; -import java.util.Map; - -import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE; - @ApplicationScoped public class DockerForGitea { @@ -40,11 +33,6 @@ public class DockerForGitea { protected static final String GITEA_CONTAINER_NAME = "gitea"; - private static final List<String> giteaHealthCheckCMD = List.of("CMD", "curl", "-fss", "127.0.0.1:3000/api/healthz"); - - @ConfigProperty(name = "karavan.gitea.image") - String giteaImage; - @Inject DockerService dockerService; @@ -57,39 +45,22 @@ public class DockerForGitea { public void startGitea() { try { LOGGER.info("Gitea container is starting..."); - - HealthCheck healthCheck = new HealthCheck().withTest(giteaHealthCheckCMD) - .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30); - - dockerService.createContainer(GITEA_CONTAINER_NAME, giteaImage, - List.of(), "3000:3000", false, List.of("3000"), healthCheck, - Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name())); - + var compose = dockerService.getInternalDockerComposeService(GITEA_CONTAINER_NAME); + Container c = dockerService.createContainerFromCompose(compose, ContainerStatus.ContainerType.internal); + copyAppIni(c.getId()); dockerService.runContainer(GITEA_CONTAINER_NAME); - LOGGER.info("Gitea container is started"); } catch (Exception e) { LOGGER.error(e.getMessage()); } } - protected void createGiteaInstance() { + protected void copyAppIni(String containerId) { try { - LOGGER.info("Creating Gitea Instance"); - Container gitea = dockerService.getContainerByName(GITEA_CONTAINER_NAME); - ExecCreateCmdResponse instance = dockerService.execCreate(gitea.getId(), - "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'"); - - dockerService.execStart(instance.getId()); - LOGGER.info("Created Gitea Instance"); + LOGGER.info("Copying Gitea app.ini"); + String ini = DockerServiceUtils.getResourceFile("/gitea/app.ini"); + dockerService.copyFile(containerId, "/etc/gitea","app.ini", ini); + LOGGER.info("Copied Gitea app.ini"); } catch (Exception e) { LOGGER.error(e.getMessage()); } @@ -128,7 +99,6 @@ public class DockerForGitea { } public void installGitea() { - createGiteaInstance(); checkGiteaInstance(); } } diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java index 802d8de2..b6b6673e 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForInfinispan.java @@ -17,7 +17,6 @@ package org.apache.camel.karavan.docker; import com.github.dockerjava.api.command.HealthState; -import com.github.dockerjava.api.model.HealthCheck; import io.vertx.core.eventbus.EventBus; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -26,9 +25,6 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; import java.util.List; -import java.util.Map; - -import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE; import static org.apache.camel.karavan.shared.EventType.INFINISPAN_STARTED; @ApplicationScoped @@ -38,12 +34,6 @@ public class DockerForInfinispan { protected static final String INFINISPAN_CONTAINER_NAME = "infinispan"; - private static final List<String> infinispanHealthCheckCMD = List.of("CMD", "curl", "-f", "http://localhost:11222/rest/v2/cache-managers/default/health/status"); - - @ConfigProperty(name = "karavan.infinispan.image") - String infinispanImage; - @ConfigProperty(name = "karavan.infinispan.port") - String infinispanPort; @ConfigProperty(name = "karavan.infinispan.username") String infinispanUsername; @ConfigProperty(name = "karavan.infinispan.password") @@ -58,17 +48,9 @@ public class DockerForInfinispan { public void startInfinispan() { try { LOGGER.info("Infinispan is starting..."); - - HealthCheck healthCheck = new HealthCheck().withTest(infinispanHealthCheckCMD) - .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30); - - List<String> exposedPorts = List.of(infinispanPort.split(":")[0]); - - dockerService.createContainer(INFINISPAN_CONTAINER_NAME, infinispanImage, - List.of("USER=" + infinispanUsername, "PASS=" + infinispanPassword), - infinispanPort, false, exposedPorts, healthCheck, - Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name())); - + var compose = dockerService.getInternalDockerComposeService(INFINISPAN_CONTAINER_NAME); + compose.getEnvironmentList().addAll(List.of("USER=" + infinispanUsername, "PASS=" + infinispanPassword)); + dockerService.createContainerFromCompose(compose, ContainerStatus.ContainerType.internal); dockerService.runContainer(INFINISPAN_CONTAINER_NAME); LOGGER.info("Infinispan is started"); } catch (Exception e) { diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java index ee0a6864..c6d2b728 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java @@ -19,7 +19,7 @@ package org.apache.camel.karavan.docker; import com.github.dockerjava.api.model.HealthCheck; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import org.apache.camel.karavan.docker.model.DevService; +import org.apache.camel.karavan.docker.model.DockerComposeService; import org.apache.camel.karavan.infinispan.model.ContainerStatus; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; @@ -62,23 +62,15 @@ public class DockerForKaravan { dockerService.createContainer(projectId, devmodeImage, env, null, false, List.of(), healthCheck, - Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId)); + Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devmode.name(), LABEL_PROJECT_ID, projectId), + Map.of()); LOGGER.infof("DevMode started for %s", projectId); } - public void createDevserviceContainer(DevService devService) throws InterruptedException { - LOGGER.infof("DevService starting for ", devService.getContainer_name()); - - HealthCheck healthCheck = dockerService.getHealthCheck(devService.getHealthcheck()); - List<String> env = devService.getEnvironment() != null ? devService.getEnvironmentList() : List.of(); - String ports = String.join(",", devService.getPorts()); - - dockerService.createContainer(devService.getContainer_name(), devService.getImage(), - env, ports, false, devService.getExpose(), healthCheck, - Map.of(LABEL_TYPE, ContainerStatus.ContainerType.devservice.name())); - - LOGGER.infof("DevService started for %s", devService.getContainer_name()); + public void createDevserviceContainer(DockerComposeService dockerComposeService) throws InterruptedException { + LOGGER.infof("DevService starting for ", dockerComposeService.getContainer_name()); + dockerService.createContainerFromCompose(dockerComposeService, ContainerStatus.ContainerType.devservice); } public void startKaravanHeadlessContainer() { @@ -92,7 +84,8 @@ public class DockerForKaravan { "INFINISPAN_PASSWORD=" + infinispanPassword ), null, false, List.of(), new HealthCheck(), - Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name())); + Map.of(LABEL_TYPE, ContainerStatus.ContainerType.internal.name()), + Map.of()); dockerService.runContainer(KARAVAN_CONTAINER_NAME); LOGGER.info("Karavan headless is started"); 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 5f4a3b10..10c8018e 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 @@ -24,20 +24,30 @@ import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.core.InvocationBuilder; +import com.github.dockerjava.core.util.CompressArchiveUtil; import com.github.dockerjava.transport.DockerHttpClient; import com.github.dockerjava.zerodep.ZerodepDockerHttpClient; -import io.vertx.core.eventbus.EventBus; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; +import org.apache.camel.karavan.docker.model.DockerComposeService; import org.apache.camel.karavan.infinispan.model.ContainerStatus; +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; -import java.io.IOException; +import java.io.*; +import java.nio.file.LinkOption; +import java.nio.file.Paths; import java.time.Instant; import java.util.*; import java.util.stream.Collectors; +import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE; + @ApplicationScoped public class DockerService extends DockerServiceUtils { @@ -52,7 +62,7 @@ public class DockerService extends DockerServiceUtils { DockerEventListener dockerEventListener; @Inject - EventBus eventBus; + Vertx vertx; private DockerClient dockerClient; @@ -132,8 +142,40 @@ public class DockerService extends DockerServiceUtils { return stats; } + public Container createContainerFromCompose(DockerComposeService compose, ContainerStatus.ContainerType type) throws InterruptedException { + List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(compose.getContainer_name())).exec(); + if (containers.isEmpty()) { + LOGGER.infof("Compose Service starting for ", compose.getContainer_name()); + + HealthCheck healthCheck = getHealthCheck(compose.getHealthcheck()); + List<String> env = compose.getEnvironment() != null ? compose.getEnvironmentList() : List.of(); + String ports = String.join(",", compose.getPorts()); + + LOGGER.infof("Compose Service started for %s", compose.getContainer_name()); + + return createContainer(compose.getContainer_name(), compose.getImage(), + env, ports, false, compose.getExpose(), healthCheck, + Map.of(LABEL_TYPE, type.name()), + Map.of()); + + } else { + LOGGER.info("Compose Service already exists: " + containers.get(0).getId()); + return containers.get(0); + } + } + + public Container createContainerFromCompose(String yaml, String name, ContainerStatus.ContainerType type) throws Exception { + var compose = convertToDockerComposeService(yaml, name); + if (compose != null) { + return createContainerFromCompose(compose, type); + } else { + throw new Exception("Service not found in compose YAML!"); + } + } + public Container createContainer(String name, String image, List<String> env, String ports, boolean inRange, - List<String> exposed, HealthCheck healthCheck, Map<String, String> labels) throws InterruptedException { + List<String> exposed, HealthCheck healthCheck, Map<String, String> labels, + Map<String, String> volumes) throws InterruptedException { List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec(); if (containers.size() == 0) { pullImage(image); @@ -141,14 +183,29 @@ public class DockerService extends DockerServiceUtils { CreateContainerCmd createContainerCmd = getDockerClient().createContainerCmd(image) .withName(name).withLabels(labels).withEnv(env).withHostName(name).withHealthcheck(healthCheck); + Ports portBindings; + List<ExposedPort> exposedPorts = new ArrayList<>(); if (exposed != null) { - List<ExposedPort> exposedPorts = exposed.stream().map(i -> ExposedPort.tcp(Integer.parseInt(i))).collect(Collectors.toList()); - createContainerCmd.withExposedPorts(exposedPorts); - createContainerCmd.withHostConfig(getHostConfig(ports, exposedPorts, inRange, NETWORK_NAME)); + exposedPorts.addAll(exposed.stream().map(i -> ExposedPort.tcp(Integer.parseInt(i))).toList()); + portBindings = getPortBindings(ports,exposedPorts, inRange); } else { - createContainerCmd.withHostConfig(getHostConfig(ports, List.of(), inRange, NETWORK_NAME)); + portBindings = getPortBindings(ports,exposedPorts, inRange); } + List<Mount> mounts = new ArrayList<>(); + if (volumes != null && !volumes.isEmpty()) { + volumes.forEach((hostPath, containerPath) -> { + mounts.add(new Mount().withType(MountType.BIND).withSource(hostPath).withTarget(containerPath)); + }); + } + + createContainerCmd.withExposedPorts(exposedPorts); + createContainerCmd.withHostConfig(new HostConfig() + .withPortBindings(portBindings) + .withMounts(mounts) + .withNetworkMode(NETWORK_NAME)); + + CreateContainerResponse response = createContainerCmd.exec(); LOGGER.info("Container created: " + response.getId()); return getDockerClient().listContainersCmd().withShowAll(true) @@ -170,10 +227,23 @@ public class DockerService extends DockerServiceUtils { } } } + public List<Container> listContainers(Boolean showAll) { return getDockerClient().listContainersCmd().withShowAll(showAll).exec(); } + public List<InspectVolumeResponse> listVolumes() { + return getDockerClient().listVolumesCmd().exec().getVolumes(); + } + + public InspectVolumeResponse getVolume(String name) { + return getDockerClient().inspectVolumeCmd(name).exec(); + } + + public CreateVolumeResponse createVolume(String name) { + return getDockerClient().createVolumeCmd().withName(name).exec(); + } + public InspectContainerResponse inspectContainer(String id) { return getDockerClient().inspectContainerCmd(id).exec(); } @@ -189,10 +259,29 @@ public class DockerService extends DockerServiceUtils { public void execStart(String id) throws InterruptedException { getDockerClient().execStartCmd(id).start().awaitCompletion(); } + public void execStart(String id, ResultCallback.Adapter<Frame> callBack) throws InterruptedException { getDockerClient().execStartCmd(id).exec(callBack).awaitCompletion(); } + public void copyFile(String id, String containerPath, String filename, String text) throws IOException { +// try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); +// TarArchiveOutputStream tarArchive = new TarArchiveOutputStream(byteArrayOutputStream)) { +// tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); +// tarArchive.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX); +// +// String temp = vertx.fileSystem().createTempDirectoryBlocking("x"); +// String path = temp + File.separator + filename; +// vertx.fileSystem().writeFileBlocking(path, Buffer.buffer(text)); +// +// ArchiveEntry archive = tarArchive.createArchiveEntry(Paths.get(path), "app.ini"); +// tarArchive.putArchiveEntry(archive);; +// tarArchive.finish(); + getDockerClient().copyArchiveToContainerCmd(id).withRemotePath("/data") + .withHostResource("/Users/marat/projects/camel-karavan/karavan-web/karavan-app/src/main/resources/gitea").exec(); +// } + } + public void logContainer(String containerName, LogCallback callback) { try { Container container = getContainerByName(containerName); diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java index 3d7cb8e3..703f33ae 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerServiceUtils.java @@ -18,28 +18,32 @@ package org.apache.camel.karavan.docker; import com.github.dockerjava.api.model.*; import io.smallrye.mutiny.tuples.Tuple2; +import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import org.apache.camel.karavan.api.KameletResources; -import org.apache.camel.karavan.docker.model.DevService; +import org.apache.camel.karavan.docker.model.DockerComposeService; import org.apache.camel.karavan.docker.model.HealthCheckConfig; import org.apache.camel.karavan.infinispan.model.ContainerStatus; import org.apache.camel.karavan.service.CodeService; import org.yaml.snakeyaml.Yaml; import jakarta.inject.Inject; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; + +import java.io.*; import java.text.DecimalFormat; +import java.time.Duration; import java.time.Instant; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; import java.util.stream.Collectors; import static org.apache.camel.karavan.shared.Constants.LABEL_TYPE; public class DockerServiceUtils { + protected static final String ENVIRONMENT = "environment"; + protected static final DecimalFormat formatCpu = new DecimalFormat("0.00"); protected static final DecimalFormat formatMiB = new DecimalFormat("0.0"); protected static final DecimalFormat formatGiB = new DecimalFormat("0.00"); @@ -67,42 +71,57 @@ public class DockerServiceUtils { } } - public DevService getDevService(String code, String name) { + public DockerComposeService getInternalDockerComposeService (String name) { + String composeText = getResourceFile("/services/internal.yaml"); + return convertToDockerComposeService(composeText, name); + } + + public DockerComposeService convertToDockerComposeService(String code, String name) { Yaml yaml = new Yaml(); Map<String, Object> obj = yaml.load(code); JsonObject json = JsonObject.mapFrom(obj); JsonObject services = json.getJsonObject("services"); if (services.containsKey(name)) { - DevService ds = services.getJsonObject(name).mapTo(DevService.class); - if (ds.getContainer_name() == null) { - ds.setContainer_name(name); - } - return ds; + JsonObject service = services.getJsonObject(name); + return convertToDockerComposeService(name, service); } else { Optional<JsonObject> j = services.fieldNames().stream() .map(services::getJsonObject) - .filter(s -> { - s.getJsonObject("container_name"); - return false; - }).findFirst(); + .filter(s -> s.getString("container_name").equalsIgnoreCase(name)).findFirst(); if (j.isPresent()) { - return j.get().mapTo(DevService.class); + return convertToDockerComposeService(name, j.get()); } } return null; } + public DockerComposeService convertToDockerComposeService(String name, JsonObject service) { + if (service.containsKey(ENVIRONMENT) && service.getValue(ENVIRONMENT) instanceof JsonArray) { + JsonObject env = new JsonObject(); + service.getJsonArray(ENVIRONMENT).forEach(o -> { + String[] kv = o.toString().split("="); + env.put(kv[0], kv[1]); + }); + service.put(ENVIRONMENT, env); + } + DockerComposeService ds = service.mapTo(DockerComposeService.class); + if (ds.getContainer_name() == null) { + ds.setContainer_name(name); + } + return ds; + } + protected HealthCheck getHealthCheck(HealthCheckConfig config) { if (config != null) { HealthCheck healthCheck = new HealthCheck().withTest(config.getTest()); if (config.getInterval() != null) { - healthCheck.withInterval(convertDuration(config.getInterval())); + healthCheck.withInterval(durationNanos(config.getInterval())); } if (config.getTimeout() != null) { - healthCheck.withTimeout(convertDuration(config.getTimeout())); + healthCheck.withTimeout(durationNanos(config.getTimeout())); } if (config.getStart_period() != null) { - healthCheck.withStartPeriod(convertDuration(config.getStart_period())); + healthCheck.withStartPeriod(durationNanos(config.getStart_period())); } if (config.getRetries() != null) { healthCheck.withRetries(config.getRetries()); @@ -112,11 +131,7 @@ public class DockerServiceUtils { return new HealthCheck(); } - protected Long convertDuration(String value) { - return Long.parseLong(value.replace("s", "")) * 1000000000L; - } - - protected String getResourceFile(String path) { + protected static String getResourceFile(String path) { try { InputStream inputStream = KameletResources.class.getResourceAsStream(path); return new BufferedReader(new InputStreamReader(inputStream)) @@ -126,7 +141,17 @@ public class DockerServiceUtils { } } - protected HostConfig getHostConfig(String ports, List<ExposedPort> exposedPorts, boolean inRange, String network) { + protected static long durationNanos(String s) { + if (Pattern.compile("\\d+d\\s").matcher(s).find()) { + int idxSpace = s.indexOf(" "); + s = "P" + s.substring(0, idxSpace) + "T" + s.substring(idxSpace + 1); + } else + s = "PT" + s; + s = s.replace(" ", ""); + return Duration.parse(s).toMillis() * 1000000L; + } + + protected Ports getPortBindings(String ports, List<ExposedPort> exposedPorts, boolean inRange) { Ports portBindings = new Ports(); getPortsFromString(ports).forEach((hostPort, containerPort) -> { @@ -135,9 +160,7 @@ public class DockerServiceUtils { : Ports.Binding.bindPort(hostPort); portBindings.bind(ExposedPort.tcp(containerPort), binding); }); - return new HostConfig() - .withPortBindings(portBindings) - .withNetworkMode(network); + return portBindings; } protected Map<Integer, Integer> getPortsFromString(String ports) { diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DevService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java similarity index 95% rename from karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DevService.java rename to karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java index af218774..eed5fa37 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DevService.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/model/DockerComposeService.java @@ -4,7 +4,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -public class DevService { +public class DockerComposeService { private String container_name; private String image; @@ -15,7 +15,7 @@ public class DevService { private Map<String,String> environment; private HealthCheckConfig healthcheck; - public DevService() { + public DockerComposeService() { } public String getContainer_name() { @@ -89,7 +89,7 @@ public class DevService { @Override public String toString() { - return "DevService{" + + return "DockerComposeService {" + "container_name='" + container_name + '\'' + ", image='" + image + '\'' + ", restart='" + restart + '\'' + diff --git a/karavan-web/karavan-app/src/main/resources/application.properties b/karavan-web/karavan-app/src/main/resources/application.properties index 80c50b65..79e37e0a 100644 --- a/karavan-web/karavan-app/src/main/resources/application.properties +++ b/karavan-web/karavan-app/src/main/resources/application.properties @@ -16,7 +16,6 @@ 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 karavan.infinispan.image=quay.io/infinispan/server:14.0.6.Final diff --git a/karavan-web/karavan-app/src/main/resources/gitea/app.ini b/karavan-web/karavan-app/src/main/resources/gitea/app.ini new file mode 100644 index 00000000..fb1fcf37 --- /dev/null +++ b/karavan-web/karavan-app/src/main/resources/gitea/app.ini @@ -0,0 +1,94 @@ +APP_NAME = Karavan +RUN_USER = git +RUN_MODE = prod +WORK_PATH = /var/lib/gitea + +[repository] +ROOT =/var/lib/gitea/data/repositories + +[repository.local] +LOCAL_COPY_PATH = /tmp/gitea/local-repo + +[repository.upload] +TEMP_PATH = /tmp/gitea/uploads + +[server] +APP_DATA_PATH = /var/lib/gitea +SSH_DOMAIN = 0.0.0.0 +HTTP_PORT = 3000 +ROOT_URL = http://0.0.0.0:3000/ +DISABLE_SSH = false +; In rootless gitea container only internal ssh server is supported +START_SSH_SERVER = true +SSH_PORT = 2222 +SSH_LISTEN_PORT = 2222 +BUILTIN_SSH_SERVER_USER = git +LFS_START_SERVER = false +DOMAIN = 0.0.0.0 +OFFLINE_MODE = false + +[database] +PATH =/var/lib/gitea/data/gitea.db +DB_TYPE = sqlite3 +HOST = localhost:3306 +NAME = gitea +USER = root +PASSWD = +SCHEMA = +SSL_MODE = disable +LOG_SQL = false + +[session] +PROVIDER_CONFIG = /var/lib/gitea/data/sessions +PROVIDER = file + +[picture] +AVATAR_UPLOAD_PATH = /var/lib/gitea/data/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /var/lib/gitea/data/repo-avatars + +[attachment] +PATH = /var/lib/gitea/data/attachments + +[log] +ROOT_PATH =/var/lib/gitea/data/log +MODE = console +LEVEL = info + +[security] +INSTALL_LOCK = true +SECRET_KEY = +REVERSE_PROXY_LIMIT = 1 +REVERSE_PROXY_TRUSTED_PROXIES = * +PASSWORD_HASH_ALGO = pbkdf2 + +[service] +DISABLE_REGISTRATION = true +REQUIRE_SIGNIN_VIEW = true +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = false +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = false +DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = false +DEFAULT_ENABLE_TIMETRACKING = false +NO_REPLY_ADDRESS = noreply.localhost +ENABLE_BASIC_AUTHENTICATION = true + +[lfs] +PATH = /var/lib/gitea/git/lfs + +[mailer] +ENABLED = false + +[openid] +ENABLE_OPENID_SIGNIN = false +ENABLE_OPENID_SIGNUP = false + +[cron.update_checker] +ENABLED = false + +[repository.pull-request] +DEFAULT_MERGE_STYLE = merge + +[repository.signing] +DEFAULT_TRUST_MODEL = committer diff --git a/karavan-web/karavan-app/src/main/resources/services/internal.yaml b/karavan-web/karavan-app/src/main/resources/services/internal.yaml new file mode 100644 index 00000000..5c970982 --- /dev/null +++ b/karavan-web/karavan-app/src/main/resources/services/internal.yaml @@ -0,0 +1,31 @@ +version: '3.8' + +services: + + infinispan: + image: quay.io/infinispan/server:14.0.6.Final + restart: always + ports: + - "11222:11222" + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost:11222/rest/v2/cache-managers/default/health/status" ] + interval: 30s + timeout: 10s + retries: 10 + start_period: 10s + + gitea: + image: gitea/gitea:1.20.2-rootless + restart: always + environment: + GITEA__server__APP_DATA_PATH: /data +# - USER_UID=1000 +# - USER_GID=1000 + ports: + - "3000:3000" + healthcheck: + test: [ "CMD", "curl", "-fss", "127.0.0.1:3000/api/healthz" ] + interval: 30s + timeout: 10s + retries: 10 + start_period: 10s