Skip to content

Commit

Permalink
[RHOAIENG-6985] Create kserve metrics feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-phillips-18 committed May 13, 2024
1 parent 93c0851 commit 758b1cd
Show file tree
Hide file tree
Showing 20 changed files with 180 additions and 36 deletions.
1 change: 1 addition & 0 deletions backend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type DashboardConfig = K8sResourceCommon & {
disablePerformanceMetrics: boolean;
disableKServe: boolean;
disableKServeAuth: boolean;
disableKServeMetrics: boolean;
disableModelMesh: boolean;
disableAcceleratorProfiles: boolean;
disablePipelineExperiments: 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 @@ -58,6 +58,7 @@ export const blankDashboardCR: DashboardConfig = {
disablePipelines: false,
disableKServe: false,
disableKServeAuth: false,
disableKServeMetrics: true,
disableModelMesh: false,
disableAcceleratorProfiles: false,
disablePipelineExperiments: true,
Expand Down
3 changes: 3 additions & 0 deletions docs/dashboard-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The following are a list of features that are supported, along with there defaul
| disableCustomServingRuntimes | false | Disables Custom Serving Runtimes from the Admin Panel. |
| disableKServe | false | Disables the ability to select KServe as a Serving Platform. |
| disableKServeAuth | false | Disables the ability to use auth in KServe. |
| disableKServeMetrics | true | Disables the ability to see KServe Metrics. |
| disableModelMesh | false | Disables the ability to select ModelMesh as a Serving Platform. |
| disableAcceleratorProfiles | false | Disables Accelerator profiles from the Admin Panel. |
| modelMetricsNamespace | false | Enables the namespace in which the Model Serving Metrics' Prometheus Operator is installed. |
Expand Down Expand Up @@ -59,6 +60,7 @@ spec:
disableCustomServingRuntimes: false
disableAcceleratorProfiles: false
modelMetricsNamespace: ''
disableKServeMetrics: true
disableBiasMetrics: false
disablePerformanceMetrics: false
disablePipelineExperiments: false
Expand Down Expand Up @@ -154,6 +156,7 @@ spec:
disableCustomServingRuntimes: false
disableAcceleratorProfiles: true
modelMetricsNamespace: ''
disableKServeMetrics: true
disableBiasMetrics: false
disablePerformanceMetrics: false
disablePipelineExperiments: true
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 @@ -16,6 +16,7 @@ type MockDashboardConfigType = {
disableCustomServingRuntimes?: boolean;
disableKServe?: boolean;
disableKServeAuth?: boolean;
disableKServeMetrics?: boolean;
disableModelMesh?: boolean;
disableAcceleratorProfiles?: boolean;
disablePerformanceMetrics?: boolean;
Expand All @@ -42,6 +43,7 @@ export const mockDashboardConfig = ({
disablePipelines = false,
disableKServe = false,
disableKServeAuth = false,
disableKServeMetrics = true,
disableModelMesh = false,
disableAcceleratorProfiles = false,
disablePerformanceMetrics = false,
Expand Down Expand Up @@ -81,6 +83,7 @@ export const mockDashboardConfig = ({
disablePerformanceMetrics,
disableKServe,
disableKServeAuth,
disableKServeMetrics,
disableModelMesh,
disableAcceleratorProfiles,
disablePipelineExperiments,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type HandlersProps = {
inferenceServices?: InferenceServiceKind[];
delayInferenceServices?: boolean;
delayServingRuntimes?: boolean;
disableKServeMetrics?: boolean;
};

const initIntercepts = ({
Expand All @@ -46,6 +47,7 @@ const initIntercepts = ({
inferenceServices = [mockInferenceServiceK8sResource({})],
delayInferenceServices,
delayServingRuntimes,
disableKServeMetrics,
}: HandlersProps) => {
cy.interceptOdh(
'GET /api/dsc/status',
Expand All @@ -58,6 +60,7 @@ const initIntercepts = ({
mockDashboardConfig({
disableKServe: disableKServeConfig,
disableModelMesh: disableModelMeshConfig,
disableKServeMetrics,
}),
);
cy.interceptK8sList(ServingRuntimeModel, mockK8sResourceList(servingRuntimes));
Expand Down Expand Up @@ -478,6 +481,22 @@ describe('Model Serving Global', () => {
modelServingGlobal.findDeployModelButton().click();
cy.findByText('Error creating model server').should('not.exist');
});
it('Navigate to kserve model metrics page only if enabled', () => {
initIntercepts({});
modelServingGlobal.visit('test-project');

// Verify initial run rows exist
modelServingGlobal.getModelRow('Test Inference Service').should('have.length', 1);
modelServingGlobal.getModelMetricLink('Test Inference Service').should('not.exist');

initIntercepts({ disableKServeMetrics: false });
modelServingGlobal.visit('test-project');

modelServingGlobal.getModelRow('Test Inference Service').should('have.length', 1);
modelServingGlobal.getModelMetricLink('Test Inference Service').should('be.visible');
modelServingGlobal.getModelMetricLink('Test Inference Service').click();
cy.findByTestId('kserve-metrics-page').should('be.visible');
});

describe('Table filter and pagination', () => {
it('filter by name', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ import {
SecretModel,
ServiceAccountModel,
TemplateModel,
InferenceServiceModel,
ServingRuntimeModel,
} from '~/__tests__/cypress/cypress/utils/models';
import { mockServingRuntimeK8sResource } from '~/__mocks__/mockServingRuntimeK8sResource';
import { mockInferenceServiceK8sResource } from '~/__mocks__/mockInferenceServiceK8sResource';

type HandlersProps = {
isEmpty?: boolean;
imageStreamName?: string;
disableKServeConfig?: boolean;
disableKServeMetrics?: boolean;
disableModelConfig?: boolean;
isEnabled?: string;
isUnknown?: boolean;
Expand All @@ -43,6 +48,7 @@ type HandlersProps = {

const initIntercepts = ({
disableKServeConfig,
disableKServeMetrics,
disableModelConfig,
isEmpty = false,
imageStreamName = 'test-image',
Expand Down Expand Up @@ -96,6 +102,7 @@ const initIntercepts = ({
mockDashboardConfig({
disableKServe: disableKServeConfig,
disableModelMesh: disableModelConfig,
disableKServeMetrics,
}),
);
if (pipelineServerInstalled) {
Expand Down Expand Up @@ -233,6 +240,13 @@ const initIntercepts = ({
};

describe('Project Details', () => {
const servingRuntimes = [mockServingRuntimeK8sResource({})];
const inferenceServices = [mockInferenceServiceK8sResource({})];
const initModelServingIntercepts = () => {
cy.interceptK8sList(ServingRuntimeModel, mockK8sResourceList(servingRuntimes));
cy.interceptK8sList(InferenceServiceModel, mockK8sResourceList(inferenceServices));
};

describe('Empty project details', () => {
it('Empty state component in project details', () => {
initIntercepts({ isEmpty: true });
Expand Down Expand Up @@ -271,6 +285,26 @@ describe('Project Details', () => {
projectDetails.findServingPlatformLabel().should('have.text', 'Single-model serving enabled');
});

it('Shows KServe metrics only when available', () => {
initIntercepts({ templates: true, disableKServeConfig: false, disableModelConfig: true });
initModelServingIntercepts();

projectDetails.visitSection('test-project', 'model-server');
projectDetails.getKserveModelMetricLink('Test Inference Service').should('not.exist');

initIntercepts({
templates: true,
disableKServeConfig: false,
disableModelConfig: true,
disableKServeMetrics: false,
});
initModelServingIntercepts();

projectDetails.visitSection('test-project', 'model-server');
projectDetails.getKserveModelMetricLink('Test Inference Service').should('be.visible');
projectDetails.getKserveModelMetricLink('Test Inference Service').click();
cy.findByTestId('kserve-metrics-page').should('be.visible');
});
it('Multi model serving platform is enabled', () => {
initIntercepts({ templates: true, disableKServeConfig: true, disableModelConfig: false });
projectDetails.visit('test-project');
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/__tests__/cypress/cypress/pages/modelServing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ class ModelServingGlobal {
return this.findModelsTable().find(`[data-label=Name]`).contains(name).parents('tr');
}

getModelMetricLink(name: string) {
return this.findModelsTable().findByTestId(`metrics-link-${name}`);
}

findEmptyResults() {
return cy.findByTestId('no-result-found-title');
}
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/__tests__/cypress/cypress/pages/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ class ProjectDetails {
findUnsupportedPipelineVersionAlert() {
return cy.findByTestId('unsupported-pipeline-version-alert');
}

private findKserveModelsTable() {
return cy.findByTestId('kserve-inference-service-table');
}

getKserveModelMetricLink(name: string) {
return this.findKserveModelsTable().findByTestId(`metrics-link-${name}`);
}
}

class ProjectDetailsSettingsTab extends ProjectDetails {
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/concepts/areas/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export const SupportedAreasStateMap: SupportedAreasState = {
reliantAreas: [SupportedArea.K_SERVE],
requiredCapabilities: [StackCapability.SERVICE_MESH, StackCapability.SERVICE_MESH_AUTHZ],
},
[SupportedArea.K_SERVE_METRICS]: {
featureFlags: ['disableKServeMetrics'],
reliantAreas: [SupportedArea.K_SERVE, SupportedArea.MODEL_SERVING],
},
[SupportedArea.MODEL_MESH]: {
featureFlags: ['disableModelMesh'],
requiredComponents: [StackComponent.MODEL_MESH],
Expand All @@ -59,7 +63,6 @@ export const SupportedAreasStateMap: SupportedAreasState = {
},
[SupportedArea.PERFORMANCE_METRICS]: {
featureFlags: ['disablePerformanceMetrics'],
requiredComponents: [StackComponent.MODEL_MESH], // TODO: remove when KServe support is added
reliantAreas: [SupportedArea.MODEL_SERVING],
},
[SupportedArea.TRUSTY_AI]: {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/concepts/areas/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export enum SupportedArea {
CUSTOM_RUNTIMES = 'custom-serving-runtimes',
K_SERVE = 'kserve',
K_SERVE_AUTH = 'kserve-auth',
K_SERVE_METRICS = 'kserve-metrics',
MODEL_MESH = 'model-mesh',
BIAS_METRICS = 'bias-metrics',
PERFORMANCE_METRICS = 'performance-metrics',
Expand Down
1 change: 1 addition & 0 deletions frontend/src/k8sTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,7 @@ export type DashboardCommonConfig = {
disablePerformanceMetrics: boolean;
disableKServe: boolean;
disableKServeAuth: boolean;
disableKServeMetrics: boolean;
disableModelMesh: boolean;
disableAcceleratorProfiles: boolean;
// TODO Temp feature flag - remove with https://issues.redhat.com/browse/RHOAIENG-3826
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import ResourceNameTooltip from '~/components/ResourceNameTooltip';
import useModelMetricsEnabled from '~/pages/modelServing/useModelMetricsEnabled';
import { InferenceServiceKind, ServingRuntimeKind } from '~/k8sTypes';
import { isModelMesh } from '~/pages/modelServing/utils';
import { SupportedArea } from '~/concepts/areas';
import useIsAreaAvailable from '~/concepts/areas/useIsAreaAvailable';
import { getInferenceServiceDisplayName } from './utils';
import InferenceServiceEndpoint from './InferenceServiceEndpoint';
import InferenceServiceProject from './InferenceServiceProject';
Expand All @@ -31,28 +33,40 @@ const InferenceServiceTableRow: React.FC<InferenceServiceTableRowProps> = ({
showServingRuntime,
}) => {
const [modelMetricsEnabled] = useModelMetricsEnabled();
const kserveMetricsEnabled = useIsAreaAvailable(SupportedArea.K_SERVE_METRICS).status;

const modelMetricsSupported = (modelMetricsInferenceService: InferenceServiceKind) =>
modelMetricsEnabled &&
modelMetricsInferenceService.metadata.annotations?.['serving.kserve.io/deploymentMode'] ===
'ModelMesh';
const modelMesh = isModelMesh(inferenceService);
const modelMetricsSupported = modelMetricsEnabled && modelMesh;
const displayName = getInferenceServiceDisplayName(inferenceService);

return (
<>
<Td dataLabel="Name">
<ResourceNameTooltip resource={inferenceService}>
{modelMetricsSupported(inferenceService) ? (
{modelMetricsSupported ? (
<Link
data-testid={`metrics-link-${displayName}`}
to={
isGlobal
? `/modelServing/${inferenceService.metadata.namespace}/metrics/${inferenceService.metadata.name}`
: `/projects/${inferenceService.metadata.namespace}/metrics/model/${inferenceService.metadata.name}`
}
>
{getInferenceServiceDisplayName(inferenceService)}
{displayName}
</Link>
) : kserveMetricsEnabled && !modelMesh ? (
<Link
data-testid={`metrics-link-${displayName}`}
to={
isGlobal
? `/modelServing/${inferenceService.metadata.namespace}/metrics/${inferenceService.metadata.name}`
: `/projects/${inferenceService.metadata.namespace}/metrics/model/${inferenceService.metadata.name}`
}
>
{displayName}
</Link>
) : (
getInferenceServiceDisplayName(inferenceService)
displayName
)}
</ResourceNameTooltip>
</Td>
Expand All @@ -70,20 +84,17 @@ const InferenceServiceTableRow: React.FC<InferenceServiceTableRowProps> = ({
<InferenceServiceEndpoint
inferenceService={inferenceService}
servingRuntime={servingRuntime}
isKserve={!isModelMesh(inferenceService)}
isKserve={!modelMesh}
/>
</Td>
<Td dataLabel="API protocol">
<InferenceServiceAPIProtocol
servingRuntime={servingRuntime}
isMultiModel={modelMetricsSupported(inferenceService)}
isMultiModel={modelMetricsSupported}
/>
</Td>
<Td dataLabel="Status">
<InferenceServiceStatus
inferenceService={inferenceService}
isKserve={!isModelMesh(inferenceService)}
/>
<InferenceServiceStatus inferenceService={inferenceService} isKserve={!modelMesh} />
</Td>
<Td isActionCell>
<ResourceActionsColumn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const GlobalModelMetricsPage: React.FC = () => {
isActive: true,
},
]}
model={model}
type={PerformanceMetricType.MODEL}
/>
);
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/pages/modelServing/screens/metrics/MetricsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import { MetricsTabKeys } from '~/pages/modelServing/screens/metrics/types';
import { PerformanceMetricType } from '~/pages/modelServing/screens/types';
import { TrustyAIContext } from '~/concepts/trustyai/context/TrustyAIContext';
import ServerMetricsPage from '~/pages/modelServing/screens/metrics/performance/ServerMetricsPage';
import { InferenceServiceKind } from '~/k8sTypes';
import { getBreadcrumbItemComponents } from './utils';

type MetricsPageProps = {
title: string;
breadcrumbItems: BreadcrumbItemType[];
type: PerformanceMetricType;
model?: InferenceServiceKind;
};

const MetricsPage: React.FC<MetricsPageProps> = ({ title, breadcrumbItems, type }) => {
const MetricsPage: React.FC<MetricsPageProps> = ({ title, breadcrumbItems, type, model }) => {
const { tab } = useParams();
const navigate = useNavigate();

Expand Down Expand Up @@ -46,7 +48,11 @@ const MetricsPage: React.FC<MetricsPageProps> = ({ title, breadcrumbItems, type
)
}
>
{type === PerformanceMetricType.SERVER ? <ServerMetricsPage /> : <MetricsPageTabs />}
{type === PerformanceMetricType.SERVER ? (
<ServerMetricsPage />
) : model ? (
<MetricsPageTabs model={model} />
) : null}

Check warning on line 55 in frontend/src/pages/modelServing/screens/metrics/MetricsPage.tsx

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/modelServing/screens/metrics/MetricsPage.tsx#L55

Added line #L55 was not covered by tests
</ApplicationsPage>
);
};
Expand Down
Loading

0 comments on commit 758b1cd

Please sign in to comment.