Skip to content

Commit

Permalink
fix: block nim re-deploy in existing projects
Browse files Browse the repository at this point in the history
Signed-off-by: Olga Lavtar <[email protected]>
  • Loading branch information
olavtar committed Dec 19, 2024
1 parent ee45a4c commit 55a9d5d
Show file tree
Hide file tree
Showing 20 changed files with 256 additions and 163 deletions.
28 changes: 0 additions & 28 deletions frontend/src/__mocks__/mockNimResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,31 +143,3 @@ export const mockNimModelPVC = (): PersistentVolumeClaimKind => {
export const mockNimServingResource = (
resource: ConfigMapKind | SecretKind,
): NimServingResponse => ({ body: { body: resource } });

export const mockOdhApplication = [
{
metadata: {
name: 'nvidia-nim',
annotations: {
'internal.config.kubernetes.io/previousKinds': 'OdhApplication',
},
},
spec: {
displayName: 'NVIDIA NIM',
provider: 'NVIDIA',
description: 'NVIDIA Inference Microservices for AI model serving.',
route: 'https://nim-route.test.com',
routeNamespace: 'redhat-ods-applications',
img: 'https://example.com/nvidia-nim.png',
docsLink: 'https://docs.nvidia.com/nim',
getStartedLink: 'https://nvidia.com/get-started-nim',
getStartedMarkDown: '**NVIDIA NIM** provides fast and efficient model serving.',
category: 'Self-managed',
shownOnEnabledPage: true,
isEnabled: true,
internalRoute: 'https://internal-nim-route.test.com',
quickStart: 'nim-quickstart-guide',
beta: false,
},
},
];
114 changes: 114 additions & 0 deletions frontend/src/__mocks__/mockOdhApplication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { OdhApplication, OdhApplicationCategory } from '~/types';

type MockOdhApplicationConfig = {
name?: string;
displayName?: string;
provider?: string;
description?: string;
route?: string | null;
routeNamespace?: string | null;
routeSuffix?: string | null;
serviceName?: string | null;
endpoint?: string | null;
link?: string | null;
img?: string;
docsLink?: string;
hidden?: boolean | null;
getStartedLink?: string;
getStartedMarkDown?: string;
category?: OdhApplicationCategory | string;
support?: string;
quickStart?: string | null;
comingSoon?: boolean | null;
beta?: boolean | null;
betaTitle?: string | null;
betaText?: string | null;
shownOnEnabledPage?: boolean | null;
isEnabled?: boolean | null;
kfdefApplications?: string[];
csvName?: string;
annotations?: { [key: string]: string };
enable?: {
title: string;
actionLabel: string;
description?: string;
linkPreface?: string;
link?: string;
variables?: { [key: string]: string };
variableDisplayText?: { [key: string]: string };
variableHelpText?: { [key: string]: string };
validationSecret: string;
validationJob: string;
validationConfigMap?: string;
};
featureFlag?: string;
internalRoute?: string;
};

export const mockOdhApplication = ({
name = 'nvidia-nim',
displayName = 'Test Application',
provider = 'Test Provider',
description = 'Test Description',
route = null,
routeNamespace = null,
routeSuffix = null,
serviceName = null,
endpoint = null,
link = null,
img = 'test-image.png',
docsLink = 'https://test-docs.com',
hidden = null,
getStartedLink = 'https://test-getting-started.com',
getStartedMarkDown = '# Getting Started',
category = 'category-1',
support = 'test-support',
quickStart = null,
comingSoon = null,
beta = null,
betaTitle = null,
betaText = null,
shownOnEnabledPage = null,
isEnabled = null,
kfdefApplications = [],
csvName = undefined,
annotations = {},
enable = undefined,
featureFlag = undefined,
internalRoute = '/api/integrations/nim',
}: MockOdhApplicationConfig = {}): OdhApplication => ({
metadata: {
name,
annotations,
},
spec: {
displayName,
provider,
description,
route,
routeNamespace,
routeSuffix,
serviceName,
endpoint,
link,
img,
docsLink,
hidden,
getStartedLink,
getStartedMarkDown,
category,
support,
quickStart,
comingSoon,
beta,
betaTitle,
betaText,
shownOnEnabledPage,
isEnabled,
kfdefApplications,
csvName,
enable,
featureFlag,
internalRoute,
},
});
10 changes: 10 additions & 0 deletions frontend/src/__tests__/cypress/cypress/support/commands/odh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
ClusterSettingsType,
DetectedAccelerators,
ImageInfo,
IntegrationAppStatus,
OdhApplication,
OdhDocument,
PrometheusQueryRangeResponse,
Expand Down Expand Up @@ -686,6 +687,15 @@ declare global {
};
},
response: OdhResponse<NimServingResponse>,
) => Cypress.Chainable<null>) &
((
type: 'GET /api/integrations/:internalRoute',
options: {
path: {
internalRoute: string;
};
},
response: OdhResponse<IntegrationAppStatus>,
) => Cypress.Chainable<null>);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ describe('NIM Model Serving', () => {
disableModelMesh: false,
disableNIMModelServing: false,
},
// true,
true,
);
projectDetailsOverviewTab.visit('test-project');
cy.findByTestId('model-serving-platform-button').should('not.exist');
Expand All @@ -277,7 +277,7 @@ describe('NIM Model Serving', () => {
disableModelMesh: false,
disableNIMModelServing: false,
},
// true,
true,
);
projectDetailsOverviewTab.visit('test-project');
projectDetailsOverviewTab.findModelServingPlatform('nvidia-nim').should('not.exist');
Expand All @@ -291,7 +291,7 @@ describe('NIM Model Serving', () => {
disableModelMesh: false,
disableNIMModelServing: false,
},
// true,
true,
);
projectDetails.visitSection('test-project', 'model-server');
cy.get('button[data-testid=deploy-button]').should('not.exist');
Expand All @@ -304,7 +304,7 @@ describe('NIM Model Serving', () => {
disableModelMesh: false,
disableNIMModelServing: false,
},
// true,
true,
);
projectDetails.visitSection('test-project', 'model-server');
projectDetails.findModelServingPlatform('nvidia-nim-model').should('not.exist');
Expand Down
46 changes: 35 additions & 11 deletions frontend/src/__tests__/cypress/cypress/utils/nimUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
PVCModel,
SecretModel,
ServingRuntimeModel,
TemplateModel,
} from '~/__tests__/cypress/cypress/utils/models';
import {
mockNimImages,
Expand All @@ -24,13 +25,14 @@ import {
mockNimProject,
mockNimServingResource,
mockNimServingRuntime,
mockNimServingRuntimeTemplate,
mockNvidiaNimAccessSecret,
mockNvidiaNimImagePullSecret,
mockOdhApplication,
} from '~/__mocks__/mockNimResource';
import { mockAcceleratorProfile } from '~/__mocks__/mockAcceleratorProfile';
import type { InferenceServiceKind } from '~/k8sTypes';
import { mockNimAccount } from '~/__mocks__/mockNimAccount';
import { mockOdhApplication } from '~/__mocks__/mockOdhApplication';

/* ###################################################
###### Interception Initialization Utilities ######
Expand Down Expand Up @@ -61,15 +63,25 @@ export const initInterceptsToEnableNim = ({ hasAllModels = false }: EnableNimCon
}),
);

cy.interceptOdh('GET /api/components', mockOdhApplication);
cy.interceptOdh('GET /api/components', null, [mockOdhApplication({})]);

cy.interceptK8sList(NIMAccountModel, mockK8sResourceList([mockNimAccount({})]));
cy.interceptOdh(
'GET /api/integrations/:internalRoute',
{ path: { internalRoute: 'nim' } },
{
isInstalled: true,
isEnabled: true,
canInstall: false,
error: '',
},
);

cy.interceptK8sList(NIMAccountModel, mockK8sResourceList([mockNimAccount({})]));
cy.interceptK8sList(ProjectModel, mockK8sResourceList([mockNimProject(hasAllModels)]));

// const templateMock = mockNimServingRuntimeTemplate();
// cy.interceptK8sList(TemplateModel, mockK8sResourceList([templateMock]));
// cy.interceptK8s(TemplateModel, templateMock);
const templateMock = mockNimServingRuntimeTemplate();
cy.interceptK8sList(TemplateModel, mockK8sResourceList([templateMock]));
cy.interceptK8s(TemplateModel, templateMock);

cy.interceptK8sList(
AcceleratorProfileModel,
Expand Down Expand Up @@ -150,13 +162,25 @@ export const initInterceptorsValidatingNimEnablement = (
): void => {
cy.interceptOdh('GET /api/config', mockDashboardConfig(dashboardConfig));

cy.interceptOdh('GET /api/components', null, [mockOdhApplication({})]);

cy.interceptOdh(
'GET /api/integrations/:internalRoute',
{ path: { internalRoute: 'nim' } },
{
isInstalled: true,
isEnabled: true,
canInstall: false,
error: '',
},
);
cy.interceptK8sList(NIMAccountModel, mockK8sResourceList([mockNimAccount({})]));

// if (!disableServingRuntime) {
// const templateMock = mockNimServingRuntimeTemplate();
// cy.interceptK8sList(TemplateModel, mockK8sResourceList([templateMock]));
// cy.interceptK8s(TemplateModel, templateMock);
// }
if (!disableServingRuntime) {
const templateMock = mockNimServingRuntimeTemplate();
cy.interceptK8sList(TemplateModel, mockK8sResourceList([templateMock]));
cy.interceptK8s(TemplateModel, templateMock);
}

cy.interceptK8sList(
ProjectModel,
Expand Down
17 changes: 10 additions & 7 deletions frontend/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import ProjectsContextProvider from '~/concepts/projects/ProjectsContext';
import { ModelRegistrySelectorContextProvider } from '~/concepts/modelRegistry/context/ModelRegistrySelectorContext';
import useStorageClasses from '~/concepts/k8s/useStorageClasses';
import AreaContextProvider from '~/concepts/areas/AreaContext';
import { NimContextProvider } from '~/concepts/nimServing/NIMAvailabilityContext';
import useDevFeatureFlags from './useDevFeatureFlags';
import Header from './Header';
import AppRoutes from './AppRoutes';
Expand Down Expand Up @@ -130,13 +131,15 @@ const App: React.FC = () => {
}
>
<ErrorBoundary>
<ProjectsContextProvider>
<ModelRegistrySelectorContextProvider>
<QuickStarts>
<AppRoutes />
</QuickStarts>
</ModelRegistrySelectorContextProvider>
</ProjectsContextProvider>
<NimContextProvider>
<ProjectsContextProvider>
<ModelRegistrySelectorContextProvider>
<QuickStarts>
<AppRoutes />
</QuickStarts>
</ModelRegistrySelectorContextProvider>
</ProjectsContextProvider>
</NimContextProvider>
<ToastNotifications />
<TelemetrySetup />
</ErrorBoundary>
Expand Down
37 changes: 37 additions & 0 deletions frontend/src/concepts/nimServing/NIMAvailabilityContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as React from 'react';
import { useIsNIMAvailable } from '~/pages/modelServing/screens/projects/useIsNIMAvailable';

export type NIMAvailabilityContextType = {
isNIMAvailable: boolean;
loaded: boolean;
};

type NIMAvailabilityContextProviderProps = {
children: React.ReactNode;
};

export const NIMAvailabilityContext = React.createContext<NIMAvailabilityContextType>({
isNIMAvailable: false,
loaded: false,
});

export const NimContextProvider: React.FC<NIMAvailabilityContextProviderProps> = ({
children,
...props
}) => {
return <EnabledNimContextProvider {...props}>{children}</EnabledNimContextProvider>;

return children;
};

const EnabledNimContextProvider: React.FC<NIMAvailabilityContextProviderProps> = ({ children }) => {
const [isNIMAvailable, loaded] = useIsNIMAvailable();

const contextValue = React.useMemo(() => ({ isNIMAvailable, loaded }), [isNIMAvailable, loaded]);

return (
<NIMAvailabilityContext.Provider value={contextValue}>
{children}
</NIMAvailabilityContext.Provider>
);
};
32 changes: 16 additions & 16 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ import { ReduxContext } from './redux/context';
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const root = createRoot(document.getElementById('root')!);
root.render(
// <React.StrictMode>
<ErrorBoundary>
<Provider store={sdkStore}>
<Provider store={store} context={ReduxContext}>
<Router>
<SDKInitialize>
<BrowserStorageContextProvider>
<ThemeProvider>
<App />
</ThemeProvider>
</BrowserStorageContextProvider>
</SDKInitialize>
</Router>
<React.StrictMode>
<ErrorBoundary>
<Provider store={sdkStore}>
<Provider store={store} context={ReduxContext}>
<Router>
<SDKInitialize>
<BrowserStorageContextProvider>
<ThemeProvider>
<App />
</ThemeProvider>
</BrowserStorageContextProvider>
</SDKInitialize>
</Router>
</Provider>
</Provider>
</Provider>
</ErrorBoundary>,
// </React.StrictMode>,
</ErrorBoundary>
</React.StrictMode>,
);
Loading

0 comments on commit 55a9d5d

Please sign in to comment.