Skip to content

Commit

Permalink
Refactor hardware profile and pod spec options across frontend compon…
Browse files Browse the repository at this point in the history
…ents

This commit introduces significant changes to how hardware profiles and pod specification options are managed across the frontend:

- Replaced nodeSelectors array with a single nodeSelector object in hardware profile types
- Updated related components to work with the new nodeSelector structure
- Removed deprecated accelerator profile and notebook size handling
- Introduced new pod spec options state management for notebooks and model serving
- Updated validation and form handling to support new hardware profile concepts
- Modified CRD to reflect the new nodeSelector structure
  • Loading branch information
Gkrumbach07 committed Feb 5, 2025
1 parent 8024849 commit 6b08118
Show file tree
Hide file tree
Showing 61 changed files with 2,275 additions and 1,232 deletions.
53 changes: 38 additions & 15 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,9 @@ export type ModelServerResources = {
};
};

export type NotebookResources = {
requests?: {
cpu?: string;
memory?: string;
} & Record<string, unknown>;
limits?: {
cpu?: string;
memory?: string;
} & Record<string, unknown>;
};

export type NotebookSize = {
name: string;
resources: NotebookResources;
resources: ContainerResources;
notUserDefined?: boolean;
};

Expand Down Expand Up @@ -429,7 +418,7 @@ export type NotebookContainer = {
envFrom?: EnvFrom[];
env: EnvironmentVariable[];
ports?: NotebookPort[];
resources?: NotebookResources;
resources?: ContainerResources;
livenessProbe?: Record<string, unknown>;
readinessProbe?: Record<string, unknown>;
volumeMounts?: VolumeMount[];
Expand Down Expand Up @@ -470,6 +459,7 @@ export type Notebook = K8sResourceCommon & {
containers: NotebookContainer[];
volumes?: Volume[];
tolerations?: Toleration[];
nodeSelector?: NodeSelector;
};
};
};
Expand Down Expand Up @@ -839,11 +829,20 @@ export enum NotebookState {
Stopped = 'stopped',
}

export type PodSpecOptions = {
resources: ContainerResources;
tolerations: Toleration[];
nodeSelector: NodeSelector;
affinity: PodAffinity;
lastSizeSelection?: string;
selectedAcceleratorProfile?: AcceleratorProfileKind;
selectedHardwareProfile?: HardwareProfileKind;
};

export type NotebookData = {
notebookSizeName: string;
imageName: string;
imageTagName: string;
acceleratorProfile?: AcceleratorProfileState;
podSpecOptions: PodSpecOptions;
envVars: EnvVarReducedTypeKeyValues;
state: NotebookState;
username?: string;
Expand Down Expand Up @@ -979,6 +978,30 @@ export type Toleration = {
tolerationSeconds?: number;
};

export type NodeSelector = Record<string, string>;

export type HardwareProfileKind = K8sResourceCommon & {
metadata: {
name: string;
namespace: string;
};
spec: {
displayName: string;
enabled: boolean;
description?: string;
tolerations?: Toleration[];
identifiers?: {
displayName: string;
identifier: string;
minCount: number | string;
maxCount: number | string;
defaultCount: number | string;
resourceType?: string;
}[];
nodeSelector?: NodeSelector;
};
};

export type AcceleratorProfileKind = K8sResourceCommon & {
metadata: {
name: string;
Expand Down
102 changes: 27 additions & 75 deletions backend/src/utils/notebookUtils.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { getDashboardConfig } from './resourceUtils';
import { mergeWith } from 'lodash';
import {
ContainerResourceAttributes,
ContainerResources,
EnvironmentVariable,
ImageInfo,
ImageTag,
KubeFastifyInstance,
Notebook,
NotebookAffinity,
NotebookData,
NotebookList,
NotebookResources,
NotebookSize,
NotebookTolerationSettings,
RecursivePartial,
Route,
Toleration,
TolerationEffect,
TolerationOperator,
VolumeMount,
} from '../types';
import { getUserInfo, usernameTranslate } from './userUtils';
Expand All @@ -28,7 +21,7 @@ import {
V1Role,
V1RoleBinding,
} from '@kubernetes/client-node';
import { DEFAULT_NOTEBOOK_SIZES, DEFAULT_PVC_SIZE, MOUNT_PATH } from './constants';
import { DEFAULT_PVC_SIZE, MOUNT_PATH } from './constants';
import { FastifyRequest } from 'fastify';
import { verifyEnvVars } from './envUtils';
import { smartMergeArraysWithNameObjects } from './objUtils';
Expand Down Expand Up @@ -124,18 +117,6 @@ export const createRBAC = async (
await fastify.kube.rbac.createNamespacedRoleBinding(namespace, notebookRoleBinding);
};

const getNotebookSize = (notebookSizeName: string): NotebookSize => {
const sizes = getDashboardConfig().spec?.notebookSizes || DEFAULT_NOTEBOOK_SIZES;

const size = sizes.find((size) => size.name === notebookSizeName);

if (!size) {
throw Error(`Error getting notebook size for ${notebookSizeName}`);
}

return size;
};

const getImageTag = (image: ImageInfo, imageTagName: string): ImageTag => {
const tag = image.tags.find((tag) => tag.name === imageTagName);

Expand All @@ -158,11 +139,8 @@ export const assembleNotebook = async (
namespace: string,
pvcName: string,
envName: string,
tolerationSettings: NotebookTolerationSettings,
): Promise<Notebook> => {
const { notebookSizeName, imageName, imageTagName, envVars } = data;

const notebookSize = getNotebookSize(notebookSizeName);
const { imageName, imageTagName, envVars, podSpecOptions } = data;

let imageUrl = ``;
let imageSelection = ``;
Expand Down Expand Up @@ -192,49 +170,16 @@ export const assembleNotebook = async (
{ mountPath: '/dev/shm', name: 'shm' },
];

const resources: NotebookResources = { ...notebookSize.resources };
const tolerations: Toleration[] = [];

const affinity: NotebookAffinity = {};
if (data.acceleratorProfile?.count > 0) {
if (!resources.limits) {
resources.limits = {};
}
if (!resources.requests) {
resources.requests = {};
}
resources.limits[data.acceleratorProfile.acceleratorProfile.spec.identifier] =
data.acceleratorProfile.count;
resources.requests[data.acceleratorProfile.acceleratorProfile.spec.identifier] =
data.acceleratorProfile.count;
} else {
// step type down to string to avoid type errors
const containerResourceKeys: string[] = Object.values(ContainerResourceAttributes);

Object.keys(resources.limits || {}).forEach((key) => {
if (!containerResourceKeys.includes(key)) {
delete resources.limits?.[key];
}
});
const {
resources,
tolerations,
affinity,
nodeSelector,
selectedAcceleratorProfile,
selectedHardwareProfile,
lastSizeSelection,
} = podSpecOptions;

Object.keys(resources.requests || {}).forEach((key) => {
if (!containerResourceKeys.includes(key)) {
delete resources.requests?.[key];
}
});
}

if (data.acceleratorProfile?.acceleratorProfile?.spec.tolerations) {
tolerations.push(...data.acceleratorProfile.acceleratorProfile.spec.tolerations);
}

if (tolerationSettings?.enabled) {
tolerations.push({
effect: TolerationEffect.NO_SCHEDULE,
key: tolerationSettings.key,
operator: TolerationOperator.EXISTS,
});
}
const translatedUsername = usernameTranslate(username);

const configMapEnvs = Object.keys(envVars.configMap).map<EnvironmentVariable>((key) => ({
Expand Down Expand Up @@ -269,12 +214,12 @@ export const assembleNotebook = async (
},
annotations: {
'notebooks.opendatahub.io/oauth-logout-url': `${url}/notebookController/${translatedUsername}/home`,
'notebooks.opendatahub.io/last-size-selection': notebookSize.name,
'notebooks.opendatahub.io/last-size-selection': lastSizeSelection,
'notebooks.opendatahub.io/last-image-selection': imageSelection,
'opendatahub.io/username': username,
'kubeflow-resource-stopped': null,
'opendatahub.io/accelerator-name':
data.acceleratorProfile?.acceleratorProfile.metadata.name || '',
'opendatahub.io/accelerator-name': selectedAcceleratorProfile?.metadata.name || '',
'opendatahub.io/hardware-profile-name': selectedHardwareProfile?.metadata.name || '',
},
name: name,
namespace: namespace,
Expand Down Expand Up @@ -307,7 +252,16 @@ export const assembleNotebook = async (
...configMapEnvs,
...secretEnvs,
],
resources,
resources: {
requests: {
cpu: resources.requests?.cpu,
memory: resources.requests?.memory,
},
limits: {
cpu: resources.limits?.cpu,
memory: resources.limits?.memory,
},
},
volumeMounts,
ports: [
{
Expand Down Expand Up @@ -344,6 +298,7 @@ export const assembleNotebook = async (
],
volumes,
tolerations,
nodeSelector,
},
},
},
Expand Down Expand Up @@ -583,7 +538,7 @@ export const updateNotebook = async (
}
};

export const verifyResources = (resources: NotebookResources): NotebookResources => {
export const verifyResources = (resources: ContainerResources): ContainerResources => {
if (resources.requests && !resources.limits) {
resources.limits = resources.requests;
}
Expand All @@ -603,8 +558,6 @@ const generateNotebookResources = async (
const pvcName = generatePvcNameFromUsername(username);
const envName = generateEnvVarFileNameFromUsername(username);
const namespace = getNamespaces(fastify).notebookNamespace;
const tolerationSettings =
getDashboardConfig().spec.notebookController?.notebookTolerationSettings;

// generate pvc
try {
Expand All @@ -628,7 +581,6 @@ const generateNotebookResources = async (
namespace,
pvcName,
envName,
tolerationSettings,
);
};

Expand Down
14 changes: 6 additions & 8 deletions frontend/src/__mocks__/mockHardwareProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type MockResourceConfigType = {
identifiers?: Identifier[];
description?: string;
enabled?: boolean;
nodeSelectors?: NodeSelector[];
nodeSelector?: NodeSelector;
tolerations?: Toleration[];
annotations?: Record<string, string>;
};
Expand Down Expand Up @@ -51,12 +51,10 @@ export const mockHardwareProfile = ({
effect: TolerationEffect.NO_SCHEDULE,
},
],
nodeSelectors = [
{
key: 'test',
value: 'va;ue',
},
],
nodeSelector = {
key: 'test',
value: 'va;ue',
},
annotations,
}: MockResourceConfigType): HardwareProfileKind => ({
apiVersion: 'dashboard.opendatahub.io/v1alpha1',
Expand All @@ -75,7 +73,7 @@ export const mockHardwareProfile = ({
displayName,
enabled,
tolerations,
nodeSelectors,
nodeSelector,
description,
},
});
14 changes: 0 additions & 14 deletions frontend/src/__mocks__/mockInferenceServiceModalData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,6 @@ export const mockInferenceServiceModalData = ({
externalRoute = false,
tokenAuth = false,
tokens = [],
modelSize = {
name: 'Small',
resources: {
requests: {
cpu: '1',
memory: '1Gi',
},
limits: {
cpu: '2',
memory: '2Gi',
},
},
},
isKServeRawDeployment,
}: MockResourceConfigType): CreatingInferenceServiceObject => ({
name,
Expand All @@ -51,6 +38,5 @@ export const mockInferenceServiceModalData = ({
externalRoute,
tokenAuth,
tokens,
modelSize,
isKServeRawDeployment,
});
42 changes: 42 additions & 0 deletions frontend/src/__mocks__/mockModelServingPodSpecOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ModelServingPodSpecOptions } from '~/concepts/hardwareProfiles/useModelServingPodSpecOptionsState';

type MockResourceConfigType = Partial<ModelServingPodSpecOptions>;

export const mockModelServingPodSpecOptions = ({
resources = {
requests: {
cpu: '1',
memory: '1Gi',
},
limits: {
cpu: '1',
memory: '1Gi',
},
},
tolerations = [],
nodeSelector = {},
affinity = {},
selectedAcceleratorProfile,
selectedHardwareProfile,
selectedModelSize = {
name: 'small',
resources: {
requests: {
cpu: '1',
memory: '1Gi',
},
limits: {
cpu: '1',
memory: '1Gi',
},
},
},
}: MockResourceConfigType): ModelServingPodSpecOptions => ({
resources,
tolerations,
nodeSelector,
affinity,
selectedAcceleratorProfile,
selectedHardwareProfile,
selectedModelSize,
});
Loading

0 comments on commit 6b08118

Please sign in to comment.