From d1fb83030e9cd7966ae2204d3a059ced195f9058 Mon Sep 17 00:00:00 2001 From: Jeff Puzzo Date: Wed, 28 Aug 2024 16:02:28 -0400 Subject: [PATCH] Update some storage class logic, naming --- frontend/src/app/AppRoutes.tsx | 5 +-- frontend/src/k8sTypes.ts | 8 ++-- .../storage/usePreferredStorageClass.ts | 10 +++-- .../storageClasses/StorageClassesPage.tsx | 38 +++++++++---------- frontend/src/pages/storageClasses/utils.ts | 14 +++++++ 5 files changed, 44 insertions(+), 31 deletions(-) create mode 100644 frontend/src/pages/storageClasses/utils.ts diff --git a/frontend/src/app/AppRoutes.tsx b/frontend/src/app/AppRoutes.tsx index e8854aa2c1..037431c5a3 100644 --- a/frontend/src/app/AppRoutes.tsx +++ b/frontend/src/app/AppRoutes.tsx @@ -73,7 +73,6 @@ const AppRoutes: React.FC = () => { const isJupyterEnabled = useCheckJupyterEnabled(); const isHomeAvailable = useIsAreaAvailable(SupportedArea.HOME).status; const isConnectionTypesAvailable = useIsAreaAvailable(SupportedArea.CONNECTION_TYPES).status; - const isStorageClassesAvailable = useIsAreaAvailable(SupportedArea.STORAGE_CLASSES).status; if (!isAllowed) { return ( @@ -131,9 +130,7 @@ const AppRoutes: React.FC = () => { {isConnectionTypesAvailable ? ( } /> ) : null} - {isStorageClassesAvailable && ( - } /> - )} + } /> } /> } /> diff --git a/frontend/src/k8sTypes.ts b/frontend/src/k8sTypes.ts index 73e7c8fc2d..ddc04353e1 100644 --- a/frontend/src/k8sTypes.ts +++ b/frontend/src/k8sTypes.ts @@ -55,7 +55,7 @@ export type StorageClassConfig = { description?: string; }; -export enum Annotation { +export enum MetadataAnnotation { StorageClassIsDefault = 'storageclass.kubernetes.io/is-default-class', K8sDescription = 'kubernetes.io/description', OdhStorageClassConfig = 'opendatahub.io/sc-config', @@ -64,10 +64,10 @@ export enum Annotation { type StorageClassAnnotations = Partial<{ // if true, enables any persistent volume claim (PVC) that does not specify a specific storage class to automatically be provisioned. // Only one, if any, StorageClass per cluster can be set as default. - [Annotation.StorageClassIsDefault]: 'true' | 'false'; + [MetadataAnnotation.StorageClassIsDefault]: 'true' | 'false'; // the description provided by the cluster admin or Container Storage Interface (CSI) provider - [Annotation.K8sDescription]: string; - [Annotation.OdhStorageClassConfig]: string; + [MetadataAnnotation.K8sDescription]: string; + [MetadataAnnotation.OdhStorageClassConfig]: string; }>; export type K8sDSGResource = K8sResourceCommon & { diff --git a/frontend/src/pages/projects/screens/spawner/storage/usePreferredStorageClass.ts b/frontend/src/pages/projects/screens/spawner/storage/usePreferredStorageClass.ts index 5e3f5d9330..e63aa2e4ff 100644 --- a/frontend/src/pages/projects/screens/spawner/storage/usePreferredStorageClass.ts +++ b/frontend/src/pages/projects/screens/spawner/storage/usePreferredStorageClass.ts @@ -1,6 +1,7 @@ import * as React from 'react'; import { AppContext } from '~/app/AppContext'; -import { Annotation, StorageClassKind } from '~/k8sTypes'; +import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas'; +import { MetadataAnnotation, StorageClassKind } from '~/k8sTypes'; const usePreferredStorageClass = (): StorageClassKind | undefined => { const { @@ -9,13 +10,16 @@ const usePreferredStorageClass = (): StorageClassKind | undefined => { }, storageClasses, } = React.useContext(AppContext); + const isStorageClassesAvailable = useIsAreaAvailable(SupportedArea.STORAGE_CLASSES).status; const defaultClusterStorageClasses = storageClasses.filter( (storageclass) => - storageclass.metadata.annotations?.[Annotation.StorageClassIsDefault] === 'true', + storageclass.metadata.annotations?.[MetadataAnnotation.StorageClassIsDefault] === 'true', ); - const configStorageClassName = notebookController?.storageClassName ?? ''; + const configStorageClassName = !isStorageClassesAvailable + ? notebookController?.storageClassName ?? '' + : ''; if (defaultClusterStorageClasses.length !== 0) { return undefined; diff --git a/frontend/src/pages/storageClasses/StorageClassesPage.tsx b/frontend/src/pages/storageClasses/StorageClassesPage.tsx index 515b766a1b..d0de060c89 100644 --- a/frontend/src/pages/storageClasses/StorageClassesPage.tsx +++ b/frontend/src/pages/storageClasses/StorageClassesPage.tsx @@ -10,11 +10,12 @@ import { AlertActionCloseButton, } from '@patternfly/react-core'; -import { Annotation, StorageClassConfig } from '~/k8sTypes'; +import { MetadataAnnotation, StorageClassConfig } from '~/k8sTypes'; import useStorageClasses from '~/concepts/k8s/useStorageClasses'; import { ProjectObjectType, typedEmptyImage } from '~/concepts/design/utils'; import ApplicationsPage from '~/pages/ApplicationsPage'; import { updateStorageClassConfig } from '~/services/StorageClassService'; +import { getStorageClassConfig, isOpenshiftDefaultStorageClass } from './utils'; const StorageClassesPage: React.FC = () => { const [storageClasses, storageClassesLoaded, storageClassesError] = useStorageClasses(); @@ -22,37 +23,34 @@ const StorageClassesPage: React.FC = () => { const defaultStorageClass = storageClasses.find( (storageClass) => - storageClass.metadata.annotations?.[Annotation.StorageClassIsDefault] === 'true', + isOpenshiftDefaultStorageClass(storageClass) || + getStorageClassConfig(storageClass)?.isDefault, ); - // Open default class alert when no default class exists - React.useEffect(() => { - setIsAlertOpen(!defaultStorageClass?.metadata.name); - }, [defaultStorageClass?.metadata.name]); - // Add storage class config annotations automatically for all storage classes without them React.useEffect(() => { - storageClasses.forEach((storageClass, index) => { + storageClasses.forEach(async (storageClass, index) => { const { metadata } = storageClass; const { name: storageClassName } = metadata; - if (!metadata.annotations?.[Annotation.OdhStorageClassConfig]) { - const isDefault = defaultStorageClass?.metadata.uid === metadata.uid; + if (!metadata.annotations?.[MetadataAnnotation.OdhStorageClassConfig]) { + let isDefault = defaultStorageClass?.metadata.uid === metadata.uid; + let isEnabled = false; + + if (!defaultStorageClass) { + isDefault = index === 0; + isEnabled = true; + } + const storageClassConfig: StorageClassConfig = { + isDefault, + isEnabled, displayName: storageClassName, - ...(!defaultStorageClass - ? { - isEnabled: true, - isDefault: index === 0, - } - : { - isDefault, - isEnabled: isDefault, - }), lastModified: new Date().toISOString(), }; - updateStorageClassConfig(storageClassName, storageClassConfig); + await updateStorageClassConfig(storageClassName, storageClassConfig); + setIsAlertOpen(!defaultStorageClass?.metadata.name); } }); }, [defaultStorageClass, storageClasses]); diff --git a/frontend/src/pages/storageClasses/utils.ts b/frontend/src/pages/storageClasses/utils.ts new file mode 100644 index 0000000000..cf12dbd5bd --- /dev/null +++ b/frontend/src/pages/storageClasses/utils.ts @@ -0,0 +1,14 @@ +import { MetadataAnnotation, StorageClassConfig, StorageClassKind } from '~/k8sTypes'; + +export const getStorageClassConfig = ( + storageClass: StorageClassKind, +): StorageClassConfig | undefined => { + const storageClassConfig: StorageClassConfig | undefined = JSON.parse( + storageClass.metadata.annotations?.[MetadataAnnotation.OdhStorageClassConfig] || '', + ); + + return storageClassConfig; +}; + +export const isOpenshiftDefaultStorageClass = (storageClass: StorageClassKind): boolean => + storageClass.metadata.annotations?.[MetadataAnnotation.StorageClassIsDefault] === 'true';