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

Added accelerator column and field #2077

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions backend/src/routes/api/images/imageUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ const mapImageStreamToBYONImage = (is: ImageStream): BYONImage => ({
imported_time: is.metadata.creationTimestamp,
url: is.metadata.annotations['opendatahub.io/notebook-image-url'],
provider: is.metadata.annotations['opendatahub.io/notebook-image-creator'],
recommendedAcceleratorIdentifiers: jsonParseRecommendedAcceleratorIdentifiers(
is.metadata.annotations['opendatahub.io/recommended-accelerators'],
),
});

export const postImage = async (
Expand Down Expand Up @@ -276,6 +279,9 @@ export const postImage = async (
'opendatahub.io/notebook-image-name': body.display_name,
'opendatahub.io/notebook-image-url': fullURL,
'opendatahub.io/notebook-image-creator': body.provider,
'opendatahub.io/recommended-accelerators': JSON.stringify(
body.recommendedAcceleratorIdentifiers ?? [],
),
},
name: `custom-${translateDisplayNameForK8s(body.display_name)}`,
namespace: namespace,
Expand Down Expand Up @@ -413,6 +419,12 @@ export const updateImage = async (
imageStream.metadata.annotations['opendatahub.io/notebook-image-desc'] = body.description;
}

if (body.recommendedAcceleratorIdentifiers !== undefined) {
imageStream.metadata.annotations['opendatahub.io/recommended-accelerators'] = JSON.stringify(
body.recommendedAcceleratorIdentifiers,
);
}

await customObjectsApi
.patchNamespacedCustomObject(
'image.openshift.io',
Expand Down Expand Up @@ -446,3 +458,11 @@ const jsonParsePackage = (unparsedPackage: string): BYONImagePackage[] => {
return [];
}
};

const jsonParseRecommendedAcceleratorIdentifiers = (unparsedRecommendations: string): string[] => {
try {
return JSON.parse(unparsedRecommendations) || [];
} catch {
return [];
}
};
1 change: 1 addition & 0 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ export type BYONImage = {
visible: boolean;
software: BYONImagePackage[];
packages: BYONImagePackage[];
recommendedAcceleratorIdentifiers: string[];
};

export type ImageTag = {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/__mocks__/mockByon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const mockByon = (opts?: RecursivePartial<BYONImage[]>): BYONImage[] =>
name: 'byon-123',
display_name: 'Testing Custom Image',
description: 'A custom notebook image',
recommendedAcceleratorIdentifiers: [],
visible: true,
packages: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,30 @@ test('Invalid id in edit page', async ({ page }) => {
page.getByText('acceleratorprofiles.dashboard.opendatahub.io "test-accelerator" not found'),
).toHaveCount(1);
});

test('One preset identifier is auto filled and disabled', async ({ page }) => {
await page.goto(
navigateToStory(
'pages-acceleratorprofiles-manageacceleratorprofile',
'create-accelerator-with-one-set-identifier',
),
);

expect(await page.getByTestId('accelerator-identifier-input').inputValue()).toBe(
'test-identifier',
);

await expect(page.getByTestId('accelerator-identifier-input')).toBeDisabled();
});

test('Multiple preset identifiers show dropdown', async ({ page }) => {
await page.goto(
navigateToStory(
'pages-acceleratorprofiles-manageacceleratorprofile',
'create-accelerator-with-multiple-set-identifiers',
),
);

await page.getByRole('button', { name: 'Options menu' }).click();
await expect(page.getByRole('option', { name: 'test-identifier-3' })).toHaveCount(1);
});
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,54 @@ export const TolerationsModal: StoryObj = {
await userEvent.click(canvas.getByText('Add toleration', { selector: 'button' }));
},
};

export const CreateAcceleratorWithOneSetIdentifier: StoryObj = {
render: () => (
<RenderComponent>
<ManageAcceleratorProfileComponent />
</RenderComponent>
),
play: async ({ canvasElement }) => {
// load page and wait until settled
const canvas = within(canvasElement);
await canvas.findByText('Identifier', undefined, {
timeout: 5000,
});
},
parameters: {
reactRouter: {
routePath: '/create',
searchParams: {
identifiers: ['test-identifier'],
},
},
},
};

export const CreateAcceleratorWithMultipleSetIdentifiers: StoryObj = {
render: () => (
<RenderComponent>
<ManageAcceleratorProfileComponent />
</RenderComponent>
),
play: async ({ canvasElement }) => {
// load page and wait until settled
const canvas = within(canvasElement);
await canvas.findByText('Identifier', undefined, {
timeout: 5000,
});
},
parameters: {
reactRouter: {
routePath: '/create',
searchParams: {
identifiers: [
'test-identifier-1',
'test-identifier-2',
'test-identifier-3',
'test-identifier-3',
],
},
},
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ test('Table filtering, sorting, searching', async ({ page }) => {
await page.getByRole('button', { name: 'Provider' }).click();
expect(page.getByText('image-0'));

// by accelerator
await page.getByRole('button', { name: 'Recommended accelerators' }).click();
expect(page.getByText('test-accelerator')).toHaveCount(0);
await page.getByRole('button', { name: 'Recommended accelerators' }).click();
expect(page.getByText('test-accelerator'));

// by enabled
await page.getByRole('button', { name: 'Enable', exact: true }).click();
expect(page.getByText('image-14'));
Expand Down Expand Up @@ -114,6 +120,30 @@ test('Import form fields', async ({ page }) => {
await page.getByLabel('Name *').fill('image');
await expect(page.getByRole('button', { name: 'Import' })).toBeEnabled();

// test accelerator select field
// select accelerator from api call
await page.getByPlaceholder('Example, nvidia.com/gpu').click();
await page.getByRole('option', { name: 'nvidia.com/gpu' }).click();

// create new and select
await page.getByPlaceholder('Example, nvidia.com/gpu').click();
await page.getByPlaceholder('Example, nvidia.com/gpu').fill('test.com/gpu');
await page.getByRole('option', { name: 'Create "test.com/gpu"' }).click();
await page.getByRole('button', { name: 'Options menu' }).click();
expect(page.getByText('test.com/gpu'));

// remove custom
await page.getByRole('button', { name: 'Remove test.com/gpu' }).click();
await page.getByRole('button', { name: 'Options menu' }).click();
await expect(page.getByText('test.com/gpu')).toHaveCount(0);

// reselect custom
await page
.getByRole('dialog', { name: 'Import notebook image' })
.getByRole('button', { name: 'Options menu' })
.click();
await page.getByRole('option', { name: 'test.com/gpu' }).click();

// test form is disabled after entering software add form
await page.getByTestId('add-software-button').click();
await expect(page.getByRole('button', { name: 'Import' })).toBeDisabled();
Expand Down Expand Up @@ -204,7 +234,7 @@ test('Edit form fields match', async ({ page }) => {
expect(await page.getByLabel('Image Location *').inputValue()).toBe('test-image:latest');
expect(await page.getByLabel('Name *').inputValue()).toBe('Testing Custom Image');
expect(await page.getByLabel('Description').inputValue()).toBe('A custom notebook image');

expect(page.getByText('nvidia.com/gpu'));
// test software and packages have correct values
expect(page.getByRole('gridcell', { name: 'test-software' }));
expect(page.getByRole('gridcell', { name: '2.0' }));
Expand Down
Loading
Loading