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 87a0b0fa Installation UI for #817 87a0b0fa is described below commit 87a0b0faf50f7a8a455dc378e1ffb621c6306cdf Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Wed Sep 6 18:42:22 2023 -0400 Installation UI for #817 --- .../org/apache/camel/karavan/api/AuthResource.java | 33 +++++++++++ .../camel/karavan/api/ConfigurationResource.java | 3 +- .../karavan/infinispan/InfinispanService.java | 4 +- .../karavan/kubernetes/KubernetesService.java | 6 +- .../camel/karavan/service/KaravanService.java | 13 ++++- .../camel/karavan/service/ProjectService.java | 4 +- .../apache/camel/karavan/shared/Configuration.java | 9 +++ .../snippets/quarkus-builder-script-docker.sh | 32 +++++++++++ .../snippets/spring-boot-builder-script-docker.sh | 32 +++++++++++ .../src/main/webui/src/api/KaravanApi.tsx | 2 +- .../src/main/webui/src/api/ProjectModels.ts | 1 + .../karavan-app/src/main/webui/src/main/Main.tsx | 64 +++++++++++++++++++--- .../src/main/webui/src/main/MainDataPoller.tsx | 42 +++++++------- 13 files changed, 203 insertions(+), 42 deletions(-) diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java index ad4b6416..ed067a60 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java @@ -16,6 +16,8 @@ */ package org.apache.camel.karavan.api; +import org.apache.camel.karavan.infinispan.InfinispanService; +import org.apache.camel.karavan.kubernetes.KubernetesService; import org.apache.camel.karavan.service.AuthService; import jakarta.inject.Inject; @@ -24,6 +26,13 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.apache.camel.karavan.service.ProjectService; +import org.apache.camel.karavan.shared.Configuration; +import org.eclipse.microprofile.health.HealthCheckResponse; + +import java.util.List; +import java.util.Map; +import java.util.Objects; @Path("/public") public class AuthResource { @@ -31,6 +40,15 @@ public class AuthResource { @Inject AuthService authService; + @Inject + ProjectService projectService; + + @Inject + KubernetesService kubernetesService; + + @Inject + InfinispanService infinispanService; + @GET @Path("/auth") @Produces(MediaType.TEXT_PLAIN) @@ -44,4 +62,19 @@ public class AuthResource { public Response ssoConfig() throws Exception { return Response.ok(authService.getSsoConfig()).build(); } + + @GET + @Path("/readiness") + @Produces(MediaType.APPLICATION_JSON) + public Response getConfiguration() throws Exception { + List<HealthCheckResponse> list = List.of( + infinispanService.call(), + kubernetesService.call(), + projectService.call() + ); + return Response.ok(Map.of( + "status", list.stream().allMatch(h -> Objects.equals(h.getStatus(), HealthCheckResponse.Status.UP)), + "checks", list + )).build(); + } } \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java index a2c8dbcc..4b43f169 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java @@ -16,14 +16,13 @@ */ package org.apache.camel.karavan.api; -import org.apache.camel.karavan.shared.ConfigService; - import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.apache.camel.karavan.shared.ConfigService; @Path("/api/configuration") public class ConfigurationResource { diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java index cda9603d..1734d8a4 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java @@ -385,9 +385,9 @@ public class InfinispanService implements HealthCheck { @Override public HealthCheckResponse call() { if (isReady()) { - return HealthCheckResponse.named("infinispan").up().build(); + return HealthCheckResponse.named("Infinispan").up().build(); } else { - return HealthCheckResponse.named("infinispan").down().build(); + return HealthCheckResponse.named("Infinispan").down().build(); } } } diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java index 90423baf..abdf4f48 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java @@ -128,12 +128,12 @@ public class KubernetesService implements HealthCheck { public HealthCheckResponse call() { if (ConfigService.inKubernetes()) { if (informers.size() == INFORMERS) { - return HealthCheckResponse.named("kubernetes").withData("mode", "kubernetes").up().build(); + return HealthCheckResponse.named("Kubernetes").up().build(); } else { - return HealthCheckResponse.named("kubernetes").down().build(); + return HealthCheckResponse.named("Kubernetes").down().build(); } } else { - return HealthCheckResponse.named("kubernetes").withData("mode", "kubernetesless").up().build(); + return HealthCheckResponse.named("Kubernetesless").up().build(); } } 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 744ed95d..1d2270d4 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 @@ -18,6 +18,7 @@ package org.apache.camel.karavan.service; import io.quarkus.runtime.Quarkus; import io.quarkus.runtime.ShutdownEvent; +import io.quarkus.runtime.Startup; import io.quarkus.runtime.StartupEvent; import io.quarkus.vertx.ConsumeEvent; import io.vertx.core.eventbus.EventBus; @@ -30,14 +31,19 @@ import org.apache.camel.karavan.infinispan.InfinispanService; import org.apache.camel.karavan.kubernetes.KubernetesService; import org.apache.camel.karavan.shared.ConfigService; import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.health.HealthCheck; +import org.eclipse.microprofile.health.HealthCheckResponse; +import org.eclipse.microprofile.health.Liveness; import org.jboss.logging.Logger; import jakarta.enterprise.event.Observes; import jakarta.inject.Inject; import java.io.IOException; +@Startup +@Liveness @Singleton -public class KaravanService { +public class KaravanService implements HealthCheck { private static final Logger LOGGER = Logger.getLogger(KaravanService.class.getName()); @@ -78,6 +84,11 @@ public class KaravanService { private static final String START_INTERNAL_DOCKER_SERVICES = "START_INTERNAL_DOCKER_SERVICES"; private static final String START_SERVICES = "START_SERVICES"; + @Override + public HealthCheckResponse call() { + return HealthCheckResponse.up("Karavan"); + } + void onStart(@Observes StartupEvent ev) throws Exception { if (!ConfigService.inKubernetes()) { eventBus.publish(START_INTERNAL_DOCKER_SERVICES, null); 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 00123f52..8755ca93 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 @@ -93,9 +93,9 @@ public class ProjectService implements HealthCheck { @Override public HealthCheckResponse call() { if (ready.get()) { - return HealthCheckResponse.named("project").up().build(); + return HealthCheckResponse.named("Projects").up().build(); } else { - return HealthCheckResponse.named("project").down().build(); + return HealthCheckResponse.named("Projects").down().build(); } } diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java index 6ccabdf9..cec29fda 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/shared/Configuration.java @@ -25,6 +25,7 @@ public class Configuration { private List<String> environments; private String runtime; private List<String> runtimes; + private List<Object> status; public Configuration() { } @@ -85,4 +86,12 @@ public class Configuration { public void setRuntimes(List<String> runtimes) { this.runtimes = runtimes; } + + public List<Object> getStatus() { + return status; + } + + public void setStatus(List<Object> status) { + this.status = status; + } } diff --git a/karavan-web/karavan-app/src/main/resources/snippets/quarkus-builder-script-docker.sh b/karavan-web/karavan-app/src/main/resources/snippets/quarkus-builder-script-docker.sh new file mode 100644 index 00000000..037632f8 --- /dev/null +++ b/karavan-web/karavan-app/src/main/resources/snippets/quarkus-builder-script-docker.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +CHECKOUT_DIR="/scripts" +KAMELETS_DIR="/scripts/kamelets" + +if [[ ${GIT_REPOSITORY} == https* ]] ; +then + replacer=https://${GIT_USERNAME}:${GIT_PASSWORD}@ + prefix=https:// + url="${GIT_REPOSITORY/$prefix/$replacer}" + git clone --depth 1 --branch ${GIT_BRANCH} $url ${CHECKOUT_DIR} +elif [[ ${GIT_REPOSITORY} == http* ]] ; +then + replacer=http://${GIT_USERNAME}:${GIT_PASSWORD}@ + prefix=http:// + url="${GIT_REPOSITORY/$prefix/$replacer}" + git clone --depth 1 --branch ${GIT_BRANCH} $url ${CHECKOUT_DIR} +else + git clone --depth 1 --branch ${GIT_BRANCH} ${GIT_REPOSITORY} ${CHECKOUT_DIR} +fi + +cd ${CHECKOUT_DIR}/${PROJECT_ID} + +jbang -Dcamel.jbang.version=${CAMEL_VERSION} camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR} + +export LAST_COMMIT=$(git rev-parse --short HEAD) +export DATE=${TAG} + +mvn package jib:build \ + -Djib.allowInsecureRegistries=true \ + -Djib.to.image=${IMAGE_REGISTRY}/${IMAGE_GROUP}/${PROJECT_ID}:${DATE} \ + -Djib.to.auth.username=${IMAGE_REGISTRY_USERNAME} \ + -Djib.to.auth.password=${IMAGE_REGISTRY_PASSWORD} \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/resources/snippets/spring-boot-builder-script-docker.sh b/karavan-web/karavan-app/src/main/resources/snippets/spring-boot-builder-script-docker.sh new file mode 100644 index 00000000..037632f8 --- /dev/null +++ b/karavan-web/karavan-app/src/main/resources/snippets/spring-boot-builder-script-docker.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +CHECKOUT_DIR="/scripts" +KAMELETS_DIR="/scripts/kamelets" + +if [[ ${GIT_REPOSITORY} == https* ]] ; +then + replacer=https://${GIT_USERNAME}:${GIT_PASSWORD}@ + prefix=https:// + url="${GIT_REPOSITORY/$prefix/$replacer}" + git clone --depth 1 --branch ${GIT_BRANCH} $url ${CHECKOUT_DIR} +elif [[ ${GIT_REPOSITORY} == http* ]] ; +then + replacer=http://${GIT_USERNAME}:${GIT_PASSWORD}@ + prefix=http:// + url="${GIT_REPOSITORY/$prefix/$replacer}" + git clone --depth 1 --branch ${GIT_BRANCH} $url ${CHECKOUT_DIR} +else + git clone --depth 1 --branch ${GIT_BRANCH} ${GIT_REPOSITORY} ${CHECKOUT_DIR} +fi + +cd ${CHECKOUT_DIR}/${PROJECT_ID} + +jbang -Dcamel.jbang.version=${CAMEL_VERSION} camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR} + +export LAST_COMMIT=$(git rev-parse --short HEAD) +export DATE=${TAG} + +mvn package jib:build \ + -Djib.allowInsecureRegistries=true \ + -Djib.to.image=${IMAGE_REGISTRY}/${IMAGE_GROUP}/${PROJECT_ID}:${DATE} \ + -Djib.to.auth.username=${IMAGE_REGISTRY_USERNAME} \ + -Djib.to.auth.password=${IMAGE_REGISTRY_PASSWORD} \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx index 259f5420..e9704a20 100644 --- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx @@ -85,7 +85,7 @@ export class KaravanApi { } static async getReadiness(after: (readiness: any) => void) { - axios.get('/q/health/ready', {headers: {'Accept': 'application/json'}}) + axios.get('/public/readiness', {headers: {'Accept': 'application/json'}}) .then(res => { if (res.status === 200) { after(res.data); diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts index 6888c0b0..29f62995 100644 --- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts +++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts @@ -7,6 +7,7 @@ export class AppConfig { environments: string[] = []; runtime: string = ''; runtimes: string[] = []; + status: any[] = []; } export enum ProjectType { diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx index 75ec85ec..6e4d70d6 100644 --- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx @@ -1,7 +1,17 @@ -import {Routes, Route, Navigate} from 'react-router-dom'; +import {Navigate, Route, Routes} from 'react-router-dom'; import React, {useEffect, useRef} from "react"; import {KaravanApi} from "../api/KaravanApi"; -import {Bullseye, Flex, FlexItem, Page, Spinner} from "@patternfly/react-core"; +import { + Bullseye, capitalize, + Flex, + FlexItem, + Page, + ProgressStep, + ProgressStepper, + Spinner, + Tooltip, + TooltipPosition +} from "@patternfly/react-core"; import Icon from "../Logo"; import {MainLogin} from "./MainLogin"; import {DashboardPage} from "../dashboard/DashboardPage"; @@ -20,10 +30,10 @@ import {TemplatesPage} from "../templates/TemplatesPage"; import {EventBus} from "../designer/utils/EventBus"; import {Notification} from "../designer/utils/Notification"; -export function Main () { +export function Main() { - const [config] = useAppConfigStore((state) => [state.config], shallow) - const { getData, getStatuses } = useMainHook(); + const [config, readiness] = useAppConfigStore((s) => [s.config, s.readiness], shallow) + const {getData, getStatuses} = useMainHook(); const initialized = useRef(false) @@ -57,14 +67,50 @@ export function Main () { EventBus.sendAlert(title, text, variant) } + function showSpinner() { + return KaravanApi.authType === undefined || readiness === undefined; + } + + function showStepper() { + return readiness !== undefined && readiness.status !== true; + } + + function getStepper() { + const steps: any[] = Array.isArray(readiness.checks) ? readiness.checks : []; + return ( + <Bullseye className=""> + <ProgressStepper aria-label="Readiness progress" isCenterAligned isVertical > + {steps.map(step => ( + <ProgressStep + variant={step.status === 'UP' ? "success" : "info"} + id={step.name} + titleId={step.name} + aria-label={step.name} + > + {step.name} + </ProgressStep> + ))} + </ProgressStepper> + </Bullseye> + ) + } + + function showMain() { + return !showStepper() && !showSpinner() && (KaravanApi.isAuthorized || KaravanApi.authType === 'public'); + } + return ( <Page className="karavan"> - {KaravanApi.authType === undefined && + {showSpinner() && <Bullseye className="loading-page"> <Spinner className="spinner" diameter="140px" aria-label="Loading..."/> - <div className="logo-placeholder">{Icon()}</div> - </Bullseye>} - {(KaravanApi.isAuthorized || KaravanApi.authType === 'public') && + <Tooltip content="Connecting to server..." position={TooltipPosition.bottom}> + <div className="logo-placeholder">{Icon()}</div> + </Tooltip> + </Bullseye> + } + {showStepper() && getStepper()} + {showMain() && <Flex direction={{default: "row"}} style={{width: "100%", height: "100%"}} alignItems={{default: "alignItemsStretch"}} spaceItems={{default: 'spaceItemsNone'}}> <FlexItem> diff --git a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx index 8d7de7ab..31885ad0 100644 --- a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx @@ -30,7 +30,7 @@ export function MainDataPoller () { return () => { clearInterval(interval); }; - }, [project, readiness]); + }, [project]); function getData() { KaravanApi.getReadiness((r: any) => { @@ -38,29 +38,27 @@ export function MainDataPoller () { }) if (readiness) { setLoading(true); - KaravanApi.getConfiguration((config: AppConfig) => { - if (project.projectId === undefined) { - KaravanApi.getProjects((projects: Project[]) => { - setProjects(projects); - }); - } - KaravanApi.getAllDeploymentStatuses((statuses: DeploymentStatus[]) => { - setDeployments(statuses); + if (project.projectId === undefined) { + KaravanApi.getProjects((projects: Project[]) => { + setProjects(projects); }); - KaravanApi.getAllServiceStatuses((statuses: ServiceStatus[]) => { - setServices(statuses); - }); - KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => { - setContainers(statuses); - }); - KaravanApi.getAllCamelStatuses(config.environment, (statuses: CamelStatus[]) => { - setCamels(statuses); - }); - KaravanApi.getPipelineStatuses(config.environment, (status: PipelineStatus[]) => { - setPipelineStatuses(status); - }); - setLoading(false); + } + KaravanApi.getAllDeploymentStatuses((statuses: DeploymentStatus[]) => { + setDeployments(statuses); + }); + KaravanApi.getAllServiceStatuses((statuses: ServiceStatus[]) => { + setServices(statuses); + }); + KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => { + setContainers(statuses); + }); + KaravanApi.getAllCamelStatuses(config.environment, (statuses: CamelStatus[]) => { + setCamels(statuses); + }); + KaravanApi.getPipelineStatuses(config.environment, (status: PipelineStatus[]) => { + setPipelineStatuses(status); }); + setLoading(false); } }