Skip to content

Commit

Permalink
fix: update central dashboard to NodeJS 16 (#7578)
Browse files Browse the repository at this point in the history
* update central-dashboard to NodeJS 16

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* update `@kubernetes/client-node` to `0.19.0`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* update `express` to `4.19.2`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* update `@grpc/grpc-js` to `1.10.8`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* update `@types/serve-static` to `1.15.5`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* update `typescript` to `4.9.5`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* fix TS2538 error in metrics query interval

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* update `webpack` to `4.47.0`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* fix tests (update kustomize + others)

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* remove unnecessary `npm rebuild`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* use `tini` as entrypoint

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* remove `script-ext-html-webpack-plugin`

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

* fix namespace selector for iframes in local dev

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>

---------

Signed-off-by: Mathew Wicks <5735406+thesuperzapper@users.noreply.github.com>
  • Loading branch information
thesuperzapper authored May 20, 2024
1 parent 7092541 commit 1b5d92d
Show file tree
Hide file tree
Showing 14 changed files with 25,206 additions and 6,607 deletions.
2 changes: 2 additions & 0 deletions components/centraldashboard/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist/
node_modules/
27 changes: 11 additions & 16 deletions components/centraldashboard/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,36 +1,31 @@
# Step 1: Builds and tests
FROM node:14.21.3-bullseye AS build
FROM node:16.20.2-bullseye AS build

ARG kubeflowversion
ARG commit

ENV BUILD_VERSION=$kubeflowversion
ENV BUILD_COMMIT=$commit
ENV CHROME_BIN=/usr/bin/chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

RUN apt update -qq && apt install -qq -y gnulib

COPY . /centraldashboard
WORKDIR /centraldashboard

RUN BUILDARCH="$(dpkg --print-architecture)" && npm rebuild && \
if [ "$BUILDARCH" = "arm64" ] || \
[ "$BUILDARCH" = "armhf" ]; then \
export CFLAGS=-Wno-error && \
export CXXFLAGS=-Wno-error; \
fi && \
npm install && \
npm run build && \
npm prune --production
RUN npm ci \
&& npm run build \
&& npm prune --production

# Step 2: Packages assets for serving
FROM node:14.21.3-alpine3.17 AS serve
FROM node:16.20.2-alpine AS serve

RUN apk add --no-cache tini

USER node

ENV NODE_ENV=production
WORKDIR /app
COPY --from=build /centraldashboard .
WORKDIR /usr/src/app
COPY --from=build --chown=node:node /centraldashboard .

EXPOSE 8082
ENTRYPOINT ["npm", "start"]
ENTRYPOINT ["/sbin/tini", "--" , "npm", "start"]
44 changes: 26 additions & 18 deletions components/centraldashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,32 @@ kubectl --record deployment.apps/centraldashboard \
## Development

### Getting Started
Make sure you have the latest LTS version of `node` installed along with `npm`.

1. Clone the repository and change directories to `components/centraldashboard`
2. Run `make build-local`. This will install all of the project dependencies and
prepare your system for development.
3. To start a development environment, run `npm run dev`.
- This runs [webpack](https://webpack.js.org/) over the front-end code in
the [public](./public) folder and starts the
[webpack-dev-server](https://webpack.js.org/configuration/dev-server/) at
http://localhost:8081.
- It also starts the Express API server at http://localhost:8082. Requests
from the front-end starting with `/api` are proxied to the Express
server. All other requests are handled by the front-end server which
mirrors the production configuration.
4. - To access the Jupyter Web App run: `kubectl port-forward -n kubeflow svc/jupyter-web-app-service 8085:80`.
- To access Pipeline Web App run: `kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8087:80`.`

This forwards requests to Kubernetes services from `http://localhost:service-proxy-port`. See the [webpack config file](https://github.com/kubeflow/kubeflow/blob/master/components/centraldashboard/webpack.config.js) for more details.

Make sure you have installed node 16!

1. We STRONGLY recommend using [nvm](https://github.com/nvm-sh/nvm):
- Uninstall any Homebrew versions with `brew uninstall node` (or `node@XX`)
- Install `nvm` with `curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash`
- Install node `16` with `nvm install 16`
- Use node `16` with `nvm use 16`
- Set node `16` as the default with `nvm alias default 16`
2. Run `cd components/centraldashboard`
3. Run `npm install` to install npm dependencies
4. Run `npm run dev` to start the development server, this will:
- Run [webpack](https://webpack.js.org/) over the front-end code in the [public](./public) folder
- Run [webpack-dev-server](https://webpack.js.org/configuration/dev-server/) at http://localhost:8081
- Run the Express API server at http://localhost:8082
- Proxy requests from the front-end starting with `/api` to the Express server.
- All other requests are handled by the front-end server which mirrors the production configuration.
5. Run port-forwards:
- Kubeflow Access Management API: `kubectl port-forward -n kubeflow svc/profiles-kfam 8081:8081`
- Kubeflow Notebooks: `kubectl port-forward -n kubeflow svc/jupyter-web-app-service 8085:80`
- Kubeflow Pipelines: `kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8087:80`
- See [`webpack.config.js`](https://github.com/kubeflow/kubeflow/blob/master/components/centraldashboard/webpack.config.js) for more details.
6. Open your browser to `http://localhost:8080` to see the dashboard:
- You will need to inject your requrests with a `kubeflow-userid` header
- You can do this in Chrome by using the [Header Editor](https://chromewebstore.google.com/detail/eningockdidmgiojffjmkdblpjocbhgh) extension
- For example, set the `kubeflow-userid` header to `user@example.com`

### Server Components

Expand Down
6 changes: 4 additions & 2 deletions components/centraldashboard/app/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ export class Api {
}

let interval = Interval.Last15m;
if (Interval[req.query.interval] !== undefined) {
interval = Number(Interval[req.query.interval]);
const intervalQuery = req.query.interval as string;
const intervalQueryKey = intervalQuery as keyof typeof Interval;
if (Interval[intervalQueryKey] !== undefined) {
interval = Interval[intervalQueryKey];
}
switch (req.params.type) {
case 'node':
Expand Down
10 changes: 5 additions & 5 deletions components/centraldashboard/app/k8s_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const APP_API_NAME = 'applications';
/** Wrap Kubernetes API calls in a simpler interface for use in routes. */
export class KubernetesService {
private namespace = process.env.POD_NAMESPACE || 'kubeflow';
private coreAPI: k8s.Core_v1Api;
private customObjectsAPI: k8s.Custom_objectsApi;
private coreAPI: k8s.CoreV1Api;
private customObjectsAPI: k8s.CustomObjectsApi;
private dashboardConfigMap = DASHBOARD_CONFIGMAP;

constructor(private kubeConfig: k8s.KubeConfig) {
Expand All @@ -63,9 +63,9 @@ export class KubernetesService {
if (context && context.namespace) {
this.namespace = context.namespace;
}
this.coreAPI = this.kubeConfig.makeApiClient(k8s.Core_v1Api);
this.coreAPI = this.kubeConfig.makeApiClient(k8s.CoreV1Api);
this.customObjectsAPI =
this.kubeConfig.makeApiClient(k8s.Custom_objectsApi);
this.kubeConfig.makeApiClient(k8s.CustomObjectsApi);
}

/** Retrieves the list of namespaces from the Cluster. */
Expand All @@ -91,7 +91,7 @@ export class KubernetesService {
}

/** Retrieves the list of events for the given Namespace from the Cluster. */
async getEventsForNamespace(namespace: string): Promise<k8s.V1Event[]> {
async getEventsForNamespace(namespace: string): Promise<k8s.CoreV1Event[]> {
try {
const {body} = await this.coreAPI.listNamespacedEvent(namespace);
return body.items;
Expand Down
14 changes: 7 additions & 7 deletions components/centraldashboard/app/k8s_service_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {KubernetesService} from './k8s_service';
describe('KubernetesService', () => {
let mockResponse: jasmine.SpyObj<IncomingMessage>;
let mockKubeConfig: jasmine.SpyObj<k8s.KubeConfig>;
let mockApiClient: jasmine.SpyObj<k8s.Core_v1Api>;
let mockCustomApiClient: jasmine.SpyObj<k8s.Custom_objectsApi>;
let mockApiClient: jasmine.SpyObj<k8s.CoreV1Api>;
let mockCustomApiClient: jasmine.SpyObj<k8s.CustomObjectsApi>;
let k8sService: KubernetesService;

beforeEach(() => {
Expand All @@ -17,13 +17,13 @@ describe('KubernetesService', () => {
'loadFromDefault', 'getContextObject', 'getCurrentContext',
'makeApiClient'
]);
mockApiClient = jasmine.createSpyObj<k8s.Core_v1Api>(
mockApiClient = jasmine.createSpyObj<k8s.CoreV1Api>(
'mockApiClient', ['listNamespace', 'listNamespacedEvent', 'listNode']);
mockCustomApiClient = jasmine.createSpyObj<k8s.Custom_objectsApi>(
mockCustomApiClient = jasmine.createSpyObj<k8s.CustomObjectsApi>(
'mockCustomApiClient', ['listNamespacedCustomObject']);
mockKubeConfig.makeApiClient.withArgs(k8s.Core_v1Api)
mockKubeConfig.makeApiClient.withArgs(k8s.CoreV1Api)
.and.returnValue(mockApiClient);
mockKubeConfig.makeApiClient.withArgs(k8s.Custom_objectsApi)
mockKubeConfig.makeApiClient.withArgs(k8s.CustomObjectsApi)
.and.returnValue(mockCustomApiClient);

k8sService = new KubernetesService(mockKubeConfig);
Expand Down Expand Up @@ -165,7 +165,7 @@ describe('KubernetesService', () => {
]
} as unknown; // needed to work around TS compiler
mockApiClient.listNamespacedEvent.and.returnValue(Promise.resolve(
{response: mockResponse, body: response as k8s.V1EventList}));
{response: mockResponse, body: response as k8s.CoreV1EventList}));

const events = await k8sService.getEventsForNamespace('kubeflow');
const eventNames = events.map((n) => n.metadata.name);
Expand Down
10 changes: 5 additions & 5 deletions components/centraldashboard/app/metrics_service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/** Time-series interval enumeration. */
export enum Interval {
Last5m,
Last15m,
Last30m,
Last60m,
Last180m
Last5m = 'Last5m',
Last15m = 'Last15m',
Last30m = 'Last30m',
Last60m = 'Last60m',
Last180m = 'Last180m',
}

/** Data-point contained in a time series. */
Expand Down
Loading

0 comments on commit 1b5d92d

Please sign in to comment.