Skip to content

Commit

Permalink
feat(15898): create MR secure db feature flag, skeleton for form elem…
Browse files Browse the repository at this point in the history
…ents (opendatahub-io#3555)

* feat(ca cert) 15898 - add disableMRSecureDB feature flag

Signed-off-by: gitdallas <[email protected]>

* add checkbox/radios for adding ca cert

Signed-off-by: gitdallas <[email protected]>

* add existing cert search fields

Signed-off-by: gitdallas <[email protected]>

* add file upload for new ca cert

Signed-off-by: gitdallas <[email protected]>

* securedb cert upload field, form validation

Signed-off-by: gitdallas <[email protected]>

* cleanup

Signed-off-by: gitdallas <[email protected]>

* renaming feature flag, fix style typo

Signed-off-by: gitdallas <[email protected]>

* remove feature flag from odhdashboardconfig

Signed-off-by: gitdallas <[email protected]>

* address pr nits

Signed-off-by: gitdallas <[email protected]>

* factor out secureDB form components

Signed-off-by: gitdallas <[email protected]>

---------

Signed-off-by: gitdallas <[email protected]>
  • Loading branch information
gitdallas authored Dec 11, 2024
1 parent 9124c70 commit 9f2b3d1
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 4 deletions.
1 change: 1 addition & 0 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type DashboardConfig = K8sResourceCommon & {
disableHardwareProfiles: boolean;
disableDistributedWorkloads: boolean;
disableModelRegistry: boolean;
disableModelRegistrySecureDB: boolean;
disableServingRuntimeParams: boolean;
disableConnectionTypes: boolean;
disableStorageClasses: boolean;
Expand Down
1 change: 1 addition & 0 deletions backend/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const blankDashboardCR: DashboardConfig = {
disableHardwareProfiles: true,
disableDistributedWorkloads: false,
disableModelRegistry: false,
disableModelRegistrySecureDB: true,
disableServingRuntimeParams: false,
disableConnectionTypes: false,
disableStorageClasses: false,
Expand Down
1 change: 1 addition & 0 deletions docs/dashboard-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ The following are a list of features that are supported, along with there defaul
| disablePerformanceMetrics | false | Disables Endpoint Performance tab from Model Serving metrics. |
| disableDistributedWorkloads | false | Disables Distributed Workload Metrics from the dashboard. |
| disableModelRegistry | false | Disables Model Registry from the dashboard. |
| disableModelRegistrySecureDB | true | Disables Model Registry Secure DB from the dashboard. |
| disableServingRuntimeParams | false | Disables Serving Runtime params from the dashboard. |
| disableStorageClasses | false | Disables storage classes settings nav item from the dashboard. |
| disableNIMModelServing | true | Disables components of NIM Model UI from the dashboard. |
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/__mocks__/mockDashboardConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export type MockDashboardConfigType = {
disableTrustyBiasMetrics?: boolean;
disableDistributedWorkloads?: boolean;
disableModelRegistry?: boolean;
disableModelRegistrySecureDB?: boolean;
disableServingRuntimeParams?: boolean;
disableConnectionTypes?: boolean;
disableStorageClasses?: boolean;
Expand Down Expand Up @@ -59,6 +60,7 @@ export const mockDashboardConfig = ({
disableTrustyBiasMetrics = false,
disableDistributedWorkloads = false,
disableModelRegistry = false,
disableModelRegistrySecureDB = true,
disableServingRuntimeParams = false,
disableConnectionTypes = true,
disableStorageClasses = false,
Expand Down Expand Up @@ -169,6 +171,7 @@ export const mockDashboardConfig = ({
disableHardwareProfiles,
disableDistributedWorkloads,
disableModelRegistry,
disableModelRegistrySecureDB,
disableServingRuntimeParams,
disableConnectionTypes,
disableStorageClasses,
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/concepts/areas/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const allFeatureFlags: string[] = Object.keys({
disableHardwareProfiles: false,
disableDistributedWorkloads: false,
disableModelRegistry: false,
disableModelRegistrySecureDB: true,
disableServingRuntimeParams: false,
disableConnectionTypes: false,
disableStorageClasses: false,
Expand Down Expand Up @@ -129,6 +130,10 @@ export const SupportedAreasStateMap: SupportedAreasState = {
featureFlags: ['disableServingRuntimeParams'],
reliantAreas: [SupportedArea.K_SERVE, SupportedArea.MODEL_SERVING],
},
[SupportedArea.MODEL_REGISTRY_SECURE_DB]: {
featureFlags: ['disableModelRegistrySecureDB'],
reliantAreas: [SupportedArea.MODEL_REGISTRY],
},
[SupportedArea.NIM_MODEL]: {
featureFlags: ['disableNIMModelServing'],
reliantAreas: [SupportedArea.K_SERVE],
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/concepts/areas/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,14 @@ export enum SupportedArea {
PERFORMANCE_METRICS = 'performance-metrics',
TRUSTY_AI = 'trusty-ai',
NIM_MODEL = 'nim-model',
SERVING_RUNTIME_PARAMS = 'serving-runtime-params',

/* Distributed Workloads areas */
DISTRIBUTED_WORKLOADS = 'distributed-workloads',

/* Model Registry areas */
MODEL_REGISTRY = 'model-registry',

/* Alter parameters areas */
SERVING_RUNTIME_PARAMS = 'serving-runtime-params',
MODEL_REGISTRY_SECURE_DB = 'model-registry-secure-db',
}

/** Components deployed by the Operator. Part of the DSC Status. */
Expand Down
1 change: 1 addition & 0 deletions frontend/src/k8sTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,7 @@ export type DashboardCommonConfig = {
disableHardwareProfiles: boolean;
disableDistributedWorkloads: boolean;
disableModelRegistry: boolean;
disableModelRegistrySecureDB: boolean;
disableServingRuntimeParams: boolean;
disableConnectionTypes: boolean;
disableStorageClasses: boolean;
Expand Down
260 changes: 260 additions & 0 deletions frontend/src/pages/modelRegistrySettings/CreateMRSecureDBSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
import React, { useState } from 'react';
import { FormGroup, Radio, Alert, MenuItem, MenuGroup } from '@patternfly/react-core';
import SearchSelector from '~/components/searchSelector/SearchSelector';
import { translateDisplayNameForK8s } from '~/concepts/k8s/utils';
import { RecursivePartial } from '~/typeHelpers';
import { PemFileUpload } from './PemFileUpload';

export enum SecureDBRType {
CLUSTER_WIDE = 'cluster-wide',
OPENSHIFT = 'openshift',
EXISTING = 'existing',
NEW = 'new',
}

export interface SecureDBInfo {
type: SecureDBRType;
configMap: string;
key: string;
certificate: string;
nameSpace: string;
isValid: boolean;
}

interface CreateMRSecureDBSectionProps {
secureDBInfo: SecureDBInfo;
modelRegistryNamespace: string;
nameDesc: { name: string };
existingCertKeys: string[];
existingCertConfigMaps: string[];
existingCertSecrets: string[];
setSecureDBInfo: (info: SecureDBInfo) => void;
}

export const CreateMRSecureDBSection: React.FC<CreateMRSecureDBSectionProps> = ({
secureDBInfo,
modelRegistryNamespace,
nameDesc,
existingCertKeys,
existingCertConfigMaps,
existingCertSecrets,
setSecureDBInfo,
}) => {
const [searchValue, setSearchValue] = useState('');

const hasContent = (value: string): boolean => !!value.trim().length;

const isValid = (info?: RecursivePartial<SecureDBInfo>) => {
const fullInfo: SecureDBInfo = { ...secureDBInfo, ...info };
if ([SecureDBRType.CLUSTER_WIDE, SecureDBRType.OPENSHIFT].includes(fullInfo.type)) {
return true;
}
if (fullInfo.type === SecureDBRType.EXISTING) {
return hasContent(fullInfo.configMap) && hasContent(fullInfo.key);
}
if (fullInfo.type === SecureDBRType.NEW) {
return hasContent(fullInfo.certificate);
}
return false;
};

const handleSecureDBTypeChange = (type: SecureDBRType) => {
const newInfo = {
type,
nameSpace: '',
key: '',
configMap: '',
certificate: '',
};
setSecureDBInfo({
...newInfo,
isValid: isValid(newInfo),
});
};

const getFilteredExistingCAResources = () => (
<>
<MenuGroup label="ConfigMaps">
{existingCertConfigMaps
.filter((configMap) => configMap.toLowerCase().includes(searchValue.toLowerCase()))
.map((configMap, index) => (
<MenuItem
key={`configmap-${index}`}
onClick={() => {
setSearchValue('');
const newInfo = {
...secureDBInfo,
configMap,
key: '',
};
setSecureDBInfo({
...newInfo,
isValid: isValid(newInfo),
});
}}
>
{configMap}
</MenuItem>
))}
</MenuGroup>
<MenuGroup label="Secrets">
{existingCertSecrets
.filter((secret) => secret.toLowerCase().includes(searchValue.toLowerCase()))
.map((secret, index) => (
<MenuItem
key={`secret-${index}`}
onClick={() => {
setSearchValue('');
const newInfo = {
...secureDBInfo,
configMap: secret,
key: '',
};
setSecureDBInfo({
...newInfo,
isValid: isValid(newInfo),
});
}}
>
{secret}
</MenuItem>
))}
</MenuGroup>
</>
);

return (
<>
<Radio
isChecked={secureDBInfo.type === SecureDBRType.CLUSTER_WIDE}
name="cluster-wide-ca"
onChange={() => handleSecureDBTypeChange(SecureDBRType.CLUSTER_WIDE)}
label="Use cluster-wide CA bundle"
description={
<>
Use the <strong>ca-bundle.crt</strong> bundle in the{' '}
<strong>odh-trusted-ca-bundle</strong> ConfigMap.
</>
}
id="cluster-wide-ca"
/>
<Radio
isChecked={secureDBInfo.type === SecureDBRType.OPENSHIFT}
name="openshift-ca"
onChange={() => handleSecureDBTypeChange(SecureDBRType.OPENSHIFT)}
label="Use OpenShift AI CA bundle"
description={
<>
Use the <strong>odh-ca-bundle.crt</strong> bundle in the{' '}
<strong>odh-trusted-ca-bundle</strong> ConfigMap.
</>
}
id="openshift-ca"
/>
<Radio
isChecked={secureDBInfo.type === SecureDBRType.EXISTING}
name="existing-ca"
onChange={() => handleSecureDBTypeChange(SecureDBRType.EXISTING)}
label="Choose from existing certificates"
description={
<>
You can select the key of any ConfigMap or Secret in the{' '}
<strong>{modelRegistryNamespace}</strong> namespace.
</>
}
id="existing-ca"
/>
{secureDBInfo.type === SecureDBRType.EXISTING && (
<>
<FormGroup
label="Resource"
isRequired
fieldId="existing-ca-resource"
style={{ marginLeft: 'var(--pf-t--global--spacer--lg)' }}
>
<SearchSelector
isFullWidth
dataTestId="existing-ca-resource-selector"
onSearchChange={(newValue) => setSearchValue(newValue)}
onSearchClear={() => setSearchValue('')}
searchValue={searchValue}
toggleText={secureDBInfo.configMap || 'Select a ConfigMap or a Secret'}
>
{getFilteredExistingCAResources()}
</SearchSelector>
</FormGroup>
<FormGroup
label="Key"
isRequired
fieldId="existing-ca-key"
style={{ marginLeft: 'var(--pf-t--global--spacer--lg)' }}
>
<SearchSelector
isFullWidth
dataTestId="existing-ca-key-selector"
onSearchChange={(newValue) => setSearchValue(newValue)}
onSearchClear={() => setSearchValue('')}
searchValue={searchValue}
toggleText={secureDBInfo.key || 'Select a key'}
>
{existingCertKeys
.filter((item) => item.toLowerCase().includes(searchValue.toLowerCase()))
.map((item, index) => (
<MenuItem
key={`key-${index}`}
onClick={() => {
setSearchValue('');
const newInfo = {
...secureDBInfo,
key: item,
};
setSecureDBInfo({ ...newInfo, isValid: isValid(newInfo) });
}}
>
{item}
</MenuItem>
))}
</SearchSelector>
</FormGroup>
</>
)}
<Radio
isChecked={secureDBInfo.type === SecureDBRType.NEW}
name="new-ca"
onChange={() => handleSecureDBTypeChange(SecureDBRType.NEW)}
label="Upload new certificate"
id="new-ca"
/>
{secureDBInfo.type === SecureDBRType.NEW && (
<>
<Alert
isInline
title="Note"
variant="info"
style={{ marginLeft: 'var(--pf-t--global--spacer--lg)' }}
>
Uploading a certificate below creates the{' '}
<strong>{translateDisplayNameForK8s(nameDesc.name)}-db-credential</strong> ConfigMap
with the <strong>ca.crt</strong> key. If you&apos;d like to upload the certificate as a
Secret instead, see the documentation for more details.
</Alert>
<FormGroup
label="Certificate"
required
style={{ marginLeft: 'var(--pf-t--global--spacer--lg)' }}
>
<PemFileUpload
onChange={(value) => {
const newInfo = {
...secureDBInfo,
certificate: value,
};
setSecureDBInfo({ ...newInfo, isValid: isValid(newInfo) });
}}
/>
</FormGroup>
</>
)}
</>
);
};
Loading

0 comments on commit 9f2b3d1

Please sign in to comment.