Skip to content

Commit

Permalink
Merge pull request #2045 from Gkrumbach07/edit-page
Browse files Browse the repository at this point in the history
Added accelerator edit page
  • Loading branch information
openshift-merge-bot[bot] authored Nov 14, 2023
2 parents 0b7492e + 5ead9a9 commit 3fcf749
Show file tree
Hide file tree
Showing 32 changed files with 1,517 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { KubeFastifyInstance, AcceleratorKind } from '../../../types';
import { FastifyRequest } from 'fastify';
import createError from 'http-errors';
import { translateDisplayNameForK8s } from '../../../utils/resourceUtils';

export const postAcceleratorProfile = async (
fastify: KubeFastifyInstance,
request: FastifyRequest,
): Promise<{ success: boolean; error: string }> => {
const customObjectsApi = fastify.kube.customObjectsApi;
const namespace = fastify.kube.namespace;
const body = request.body as AcceleratorKind['spec'];

const payload: AcceleratorKind = {
apiVersion: 'dashboard.opendatahub.io/v1',
kind: 'AcceleratorProfile',
metadata: {
name: translateDisplayNameForK8s(body.displayName),
namespace: namespace,
annotations: {
'opendatahub.io/modified-date': new Date().toISOString(),
},
},
spec: body,
};

try {
await customObjectsApi
.createNamespacedCustomObject(
'dashboard.opendatahub.io',
'v1',
namespace,
'acceleratorprofiles',
payload,
)
.catch((e) => {
throw createError(e.statusCode, e?.body?.message);
});
return { success: true, error: null };
} catch (e) {
if (e.response?.statusCode !== 404) {
fastify.log.error(e, 'Unable to add accelerator profile.');
return { success: false, error: 'Unable to add accelerator profile: ' + e.message };
}
throw e;
}
};

export const deleteAcceleratorProfile = async (
fastify: KubeFastifyInstance,
request: FastifyRequest,
): Promise<{ success: boolean; error: string }> => {
const customObjectsApi = fastify.kube.customObjectsApi;
const namespace = fastify.kube.namespace;
const params = request.params as { acceleratorProfileName: string };

try {
await customObjectsApi
.deleteNamespacedCustomObject(
'dashboard.opendatahub.io',
'v1',
namespace,
'acceleratorprofiles',
params.acceleratorProfileName,
)
.catch((e) => {
throw createError(e.statusCode, e?.body?.message);
});
return { success: true, error: null };
} catch (e) {
if (e.response?.statusCode === 404) {
fastify.log.error(e, 'Unable to delete accelerator profile.');
return { success: false, error: 'Unable to delete accelerator profile: ' + e.message };
}
throw e;
}
};

export const updateAcceleratorProfile = async (
fastify: KubeFastifyInstance,
request: FastifyRequest,
): Promise<{ success: boolean; error: string }> => {
const customObjectsApi = fastify.kube.customObjectsApi;
const namespace = fastify.kube.namespace;
const params = request.params as { acceleratorProfileName: string };
const body = request.body as Partial<AcceleratorKind['spec']>;

try {
const currentProfile = await customObjectsApi
.getNamespacedCustomObject(
'dashboard.opendatahub.io',
'v1',
namespace,
'acceleratorprofiles',
params.acceleratorProfileName,
)
.then((r) => r.body as AcceleratorKind)
.catch((e) => {
throw createError(e.statusCode, e?.body?.message);
});

if (body.displayName !== undefined) {
currentProfile.spec.displayName = body.displayName;
}
if (body.enabled !== undefined) {
currentProfile.spec.enabled = body.enabled;
}
if (body.identifier !== undefined) {
currentProfile.spec.identifier = body.identifier;
}
if (body.description !== undefined) {
currentProfile.spec.description = body.description;
}
if (body.tolerations !== undefined) {
currentProfile.spec.tolerations = body.tolerations;
}

// Update the modified date annotation
if (!currentProfile.metadata.annotations) {
currentProfile.metadata.annotations = {};
}
currentProfile.metadata.annotations['opendatahub.io/modified-date'] = new Date().toISOString();

await customObjectsApi
.patchNamespacedCustomObject(
'dashboard.opendatahub.io',
'v1',
namespace,
'acceleratorprofiles',
params.acceleratorProfileName,
currentProfile,
undefined,
undefined,
undefined,
{
headers: { 'Content-Type': 'application/merge-patch+json' },
},
)
.catch((e) => {
throw createError(e.statusCode, e?.body?.message);
});
return { success: true, error: null };
} catch (e) {
if (e.response?.statusCode !== 404) {
fastify.log.error(e, 'Unable to update accelerator profile.');
return { success: false, error: 'Unable to update accelerator profile: ' + e.message };
}
throw e;
}
};
48 changes: 48 additions & 0 deletions backend/src/routes/api/accelerator-profiles/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { secureAdminRoute } from '../../../utils/route-security';
import {
deleteAcceleratorProfile,
postAcceleratorProfile,
updateAcceleratorProfile,
} from './acceleratorProfilesUtils';

export default async (fastify: FastifyInstance): Promise<void> => {
fastify.delete(
'/:acceleratorProfileName',
secureAdminRoute(fastify)(async (request: FastifyRequest, reply: FastifyReply) => {
return deleteAcceleratorProfile(fastify, request)
.then((res) => {
return res;
})
.catch((res) => {
reply.send(res);
});
}),
);

fastify.put(
'/:acceleratorProfileName',
secureAdminRoute(fastify)(async (request: FastifyRequest, reply: FastifyReply) => {
return updateAcceleratorProfile(fastify, request)
.then((res) => {
return res;
})
.catch((res) => {
reply.send(res);
});
}),
);

fastify.post(
'/',
secureAdminRoute(fastify)(async (request: FastifyRequest, reply: FastifyReply) => {
return postAcceleratorProfile(fastify, request)
.then((res) => {
return res;
})
.catch((res) => {
reply.send(res);
});
}),
);
};
8 changes: 1 addition & 7 deletions backend/src/routes/api/images/imageUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IMAGE_ANNOTATIONS } from '../../../utils/constants';
import { convertLabelsToString } from '../../../utils/componentUtils';
import { translateDisplayNameForK8s } from '../../../utils/resourceUtils';
import {
ImageStreamTag,
ImageTagInfo,
Expand All @@ -13,13 +14,6 @@ import {
import { FastifyRequest } from 'fastify';
import createError from 'http-errors';

const translateDisplayNameForK8s = (name: string): string =>
name
.trim()
.toLowerCase()
.replace(/\s/g, '-')
.replace(/[^A-Za-z0-9-]/g, '');

/**
* This function uses a regex to match the image location string
* The match result will return an array of 4 elements:
Expand Down
7 changes: 7 additions & 0 deletions backend/src/utils/resourceUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -952,3 +952,10 @@ export const migrateTemplateDisablement = async (

export const getServingRuntimeNameFromTemplate = (template: Template): string =>
template.objects[0].metadata.name;

export const translateDisplayNameForK8s = (name: string): string =>
name
.trim()
.toLowerCase()
.replace(/\s/g, '-')
.replace(/[^A-Za-z0-9-]/g, '');
50 changes: 31 additions & 19 deletions frontend/src/__mocks__/mockAcceleratorProfile.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
import _ from 'lodash';
import { AcceleratorKind } from '~/k8sTypes';
import { RecursivePartial } from '~/typeHelpers';
import { TolerationEffect, TolerationOperator } from '~/types';

export const mockAcceleratorProfile = (): AcceleratorKind => ({
apiVersion: 'dashboard.opendatahub.io/v1',
kind: 'AcceleratorProfile',
metadata: {
name: 'test-accelerator',
},
spec: {
displayName: 'test-accelerator',
enabled: true,
identifier: 'nvidia.com/gpu',
description: 'Test description',
tolerations: [
{
key: 'nvidia.com/gpu',
operator: 'Exists',
effect: 'NoSchedule',
export const mockAcceleratorProfile = (
data: RecursivePartial<AcceleratorKind> = {},
): AcceleratorKind =>
_.merge(
{
apiVersion: 'dashboard.opendatahub.io/v1',
kind: 'AcceleratorProfile',
metadata: {
name: 'test-accelerator',
annotations: {
'opendatahub.io/modified-date': '2023-10-31T21:16:11.721Z',
},
},
],
},
});
spec: {
displayName: 'Test Accelerator',
enabled: true,
identifier: 'nvidia.com/gpu',
description: 'Test description',
tolerations: [
{
key: 'nvidia.com/gpu',
operator: TolerationOperator.EXISTS,
effect: TolerationEffect.NO_SCHEDULE,
},
],
},
} as AcceleratorKind,
data,
);
32 changes: 4 additions & 28 deletions frontend/src/__mocks__/mockNotebookK8sResource.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { KnownLabels, NotebookKind } from '~/k8sTypes';
import { DEFAULT_NOTEBOOK_SIZES } from '~/pages/projects/screens/spawner/const';
import { ContainerResources } from '~/types';
import { ContainerResources, TolerationEffect, TolerationOperator } from '~/types';
import { genUID } from '~/__mocks__/mockUtils';

type MockResourceConfigType = {
Expand Down Expand Up @@ -135,23 +135,6 @@ export const mockNotebookK8sResource = ({
workingDir: '/opt/app-root/src',
},
{
args: [
'--provider=openshift',
'--https-address=:8443',
'--http-address=',
'--openshift-service-account=workbench',
'--cookie-secret-file=/etc/oauth/config/cookie_secret',
'--cookie-expire=24h0m0s',
'--tls-cert=/etc/tls/private/tls.crt',
'--tls-key=/etc/tls/private/tls.key',
'--upstream=http://localhost:8888',
'--upstream-ca=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt',
'--skip-auth-regex=^(?:/notebook/$(NAMESPACE)/workbench)?/api$',
'--email-domain=*',
'--skip-provider-button',
'--openshift-sar={"verb":"get","resource":"notebooks","resourceAPIGroup":"kubeflow.org","resourceName":"workbench","namespace":"$(NAMESPACE)"}',
'--logout-url=http://localhost:4010/projects/project?notebookLogout=workbench',
],
env: [
{
name: 'NAMESPACE',
Expand Down Expand Up @@ -220,12 +203,11 @@ export const mockNotebookK8sResource = ({
},
],
enableServiceLinks: false,
serviceAccountName: name,
tolerations: [
{
effect: 'NoSchedule',
effect: TolerationEffect.NO_SCHEDULE,
key: 'NotebooksOnlyChange',
operator: 'Exists',
operator: TolerationOperator.EXISTS,
},
],
volumes: [
Expand All @@ -238,14 +220,12 @@ export const mockNotebookK8sResource = ({
{
name: 'oauth-config',
secret: {
defaultMode: 420,
secretName: 'workbench-oauth-config',
},
},
{
name: 'tls-certificates',
secret: {
defaultMode: 420,
secretName: 'workbench-tls',
},
},
Expand Down Expand Up @@ -284,11 +264,7 @@ export const mockNotebookK8sResource = ({
type: 'Waiting',
},
],
containerState: {
running: {
startedAt: '2023-02-14T22:06:52Z',
},
},
containerState: {},
readyReplicas: 1,
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { mockK8sResourceList } from '~/__mocks__/mockK8sResourceList';
import useDetectUser from '~/utilities/useDetectUser';
import { mockStatus } from '~/__mocks__/mockStatus';

import AcceleratorProfiles from '~/pages/acceleratorProfiles/AcceleratorProfiles';
import AcceleratorProfiles from '~/pages/acceleratorProfiles/screens/list/AcceleratorProfiles';

export default {
component: AcceleratorProfiles,
Expand Down
Loading

0 comments on commit 3fcf749

Please sign in to comment.