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 def90df7ca63cc9e68c90a29b57f866ac46d0013 Author: Marat Gubaidullin <marat.gubaidul...@gmail.com> AuthorDate: Thu Jul 13 20:38:59 2023 -0400 Infrasructure config for logs #817 --- .../apache/camel/karavan/api/DevModeResource.java | 4 +- .../camel/karavan/api/InfrastructureResource.java | 5 +- .../apache/camel/karavan/api/LogWatchResource.java | 44 ++-- .../karavan/listener/DevModeCommandListener.java | 6 +- .../camel/karavan/service/KaravanService.java | 2 +- .../webui/src/designer/beans/BeanProperties.tsx | 38 ++-- .../route/property/ComponentParameterField.tsx | 36 +-- .../designer/route/property/DslPropertyField.tsx | 36 +-- .../route/property/InfrastructureSelector.tsx | 7 +- .../route/property/KameletPropertyField.tsx | 36 +-- .../designer/route/property/KubernetesSelector.tsx | 243 --------------------- .../camel/karavan/bashi/ConductorService.java | 75 ++++--- .../org/apache/camel/karavan/bashi/Constants.java | 1 - .../karavan/bashi/docker/DockerEventListener.java | 70 ++++-- .../camel/karavan/bashi/docker/DockerService.java | 31 ++- .../camel/karavan/bashi/docker/LogCallback.java | 26 +++ .../camel/karavan/datagrid/DatagridService.java | 46 ++-- .../camel/karavan/datagrid/model/CommandName.java | 10 - .../karavan/datagrid/model/ContainerInfo.java | 70 ++++++ .../karavan/datagrid/model/DevModeCommand.java | 45 +++- .../karavan/datagrid/model/DevModeCommandName.java | 12 + .../karavan/datagrid/model/DevModeCommandType.java | 9 + .../karavan/datagrid/model/KaravanSchema.java | 6 +- .../camel/karavan/datagrid/DataGridTest.java | 22 +- .../src/designer/beans/BeanProperties.tsx | 38 ++-- .../route/property/ComponentParameterField.tsx | 36 +-- .../designer/route/property/DslPropertyField.tsx | 36 +-- .../route/property/InfrastructureSelector.tsx | 7 +- .../route/property/KameletPropertyField.tsx | 36 +-- 29 files changed, 520 insertions(+), 513 deletions(-) diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java index f56ad4d3..d0681bf4 100644 --- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java +++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java @@ -57,7 +57,7 @@ public class DevModeResource { PodStatus status = datagridService.getDevModePodStatuses(runnerName, environment); if (status == null) { datagridService.saveDevModeStatus(new DevModeStatus(project.getProjectId(), null, null, false)); - datagridService.sendDevModeCommand(project.getProjectId(), new DevModeCommand(CommandName.RUN, Instant.now().toEpochMilli())); + datagridService.sendDevModeCommand(DevModeCommand.createDevModeCommand(DevModeCommandName.RUN, project.getProjectId())); return Response.ok(runnerName).build(); } return Response.notModified().build(); @@ -83,7 +83,7 @@ public class DevModeResource { @Consumes(MediaType.APPLICATION_JSON) @Path("/{projectId}/{deletePVC}") public Response deleteRunner(@PathParam("projectId") String projectId, @PathParam("deletePVC") boolean deletePVC) { - datagridService.sendDevModeCommand(projectId, new DevModeCommand(CommandName.DELETE, Instant.now().toEpochMilli())); + datagridService.sendDevModeCommand(DevModeCommand.createDevModeCommand(DevModeCommandName.DELETE, projectId)); datagridService.deleteDevModeStatus(projectId); return Response.accepted().build(); } diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java index d2749563..f525f6a5 100644 --- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java +++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java @@ -203,7 +203,10 @@ public class InfrastructureResource { if (kubernetesService.inKubernetes()) { return Response.ok(kubernetesService.getServices(kubernetesService.getNamespace())).build(); } else { - return Response.ok(List.of()).build(); + List<String> list = datagridService.getContainerInfos(environment).stream() + .map(ci -> ci.getPorts().stream().map(i -> ci.getContainerName() + ":" + i).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + return Response.ok(list).build(); } } diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java index 5b1ba723..0fece15e 100644 --- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java +++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java @@ -17,6 +17,9 @@ package org.apache.camel.karavan.api; import io.fabric8.kubernetes.client.dsl.LogWatch; +import org.apache.camel.karavan.datagrid.DatagridService; +import org.apache.camel.karavan.datagrid.model.DevModeCommand; +import org.apache.camel.karavan.datagrid.model.DevModeCommandName; import org.apache.camel.karavan.service.KubernetesService; import org.eclipse.microprofile.context.ManagedExecutor; import org.jboss.logging.Logger; @@ -44,6 +47,9 @@ public class LogWatchResource { @Inject KubernetesService kubernetesService; + @Inject + DatagridService datagridService; + @Inject ManagedExecutor managedExecutor; @@ -57,22 +63,30 @@ public class LogWatchResource { ) { managedExecutor.execute(() -> { LOGGER.info("LogWatch for " + name + " starting..."); - try (SseEventSink sink = eventSink) { - LogWatch logWatch = type.equals("container") - ? kubernetesService.getContainerLogWatch(name) - : kubernetesService.getPipelineRunLogWatch(name); - BufferedReader reader = new BufferedReader(new InputStreamReader(logWatch.getOutput())); - try { - for (String line; (line = reader.readLine()) != null && !sink.isClosed(); ) { - sink.send(sse.newEvent(line)); - } - } catch (IOException e) { - LOGGER.error(e.getMessage()); - } - logWatch.close(); - sink.close(); - LOGGER.info("LogWatch for " + name + " closed"); + if (kubernetesService.inKubernetes()) { + getKubernetesLogs(type, name, eventSink, sse); + } else { + datagridService.sendDevModeCommand(DevModeCommand.createDevModeCommand(DevModeCommandName.LOG, name)); } }); } + + private void getKubernetesLogs(String type, String name, SseEventSink eventSink, Sse sse) { + try (SseEventSink sink = eventSink) { + LogWatch logWatch = type.equals("container") + ? kubernetesService.getContainerLogWatch(name) + : kubernetesService.getPipelineRunLogWatch(name); + BufferedReader reader = new BufferedReader(new InputStreamReader(logWatch.getOutput())); + try { + for (String line; (line = reader.readLine()) != null && !sink.isClosed(); ) { + sink.send(sse.newEvent(line)); + } + } catch (IOException e) { + LOGGER.error(e.getMessage()); + } + logWatch.close(); + sink.close(); + LOGGER.info("LogWatch for " + name + " closed"); + } + } } \ No newline at end of file diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java index 26fea711..8c1956ad 100644 --- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java +++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java @@ -3,8 +3,8 @@ package org.apache.camel.karavan.listener; import io.quarkus.vertx.ConsumeEvent; import io.vertx.core.json.JsonObject; import org.apache.camel.karavan.datagrid.DatagridService; -import org.apache.camel.karavan.datagrid.model.CommandName; import org.apache.camel.karavan.datagrid.model.DevModeCommand; +import org.apache.camel.karavan.datagrid.model.DevModeCommandName; import org.apache.camel.karavan.datagrid.model.Project; import org.apache.camel.karavan.service.KubernetesService; import org.eclipse.microprofile.config.inject.ConfigProperty; @@ -34,10 +34,10 @@ public class DevModeCommandListener { if (kubernetesService.inKubernetes()) { DevModeCommand command = message.mapTo(DevModeCommand.class); String runnerName = command.getProjectId() + "-" + DEVMODE_SUFFIX; - if (Objects.equals(command.getCommandName(), CommandName.RUN)) { + if (Objects.equals(command.getCommandName(), DevModeCommandName.RUN)) { Project p = datagridService.getProject(command.getProjectId()); kubernetesService.tryCreateRunner(p, runnerName, ""); - } else if (Objects.equals(command.getCommandName(), CommandName.DELETE)){ + } else if (Objects.equals(command.getCommandName(), DevModeCommandName.DELETE)){ kubernetesService.deleteRunner(runnerName, false); datagridService.deleteDevModeStatus(command.getProjectId()); } diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java index 177401a6..b0b1f359 100644 --- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java +++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java @@ -48,7 +48,7 @@ public class KaravanService { void onStart(@Observes StartupEvent ev) { LOGGER.info("Start Karavan"); datagridService.start(); -// datagridService.clearAllStatuses(); + datagridService.clearAllStatuses(); setEnvironment(); initialImport(); startInformers(); diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx index b7ab5532..24c1e202 100644 --- a/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx +++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx @@ -54,9 +54,9 @@ interface State { bean?: NamedBeanDefinition properties: Map<string, [string, string, boolean]> key: string, - showKubernetesSelector: boolean - kubernetesSelectorUuid?: string - kubernetesSelectorProperty?: string + showInfrastructureSelector: boolean + infrastructureSelectorUuid?: string + infrastructureSelectorProperty?: string } export class BeanProperties extends React.Component<Props, State> { @@ -70,7 +70,7 @@ export class BeanProperties extends React.Component<Props, State> { public state: State = { bean: this.props.bean, key: '', - showKubernetesSelector: false, + showInfrastructureSelector: false, properties: this.props.bean?.properties ? this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, [string, string, boolean]>() }; @@ -118,31 +118,31 @@ export class BeanProperties extends React.Component<Props, State> { }) } - selectKubernetes = (value: string) => { - const propertyId = this.state.kubernetesSelectorProperty; - const uuid = this.state.kubernetesSelectorUuid; + selectInfrastructure = (value: string) => { + const propertyId = this.state.infrastructureSelectorProperty; + const uuid = this.state.infrastructureSelectorUuid; if (propertyId && uuid){ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.propertyChanged(uuid, propertyId, value, false); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (uuid: string, propertyName: string) => { - this.setState({kubernetesSelectorUuid: uuid, kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (uuid: string, propertyName: string) => { + this.setState({infrastructureSelectorUuid: uuid, infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({showInfrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.showInfrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } cloneBean = () => { @@ -208,8 +208,8 @@ export class BeanProperties extends React.Component<Props, State> { onChange={e => this.propertyChanged(i, e, value, showPassword)}/> <InputGroup> {inInfrastructure && - <Tooltip position="bottom-end" content="Select value from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(i, key)}> + <Tooltip position="bottom-end" content="Select value from Infrastructure"> + <Button variant="control" onClick={e => this.openInfrastructureSelector(i, key)}> {icon} </Button> </Tooltip>} @@ -246,7 +246,7 @@ export class BeanProperties extends React.Component<Props, State> { {this.state.bean === undefined && <IntegrationHeader integration={this.props.integration}/>} {this.state.bean !== undefined && this.getBeanForm()} </Form> - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </div> ) } diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx index 39817f7c..ca1f6a0d 100644 --- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx +++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx @@ -23,7 +23,7 @@ import { Select, SelectVariant, SelectDirection, - SelectOption, InputGroup, TextArea, Tooltip, Button, + SelectOption, InputGroup, TextArea, Tooltip, Button, capitalize, } from '@patternfly/react-core'; import '../../karavan.css'; import "@patternfly/patternfly/patternfly.css"; @@ -57,8 +57,8 @@ interface State { selectStatus: Map<string, boolean> showEditor: boolean showPassword: boolean - showKubernetesSelector: boolean - kubernetesSelectorProperty?: string + showInfrastructureSelector: boolean + infrastructureSelectorProperty?: string ref: any id: string } @@ -69,7 +69,7 @@ export class ComponentParameterField extends React.Component<Props, State> { selectStatus: new Map<string, boolean>(), showEditor: false, showPassword: false, - showKubernetesSelector: false, + showInfrastructureSelector: false, ref: React.createRef(), id: prefix + "-" + this.props.property.name } @@ -179,7 +179,7 @@ export class ComponentParameterField extends React.Component<Props, State> { </InputGroup> } - selectKubernetes = (value: string) => { + selectInfrastructure = (value: string) => { // check if there is a selection const textVal = this.state.ref.current; const cursorStart = textVal.selectionStart; @@ -189,29 +189,29 @@ export class ComponentParameterField extends React.Component<Props, State> { const selectedText = prevValue.substring(cursorStart, cursorEnd) value = prevValue.replace(selectedText, value); } - const propertyName = this.state.kubernetesSelectorProperty; + const propertyName = this.state.infrastructureSelectorProperty; if (propertyName) { if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.parametersChanged(propertyName, value); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (propertyName: string) => { - this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (propertyName: string) => { + this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({showInfrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.showInfrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } getStringInput(property: ComponentProperty, value: any) { @@ -221,8 +221,8 @@ export class ComponentParameterField extends React.Component<Props, State> { const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/> return <InputGroup> {inInfrastructure && !showEditor && !noInfraSelectorButton && - <Tooltip position="bottom-end" content="Select from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}> + <Tooltip position="bottom-end" content={"Select from " + capitalize((InfrastructureAPI.infrastructure))}> + <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}> {icon} </Button> </Tooltip>} @@ -340,7 +340,7 @@ export class ComponentParameterField extends React.Component<Props, State> { && this.getSelect(property, value)} {property.type === 'boolean' && this.getSwitch(property, value)} - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </FormGroup> ) } diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx index e11ee485..d17a26c3 100644 --- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx +++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx @@ -35,7 +35,7 @@ import { Text, Tooltip, Card, - InputGroup, + InputGroup, capitalize, } from '@patternfly/react-core'; import '../../karavan.css'; import "@patternfly/patternfly/patternfly.css"; @@ -87,8 +87,8 @@ interface State { isShowAdvanced: Map<string, boolean>, arrayValues: Map<string, string>, showEditor: boolean - showKubernetesSelector: boolean - kubernetesSelectorProperty?: string + infrastructureSelector: boolean + infrastructureSelectorProperty?: string customCode?: string ref: any } @@ -100,7 +100,7 @@ export class DslPropertyField extends React.Component<Props, State> { arrayValues: new Map<string, string>(), isShowAdvanced: new Map<string, boolean>(), showEditor: false, - showKubernetesSelector: false, + infrastructureSelector: false, ref: React.createRef(), }; @@ -176,7 +176,7 @@ export class DslPropertyField extends React.Component<Props, State> { return property.name === 'uri' && !['ToDefinition', 'ToDynamicDefinition', 'WireTapDefinition'].includes(dslName) } - selectKubernetes = (value: string) => { + selectInfrastructure = (value: string) => { // check if there is a selection const textVal = this.state.ref.current; const cursorStart = textVal.selectionStart; @@ -186,29 +186,29 @@ export class DslPropertyField extends React.Component<Props, State> { const selectedText = prevValue.substring(cursorStart, cursorEnd) value = prevValue.replace(selectedText, value); } - const propertyName = this.state.kubernetesSelectorProperty; + const propertyName = this.state.infrastructureSelectorProperty; if (propertyName) { if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.propertyChanged(propertyName, value); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({infrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (propertyName: string) => { - this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (propertyName: string) => { + this.setState({infrastructureSelectorProperty: propertyName, infrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({infrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.infrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } getStringInput = (property: PropertyMeta, value: any) => { @@ -218,8 +218,8 @@ export class DslPropertyField extends React.Component<Props, State> { const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/> return (<InputGroup> {inInfrastructure && !showEditor && !noInfraSelectorButton && - <Tooltip position="bottom-end" content="Select from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}> + <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}> + <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}> {icon} </Button> </Tooltip>} @@ -732,7 +732,7 @@ export class DslPropertyField extends React.Component<Props, State> { {isKamelet && property.name === 'parameters' && this.getKameletParameters()} {!isKamelet && property.name === 'parameters' && this.getComponentParameters(property)} </FormGroup> - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </div> ) } diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx index 04c8d43a..e0069bc0 100644 --- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx +++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx @@ -208,6 +208,7 @@ export class InfrastructureSelector extends React.Component<Props, State> { render() { const tabIndex = this.state.tabIndex; + const tabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['configMap', 'secret', 'services'] : ['services']; return ( <Modal aria-label="Select from Infrastructure" @@ -223,9 +224,7 @@ export class InfrastructureSelector extends React.Component<Props, State> { </FlexItem> <FlexItem> <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}> - <Tab eventKey={"configMap"} key={"configMap"} title={<TabTitleText>ConfigMaps</TabTitleText>} /> - <Tab eventKey={"secret"} key={"secret"} title={<TabTitleText>Secrets</TabTitleText>} /> - <Tab eventKey={"service"} key={"service"} title={<TabTitleText>Services</TabTitleText>} /> + {tabs.map(tab => <Tab eventKey={tab} key={tab} title={<TabTitleText>{capitalize(tab)}</TabTitleText>} />)} </Tabs> </FlexItem> </Flex> @@ -235,7 +234,7 @@ export class InfrastructureSelector extends React.Component<Props, State> { {this.searchInput()} {tabIndex === 'configMap' && this.getConfigMapTable()} {tabIndex === 'secret' && this.getSecretsTable()} - {tabIndex === 'service' && this.getServicesTable()} + {tabIndex === 'services' && this.getServicesTable()} </PageSection> </Modal> ) diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx index 8beed690..9b0a3b39 100644 --- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx +++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx @@ -19,7 +19,7 @@ import { FormGroup, TextInput, Popover, - Switch, InputGroup, Button, TextArea, Tooltip + Switch, InputGroup, Button, TextArea, Tooltip, capitalize } from '@patternfly/react-core'; import '../../karavan.css'; import "@patternfly/patternfly/patternfly.css"; @@ -45,8 +45,8 @@ interface State { selectIsOpen: boolean showEditor: boolean showPassword: boolean - showKubernetesSelector: boolean - kubernetesSelectorProperty?: string + showInfrastructureSelector: boolean + infrastructureSelectorProperty?: string ref: any } @@ -56,7 +56,7 @@ export class KameletPropertyField extends React.Component<Props, State> { selectIsOpen: false, showEditor: false, showPassword: false, - showKubernetesSelector: false, + showInfrastructureSelector: false, ref: React.createRef(), } @@ -69,7 +69,7 @@ export class KameletPropertyField extends React.Component<Props, State> { this.setState({selectIsOpen: false}); } - selectKubernetes = (value: string) => { + selectInfrastructure = (value: string) => { // check if there is a selection const textVal = this.state.ref.current; const cursorStart = textVal.selectionStart; @@ -79,29 +79,29 @@ export class KameletPropertyField extends React.Component<Props, State> { const selectedText = prevValue.substring(cursorStart, cursorEnd) value = prevValue.replace(selectedText, value); } - const propertyId = this.state.kubernetesSelectorProperty; + const propertyId = this.state.infrastructureSelectorProperty; if (propertyId){ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.parametersChanged(propertyId, value); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (propertyName: string) => { - this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (propertyName: string) => { + this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({showInfrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.showInfrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } getStringInput() { @@ -115,8 +115,8 @@ export class KameletPropertyField extends React.Component<Props, State> { const showInfraSelectorButton = inInfrastructure && !showEditor && !noInfraSelectorButton return <InputGroup> {showInfraSelectorButton && - <Tooltip position="bottom-end" content="Select from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(property.id)}> + <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}> + <Button variant="control" onClick={e => this.openInfrastructureSelector(property.id)}> {icon} </Button> </Tooltip>} @@ -197,7 +197,7 @@ export class KameletPropertyField extends React.Component<Props, State> { onChange={e => this.parametersChanged(property.id, !Boolean(value))}/> } </FormGroup> - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </div> ) } diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx deleted file mode 100644 index b7997eda..00000000 --- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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 { - Badge, - Button, Flex, FlexItem, - Form, FormGroup, Modal, PageSection, - Tab, Tabs, TabTitleText, TextInput, -} from '@patternfly/react-core'; -import '../../karavan.css'; -import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table"; -import {InfrastructureAPI} from "../../utils/InfrastructureAPI"; - -interface Props { - onSelect: (value: string) => void, - onClose?: () => void, - isOpen: boolean, - dark: boolean, -} - -interface State { - tabIndex: string | number - filter?: string - configMaps: string[] - secrets: string[] - services: string[] -} - -export class KubernetesSelector extends React.Component<Props, State> { - - public state: State = { - tabIndex: "configMap", - configMaps: InfrastructureAPI.configMaps, - secrets: InfrastructureAPI.secrets, - services: InfrastructureAPI.services - }; - - selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => { - this.setState({tabIndex: eventKey}) - } - - checkFilter = (name: string): boolean => { - if (this.state.filter !== undefined && name) { - return name.toLowerCase().includes(this.state.filter.toLowerCase()) - } else { - return true; - } - } - - searchInput = () => { - return ( - <Form isHorizontal className="search" autoComplete="off"> - <FormGroup fieldId="search"> - <TextInput className="text-field" type="text" id="search" name="search" iconVariant='search' - value={this.state.filter} - onChange={e => this.setState({filter: e})}/> - </FormGroup> - </Form> - ) - } - - getConfigMapTable() { - const configMaps = this.state.configMaps; - return ( - <TableComposable variant='compact' borders={false}> - <Thead> - <Tr> - <Th/> - <Th key='name'>Name</Th> - <Th key='data'>Data</Th> - </Tr> - </Thead> - <Tbody> - {configMaps - .filter(name => this.checkFilter(name)) - .map((name, idx: number) => { - const configMapName = name.split("/")[0]; - const data = name.split("/")[1]; - return ( - <Tr key={name}> - <Td noPadding isActionCell> - <Badge>CM</Badge> - </Td> - <Td noPadding> - {configMapName} - </Td> - <Td noPadding> - <Button style={{padding: '6px'}} variant={"link"} onClick={ - e => this.props.onSelect?.call(this, "configmap:" + name)}> - {data} - </Button> - </Td> - </Tr> - ) - })} - </Tbody> - </TableComposable> - ) - } - - getSecretsTable() { - const secrets = this.state.secrets; - return ( - <TableComposable variant='compact' borders={false}> - <Thead> - <Tr> - <Th/> - <Th key='name'>Name</Th> - <Th key='data'>Data</Th> - </Tr> - </Thead> - <Tbody> - {secrets - .filter(name => this.checkFilter(name)) - .map((name, idx: number) => { - const configMapName = name.split("/")[0]; - const data = name.split("/")[1]; - return ( - <Tr key={name}> - <Td noPadding isActionCell> - <Badge>S</Badge> - </Td> - <Td noPadding> - {configMapName} - </Td> - <Td noPadding> - <Button style={{padding: '6px'}} variant={"link"} onClick={ - e => this.props.onSelect?.call(this, "secret:" + name)}> - {data} - </Button> - </Td> - </Tr> - ) - })} - </Tbody> - </TableComposable> - ) - } - - getServicesTable() { - const services = this.state.services; - return ( - <TableComposable variant='compact' borders={false}> - <Thead> - <Tr> - <Th/> - <Th key='name'>Name</Th> - {/*<Th key='hostPort'>Host:Port</Th>*/} - <Th key='host'>Host</Th> - <Th key='port'>Port</Th> - </Tr> - </Thead> - <Tbody> - {services - .filter(name => this.checkFilter(name)) - .map((name, idx: number) => { - const serviceName = name.split("|")[0]; - const hostPort = name.split("|")[1]; - const host = hostPort.split(":")[0]; - const port = hostPort.split(":")[1]; - return ( - <Tr key={name}> - <Td noPadding isActionCell> - <Badge>S</Badge> - </Td> - {/*<Td noPadding>*/} - {/* {serviceName}*/} - {/*</Td>*/} - <Td noPadding> - <Button style={{padding: '6px'}} variant={"link"} onClick={ - e => this.props.onSelect?.call(this, hostPort)}> - {serviceName} - </Button> - </Td> - <Td noPadding> - <Button style={{padding: '6px'}} variant={"link"} onClick={ - e => this.props.onSelect?.call(this, host)}> - {host} - </Button> - </Td> - <Td noPadding> - <Button style={{padding: '6px'}} variant={"link"} onClick={ - e => this.props.onSelect?.call(this, port)}> - {port} - </Button> - </Td> - </Tr> - ) - })} - </Tbody> - </TableComposable> - ) - } - - render() { - const tabIndex = this.state.tabIndex; - return ( - <Modal - aria-label="Select from Kubernetes" - width={'50%'} - className='dsl-modal' - isOpen={this.props.isOpen} - onClose={this.props.onClose} - header={ - <Flex direction={{default: "column"}}> - <FlexItem> - <h3>{"Select from Kubernetes"}</h3> - {this.searchInput()} - </FlexItem> - <FlexItem> - <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}> - <Tab eventKey={"configMap"} key={"configMap"} title={<TabTitleText>ConfigMaps</TabTitleText>} /> - <Tab eventKey={"secret"} key={"secret"} title={<TabTitleText>Secrets</TabTitleText>} /> - <Tab eventKey={"service"} key={"service"} title={<TabTitleText>Services</TabTitleText>} /> - </Tabs> - </FlexItem> - </Flex> - } - actions={{}}> - <PageSection variant={this.props.dark ? "darker" : "light"}> - {this.searchInput()} - {tabIndex === 'configMap' && this.getConfigMapTable()} - {tabIndex === 'secret' && this.getSecretsTable()} - {tabIndex === 'service' && this.getServicesTable()} - </PageSection> - </Modal> - ) - } -} \ No newline at end of file diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java index 09548632..c9998219 100644 --- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java +++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java @@ -102,32 +102,6 @@ public class ConductorService { } } - @ConsumeEvent(value = DatagridService.ADDRESS_DEVMODE_COMMAND, blocking = true, ordered = true) - void receiveCommand(JsonObject message) throws InterruptedException { - LOGGER.info("DevMode Command: " + message); - DevModeCommand command = message.mapTo(DevModeCommand.class); - String containerName = command.getProjectId() + "-" + DEVMODE_SUFFIX; - Project p = datagridService.getProject(command.getProjectId()); - if (Objects.equals(command.getCommandName(), CommandName.RUN)) { - LOGGER.infof("DevMode starting for %s", p.getProjectId()); - - HealthCheck healthCheck = new HealthCheck().withTest(List.of("CMD", "curl", "-f", "http://localhost:8080/q/dev/health")) - .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30); - - dockerService.createContainer(containerName, runnerImage, - List.of(), "", false, healthCheck, - Map.of("type", "devmode", "projectId", p.getProjectId()) - ); - dockerService.startContainer(containerName); - LOGGER.infof("DevMode started for %s", p.getProjectId()); - - } else if (Objects.equals(command.getCommandName(), CommandName.DELETE)){ - dockerService.stopContainer(containerName); - dockerService.deleteContainer(containerName); - datagridService.deleteDevModeStatus(p.getName()); - } - } - @ConsumeEvent(value = ADDRESS_CONTAINER_STATS, blocking = true, ordered = true) public void saveStats(JsonObject data) { String projectId = data.getString("projectId"); @@ -142,4 +116,53 @@ public class ConductorService { } } } + + @ConsumeEvent(value = DatagridService.ADDRESS_DEVMODE_COMMAND, blocking = true, ordered = true) + void receiveCommand(JsonObject message) throws InterruptedException { + LOGGER.info("DevMode Command: " + message); + DevModeCommand command = message.mapTo(DevModeCommand.class); + switch (command.getCommandName()){ + case RUN: + runContainer(command); + break; + case DELETE: + deleteContainer(command); + break; + case LOG: + logContainer(command); + break; + } + datagridService.deleteDevModeCommand(command); + } + + void runContainer(DevModeCommand command) throws InterruptedException { + if (DevModeCommandType.DEVMODE.equals(command.getType())) { + String projectId = command.getProjectId(); + LOGGER.infof("DevMode starting for %s", projectId); + HealthCheck healthCheck = new HealthCheck().withTest(List.of("CMD", "curl", "-f", "http://localhost:8080/q/dev/health")) + .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30); + dockerService.createContainer(command.getContainerName(), runnerImage, + List.of(), "", false, healthCheck, + Map.of("type", "devmode", "projectId", projectId)); + dockerService.startContainer(command.getContainerName()); + LOGGER.infof("DevMode started for %s", projectId); + } else { + + } + } + + void deleteContainer(DevModeCommand command) { + if (DevModeCommandType.DEVMODE.equals(command.getType())) { + datagridService.deleteDevModeStatus(command.getProjectId()); + dockerService.stopContainer(command.getContainerName()); + dockerService.deleteContainer(command.getContainerName()); + } else { + dockerService.stopContainer(command.getContainerName()); + dockerService.deleteContainer(command.getContainerName()); + } + } + + void logContainer(DevModeCommand command) { + dockerService.logContainer(command.getContainerName()); + } } \ No newline at end of file diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java index a0575eb2..38c3a89e 100644 --- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java +++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java @@ -6,5 +6,4 @@ public class Constants { public static final String DATAGRID_CONTAINER_NAME = "infinispan"; public static final String KARAVAN_CONTAINER_NAME = "karavan"; - public static final String DEVMODE_SUFFIX = "devmode"; } diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java index 4910e603..9b57dc72 100644 --- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java +++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java @@ -2,12 +2,13 @@ package org.apache.camel.karavan.bashi.docker; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.ContainerPort; import com.github.dockerjava.api.model.Event; import com.github.dockerjava.api.model.EventType; import io.vertx.core.eventbus.EventBus; import org.apache.camel.karavan.bashi.ConductorService; -import org.apache.camel.karavan.bashi.Constants; import org.apache.camel.karavan.datagrid.DatagridService; +import org.apache.camel.karavan.datagrid.model.ContainerInfo; import org.apache.camel.karavan.datagrid.model.DevModeStatus; import org.apache.camel.karavan.datagrid.model.PodStatus; import org.eclipse.microprofile.config.inject.ConfigProperty; @@ -19,7 +20,11 @@ import java.io.Closeable; import java.io.IOException; import java.time.Instant; import java.util.Arrays; +import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; + +import static org.apache.camel.karavan.datagrid.model.DevModeCommand.DEVMODE_SUFFIX; @ApplicationScoped public class DockerEventListener implements ResultCallback<Event> { @@ -48,32 +53,61 @@ public class DockerEventListener implements ResultCallback<Event> { try { if (Objects.equals(event.getType(), EventType.CONTAINER)) { Container container = dockerService.getContainer(event.getId()); + onContainerEvent(event, container); String status = event.getStatus(); if (container.getNames()[0].equals("/infinispan") && status.startsWith("health_status:")) { + onInfinispanHealthEvent(event, container); + } else if (container.getNames()[0].endsWith(DEVMODE_SUFFIX) || Objects.equals(container.getLabels().get("type"), "devmode")) { + onDevModeEvent(event, container); + } + } + } catch (Exception exception) { + LOGGER.error(exception.getMessage()); + } + } + + public void onContainerEvent(Event event, Container container) { + if (datagridService.isReady()) { + String name = container.getNames()[0].replace("/", ""); + if (Arrays.asList("destroy", "stop", "die", "kill", "pause", "destroy", "rename").contains(event.getStatus())) { + datagridService.deleteContainerInfo(name); + } else if (Arrays.asList("create", "start", "unpause").contains(event.getStatus())) { + List<Integer> ports = Arrays.stream(container.getPorts()).map(ContainerPort::getPrivatePort).filter(Objects::nonNull).collect(Collectors.toList()); + ContainerInfo ci = new ContainerInfo(name, container.getId(), container.getImage(), ports, environment); + datagridService.saveContainerInfo(ci); + } + } + } + + public void onInfinispanHealthEvent(Event event, Container container) { + String status = event.getStatus(); + String health = status.replace("health_status: ", ""); + LOGGER.infof("Container %s health status: %s", container.getNames()[0], health); + eventBus.publish(ConductorService.ADDRESS_INFINISPAN_HEALTH, health); + } + + public void onDevModeEvent(Event event, Container container) { + try { + if (datagridService.isReady()) { + String status = event.getStatus(); + String name = container.getNames()[0].replace("/", ""); + if (Arrays.asList("stop", "die", "kill", "pause", "destroy").contains(event.getStatus())) { + String projectId = name.replace(DEVMODE_SUFFIX, ""); + datagridService.deletePodStatus(projectId, environment, name); + datagridService.deleteCamelStatuses(projectId, environment); + } else if (Arrays.asList("start", "unpause").contains(event.getStatus())) { + String projectId = name.replace(DEVMODE_SUFFIX, ""); + PodStatus ps = new PodStatus(name, true, null, projectId, environment, true, Instant.ofEpochSecond(container.getCreated()).toString()); + datagridService.savePodStatus(ps); + } else if (status.startsWith("health_status:")) { String health = status.replace("health_status: ", ""); LOGGER.infof("Container %s health status: %s", container.getNames()[0], health); - eventBus.publish(ConductorService.ADDRESS_INFINISPAN_HEALTH, health); - } else if (Objects.equals(container.getLabels().get("type"), "devmode") && status.startsWith("health_status:")) { - String health = status.replace("health_status: ", ""); - LOGGER.infof("Container %s health status: %s", container.getNames()[0], health); -// update DevModeStatus + //update DevModeStatus String containerName = container.getNames()[0].replace("/", ""); DevModeStatus dms = datagridService.getDevModeStatus(container.getLabels().get("projectId")); dms.setContainerName(containerName); dms.setContainerId(container.getId()); datagridService.saveDevModeStatus(dms); - } else if (container.getNames()[0].endsWith(Constants.DEVMODE_SUFFIX)) { - if (Arrays.asList("stop", "die", "kill", "pause", "destroy").contains(event.getStatus())) { - String name = container.getNames()[0].replace("/", ""); - String projectId = name.replace("-" + Constants.DEVMODE_SUFFIX, ""); - datagridService.deletePodStatus(projectId, environment, name); - datagridService.deleteCamelStatuses(projectId, environment); - } else if (Arrays.asList("start", "unpause").contains(event.getStatus())) { - String name = container.getNames()[0].replace("/", ""); - String projectId = name.replace("-" + Constants.DEVMODE_SUFFIX, ""); - PodStatus ps = new PodStatus(name, true, null, projectId, environment, true, Instant.ofEpochSecond(container.getCreated()).toString()); - datagridService.savePodStatus(ps); - } } } } catch (Exception exception) { diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java index eb4c8ef3..7c58465d 100644 --- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java +++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java @@ -5,6 +5,7 @@ import com.github.dockerjava.api.async.ResultCallback; 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.LogContainerCmd; import com.github.dockerjava.api.model.*; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; @@ -16,7 +17,6 @@ import io.quarkus.scheduler.Scheduled; import io.smallrye.mutiny.tuples.Tuple2; import io.vertx.core.eventbus.EventBus; import io.vertx.core.json.JsonObject; -import org.apache.camel.karavan.bashi.Constants; import org.jboss.logging.Logger; import javax.enterprise.context.ApplicationScoped; @@ -25,12 +25,14 @@ import java.io.IOException; import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.apache.camel.karavan.bashi.ConductorService.ADDRESS_CONTAINER_STATS; import static org.apache.camel.karavan.bashi.ConductorService.ADDRESS_INFINISPAN_HEALTH; import static org.apache.camel.karavan.bashi.Constants.DATAGRID_CONTAINER_NAME; import static org.apache.camel.karavan.bashi.Constants.NETWORK_NAME; +import static org.apache.camel.karavan.datagrid.model.DevModeCommand.DEVMODE_SUFFIX; @ApplicationScoped public class DockerService { @@ -53,7 +55,7 @@ public class DockerService { Statistics stats = getContainerStats(container.getId()); String name = container.getNames()[0].replace("/", ""); - String projectId = name.replace("-" + Constants.DEVMODE_SUFFIX, ""); + String projectId = name.replace(DEVMODE_SUFFIX, ""); String memoryUsage = formatMemory(stats.getMemoryStats().getUsage()); String memoryLimit = formatMemory(stats.getMemoryStats().getLimit()); JsonObject data = JsonObject.of( @@ -132,6 +134,11 @@ public class DockerService { return containers.get(0); } + public Container getContainerByName(String name) { + List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec(); + return containers.get(0); + } + public Statistics getContainerStats(String containerId) { InvocationBuilder.AsyncResultCallback<Statistics> callback = new InvocationBuilder.AsyncResultCallback<>(); getDockerClient().statsCmd(containerId).withContainerId(containerId).withNoStream(true).exec(callback); @@ -186,6 +193,18 @@ public class DockerService { startContainer(name); } + public void logContainer(String containerName) { + try { + LogCallback callback = new LogCallback(); + Container container = getContainerByName(containerName); + getDockerClient().logContainerCmd(container.getId()) + .withStdOut(true).withStdErr(true).withTimestamps(true).exec(callback); + callback.awaitCompletion(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + public void stopContainer(String name) { List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec(); if (containers.size() == 1) { @@ -204,6 +223,14 @@ public class DockerService { } } + public void killContainer(String name) { + List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec(); + if (containers.size() == 1) { + Container container = containers.get(0); + getDockerClient().killContainerCmd(container.getId()).exec(); + } + } + public void pullImage(String image) throws InterruptedException { List<Image> images = getDockerClient().listImagesCmd().withShowAll(true).exec(); if (!images.stream().filter(i -> Arrays.asList(i.getRepoTags()).contains(image)).findFirst().isPresent()) { diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java new file mode 100644 index 00000000..48c061cd --- /dev/null +++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java @@ -0,0 +1,26 @@ +package org.apache.camel.karavan.bashi.docker; + +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.model.Frame; + +import java.util.ArrayList; +import java.util.List; + +public class LogCallback extends ResultCallback.Adapter<Frame> { + protected final StringBuffer log = new StringBuffer(); + + List<Frame> collectedFrames = new ArrayList<>(); + + boolean collectFrames = false; + + @Override + public void onNext(Frame frame) { + if (collectFrames) collectedFrames.add(frame); + log.append(new String(frame.getPayload())); + } + + @Override + public String toString() { + return log.toString(); + } +} \ No newline at end of file diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java index 38f40026..5df37b50 100644 --- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java +++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java @@ -73,6 +73,7 @@ public class DatagridService { private RemoteCache<String, Environment> environments; private RemoteCache<String, String> commits; private RemoteCache<GroupedKey, DevModeStatus> devmodeStatuses; + private RemoteCache<GroupedKey, ContainerInfo> containers; private RemoteCache<GroupedKey, DevModeCommand> devmodeCommands; private final AtomicBoolean ready = new AtomicBoolean(false); @@ -120,6 +121,7 @@ public class DatagridService { commits = getOrCreateCache("commits", false); deploymentStatuses = getOrCreateCache(DeploymentStatus.CACHE, false); devmodeStatuses = getOrCreateCache(DevModeStatus.CACHE, false); + containers = getOrCreateCache(ContainerInfo.CACHE, false); devmodeCommands = getOrCreateCache(DevModeCommand.CACHE, true); cacheManager.getCache(DevModeCommand.CACHE).addClientListener(new DevModeCommandListener(eventBus)); @@ -140,15 +142,6 @@ public class DatagridService { return cacheManager.administration().getOrCreateCache(name, new StringConfiguration(String.format(config, name))); } - private void cleanData() { - environments.clear(); - deploymentStatuses.clear(); - podStatuses.clear(); - pipelineStatuses.clear(); - camelStatuses.clear(); - devmodeCommands.clear(); - } - @ConsumeEvent(value = ADDRESS_DEVMODE_COMMAND_INTERNAL, blocking = true, ordered = true, local = false) void sendCommand(JsonObject message) { GroupedKey key = message.mapTo(GroupedKey.class); @@ -323,7 +316,7 @@ public class DatagridService { public List<CamelStatus> getCamelStatusesByProjectIdEnv(String projectId, String env) { QueryFactory queryFactory = Search.getQueryFactory(camelStatuses); - return queryFactory.<CamelStatus>create("FROM karavan.CamelStatus WHERE projectId = :projectId AND name = :env") + return queryFactory.<CamelStatus>create("FROM karavan.CamelStatus WHERE projectId = :projectId AND env = :env") .setParameter("projectId", projectId) .setParameter("env", env) .execute().list(); @@ -394,19 +387,35 @@ public class DatagridService { return new ArrayList<>(devmodeStatuses.values()); } - public void sendDevModeCommand(String projectId, DevModeCommand command) { - if (command.getProjectId() == null) { - command.setProjectId(projectId); - } - devmodeCommands.put(GroupedKey.create(projectId, DEFAULT_ENVIRONMENT, UUID.randomUUID().toString()), command); + public void sendDevModeCommand(DevModeCommand command) { + devmodeCommands.put(GroupedKey.create(command.getContainerName(), DEFAULT_ENVIRONMENT, command.getTime().toString()), command); } public DevModeCommand getDevModeCommand(GroupedKey key) { return devmodeCommands.get(key); } - public DevModeCommand getDevModeCommand(String projectId) { - return getDevModeCommand(GroupedKey.create(projectId, DEFAULT_ENVIRONMENT, projectId)); + public void deleteDevModeCommand(DevModeCommand command) { + containers.remove(GroupedKey.create(command.getContainerName(), DEFAULT_ENVIRONMENT, command.getTime().toString())); + } + + public void saveContainerInfo(ContainerInfo ci) { + containers.put(GroupedKey.create(ci.getContainerName(), ci.getEnv() != null ? ci.getEnv() : DEFAULT_ENVIRONMENT, ci.getContainerName()), ci); + } + + public void getContainerInfo(String name, String env) { + containers.get(GroupedKey.create(name, env, name)); + } + + public List<ContainerInfo> getContainerInfos(String env) { + QueryFactory queryFactory = Search.getQueryFactory(containers); + return queryFactory.<ContainerInfo>create("FROM karavan.ContainerInfo WHERE env = :env") + .setParameter("env", env) + .execute().list(); + } + + public void deleteContainerInfo(String containerName) { + containers.remove(GroupedKey.create(containerName, DEFAULT_ENVIRONMENT, containerName)); } public void clearAllStatuses() { @@ -415,7 +424,8 @@ public class DatagridService { podStatuses.clearAsync(), pipelineStatuses.clearAsync(), camelStatuses.clearAsync(), - devmodeCommands.clearAsync() + devmodeCommands.clearAsync(), + devmodeStatuses.clearAsync() ).join(); } diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java deleted file mode 100644 index ff34f9ad..00000000 --- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.apache.camel.karavan.datagrid.model; - -import org.infinispan.protostream.annotations.ProtoEnumValue; - -public enum CommandName { - - @ProtoEnumValue(number = 0, name = "RUN") RUN, - @ProtoEnumValue (number = 1, name = "DELETE") DELETE, - @ProtoEnumValue (number = 2, name = "RELOAD") RELOAD -} diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java new file mode 100644 index 00000000..c23dcd16 --- /dev/null +++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java @@ -0,0 +1,70 @@ +package org.apache.camel.karavan.datagrid.model; + +import org.infinispan.protostream.annotations.ProtoFactory; +import org.infinispan.protostream.annotations.ProtoField; + +import java.util.ArrayList; +import java.util.List; + +public class ContainerInfo { + public static final String CACHE = "container_infos"; + @ProtoField(number = 1) + String containerName; + @ProtoField(number = 2) + String containerId; + @ProtoField(number = 3) + String image; + @ProtoField(number = 4, collectionImplementation = ArrayList.class) + List<Integer> ports; + @ProtoField(number = 5) + String env; + + @ProtoFactory + public ContainerInfo(String containerName, String containerId, String image, List<Integer> ports, String env) { + this.containerName = containerName; + this.containerId = containerId; + this.image = image; + this.ports = ports; + this.env = env; + } + + public String getEnv() { + return env; + } + + public void setEnv(String env) { + this.env = env; + } + + public String getContainerName() { + return containerName; + } + + public void setContainerName(String containerName) { + this.containerName = containerName; + } + + public String getContainerId() { + return containerId; + } + + public void setContainerId(String containerId) { + this.containerId = containerId; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public List<Integer> getPorts() { + return ports; + } + + public void setPorts(List<Integer> ports) { + this.ports = ports; + } +} diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java index 1d5a6517..3bc80546 100644 --- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java +++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java @@ -3,29 +3,46 @@ package org.apache.camel.karavan.datagrid.model; import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; +import java.time.Instant; + public class DevModeCommand { public static final String CACHE = "devmode_commands"; + public static final String DEVMODE_SUFFIX = "-devmode"; @ProtoField(number = 1) - CommandName commandName; + DevModeCommandName commandName; @ProtoField(number = 2) String projectId; @ProtoField(number = 3) + String containerName; + @ProtoField(number = 4) + DevModeCommandType type; + @ProtoField(number = 5) Long time; @ProtoFactory - public DevModeCommand(CommandName commandName, String projectId, Long time) { + public DevModeCommand(DevModeCommandName commandName, String projectId, String containerName, DevModeCommandType type, Long time) { this.commandName = commandName; this.projectId = projectId; + this.containerName = containerName; + this.type = type; this.time = time; } - public DevModeCommand(CommandName commandName, Long time) { - this.commandName = commandName; - this.time = time; + public static DevModeCommand createDevModeCommand(DevModeCommandName commandName, String projectId) { + return new DevModeCommand(commandName, projectId, projectId + DEVMODE_SUFFIX, DevModeCommandType.DEVMODE, Instant.now().toEpochMilli()); + } + + public static DevModeCommand createDevServiceCommand(DevModeCommandName commandName, String serviceName) { + return new DevModeCommand(commandName, null, serviceName, DevModeCommandType.DEVSERVICE, Instant.now().toEpochMilli()); } - public DevModeCommand() { + public DevModeCommandName getCommandName() { + return commandName; + } + + public void setCommandName(DevModeCommandName commandName) { + this.commandName = commandName; } public String getProjectId() { @@ -36,12 +53,20 @@ public class DevModeCommand { this.projectId = projectId; } - public CommandName getCommandName() { - return commandName; + public String getContainerName() { + return containerName; } - public void setCommandName(CommandName commandName) { - this.commandName = commandName; + public void setContainerName(String containerName) { + this.containerName = containerName; + } + + public DevModeCommandType getType() { + return type; + } + + public void setType(DevModeCommandType type) { + this.type = type; } public Long getTime() { diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java new file mode 100644 index 00000000..aa0a550b --- /dev/null +++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java @@ -0,0 +1,12 @@ +package org.apache.camel.karavan.datagrid.model; + +import org.infinispan.protostream.annotations.ProtoEnumValue; + +public enum DevModeCommandName { + + @ProtoEnumValue(number = 0, name = "RUN") RUN, + @ProtoEnumValue (number = 1, name = "STOP") STOP, + @ProtoEnumValue (number = 2, name = "DELETE") DELETE, + @ProtoEnumValue (number = 3, name = "RELOAD") RELOAD, + @ProtoEnumValue (number = 4, name = "LOG") LOG +} diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java new file mode 100644 index 00000000..c0a1d582 --- /dev/null +++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java @@ -0,0 +1,9 @@ +package org.apache.camel.karavan.datagrid.model; + +import org.infinispan.protostream.annotations.ProtoEnumValue; + +public enum DevModeCommandType { + + @ProtoEnumValue(number = 0, name = "DEVMODE") DEVMODE, + @ProtoEnumValue (number = 1, name = "DEVSERVICE") DEVSERVICE +} diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java index be78b42a..22d5e741 100644 --- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java +++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java @@ -14,10 +14,12 @@ import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder; PodStatus.class, Environment.class, ServiceStatus.class, - CommandName.class, + DevModeCommandName.class, + DevModeCommandType.class, CamelStatusName.class, DevModeCommand.class, - DevModeStatus.class + DevModeStatus.class, + ContainerInfo.class }, schemaFileName = "karavan.proto", schemaFilePath = "proto/", diff --git a/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java b/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java index 5e4fb8c0..e809d178 100644 --- a/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java +++ b/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java @@ -10,7 +10,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import javax.inject.Inject; -import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; @@ -38,15 +37,24 @@ public class DataGridTest { commandsReceived.add(message.mapTo(DevModeCommand.class)); } -// @Test + @Test + public void testContainersStatuses() throws InterruptedException { + ContainerInfo ci = new ContainerInfo("demo", "id", "image", List.of(8080, 8081, 8082), "dev"); + datagridService.saveContainerInfo(ci); + List<ContainerInfo> list = datagridService.getContainerInfos("dev"); + System.out.println(list); + assertEquals(1, list.size()); + } + + @Test public void sendCommand() throws InterruptedException { List<DevModeCommand> commandsSent = List.of( - new DevModeCommand(CommandName.RUN, Instant.now().toEpochMilli()), - new DevModeCommand(CommandName.RELOAD, Instant.now().toEpochMilli()), - new DevModeCommand(CommandName.DELETE, Instant.now().toEpochMilli()), - new DevModeCommand(CommandName.RUN, Instant.now().toEpochMilli()) + DevModeCommand.createDevModeCommand(DevModeCommandName.RUN, "test1"), + DevModeCommand.createDevModeCommand(DevModeCommandName.RELOAD, "test1"), + DevModeCommand.createDevModeCommand(DevModeCommandName.DELETE, "test1"), + DevModeCommand.createDevModeCommand(DevModeCommandName.RUN, "test1") ); - commandsSent.forEach(devModeCommand -> datagridService.sendDevModeCommand("test1", devModeCommand)); + commandsSent.forEach(devModeCommand -> datagridService.sendDevModeCommand(devModeCommand)); CountDownLatch latch = new CountDownLatch(4); latch.await(5, TimeUnit.SECONDS); diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx b/karavan-designer/src/designer/beans/BeanProperties.tsx index b7ab5532..24c1e202 100644 --- a/karavan-designer/src/designer/beans/BeanProperties.tsx +++ b/karavan-designer/src/designer/beans/BeanProperties.tsx @@ -54,9 +54,9 @@ interface State { bean?: NamedBeanDefinition properties: Map<string, [string, string, boolean]> key: string, - showKubernetesSelector: boolean - kubernetesSelectorUuid?: string - kubernetesSelectorProperty?: string + showInfrastructureSelector: boolean + infrastructureSelectorUuid?: string + infrastructureSelectorProperty?: string } export class BeanProperties extends React.Component<Props, State> { @@ -70,7 +70,7 @@ export class BeanProperties extends React.Component<Props, State> { public state: State = { bean: this.props.bean, key: '', - showKubernetesSelector: false, + showInfrastructureSelector: false, properties: this.props.bean?.properties ? this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, [string, string, boolean]>() }; @@ -118,31 +118,31 @@ export class BeanProperties extends React.Component<Props, State> { }) } - selectKubernetes = (value: string) => { - const propertyId = this.state.kubernetesSelectorProperty; - const uuid = this.state.kubernetesSelectorUuid; + selectInfrastructure = (value: string) => { + const propertyId = this.state.infrastructureSelectorProperty; + const uuid = this.state.infrastructureSelectorUuid; if (propertyId && uuid){ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.propertyChanged(uuid, propertyId, value, false); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (uuid: string, propertyName: string) => { - this.setState({kubernetesSelectorUuid: uuid, kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (uuid: string, propertyName: string) => { + this.setState({infrastructureSelectorUuid: uuid, infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({showInfrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.showInfrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } cloneBean = () => { @@ -208,8 +208,8 @@ export class BeanProperties extends React.Component<Props, State> { onChange={e => this.propertyChanged(i, e, value, showPassword)}/> <InputGroup> {inInfrastructure && - <Tooltip position="bottom-end" content="Select value from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(i, key)}> + <Tooltip position="bottom-end" content="Select value from Infrastructure"> + <Button variant="control" onClick={e => this.openInfrastructureSelector(i, key)}> {icon} </Button> </Tooltip>} @@ -246,7 +246,7 @@ export class BeanProperties extends React.Component<Props, State> { {this.state.bean === undefined && <IntegrationHeader integration={this.props.integration}/>} {this.state.bean !== undefined && this.getBeanForm()} </Form> - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </div> ) } diff --git a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx index 39817f7c..ca1f6a0d 100644 --- a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx +++ b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx @@ -23,7 +23,7 @@ import { Select, SelectVariant, SelectDirection, - SelectOption, InputGroup, TextArea, Tooltip, Button, + SelectOption, InputGroup, TextArea, Tooltip, Button, capitalize, } from '@patternfly/react-core'; import '../../karavan.css'; import "@patternfly/patternfly/patternfly.css"; @@ -57,8 +57,8 @@ interface State { selectStatus: Map<string, boolean> showEditor: boolean showPassword: boolean - showKubernetesSelector: boolean - kubernetesSelectorProperty?: string + showInfrastructureSelector: boolean + infrastructureSelectorProperty?: string ref: any id: string } @@ -69,7 +69,7 @@ export class ComponentParameterField extends React.Component<Props, State> { selectStatus: new Map<string, boolean>(), showEditor: false, showPassword: false, - showKubernetesSelector: false, + showInfrastructureSelector: false, ref: React.createRef(), id: prefix + "-" + this.props.property.name } @@ -179,7 +179,7 @@ export class ComponentParameterField extends React.Component<Props, State> { </InputGroup> } - selectKubernetes = (value: string) => { + selectInfrastructure = (value: string) => { // check if there is a selection const textVal = this.state.ref.current; const cursorStart = textVal.selectionStart; @@ -189,29 +189,29 @@ export class ComponentParameterField extends React.Component<Props, State> { const selectedText = prevValue.substring(cursorStart, cursorEnd) value = prevValue.replace(selectedText, value); } - const propertyName = this.state.kubernetesSelectorProperty; + const propertyName = this.state.infrastructureSelectorProperty; if (propertyName) { if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.parametersChanged(propertyName, value); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (propertyName: string) => { - this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (propertyName: string) => { + this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({showInfrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.showInfrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } getStringInput(property: ComponentProperty, value: any) { @@ -221,8 +221,8 @@ export class ComponentParameterField extends React.Component<Props, State> { const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/> return <InputGroup> {inInfrastructure && !showEditor && !noInfraSelectorButton && - <Tooltip position="bottom-end" content="Select from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}> + <Tooltip position="bottom-end" content={"Select from " + capitalize((InfrastructureAPI.infrastructure))}> + <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}> {icon} </Button> </Tooltip>} @@ -340,7 +340,7 @@ export class ComponentParameterField extends React.Component<Props, State> { && this.getSelect(property, value)} {property.type === 'boolean' && this.getSwitch(property, value)} - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </FormGroup> ) } diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx b/karavan-designer/src/designer/route/property/DslPropertyField.tsx index e11ee485..d17a26c3 100644 --- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx +++ b/karavan-designer/src/designer/route/property/DslPropertyField.tsx @@ -35,7 +35,7 @@ import { Text, Tooltip, Card, - InputGroup, + InputGroup, capitalize, } from '@patternfly/react-core'; import '../../karavan.css'; import "@patternfly/patternfly/patternfly.css"; @@ -87,8 +87,8 @@ interface State { isShowAdvanced: Map<string, boolean>, arrayValues: Map<string, string>, showEditor: boolean - showKubernetesSelector: boolean - kubernetesSelectorProperty?: string + infrastructureSelector: boolean + infrastructureSelectorProperty?: string customCode?: string ref: any } @@ -100,7 +100,7 @@ export class DslPropertyField extends React.Component<Props, State> { arrayValues: new Map<string, string>(), isShowAdvanced: new Map<string, boolean>(), showEditor: false, - showKubernetesSelector: false, + infrastructureSelector: false, ref: React.createRef(), }; @@ -176,7 +176,7 @@ export class DslPropertyField extends React.Component<Props, State> { return property.name === 'uri' && !['ToDefinition', 'ToDynamicDefinition', 'WireTapDefinition'].includes(dslName) } - selectKubernetes = (value: string) => { + selectInfrastructure = (value: string) => { // check if there is a selection const textVal = this.state.ref.current; const cursorStart = textVal.selectionStart; @@ -186,29 +186,29 @@ export class DslPropertyField extends React.Component<Props, State> { const selectedText = prevValue.substring(cursorStart, cursorEnd) value = prevValue.replace(selectedText, value); } - const propertyName = this.state.kubernetesSelectorProperty; + const propertyName = this.state.infrastructureSelectorProperty; if (propertyName) { if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.propertyChanged(propertyName, value); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({infrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (propertyName: string) => { - this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (propertyName: string) => { + this.setState({infrastructureSelectorProperty: propertyName, infrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({infrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.infrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } getStringInput = (property: PropertyMeta, value: any) => { @@ -218,8 +218,8 @@ export class DslPropertyField extends React.Component<Props, State> { const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/> return (<InputGroup> {inInfrastructure && !showEditor && !noInfraSelectorButton && - <Tooltip position="bottom-end" content="Select from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}> + <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}> + <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}> {icon} </Button> </Tooltip>} @@ -732,7 +732,7 @@ export class DslPropertyField extends React.Component<Props, State> { {isKamelet && property.name === 'parameters' && this.getKameletParameters()} {!isKamelet && property.name === 'parameters' && this.getComponentParameters(property)} </FormGroup> - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </div> ) } diff --git a/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx index 04c8d43a..e0069bc0 100644 --- a/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx +++ b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx @@ -208,6 +208,7 @@ export class InfrastructureSelector extends React.Component<Props, State> { render() { const tabIndex = this.state.tabIndex; + const tabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['configMap', 'secret', 'services'] : ['services']; return ( <Modal aria-label="Select from Infrastructure" @@ -223,9 +224,7 @@ export class InfrastructureSelector extends React.Component<Props, State> { </FlexItem> <FlexItem> <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}> - <Tab eventKey={"configMap"} key={"configMap"} title={<TabTitleText>ConfigMaps</TabTitleText>} /> - <Tab eventKey={"secret"} key={"secret"} title={<TabTitleText>Secrets</TabTitleText>} /> - <Tab eventKey={"service"} key={"service"} title={<TabTitleText>Services</TabTitleText>} /> + {tabs.map(tab => <Tab eventKey={tab} key={tab} title={<TabTitleText>{capitalize(tab)}</TabTitleText>} />)} </Tabs> </FlexItem> </Flex> @@ -235,7 +234,7 @@ export class InfrastructureSelector extends React.Component<Props, State> { {this.searchInput()} {tabIndex === 'configMap' && this.getConfigMapTable()} {tabIndex === 'secret' && this.getSecretsTable()} - {tabIndex === 'service' && this.getServicesTable()} + {tabIndex === 'services' && this.getServicesTable()} </PageSection> </Modal> ) diff --git a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx index 8beed690..9b0a3b39 100644 --- a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx +++ b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx @@ -19,7 +19,7 @@ import { FormGroup, TextInput, Popover, - Switch, InputGroup, Button, TextArea, Tooltip + Switch, InputGroup, Button, TextArea, Tooltip, capitalize } from '@patternfly/react-core'; import '../../karavan.css'; import "@patternfly/patternfly/patternfly.css"; @@ -45,8 +45,8 @@ interface State { selectIsOpen: boolean showEditor: boolean showPassword: boolean - showKubernetesSelector: boolean - kubernetesSelectorProperty?: string + showInfrastructureSelector: boolean + infrastructureSelectorProperty?: string ref: any } @@ -56,7 +56,7 @@ export class KameletPropertyField extends React.Component<Props, State> { selectIsOpen: false, showEditor: false, showPassword: false, - showKubernetesSelector: false, + showInfrastructureSelector: false, ref: React.createRef(), } @@ -69,7 +69,7 @@ export class KameletPropertyField extends React.Component<Props, State> { this.setState({selectIsOpen: false}); } - selectKubernetes = (value: string) => { + selectInfrastructure = (value: string) => { // check if there is a selection const textVal = this.state.ref.current; const cursorStart = textVal.selectionStart; @@ -79,29 +79,29 @@ export class KameletPropertyField extends React.Component<Props, State> { const selectedText = prevValue.substring(cursorStart, cursorEnd) value = prevValue.replace(selectedText, value); } - const propertyId = this.state.kubernetesSelectorProperty; + const propertyId = this.state.infrastructureSelectorProperty; if (propertyId){ if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}"; this.parametersChanged(propertyId, value); - this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined}) + this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined}) } } - openKubernetesSelector = (propertyName: string) => { - this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true}); + openInfrastructureSelector = (propertyName: string) => { + this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true}); } - closeKubernetesSelector = () => { - this.setState({showKubernetesSelector: false}) + closeInfrastructureSelector = () => { + this.setState({showInfrastructureSelector: false}) } - getKubernetesSelectorModal() { + getInfrastructureSelectorModal() { return ( <InfrastructureSelector dark={false} - isOpen={this.state.showKubernetesSelector} - onClose={() => this.closeKubernetesSelector()} - onSelect={this.selectKubernetes}/>) + isOpen={this.state.showInfrastructureSelector} + onClose={() => this.closeInfrastructureSelector()} + onSelect={this.selectInfrastructure}/>) } getStringInput() { @@ -115,8 +115,8 @@ export class KameletPropertyField extends React.Component<Props, State> { const showInfraSelectorButton = inInfrastructure && !showEditor && !noInfraSelectorButton return <InputGroup> {showInfraSelectorButton && - <Tooltip position="bottom-end" content="Select from Kubernetes"> - <Button variant="control" onClick={e => this.openKubernetesSelector(property.id)}> + <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}> + <Button variant="control" onClick={e => this.openInfrastructureSelector(property.id)}> {icon} </Button> </Tooltip>} @@ -197,7 +197,7 @@ export class KameletPropertyField extends React.Component<Props, State> { onChange={e => this.parametersChanged(property.id, !Boolean(value))}/> } </FormGroup> - {this.getKubernetesSelectorModal()} + {this.getInfrastructureSelectorModal()} </div> ) }