Skip to content
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

feat(selector): select Cryostat instances by labelled Services #5

Merged
merged 14 commits into from
Jan 9, 2025
Merged
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
!.stylelintrc.yaml
!.prettierrc.yml
!.eslintrc.yml
!i18next-parser.config.js

!src/**
src/**/node_modules
!backend/**
!locales/**
!i18n-scripts/**

!ct.yaml
!console-extensions.json
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
**/node_modules
.yarn/
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
**/dist
**/.DS_Store
.devcontainer/dev.env
Expand Down
874 changes: 874 additions & 0 deletions .yarn/releases/yarn-3.6.3.cjs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
nodeLinker: node-modules

yarnPath: .yarn/releases/yarn-3.6.3.cjs
14 changes: 10 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ ARG APP_DIR=/opt/app-root/src
FROM registry.access.redhat.com/ubi9/nodejs-20:latest AS frontend_build
USER root
WORKDIR /usr/src/app
ADD . /usr/src/app
RUN (command -v yarn || npm i -g yarn) && \
yarn install --immutable && \
yarn build
ADD console-extensions.json .eslintrc.yml i18next-parser.config.js package.json yarn.lock .prettierrc.yml tsconfig.json webpack.config.ts /usr/src/app
ADD locales /usr/src/app/locales
ADD i18n-scripts /usr/src/app/i18n-scripts
ADD src/openshift /usr/src/app/src/openshift
ADD src/cryostat-web /usr/src/app/src/cryostat-web
RUN (command -v corepack || npm install --global corepack) && \
corepack enable
RUN npm install && yarn install
RUN cd src/cryostat-web && yarn install && yarn yarn:frzinstall
RUN yarn build-dev # FIXME this should be 'yarn build', not 'build-dev'

FROM registry.access.redhat.com/ubi9/nodejs-20:latest AS backend_build
USER root
Expand Down
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
## Initialize the project:
```bash
$ git submodule init
$ git submodule update --remote
$ pushd src/cryostat-web
$ yarn install
$ yarn yarn:frzinstall
$ popd
$ yarn install
$ pushd backend
$ npm ci
$ popd
```

## Deploying the plugin:
```bash
$ export PLUGIN_NAME=cryostat-plugin
$ ./build.bash
$ podman manifest push quay.io/andrewazores/openshift-console-plugin-test:latest
$ helm upgrade -i $PLUGIN_NAME charts/openshift-console-plugin -n plugin--${PLUGIN_NAME,,} --create-namespace
$ helm uninstall $PLUGIN_NAME
$ export IMAGE_TAG=quay.io/$myusername/cryostat-openshift-console-plugin:latest # replace $myusername with your quay.io username, or else set this to a different repository
$ MANIFEST=$IMAGE_TAG ./build.bash
$ podman manifest push $IMAGE_TAG
$ helm upgrade --set plugin.image=$IMAGE_TAG -i $PLUGIN_NAME charts/openshift-console-plugin -n plugin--${PLUGIN_NAME,,} --create-namespace
$ helm uninstall $PLUGIN_NAME -n plugin--${PLUGIN_NAME,,}
```

## Development using local backend (Cryostat or Prism):
Expand All @@ -24,10 +39,10 @@ yarn run mock-server
OR

(in a Cryostat repo)
bash smoketest.sh -t
CRYOSTAT_HTTP_PORT=8181 bash smoketest.bash -tkp
```

Cryostat is accessble at http://localhost:8181, and for simplicity Prism has been configured to use the same port.
Cryostat is accessible at http://localhost:8181, and for simplicity Prism has been configured to use the same port.

### Terminal 3: Run a local OpenShift Console with plugin-proxy
```
Expand Down
59 changes: 45 additions & 14 deletions backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const morgan = require('morgan');
const qs = require('qs');
const app = express();
const port = process.env.PORT || 9943;
const crVersion = process.env.CRYOSTAT_CR_VERSION || 'v1beta2';
const skipTlsVerify = process.env.SKIP_TLS_VERIFY == 'true';
const htmlDir = process.env.HTML_DIR || './html';

Expand All @@ -24,7 +23,7 @@ kc.applyToRequest({
strictSSL: !skipTlsVerify,
});

const k8sApi = kc.makeApiClient(k8s.CustomObjectsApi);
const k8sApi = kc.makeApiClient(k8s.CoreV1Api);

app.use(morgan('combined'));

Expand All @@ -37,26 +36,57 @@ app.get('/health', (req, res) => {
});

app.use('/upstream/*', async (req, res) => {
let ns = req.headers['cryostat-cr-ns'];
let name = req.headers['cryostat-cr-name'];
let ns = req.headers['cryostat-svc-ns'];
let name = req.headers['cryostat-svc-name'];
if (!ns || !name) {
res.status(400).send();
return;
}

const cr = await k8sApi.getNamespacedCustomObjectStatus('operator.cryostat.io', crVersion, ns, 'cryostats', name);
let host = cr.body.status.applicationUrl;
const svc = await k8sApi.readNamespacedService(name, ns);
const svcLabels = svc?.body?.metadata?.labels ?? {};
if (!(svcLabels['app.kubernetes.io/part-of'] === 'cryostat' && svcLabels['app.kubernetes.io/component'] === 'cryostat')) {
throw new Error(`Selected Service "${name}" in namspace "${ns}" does not have the expected Cryostat selector labels`);
}

let host = `${name}.${ns}`;

const method = req.method;
let tls = host.startsWith('https://');
const proto = (tls ? https : http);
if (tls) {
host = host.slice('https://'.length);
} else if (host.startsWith('http://')) {
host = host.slice('http://'.length);
} else {
throw new Error(`Cannot handle scheme for URL: ${host}`)

let tls;
let svcPort;
// select ports by appProtocol, preferring https over http
for (const port of svc?.body?.spec?.ports ?? []) {
if (port.appProtocol === 'https') {
tls = true;
svcPort = port.port;
break;
} else if (port.appProtocol === 'http') {
tls = false;
svcPort = port.port;
}
}
if (!svcPort) {
// if we haven't selected a port by appProtocol, then try to select by name
for (const port of svc?.body?.spec?.ports ?? []) {
if (!port.name) {
continue;
}
if (port.name.endsWith('https')) {
tls = true;
svcPort = port.port;
break;
} else if (port.name.endsWith('http')) {
tls = false;
svcPort = port.port;
}
}
}
if (!svcPort) {
throw new Error(`Could not find suitable port with http(s) appProtocol or with name ending in http(s) on <${name}, ${ns}>`);
}

const proto = (tls ? https : http);

let path = (req.baseUrl + req.path).slice('/upstream'.length);
if (path.endsWith('/')) {
Expand All @@ -70,6 +100,7 @@ app.use('/upstream/*', async (req, res) => {
host,
method,
path,
port: svcPort,
headers: {
'Authorization': req.headers.authorization,
'Referer': req.headers.referer,
Expand Down
2 changes: 1 addition & 1 deletion build.bash
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -xe

DIR="$(dirname "$(readlink -f "$0")")"
MANIFEST="${MANIFEST:-quay.io/andrewazores/openshift-console-plugin-test:latest}"
MANIFEST="${MANIFEST:-quay.io/cryostat/cryostat-openshift-console-plugin:latest}"

if podman manifest exists "${MANIFEST}"; then
podman manifest rm "${MANIFEST}"
Expand Down
2 changes: 1 addition & 1 deletion charts/openshift-console-plugin/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
plugin:
name: cryostat-plugin
description: ""
image: quay.io/andrewazores/openshift-console-plugin-test:latest
image: quay.io/cryostat/cryostat-openshift-console-plugin:latest
imagePullPolicy: Always
replicas: 1
port: 9443
Expand Down
27 changes: 14 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,29 @@
"@openshift-console/dynamic-plugin-sdk-webpack": "1.1.1",
"@patternfly/quickstarts": "^5.4.0",
"@patternfly/react-catalog-view-extension": "^5.0.0",
"@patternfly/react-charts": "^7.4.3",
"@patternfly/react-core": "^5.4.1",
"@patternfly/react-charts": "^7.4.5",
"@patternfly/react-core": "^5.4.2",
"@patternfly/react-icons": "^5.4.0",
"@patternfly/react-styles": "^5.4.0",
"@patternfly/react-table": "^5.4.0",
"@patternfly/react-styles": "^5.4.1",
"@patternfly/react-table": "^5.4.8",
"@patternfly/react-topology": "^5.4.0",
"@reduxjs/toolkit": "^1.9.3",
"@stoplight/prism-cli": "^5.10.0",
"@types/node": "^18.0.0",
"@types/react": "^17.0.37",
"@types/react": "^17.0.69",
"@types/react-helmet": "^6.1.4",
"@types/react-router-dom": "^5.3.2",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
"@typescript-eslint/eslint-plugin": "^8.12.2",
"@typescript-eslint/parser": "^8.12.2",
"copy-webpack-plugin": "^6.4.1",
"css-loader": "^6.7.1",
"cypress": "^12.17.4",
"cypress-multi-reporters": "^1.6.2",
"eslint": "^8.10.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-cypress": "^2.12.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.29.1",
"eslint-plugin-react": "^7.37.2",
"humanize-duration": "^3.32.1",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-parser": "^3.11.0",
Expand All @@ -62,8 +62,8 @@
"pluralize": "^8.0.0",
"prettier": "^2.7.1",
"prettier-stylelint": "^0.4.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-i18next": "^11.7.3",
"react-joyride": "^2.9.2",
Expand All @@ -75,7 +75,7 @@
"ts-loader": "^9.3.1",
"ts-node": "^10.8.1",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"typescript": "^4.7.4",
"typescript": "^5.6.3",
"webpack": "5.75.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
Expand Down Expand Up @@ -113,5 +113,6 @@
},
"config": {
"api_schema_path": "https://raw.githubusercontent.com/cryostatio/cryostat/refs/heads/main/schema/openapi.yaml"
}
},
"packageManager": "[email protected]"
}
2 changes: 1 addition & 1 deletion src/cryostat-web
2 changes: 1 addition & 1 deletion src/openshift/pages/AboutPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { About } from '@app/About/About';
import React from 'react';
import '@app/app.css';
import { CryostatContainer } from '../components/CryostatContainer';
import { CryostatContainer } from '@console-plugin/components/CryostatContainer';

export default function AboutPage() {
return (
Expand Down
2 changes: 1 addition & 1 deletion src/openshift/pages/ArchivesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Archives from '@app/Archives/Archives';
import React from 'react';
import '@app/app.css';
import { CryostatContainer } from '../components/CryostatContainer';
import { CryostatContainer } from '@console-plugin/components/CryostatContainer';

export default function ArchivesPage() {
return (
Expand Down
2 changes: 1 addition & 1 deletion src/openshift/pages/AutomatedRulesPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import '@app/app.css';
import { CryostatContainer } from '../components/CryostatContainer';
import { CryostatContainer } from '@console-plugin/components/CryostatContainer';
import Rules from '@app/Rules/Rules';

export default function AutomatedRulesPage() {
Expand Down
2 changes: 1 addition & 1 deletion src/openshift/pages/DashboardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Dashboard from '@app/Dashboard/Dashboard';
import React from 'react';
import '@app/app.css';
import { CryostatContainer } from '../components/CryostatContainer';
import { CryostatContainer } from '@console-plugin/components/CryostatContainer';

export default function DashboardPage() {
// The Kiali plugin here runs a number of functions
Expand Down
2 changes: 1 addition & 1 deletion src/openshift/pages/EventsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Events from '@app/Events/Events';
import React from 'react';
import '@app/app.css';
import { CryostatContainer } from '../components/CryostatContainer';
import { CryostatContainer } from '@console-plugin/components/CryostatContainer';

export default function EventsPage() {
return (
Expand Down
Loading