Skip to content

Use camel-dashboard-operator as backend #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ jobs:
shell: bash
run: |
make CUSTOM_PLUGIN_IMAGE=quay.io/camel-tooling/camel-openshift-console-plugin image
make CUSTOM_PLUGIN_IMAGE=quay.io/camel-tooling/camel-openshift-console-plugin CUSTOM_PLUGIN_VERSION=latest image

- name: Push plugin container
if: github.ref == 'refs/heads/main'
shell: bash
run: |
make CUSTOM_PLUGIN_IMAGE=quay.io/camel-tooling/camel-openshift-console-plugin push
make CUSTOM_PLUGIN_IMAGE=quay.io/camel-tooling/camel-openshift-console-plugin CUSTOM_PLUGIN_VERSION=latest push
43 changes: 15 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
# camel-openshift-console-plugin
Camel Openshift Console Plugin
# Camel Openshift Console Plugin

> [!WARNING]
> The project is still a work in progress that has not been released yet.
> Unstability is to be expected.

This project provides a [console plugin](https://github.com/openshift/console/tree/master/frontend/packages/console-dynamic-plugin-sdk) for [Camel](https://camel.apache.org).
The project is created using [openshift console plugin template](https://github.com/openshift/console-plugin-template)

It requires:
* OpenShift 4.18
* [Camel Dashboard Operator](https://github.com/squakez/camel-dashboard-operator)

# Local Development

Node.js 20+ and Yarn are required to build and run this locally. To run OpenShift console in a container, [podman 3.2.0+](https://podman.io) or [Docker](https://www.docker.com) is required.

For development you can login to an existing [OpenShift](https://www.redhat.com/en/technologies/cloud-computing/openshift) and run the console with the plugin included locally.
**Note**: Works well with [OpenShift Sandbox](https://developers.redhat.com/developer-sandbox).

In one terminal window, run:

```sh
yarn install
yarn run start
```
1. `yarn install`
2. `yarn run start`

In another terminal window, run:

After running `oc login` (requires [oc](https://console.redhat.com/openshift/downloads) and an [OpenShift cluster](https://console.redhat.com/openshift/create))

```sh
yarn run start-console
```
(requires [podman 3.2.0+](https://podman.io) or [Docker](https://www.docker.com))

1. `oc login` (requires [oc](https://console.redhat.com/openshift/downloads) and an [OpenShift cluster](https://console.redhat.com/openshift/create))
2. `yarn run start-console` (requires [Docker](https://www.docker.com) or [podman 3.2.0+](https://podman.io))

This will run the OpenShift console in a container connected to the cluster
you've logged into. The plugin HTTP server runs on port 9001 with CORS enabled.
Expand Down Expand Up @@ -59,17 +60,3 @@ In the developer perpective the Camel section is now shown:
[![The Camel Plugin Home](screenshots/home.png)](screenshots/home.png)


# Development notes

The frontend is able to retrieve information from the console using the following APIs:

## Kubernetes API /api/kubernetes
**Examples**:
- /api/kubernetes/apis/apps/v1/namespaces/<namespace>/deployments
- /api/kubernetes/apis/apps.openshift.io/v1/namespaces/<namespace>/deploymentconfigs

## Prometheus API /api/prometheus

**Examples**:
- /api/prometheus/api/v1/query_range

2 changes: 1 addition & 1 deletion console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"type": "console.page/route",
"properties": {
"exact": false,
"path": "/camel/app/ns/:ns/kind/:kind/name/:name",
"path": "/camel/app/ns/:ns/name/:name",
"component": { "$codeRef": "CamelApp" }
}
},
Expand Down
21 changes: 12 additions & 9 deletions locales/en/plugin__camel-openshift-console-plugin.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
{
"Build Timestamp": "Build Timestamp",
"C": "C",
"Camel": "Camel",
"Camel App Details": "Camel App Details",
"Camel Details": "Camel Details",
"Created": "Created",
"Camel Version": "Camel Version",
"Details": "Details",
"Endpoints": "Endpoints",
"Frameworks": "Frameworks",
"Health Endpoints": "Health Endpoints",
"Exchange": "Exchange",
"failed": "failed",
"Health": "Health",
"Image": "Image",
"Internal IP": "Internal IP",
"Kind": "Kind",
"Location:": "Location:",
"Metrics Endpoint": "Metrics Endpoint",
"Metrics": "Metrics",
"Name": "Name",
"Namespace": "Namespace",
"No build timestamp": "No build timestamp",
"No camel version": "No camel version",
"No namespace": "No namespace",
"No resources found": "No resources found",
"No version": "No version",
"pending": "pending",
"Pod port:": "Pod port:",
"Resources": "Resources",
"Runtime": "Runtime",
"Runtime version": "Runtime version",
"Runtime Provider": "Runtime Provider",
"Runtime Version": "Runtime Version",
"Service port:": "Service port:",
"Status": "Status",
"succeed": "succeed",
"total": "total",
"unknown host": "unknown host",
"Version": "Version",
"View Logs": "View Logs"
}
83 changes: 21 additions & 62 deletions src/components/camel-app-details/CamelAppDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';
import { CamelAppKind } from '../../types';
import { Card, CardBody, CardTitle, TextContent } from '@patternfly/react-core';
import { Card, CardBody, TextContent } from '@patternfly/react-core';
import { useTranslation } from 'react-i18next';
import { K8sGroupVersionKind, ResourceLink } from '@openshift-console/dynamic-plugin-sdk';
import { CamelAppGVK, getBuildTimestamp, getHealthEndpoints } from '../../utils';
import { camelAppGVK } from '../../const';
import CamelAppStatusPod from './CamelAppStatusPod';

type CamelAppDetailsProps = {
obj: CamelAppKind;
Expand All @@ -25,77 +26,35 @@ type CamelAppDetails = {
const CamelAppDetails: React.FC<CamelAppDetailsProps> = ({ obj: camelInt }) => {
const { t } = useTranslation('plugin__camel-openshift-console-plugin');

// TODO : replace with real CR values
const CamelAppDetails = {
groupVersionKind: CamelAppGVK(camelInt.kind),
name: camelInt.metadata.name,
namespace: camelInt.metadata.namespace,
version: '4.10.2',
buildTimestamp: getBuildTimestamp(camelInt),
runtimeFramework: 'quarkus',
runtimeVersion: '3.20.0',
healthEndpoints: getHealthEndpoints('quarkus'),
metricsEndpoint: '/observe/metrics',
};

return (
<div className="co-m-pane__body">
<h2>{t('Camel App Details')}</h2>
<Card>
<CardTitle>{t('Details')}</CardTitle>
<CardBody>
<ResourceLink
groupVersionKind={CamelAppDetails.groupVersionKind}
name={CamelAppDetails.name}
namespace={CamelAppDetails.namespace}
linkTo={true}
displayName={camelInt.metadata.name}
groupVersionKind={camelAppGVK}
name={camelInt.metadata.name}
namespace={camelInt.metadata.namespace}
/>
<TextContent>
<strong>{t('Version')}: </strong>
{CamelAppDetails.version || (
<span className="text-muted">{t('No version')}</span>
)}
</TextContent>
<TextContent>
<strong>{t('Build Timestamp')}: </strong>
{CamelAppDetails.buildTimestamp || (
<span className="text-muted">{t('No build timestamp')}</span>
)}
</TextContent>
</CardBody>
</Card>
<Card>
<CardTitle>{t('Endpoints')}</CardTitle>
<CardBody>
<TextContent>
<strong>{t('Health Endpoints')}: </strong>
{CamelAppDetails.healthEndpoints
? CamelAppDetails.healthEndpoints.map((endpoint, i) => {
return <TextContent key={i}> {endpoint}</TextContent>;
})
: '-'}
</TextContent>
<TextContent>
<strong>{t('Metrics Endpoint')}: </strong>
{CamelAppDetails.metricsEndpoint ? (
<TextContent> {CamelAppDetails.metricsEndpoint}</TextContent>
) : (
'-'
)}
</TextContent>
</CardBody>
</Card>
<Card>
<CardTitle>{t('Frameworks')}</CardTitle>
<CardBody>
<TextContent>
<strong>{t('Runtime')}: </strong> {CamelAppDetails.runtimeFramework}
</TextContent>
<TextContent>
<strong>{t('Runtime version')}: </strong> {CamelAppDetails.runtimeVersion}
<strong>{t('Image')}: </strong>
{camelInt.status.image}
</TextContent>
</CardBody>
</Card>

<ul className="list-group">
{camelInt.status.pods
? camelInt.status.pods.map((pod, i) => {
return (
<li key={i} className="list-group-item">
<CamelAppStatusPod obj={camelInt} pod={pod} />
</li>
);
})
: ''}
</ul>
</div>
);
};
Expand Down
116 changes: 116 additions & 0 deletions src/components/camel-app-details/CamelAppStatusPod.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import * as React from 'react';
import { CamelAppKind, CamelAppStatusPod } from '../../types';
import {
Card,
CardBody,
TextList,
TextListItem,
DescriptionList,
DescriptionListGroup,
DescriptionListTerm,
DescriptionListDescription,
} from '@patternfly/react-core';
import { podGVK } from '../../const';
import { ResourceLink, ResourceStatus } from '@openshift-console/dynamic-plugin-sdk';
import { useTranslation } from 'react-i18next';
import Status from '@openshift-console/dynamic-plugin-sdk/lib/app/components/status/Status';

type CamelAppStatusPodProps = {
obj: CamelAppKind;
pod: CamelAppStatusPod;
};

const CamelAppStatusPod: React.FC<CamelAppStatusPodProps> = ({ obj: camelInt, pod: camelPod }) => {
const { t } = useTranslation('plugin__camel-openshift-console-plugin');

return (
<>
<Card>
<CardBody>
<h4>
<ResourceLink
displayName={camelPod.name}
groupVersionKind={podGVK}
name={camelPod.name}
namespace={camelInt.metadata.namespace}
>
<ResourceStatus additionalClassNames="hidden-xs">
<Status status={camelPod.status} />
</ResourceStatus>
</ResourceLink>
</h4>
<DescriptionList
columnModifier={{
default: '1Col',
}}
>
<DescriptionListGroup>
<DescriptionListTerm>{t('Internal IP')}:</DescriptionListTerm>
<DescriptionListDescription>{camelPod.internalIp}</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Runtime')}:</DescriptionListTerm>
<DescriptionListDescription>
<TextList>
<TextListItem>
<strong>{t('Camel Version')}: </strong>
{camelPod.runtime.camelVersion}
</TextListItem>
<TextListItem>
<strong>{t('Runtime Provider')}: </strong>
{camelPod.runtime.runtimeProvider}
</TextListItem>
<TextListItem>
<strong>{t('Runtime Version')}: </strong>
{camelPod.runtime.runtimeVersion}
</TextListItem>
</TextList>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{t('Exchange')}:</DescriptionListTerm>
<DescriptionListDescription>
<TextList>
<TextListItem>
<strong>{t('succeed')}: </strong>{' '}
{camelPod.runtime.exchange.succeed ? camelPod.runtime.exchange.succeed : 0}
</TextListItem>
<TextListItem>
<strong>{t('pending')}: </strong>{' '}
{camelPod.runtime.exchange.pending ? camelPod.runtime.exchange.pending : 0}
</TextListItem>
<TextListItem>
<strong>{t('failed')}: </strong>{' '}
{camelPod.runtime.exchange.failed ? camelPod.runtime.exchange.failed : 0}
</TextListItem>
<TextListItem>
<strong>{t('total')}: </strong>{' '}
{camelPod.runtime.exchange.total ? camelPod.runtime.exchange.total : 0}
</TextListItem>
</TextList>
</DescriptionListDescription>
</DescriptionListGroup>

<DescriptionListGroup>
<DescriptionListTerm>{t('Endpoints')}:</DescriptionListTerm>
<DescriptionListDescription>
<TextList>
<TextListItem>
<strong>{t('Health')}: </strong>
{camelPod.observe.healthEndpoint}:{camelPod.observe.healthPort}
</TextListItem>
<TextListItem>
<strong>{t('Metrics')}: </strong>
{camelPod.observe.metricsEndpoint}:{camelPod.observe.metricsPort}
</TextListItem>
</TextList>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
</CardBody>
</Card>
</>
);
};

export default CamelAppStatusPod;
13 changes: 4 additions & 9 deletions src/components/camel-app-page/CamelApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,20 @@ import { useCamelAppTabs } from './useCamelAppTabs';
import CamelAppTitle from './CamelAppTitle';

const CamelApp: React.FC = () => {
const {
ns: namespace,
name,
kind,
} = useParams<{
const { ns: namespace, name } = useParams<{
ns?: string;
name?: string;
kind?: string;
}>();

const { CamelApp, isLoading, error } = useCamelApp(name, namespace, kind);
const { CamelApp, isLoading, error } = useCamelApp(name, namespace);

const pages = useCamelAppTabs(CamelApp);

// TODO A common loading spinner component
if (isLoading) {
return (
<>
<CamelAppTitle name={name} namespace={namespace} />
<CamelAppTitle name={name} namespace={namespace} obj={CamelApp} />
<Spinner />
</>
);
Expand All @@ -39,7 +34,7 @@ const CamelApp: React.FC = () => {
return (
<>
<NamespaceBar isDisabled />
<CamelAppTitle name={name} namespace={namespace} />
<CamelAppTitle name={name} namespace={namespace} obj={CamelApp} />
<HorizontalNav pages={pages} />
</>
);
Expand Down
Loading