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 2022/06/29 01:27:58 UTC
[camel-karavan] branch main updated: Fix issue with pipeline (#400)
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 8625fe0 Fix issue with pipeline (#400)
8625fe0 is described below
commit 8625fe0de74adca6e7ff795a8906010b10b2e464
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Tue Jun 28 21:27:54 2022 -0400
Fix issue with pipeline (#400)
---
karavan-app/pom.xml | 4 +
.../camel/karavan/service/KubernetesService.java | 18 +++
.../camel/karavan/service/StatusService.java | 2 +
.../src/main/resources/application.properties | 2 +-
.../src/main/webapp/src/builder/BuilderPage.tsx | 2 +-
.../main/webapp/src/projects/ProjectDashboard.tsx | 12 +-
.../src/main/webapp/src/projects/ProjectHeader.tsx | 27 ++--
.../src/main/webapp/src/projects/ProjectsPage.tsx | 5 +-
.../main/webapp/src/projects/PropertiesEditor.tsx | 2 +-
.../main/webapp/src/projects/PropertiesTable.tsx | 148 +++++++++++++++++++++
.../openshift/karavan-quarkus-task.yaml | 15 ++-
11 files changed, 211 insertions(+), 26 deletions(-)
diff --git a/karavan-app/pom.xml b/karavan-app/pom.xml
index 3457950..64b0c30 100644
--- a/karavan-app/pom.xml
+++ b/karavan-app/pom.xml
@@ -83,6 +83,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-openshift-client</artifactId>
+ </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-health</artifactId>
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index 71401df..d48e1a7 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -21,6 +21,8 @@ import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.openshift.api.model.DeploymentConfig;
+import io.fabric8.openshift.client.OpenShiftClient;
import io.fabric8.tekton.client.DefaultTektonClient;
import io.fabric8.tekton.pipeline.v1beta1.ParamBuilder;
import io.fabric8.tekton.pipeline.v1beta1.PipelineRef;
@@ -54,6 +56,11 @@ public class KubernetesService {
return new DefaultTektonClient(kubernetesClient());
}
+ @Produces
+ public OpenShiftClient openshiftClient() {
+ return kubernetesClient().adapt(OpenShiftClient.class);
+ }
+
private static final Logger LOGGER = Logger.getLogger(KubernetesService.class.getName());
public String createPipelineRun(Project project, String namespace) throws Exception {
@@ -91,6 +98,17 @@ public class KubernetesService {
return tektonClient().v1beta1().pipelineRuns().inNamespace(namespace).withName(name).get();
}
+ public String getReplicas(String name, String namespace) {
+ if (kubernetesClient().isAdaptable(OpenShiftClient.class)) {
+ DeploymentConfig dc = openshiftClient().deploymentConfigs().inNamespace(namespace).withName(name).get();
+ dc.getSpec().getReplicas();
+ dc.getStatus().getReadyReplicas();
+ } else {
+// throw new Exception("Adapting to OpenShiftClient not support. Check if adapter is present, and that env provides /oapi root path.");
+ }
+ return "";
+ }
+
public Secret getKaravanSecret() {
return kubernetesClient().secrets().inNamespace(namespace).withName("karavan").get();
}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
index 074feb8..3742873 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
@@ -69,6 +69,7 @@ public class StatusService {
LOGGER.info("Event received to collect statuses for the project " + projectId);
if (System.currentTimeMillis() - lastCollect > configuration.statusThreshold()){
getStatuses(projectId);
+ lastCollect = System.currentTimeMillis();
}
}
@@ -89,6 +90,7 @@ public class StatusService {
Project project = infinispanService.getProject(projectId);
Tuple2<Boolean, String> p = getProjectPipelineStatus(project.getLastPipelineRun());
+ System.out.println(p.getItem2());
if (p.getItem1()) status.setPipeline(p.getItem2());
LOGGER.info("Storing status in cache for " + projectId);
diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties
index b8ff145..421b93d 100644
--- a/karavan-app/src/main/resources/application.properties
+++ b/karavan-app/src/main/resources/application.properties
@@ -13,7 +13,7 @@ karavan.config.group-id=org.camel.karavan.demo
karavan.config.image-group=karavan
karavan.config.runtime=QUARKUS
karavan.config.runtime-version=2.10.0.Final
-karavan.config.status-threshold=5000
+karavan.config.status-threshold=1000
karavan.config.environments[0].name=dev
karavan.config.environments[0].namespace=karavan
karavan.config.environments[0].cluster=svc.cluster.local
diff --git a/karavan-app/src/main/webapp/src/builder/BuilderPage.tsx b/karavan-app/src/main/webapp/src/builder/BuilderPage.tsx
index 605521c..803c9c4 100644
--- a/karavan-app/src/main/webapp/src/builder/BuilderPage.tsx
+++ b/karavan-app/src/main/webapp/src/builder/BuilderPage.tsx
@@ -53,7 +53,7 @@ import ProjectIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
import ClipboardIcon from '@patternfly/react-icons/dist/esm/icons/clipboard-icon';
import RunIcon from '@patternfly/react-icons/dist/esm/icons/play-circle-icon';
import {ProjectModel, StepStatus} from "karavan-core/lib/model/ProjectModel";
-import {PropertiesTable} from "./PropertiesTable";
+import {PropertiesTable} from "../projects/PropertiesTable";
interface Props {
project: ProjectModel,
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx b/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
index 203bd6f..a49f2bb 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
@@ -118,14 +118,14 @@ export class ProjectDashboard extends React.Component<Props, State> {
getEnvironmentData() {
const used = true;
- const specReplicas = 3;
- const data = Array.from({length: specReplicas}, (v, k) => {
- return { x: k, y: 100/specReplicas }
+ const replicas = 3;
+ const data = Array.from({length: replicas}, (v, k) => {
+ return { x: k, y: 100/replicas }
});
- const statusReplicas = 2;
- const colorScale = Array.from({length: specReplicas}, (v, k) => {
+ const readyReplicas = 2;
+ const colorScale = Array.from({length: replicas}, (v, k) => {
console.log(" " + k)
- if (k < statusReplicas) return "rgb(56, 129, 47)"
+ if (k < readyReplicas) return "rgb(56, 129, 47)"
else return "#8bc1f7"
})
return (
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx b/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx
index 85ed5d2..efb4e2a 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectHeader.tsx
@@ -49,7 +49,7 @@ export class ProjectHeader extends React.Component<Props, State> {
componentDidMount() {
this.onRefresh();
- this.interval = setInterval(() => this.onRefreshStatus(), 3000);
+ this.interval = setInterval(() => this.onRefreshStatus(), 700);
}
componentWillUnmount() {
@@ -152,18 +152,21 @@ export class ProjectHeader extends React.Component<Props, State> {
const isSucceeded = status?.pipeline === 'Succeeded';
let classname = "pipeline"
if (isRunning) classname = classname + " pipeline-running";
- if (isFailed) classname = classname + " pipeline-running";
+ if (isFailed) classname = classname + " pipeline-failed";
if (isSucceeded) classname = classname + " pipeline-succeeded";
return (
- <Flex spaceItems={{default: 'spaceItemsNone'}} className={classname} direction={{default: "row"}}
- alignItems={{default: "alignItemsCenter"}}>
- <FlexItem style={{height: "18px"}}>
- {isRunning && <Spinner isSVG diameter="16px"/>}
- </FlexItem>
- <FlexItem style={{height: "18px"}}>
- {project?.lastPipelineRun ? project?.lastPipelineRun : "-"}
- </FlexItem>
- </Flex>
+ <Tooltip content={status?.pipeline} position={"right"}>
+ <Flex spaceItems={{default: 'spaceItemsNone'}} className={classname} direction={{default: "row"}}
+ alignItems={{default: "alignItemsCenter"}}>
+ <FlexItem style={{height: "18px"}}>
+ {isRunning && <Spinner isSVG diameter="16px"/>}
+ </FlexItem>
+ <FlexItem style={{height: "18px"}}>
+ {project?.lastPipelineRun ? project?.lastPipelineRun : "-"}
+ </FlexItem>
+ </Flex>
+ </Tooltip>
+
)
}
@@ -203,7 +206,7 @@ export class ProjectHeader extends React.Component<Props, State> {
<DescriptionListGroup>
<DescriptionListTerm>Commit</DescriptionListTerm>
<DescriptionListDescription>
- <Tooltip content={project?.lastCommit} position={"bottom"}>
+ <Tooltip content={project?.lastCommit} position={"right"}>
<Badge>{project?.lastCommit ? project?.lastCommit?.substr(0, 7) : "-"}</Badge>
</Tooltip>
</DescriptionListDescription>
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
index 836e54a..2e348d3 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
@@ -147,6 +147,7 @@ export class ProjectsPage extends React.Component<Props, State> {
}
render() {
+ const runtime = this.props.config?.runtime ? this.props.config.runtime : "QUARKUS";
const projects = this.state.projects.filter(p => p.name.includes(this.state.filter) || p.description.includes(this.state.filter));
const environments: string[] = this.props.config.environments && Array.isArray(this.props.config.environments)
? Array.from(this.props.config.environments)
@@ -173,8 +174,8 @@ export class ProjectsPage extends React.Component<Props, State> {
{projects.map(project => (
<Tr key={project.projectId}>
<Td modifier={"fitContent"}>
- <Tooltip content={this.props.config.runtime} position={"left"}>
- <Badge className="runtime-badge">{this.props.config.runtime.substring(0,1)}</Badge>
+ <Tooltip content={runtime} position={"left"}>
+ <Badge className="runtime-badge">{runtime.substring(0,1)}</Badge>
</Tooltip>
</Td>
<Td>
diff --git a/karavan-app/src/main/webapp/src/projects/PropertiesEditor.tsx b/karavan-app/src/main/webapp/src/projects/PropertiesEditor.tsx
index bac7763..592350c 100644
--- a/karavan-app/src/main/webapp/src/projects/PropertiesEditor.tsx
+++ b/karavan-app/src/main/webapp/src/projects/PropertiesEditor.tsx
@@ -4,7 +4,7 @@ import {
} from '@patternfly/react-core';
import '../designer/karavan.css';
import {Project, ProjectFile, ProjectFileTypes} from "../models/ProjectModels";
-import {PropertiesTable} from "../builder/PropertiesTable";
+import {PropertiesTable} from "./PropertiesTable";
import {ProjectModel} from "karavan-core/lib/model/ProjectModel";
import {ProjectModelApi} from "karavan-core/lib/api/ProjectModelApi";
diff --git a/karavan-app/src/main/webapp/src/projects/PropertiesTable.tsx b/karavan-app/src/main/webapp/src/projects/PropertiesTable.tsx
new file mode 100644
index 0000000..e3f5958
--- /dev/null
+++ b/karavan-app/src/main/webapp/src/projects/PropertiesTable.tsx
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+import React from 'react';
+import {
+ Button, Flex, FlexItem,
+ Modal,
+ PageSection,
+ Panel,
+ PanelMain,
+ PanelMainBody,
+ TextInput
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {ProjectProperty} from "karavan-core/lib/model/ProjectModel";
+
+interface Props {
+ properties: ProjectProperty[]
+ onChange?: (properties: ProjectProperty[]) => void
+}
+
+interface State {
+ properties: ProjectProperty[]
+ showDeleteConfirmation: boolean
+ deleteId?: string
+}
+
+export class PropertiesTable extends React.Component<Props, State> {
+
+ public state: State = {
+ properties: this.props.properties,
+ showDeleteConfirmation: false,
+ };
+
+ sendUpdate = (props: ProjectProperty[]) => {
+ this.props.onChange?.call(this, props);
+ }
+
+ changeProperty(p: ProjectProperty, field: "key" | "value", val?: string) {
+ const key: string = field === 'key' && val !== undefined ? val : p.key;
+ const value: any = field === 'value' ? val : p.value;
+ const property: ProjectProperty = {id: p.id, key: key, value: value};
+ const props = this.state.properties.map(prop => prop.id === property.id ? property : prop);
+ this.setState({properties: props});
+ this.sendUpdate(props);
+ }
+
+ startDelete(id: string) {
+ this.setState({showDeleteConfirmation: true, deleteId: id});
+ }
+
+ confirmDelete() {
+ const props = this.state.properties.filter(p => p.id !== this.state.deleteId);
+ this.setState({properties: props, showDeleteConfirmation: false, deleteId: undefined});
+ this.sendUpdate(props);
+ }
+
+ addProperty() {
+ const props = [...this.state.properties];
+ props.push(ProjectProperty.createNew("", ""))
+ this.setState({properties: props, showDeleteConfirmation: false, deleteId: undefined});
+ this.sendUpdate(props);
+ }
+
+ getDeleteConfirmation() {
+ return (<Modal
+ className="modal-delete"
+ title="Confirmation"
+ isOpen={this.state.showDeleteConfirmation}
+ onClose={() => this.setState({showDeleteConfirmation: false})}
+ actions={[
+ <Button key="confirm" variant="primary" onClick={e => this.confirmDelete()}>Delete</Button>,
+ <Button key="cancel" variant="link"
+ onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
+ ]}
+ onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
+ <div>Delete property?</div>
+ </Modal>)
+ }
+
+ getTextInputField(property: ProjectProperty, field: "key" | "value", readOnly: boolean) {
+ return (<TextInput isDisabled={readOnly} isRequired={true} className="text-field" type={"text"} id={"key"} name={"key"}
+ value={field === "key" ? property.key : property.value}
+ onChange={val => this.changeProperty(property, field, val)}/>)
+ }
+
+ render() {
+ const properties = this.state.properties;
+ return (
+ <PageSection padding={{default: "noPadding"}}>
+ {properties.length > 0 &&
+ <TableComposable aria-label="Property table" variant='compact' borders={false}
+ className="project-properties">
+ <Thead>
+ <Tr>
+ <Th key='name'>Name</Th>
+ <Th key='value'>Value</Th>
+ <Td></Td>
+ </Tr>
+ </Thead>
+ <Tbody>
+ {properties.map((property, idx: number) => {
+ const readOnly = property.key.startsWith("camel.jbang");
+ return (
+ <Tr key={property.id}>
+ <Td noPadding width={20} dataLabel="key">{this.getTextInputField(property, "key", readOnly)}</Td>
+ <Td noPadding width={10} dataLabel="value">{this.getTextInputField(property, "value", readOnly)}</Td>
+ <Td noPadding isActionCell dataLabel="delete">
+ {!readOnly && <Button variant={"plain"} icon={<DeleteIcon/>} className={"delete-button"}
+ onClick={event => this.startDelete(property.id)}/>}
+ </Td>
+ </Tr>
+ )})}
+ </Tbody>
+ </TableComposable>}
+ <Panel>
+ <PanelMain>
+ <PanelMainBody>
+ <Flex direction={{default:"row"}} >
+ <FlexItem align={{ default: 'alignRight' }}>
+ <Button isInline variant={"primary"} icon={<PlusIcon/>}
+ className={"add-button"}
+ onClick={event => this.addProperty()}>Add property</Button>
+ </FlexItem>
+ </Flex>
+ </PanelMainBody>
+ </PanelMain>
+ </Panel>
+ </PageSection>
+ )
+ }
+}
\ No newline at end of file
diff --git a/karavan-builder/openshift/karavan-quarkus-task.yaml b/karavan-builder/openshift/karavan-quarkus-task.yaml
index d9e9a79..d309c67 100644
--- a/karavan-builder/openshift/karavan-quarkus-task.yaml
+++ b/karavan-builder/openshift/karavan-quarkus-task.yaml
@@ -12,14 +12,22 @@ spec:
#!/usr/bin/env bash
CHECKOUT_DIR="/scripts"
- git clone --depth 1 --branch main ${GIT_REPOSITORY} ${CHECKOUT_DIR}
-
+ if [[ $GIT_REPOSITORY == https* ]] ;
+ then
+ replacer=https://$GIT_PASSWORD@
+ prefix=https://
+ url="${GIT_REPOSITORY/$prefix/$replacer}"
+ git clone --depth 1 --branch main $url ${CHECKOUT_DIR}
+ fi
+
cd ${CHECKOUT_DIR}/$(inputs.params.project)
entrypoint -Dcamel.jbang.version=3.18.0-SNAPSHOT camel@apache/camel export
export LAST_COMMIT=$(git rev-parse --short HEAD)
export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
+ export NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
+
/opt/mvnd/bin/mvnd package \
-Dquarkus.container-image.build=true \
-Dquarkus.container-image.push=true \
@@ -30,7 +38,8 @@ spec:
-Dquarkus.container-image.builder=jib \
-Dquarkus.kubernetes-client.master-url=kubernetes.default.svc \
-Dquarkus.kubernetes-client.token=${TOKEN} \
- -Dquarkus.kubernetes.deploy=true
+ -Dquarkus.kubernetes.deploy=true \
+ -Dquarkus.container-image.group=${NAMESPACE}
image: 'ghcr.io/apache/camel-karavan-builder:0.0.16'
volumeMounts:
- mountPath: /root/.m2