From 3ae2905e8687136b4ed3dadf87c683d662a09a5a Mon Sep 17 00:00:00 2001 From: Griffin-Sullivan Date: Tue, 26 Nov 2024 10:39:58 -0500 Subject: [PATCH] Add Istio overlay for UI integration with Central Dashboard Signed-off-by: Griffin-Sullivan --- clients/ui/frontend/config/dotenv.js | 2 + clients/ui/frontend/config/webpack.common.js | 5 +- .../frontend/src/__mocks__/mockNamespace.ts | 9 ++++ .../cypress/cypress/pages/modelRegistry.ts | 2 +- .../cypress/pages/modelRegistrySettings.ts | 2 +- .../modelRegistryView/modelVersionArchive.ts | 8 +-- .../modelRegistryView/modelVersionDetails.ts | 2 +- .../modelRegistryView/registerModelPage.ts | 2 +- .../registeredModelArchive.ts | 10 ++-- .../cypress/cypress/support/commands/api.ts | 7 ++- .../__tests__/cypress/cypress/support/e2e.ts | 11 ++++ .../tests/mocked/modelVersionArchive.cy.ts | 10 ++-- .../tests/mocked/modelVersionDetails.cy.ts | 2 +- .../cypress/tests/mocked/modelVersions.cy.ts | 12 ++--- .../tests/mocked/registeredModelArchive.cy.ts | 20 ++++---- clients/ui/frontend/src/app/App.tsx | 22 ++++---- clients/ui/frontend/src/app/AppRoutes.tsx | 10 ++-- .../src/app/context/ModelRegistryContext.tsx | 3 +- .../ModelVersionDetails.tsx | 2 +- .../screens/ModelVersions/ModelVersions.tsx | 2 +- .../ArchiveModelVersionDetailsBreadcrumb.tsx | 2 +- .../ModelVersionArchiveDetailsBreadcrumb.tsx | 2 +- .../ModelVersionsArchive.tsx | 2 +- ...egisteredModelArchiveDetailsBreadcrumb.tsx | 2 +- .../RegisteredModelsArchive.tsx | 2 +- .../pages/modelRegistry/screens/routeUtils.ts | 2 +- clients/ui/frontend/src/index.html | 2 +- clients/ui/frontend/src/shared/api/k8s.ts | 35 ++++++------- .../shared/hooks/useQueryParamNamespaces.ts | 4 +- .../ui/frontend/src/shared/utilities/const.ts | 12 ++++- clients/ui/manifests/{base => }/README.md | 5 ++ clients/ui/manifests/base/kustomization.yaml | 10 ++-- ...> model-registry-bff-service-account.yaml} | 3 +- .../base/model-registry-bff-service.yaml | 6 ++- .../base/model-registry-ui-deployment.yaml | 2 +- .../base/model-registry-ui-service.yaml | 8 ++- .../kubeflow/kubeflow-dashboard-rbac.yaml | 51 +++++++++++++++++++ .../ui/manifests/kubeflow/kustomization.yaml | 6 ++- .../model-registry-ui-deployment.yaml | 2 +- .../istio/authorization-policy-bff.yaml | 13 +++++ .../istio/authorization-policy-ui.yaml | 16 ++++++ .../overlays/istio/destination-rule-bff.yaml | 11 ++++ .../overlays/istio/destination-rule-ui.yaml | 11 ++++ .../overlays/istio/kustomization.yaml | 17 +++++++ .../istio/model-registry-ui-service.yaml | 3 ++ .../overlays/istio/virtual-service.yaml | 26 ++++++++++ .../manifests/standalone/kustomization.yaml | 2 +- 47 files changed, 306 insertions(+), 94 deletions(-) create mode 100644 clients/ui/frontend/src/__mocks__/mockNamespace.ts rename clients/ui/manifests/{base => }/README.md (92%) rename clients/ui/manifests/base/{model-registry-service-account.yaml => model-registry-bff-service-account.yaml} (59%) create mode 100644 clients/ui/manifests/kubeflow/kubeflow-dashboard-rbac.yaml create mode 100644 clients/ui/manifests/overlays/istio/authorization-policy-bff.yaml create mode 100644 clients/ui/manifests/overlays/istio/authorization-policy-ui.yaml create mode 100644 clients/ui/manifests/overlays/istio/destination-rule-bff.yaml create mode 100644 clients/ui/manifests/overlays/istio/destination-rule-ui.yaml create mode 100644 clients/ui/manifests/overlays/istio/kustomization.yaml create mode 100644 clients/ui/manifests/overlays/istio/model-registry-ui-service.yaml create mode 100644 clients/ui/manifests/overlays/istio/virtual-service.yaml diff --git a/clients/ui/frontend/config/dotenv.js b/clients/ui/frontend/config/dotenv.js index c0e765f70..ae601dfc8 100644 --- a/clients/ui/frontend/config/dotenv.js +++ b/clients/ui/frontend/config/dotenv.js @@ -157,6 +157,7 @@ const setupDotenvFilesForEnv = ({ env }) => { const PROXY_PORT = process.env.PROXY_PORT || process.env.PORT || 4000; const DEV_MODE = process.env.DEV_MODE || undefined; const OUTPUT_ONLY = process.env._OUTPUT_ONLY === 'true'; + const DEPLOYMENT_MODE = process.env.DEPLOYMENT_MODE || 'integrated'; process.env._RELATIVE_DIRNAME = RELATIVE_DIRNAME; process.env._IS_PROJECT_ROOT_DIR = IS_ROOT; @@ -172,6 +173,7 @@ const setupDotenvFilesForEnv = ({ env }) => { process.env._PROXY_PORT = PROXY_PORT; process.env._OUTPUT_ONLY = OUTPUT_ONLY; process.env._DEV_MODE = DEV_MODE; + process.env._DEPLOYMENT_MODE = DEPLOYMENT_MODE; }; module.exports = { setupWebpackDotenvFilesForEnv, setupDotenvFilesForEnv }; diff --git a/clients/ui/frontend/config/webpack.common.js b/clients/ui/frontend/config/webpack.common.js index 8b8a000ec..c88cd17e2 100644 --- a/clients/ui/frontend/config/webpack.common.js +++ b/clients/ui/frontend/config/webpack.common.js @@ -14,6 +14,8 @@ const OUTPUT_ONLY = process.env._OUTPUT_ONLY; const FAVICON = process.env.FAVICON; const PRODUCT_NAME = process.env.PRODUCT_NAME; const COVERAGE = process.env.COVERAGE; +const DEPLOYMENT_MODE = process.env._DEPLOYMENT_MODE; +const BASE_PATH = DEPLOYMENT_MODE === 'integrated' ? '/model-registry/' : PUBLIC_PATH; if (OUTPUT_ONLY !== 'true') { console.info( @@ -173,7 +175,7 @@ module.exports = (env) => { output: { filename: '[name].bundle.js', path: DIST_DIR, - publicPath: PUBLIC_PATH, + publicPath: BASE_PATH, }, plugins: [ ...setupWebpackDotenvFilesForEnv({ @@ -184,6 +186,7 @@ module.exports = (env) => { template: path.join(SRC_DIR, 'index.html'), title: PRODUCT_NAME, favicon: path.join(SRC_DIR, 'images', FAVICON), + baseUrl: BASE_PATH }), new CopyPlugin({ patterns: [ diff --git a/clients/ui/frontend/src/__mocks__/mockNamespace.ts b/clients/ui/frontend/src/__mocks__/mockNamespace.ts new file mode 100644 index 000000000..90d86c0e2 --- /dev/null +++ b/clients/ui/frontend/src/__mocks__/mockNamespace.ts @@ -0,0 +1,9 @@ +import { Namespace } from '~/shared/types'; + +type MockNamespace = { + name?: string; +}; + +export const mockNamespace = ({ name = 'kubeflow' }: MockNamespace): Namespace => ({ + name, +}); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistry.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistry.ts index 8984975ae..6e4b28591 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistry.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistry.ts @@ -59,7 +59,7 @@ class ModelRegistry { } visit() { - cy.visit(`/modelRegistry`); + cy.visit(`/model-registry`); this.wait(); } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistrySettings.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistrySettings.ts index 1bac8692c..efa003802 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistrySettings.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistrySettings.ts @@ -28,7 +28,7 @@ export enum DatabaseDetailsTestId { class ModelRegistrySettings { visit(wait = true) { - cy.visit('/modelRegistrySettings'); + cy.visit('/model-registry-settings'); if (wait) { this.wait(); } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionArchive.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionArchive.ts index 81afa0638..951b3b04c 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionArchive.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionArchive.ts @@ -57,7 +57,7 @@ class ModelVersionArchive { visit() { const rmId = '1'; const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}/versions/archive`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/${rmId}/versions/archive`); this.wait(); } @@ -66,14 +66,14 @@ class ModelVersionArchive { const rmId = '1'; const preferredModelRegistry = 'modelregistry-sample'; cy.visit( - `/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}/versions/archive/${mvId}`, + `/model-registry/${preferredModelRegistry}/registeredModels/${rmId}/versions/archive/${mvId}`, ); } visitModelVersionList() { const rmId = '1'; const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}/versions`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/${rmId}/versions`); this.wait(); } @@ -81,7 +81,7 @@ class ModelVersionArchive { const mvId = '3'; const rmId = '1'; const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}/versions/${mvId}`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/${rmId}/versions/${mvId}`); this.wait(); } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionDetails.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionDetails.ts index b311fa896..c3d44c5f7 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionDetails.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/modelVersionDetails.ts @@ -3,7 +3,7 @@ class ModelVersionDetails { const preferredModelRegistry = 'modelregistry-sample'; const rmId = '1'; const mvId = '1'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}/versions/${mvId}`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/${rmId}/versions/${mvId}`); this.wait(); } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registerModelPage.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registerModelPage.ts index 7b55feaec..80d38bd61 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registerModelPage.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registerModelPage.ts @@ -17,7 +17,7 @@ export enum FormFieldSelector { class RegisterModelPage { visit() { const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registerModel`); + cy.visit(`/model-registry/${preferredModelRegistry}/registerModel`); this.wait(); } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registeredModelArchive.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registeredModelArchive.ts index 05b1186ea..561db8e36 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registeredModelArchive.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/pages/modelRegistryView/registeredModelArchive.ts @@ -56,31 +56,31 @@ class ModelArchive { visit() { const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/archive`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/archive`); this.wait(); } visitArchiveModelDetail() { const rmId = '2'; const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/archive/${rmId}`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/archive/${rmId}`); } visitArchiveModelVersionList() { const rmId = '2'; const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/archive/${rmId}/versions`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/archive/${rmId}/versions`); } visitModelList() { - cy.visit('/modelRegistry/modelregistry-sample'); + cy.visit('/model-registry/modelregistry-sample'); this.wait(); } visitModelDetails() { const rmId = '2'; const preferredModelRegistry = 'modelregistry-sample'; - cy.visit(`/modelRegistry/${preferredModelRegistry}/registeredModels/${rmId}`); + cy.visit(`/model-registry/${preferredModelRegistry}/registeredModels/${rmId}`); this.wait(); } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts index 54cbb27e3..f4fc6018d 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/support/commands/api.ts @@ -9,7 +9,7 @@ import type { RegisteredModel, RegisteredModelList, } from '~/app/types'; -import type { UserSettings } from '~/shared/types'; +import type { Namespace, UserSettings } from '~/shared/types'; const MODEL_REGISTRY_API_VERSION = 'v1'; export { MODEL_REGISTRY_API_VERSION }; @@ -108,6 +108,11 @@ declare global { type: 'GET /api/:apiVersion/user', options: { path: { apiVersion: string } }, response: ApiResponse, + ) => Cypress.Chainable) & + (( + type: 'GET /api/:apiVersion/namespaces', + options: { path: { apiVersion: string } }, + response: ApiResponse, ) => Cypress.Chainable); } } diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts index 5b196a706..f69a3b97c 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/support/e2e.ts @@ -18,6 +18,7 @@ import '@cypress/code-coverage/support'; import { mockUserSettings } from '~/__mocks__/mockUserSettings'; import 'cypress-mochawesome-reporter/register'; import './commands'; +import { mockNamespace } from '~/__mocks__/mockNamespace'; import { MODEL_REGISTRY_API_VERSION } from './commands/api'; chai.use(chaiSubset); @@ -40,5 +41,15 @@ beforeEach(() => { }, mockUserSettings({}), ); + + cy.interceptApi( + 'GET /api/:apiVersion/namespaces', + { + path: { + apiVersion: MODEL_REGISTRY_API_VERSION, + }, + }, + [mockNamespace({})], + ); } }); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionArchive.cy.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionArchive.cy.ts index 291250583..eeed18eda 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionArchive.cy.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionArchive.cy.ts @@ -129,7 +129,7 @@ describe('Model version archive list', () => { it('No archive versions in the selected registered model', () => { initIntercepts({ modelVersions: [mockModelVersion({ id: '3', name: 'model version 2' })] }); modelVersionArchive.visitModelVersionList(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/1/versions'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/1/versions'); modelVersionArchive .findModelVersionsTableKebab() .findDropdownItem('View archived versions') @@ -140,15 +140,15 @@ describe('Model version archive list', () => { it('Archived version details browser back button should lead to archived versions table', () => { initIntercepts({}); modelVersionArchive.visit(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/1/versions/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/1/versions/archive'); modelVersionArchive.findArchiveVersionBreadcrumbItem().contains('Archived version'); const archiveVersionRow = modelVersionArchive.getRow('model version 2'); archiveVersionRow.findName().contains('model version 2').click(); verifyRelativeURL( - '/modelRegistry/modelregistry-sample/registeredModels/1/versions/archive/2/details', + '/model-registry/modelregistry-sample/registeredModels/1/versions/archive/2/details', ); cy.go('back'); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/1/versions/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/1/versions/archive'); modelVersionArchive.findArchiveVersionBreadcrumbItem().contains('Archived version'); archiveVersionRow.findName().contains('model version 2').should('exist'); }); @@ -156,7 +156,7 @@ describe('Model version archive list', () => { it('Archive version list', () => { initIntercepts({}); modelVersionArchive.visit(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/1/versions/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/1/versions/archive'); //breadcrumb modelVersionArchive.findArchiveVersionBreadcrumbItem().contains('Archived version'); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionDetails.cy.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionDetails.cy.ts index c07827db9..58f28ac6a 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionDetails.cy.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersionDetails.cy.ts @@ -139,7 +139,7 @@ describe('Model version details', () => { it('Model version details page header', () => { verifyRelativeURL( - '/modelRegistry/modelregistry-sample/registeredModels/1/versions/1/details', + '/model-registry/modelregistry-sample/registeredModels/1/versions/1/details', ); cy.findByTestId('app-page-title').should('have.text', 'Version 1'); cy.findByTestId('breadcrumb-version-name').should('have.text', 'Version 1'); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersions.cy.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersions.cy.ts index 7ad00d4a0..842392f6b 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersions.cy.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/modelVersions.cy.ts @@ -110,7 +110,7 @@ describe('Model Versions', () => { modelRegistry.visit(); const registeredModelRow = modelRegistry.getRow('Fraud detection model'); registeredModelRow.findName().contains('Fraud detection model').click(); - verifyRelativeURL(`/modelRegistry/modelregistry-sample/registeredModels/1/versions`); + verifyRelativeURL(`/model-registry/modelregistry-sample/registeredModels/1/versions`); modelRegistry.shouldmodelVersionsEmpty(); }); @@ -122,9 +122,9 @@ describe('Model Versions', () => { modelRegistry.visit(); const registeredModelRow = modelRegistry.getRow('Fraud detection model'); registeredModelRow.findName().contains('Fraud detection model').click(); - verifyRelativeURL(`/modelRegistry/modelregistry-sample/registeredModels/1/versions`); + verifyRelativeURL(`/model-registry/modelregistry-sample/registeredModels/1/versions`); cy.go('back'); - verifyRelativeURL(`/modelRegistry/modelregistry-sample`); + verifyRelativeURL(`/model-registry/modelregistry-sample`); registeredModelRow.findName().contains('Fraud detection model').should('exist'); }); @@ -143,7 +143,7 @@ describe('Model Versions', () => { //cy.reload(); const registeredModelRow = modelRegistry.getRow('Fraud detection model'); registeredModelRow.findName().contains('Fraud detection model').click(); - verifyRelativeURL(`/modelRegistry/modelregistry-sample/registeredModels/1/versions`); + verifyRelativeURL(`/model-registry/modelregistry-sample/registeredModels/1/versions`); modelRegistry.findModelBreadcrumbItem().contains('test'); //modelRegistry.findModelVersionsTableKebab().findDropdownItem('View archived versions'); //modelRegistry.findModelVersionsHeaderAction().findDropdownItem('Archive model'); @@ -209,10 +209,10 @@ describe('Model Versions', () => { registeredModelRow.findName().contains('Fraud detection model').click(); const modelVersionRow = modelRegistry.getModelVersionRow('model version'); modelVersionRow.findModelVersionName().contains('model version').click(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/1/versions/1/details'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/1/versions/1/details'); cy.findByTestId('app-page-title').should('have.text', 'model version'); cy.findByTestId('breadcrumb-version-name').should('have.text', 'model version'); cy.go('back'); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/1/versions'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/1/versions'); }); }); diff --git a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/registeredModelArchive.cy.ts b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/registeredModelArchive.cy.ts index d07c89a1e..6601e3290 100644 --- a/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/registeredModelArchive.cy.ts +++ b/clients/ui/frontend/src/__tests__/cypress/cypress/tests/mocked/registeredModelArchive.cy.ts @@ -133,28 +133,28 @@ describe('Model archive list', () => { registeredModels: [], }); registeredModelArchive.visit(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive'); registeredModelArchive.shouldArchiveVersionsEmpty(); }); it('Archived model details browser back button should lead to archived models table', () => { initIntercepts({}); registeredModelArchive.visit(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive'); registeredModelArchive.findArchiveModelBreadcrumbItem().contains('Archived models'); const archiveModelRow = registeredModelArchive.getRow('model 2'); archiveModelRow.findName().contains('model 2').click(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive/2/versions'); cy.findByTestId('app-page-title').should('have.text', 'model 2Archived'); cy.go('back'); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive'); registeredModelArchive.findArchiveModelTable().should('be.visible'); }); it('Archived model with no versions', () => { initIntercepts({ modelVersions: [] }); registeredModelArchive.visit(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive'); registeredModelArchive.findArchiveModelBreadcrumbItem().contains('Archived models'); const archiveModelRow = registeredModelArchive.getRow('model 2'); archiveModelRow.findName().contains('model 2').click(); @@ -164,23 +164,23 @@ describe('Model archive list', () => { it('Archived model flow', () => { initIntercepts({}); registeredModelArchive.visitArchiveModelVersionList(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive/2/versions'); modelRegistry.findModelVersionsTable().should('be.visible'); modelRegistry.findModelVersionsTableRows().should('have.length', 2); const version = modelRegistry.getModelVersionRow('model version'); version.findModelVersionName().contains('model version').click(); verifyRelativeURL( - '/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions/1/details', + '/model-registry/modelregistry-sample/registeredModels/archive/2/versions/1/details', ); cy.go('back'); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive/2/versions'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive/2/versions'); }); it('Archive models list', () => { initIntercepts({}); registeredModelArchive.visit(); - verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive'); + verifyRelativeURL('/model-registry/modelregistry-sample/registeredModels/archive'); //breadcrumb registeredModelArchive.findArchiveModelBreadcrumbItem().contains('Archived models'); @@ -233,7 +233,7 @@ describe('Model archive list', () => { archiveModelRow.findKebabAction('View details').click(); cy.location('pathname').should( 'be.equals', - '/modelRegistry/modelregistry-sample/registeredModels/archive/2/details', + '/model-registry/modelregistry-sample/registeredModels/archive/2/details', ); }); }); diff --git a/clients/ui/frontend/src/app/App.tsx b/clients/ui/frontend/src/app/App.tsx index ed0785a64..4c56853bd 100644 --- a/clients/ui/frontend/src/app/App.tsx +++ b/clients/ui/frontend/src/app/App.tsx @@ -13,7 +13,7 @@ import { } from '@patternfly/react-core'; import ToastNotifications from '~/shared/components/ToastNotifications'; import { useSettings } from '~/shared/hooks/useSettings'; -import { isMUITheme, Theme, AUTH_HEADER, MOCK_AUTH } from '~/shared/utilities/const'; +import { isMUITheme, Theme, AUTH_HEADER, MOCK_AUTH, isStandalone } from '~/shared/utilities/const'; import { logout } from '~/shared/utilities/appUtils'; import { NamespaceSelectorContext } from '~/shared/context/NamespaceSelectorContext'; import NavSidebar from './NavSidebar'; @@ -108,15 +108,19 @@ const App: React.FC = () => { { - logout().then(() => window.location.reload()); - }} - /> + isStandalone() ? ( + { + logout().then(() => window.location.reload()); + }} + /> + ) : ( + '' + ) } - isManagedSidebar - sidebar={} + isManagedSidebar={isStandalone()} + sidebar={isStandalone() ? : ''} > diff --git a/clients/ui/frontend/src/app/AppRoutes.tsx b/clients/ui/frontend/src/app/AppRoutes.tsx index 1f0f6461c..60a69d480 100644 --- a/clients/ui/frontend/src/app/AppRoutes.tsx +++ b/clients/ui/frontend/src/app/AppRoutes.tsx @@ -32,7 +32,7 @@ export const useAdminSettings = (): NavDataItem[] => { return [ { label: 'Settings', - children: [{ label: 'Model Registry', path: '/modelRegistrySettings' }], + children: [{ label: 'Model Registry', path: '/model-registry-settings' }], }, ]; }; @@ -40,7 +40,7 @@ export const useAdminSettings = (): NavDataItem[] => { export const useNavData = (): NavDataItem[] => [ { label: 'Model Registry', - path: '/modelRegistry', + path: '/model-registry', }, ...useAdminSettings(), ]; @@ -50,12 +50,12 @@ const AppRoutes: React.FC = () => { return ( - } /> - } /> + } /> + } /> } /> {/* TODO: [Conditional render] Follow up add testing and conditional rendering when in standalone mode*/} {clusterAdmin && ( - } /> + } /> )} ); diff --git a/clients/ui/frontend/src/app/context/ModelRegistryContext.tsx b/clients/ui/frontend/src/app/context/ModelRegistryContext.tsx index 28ce82907..3b8c8de2c 100644 --- a/clients/ui/frontend/src/app/context/ModelRegistryContext.tsx +++ b/clients/ui/frontend/src/app/context/ModelRegistryContext.tsx @@ -4,6 +4,7 @@ import useQueryParamNamespaces from '~/shared/hooks/useQueryParamNamespaces'; import useModelRegistryAPIState, { ModelRegistryAPIState, } from '~/app/hooks/useModelRegistryAPIState'; +import { URL_PREFIX } from '~/shared/utilities/const'; export type ModelRegistryContextType = { apiState: ModelRegistryAPIState; @@ -26,7 +27,7 @@ export const ModelRegistryContextProvider: React.FC { const hostPath = modelRegistryName - ? `/api/${BFF_API_VERSION}/model_registry/${modelRegistryName}` + ? `${URL_PREFIX}/api/${BFF_API_VERSION}/model_registry/${modelRegistryName}` : null; const queryParams = useQueryParamNamespaces(); diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx index c59fecab8..61523b501 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionDetails/ModelVersionDetails.tsx @@ -57,7 +57,7 @@ const ModelVersionsDetails: React.FC = ({ tab, ...page ( - Model registry - {preferredModelRegistry?.name} + Model registry - {preferredModelRegistry?.name} )} /> = ({ tab, ...pageProps }) => { ( - Model registry - {preferredModelRegistry?.name} + Model registry - {preferredModelRegistry?.name} )} /> diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx index 8356589be..bce6f43d7 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ArchiveModelVersionDetailsBreadcrumb.tsx @@ -20,7 +20,7 @@ const ArchiveModelVersionDetailsBreadcrumb: React.FC ( Model registry - {preferredModelRegistry}} + render={() => Model registry - {preferredModelRegistry}} /> ( diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetailsBreadcrumb.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetailsBreadcrumb.tsx index c706fef05..065bf0053 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetailsBreadcrumb.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionArchiveDetailsBreadcrumb.tsx @@ -20,7 +20,7 @@ const ModelVersionArchiveDetailsBreadcrumb: React.FC ( Model registry - {preferredModelRegistry}} + render={() => Model registry - {preferredModelRegistry}} /> ( diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchive.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchive.tsx index e456773e9..3d57fe309 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchive.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersionsArchive/ModelVersionsArchive.tsx @@ -29,7 +29,7 @@ const ModelVersionsArchive: React.FC = ({ ...pageProp ( - Model registry - {preferredModelRegistry?.name} + Model registry - {preferredModelRegistry?.name} )} /> = ({ preferredModelRegistry, registeredModel }) => ( Model registry - {preferredModelRegistry}} + render={() => Model registry - {preferredModelRegistry}} /> ( diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchive.tsx b/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchive.tsx index 17630f394..0311e5cbb 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchive.tsx +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/RegisteredModelsArchive/RegisteredModelsArchive.tsx @@ -23,7 +23,7 @@ const RegisteredModelsArchive: React.FC = ({ ...pa ( - Model registry - {preferredModelRegistry?.name} + Model registry - {preferredModelRegistry?.name} )} /> diff --git a/clients/ui/frontend/src/app/pages/modelRegistry/screens/routeUtils.ts b/clients/ui/frontend/src/app/pages/modelRegistry/screens/routeUtils.ts index 5ff99f3b0..30d531ec5 100644 --- a/clients/ui/frontend/src/app/pages/modelRegistry/screens/routeUtils.ts +++ b/clients/ui/frontend/src/app/pages/modelRegistry/screens/routeUtils.ts @@ -1,5 +1,5 @@ export const modelRegistryUrl = (preferredModelRegistry?: string): string => - `/modelRegistry/${preferredModelRegistry}`; + `/model-registry/${preferredModelRegistry}`; export const registeredModelsUrl = (preferredModelRegistry?: string): string => `${modelRegistryUrl(preferredModelRegistry)}/registeredModels`; diff --git a/clients/ui/frontend/src/index.html b/clients/ui/frontend/src/index.html index 8c5c8cb1e..319e66d3e 100644 --- a/clients/ui/frontend/src/index.html +++ b/clients/ui/frontend/src/index.html @@ -10,7 +10,7 @@ - + diff --git a/clients/ui/frontend/src/shared/api/k8s.ts b/clients/ui/frontend/src/shared/api/k8s.ts index 1687740f5..e182ff793 100644 --- a/clients/ui/frontend/src/shared/api/k8s.ts +++ b/clients/ui/frontend/src/shared/api/k8s.ts @@ -3,13 +3,14 @@ import { handleRestFailures } from '~/shared/api/errorUtils'; import { isModelRegistryResponse, restGET } from '~/shared/api/apiUtils'; import { ModelRegistry } from '~/app/types'; import { BFF_API_VERSION } from '~/app/const'; +import { URL_PREFIX } from '~/shared/utilities/const'; import { Namespace, UserSettings } from '~/shared/types'; export const getListModelRegistries = (hostPath: string, queryParams: Record = {}) => (opts: APIOptions): Promise => handleRestFailures( - restGET(hostPath, `/api/${BFF_API_VERSION}/model_registry`, queryParams, opts), + restGET(hostPath, `${URL_PREFIX}/api/${BFF_API_VERSION}/model_registry`, queryParams, opts), ).then((response) => { if (isModelRegistryResponse(response)) { return response.data; @@ -20,23 +21,23 @@ export const getListModelRegistries = export const getUser = (hostPath: string) => (opts: APIOptions): Promise => - handleRestFailures(restGET(hostPath, `/api/${BFF_API_VERSION}/user`, {}, opts)).then( - (response) => { - if (isModelRegistryResponse(response)) { - return response.data; - } - throw new Error('Invalid response format'); - }, - ); + handleRestFailures( + restGET(hostPath, `${URL_PREFIX}/api/${BFF_API_VERSION}/user`, {}, opts), + ).then((response) => { + if (isModelRegistryResponse(response)) { + return response.data; + } + throw new Error('Invalid response format'); + }); export const getNamespaces = (hostPath: string) => (opts: APIOptions): Promise => - handleRestFailures(restGET(hostPath, `/api/${BFF_API_VERSION}/namespaces`, {}, opts)).then( - (response) => { - if (isModelRegistryResponse(response)) { - return response.data; - } - throw new Error('Invalid response format'); - }, - ); + handleRestFailures( + restGET(hostPath, `${URL_PREFIX}/api/${BFF_API_VERSION}/namespaces`, {}, opts), + ).then((response) => { + if (isModelRegistryResponse(response)) { + return response.data; + } + throw new Error('Invalid response format'); + }); diff --git a/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts b/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts index e24ce3de6..c9bb8636c 100644 --- a/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts +++ b/clients/ui/frontend/src/shared/hooks/useQueryParamNamespaces.ts @@ -1,12 +1,12 @@ import React from 'react'; import { NamespaceSelectorContext } from '~/shared/context/NamespaceSelectorContext'; import { isStandalone } from '~/shared/utilities/const'; -import { getNamespaceQueryParam } from '~/shared/api/apiUtils'; import { useDeepCompareMemoize } from '~/shared/utilities/useDeepCompareMemoize'; const useQueryParamNamespaces = (): Record => { const { preferredNamespace: namespaceSelector } = React.useContext(NamespaceSelectorContext); - const namespace = isStandalone() ? namespaceSelector?.name : getNamespaceQueryParam(); + // TODO: Readd GetNamespaceQueryParam once it's working + const namespace = isStandalone() ? namespaceSelector?.name : 'kubeflow'; return useDeepCompareMemoize({ namespace }); }; diff --git a/clients/ui/frontend/src/shared/utilities/const.ts b/clients/ui/frontend/src/shared/utilities/const.ts index eef4905f4..ddcdd7b9e 100644 --- a/clients/ui/frontend/src/shared/utilities/const.ts +++ b/clients/ui/frontend/src/shared/utilities/const.ts @@ -22,5 +22,15 @@ const AUTH_HEADER = process.env.AUTH_HEADER || 'kubeflow-userid'; const USERNAME = process.env.USERNAME || 'user@example.com'; const IMAGE_DIR = process.env.IMAGE_DIR || 'images'; const LOGO_LIGHT = process.env.LOGO || 'logo-light-theme.svg'; +const URL_PREFIX = DEPLOYMENT_MODE === DeploymentMode.Integrated ? '/model-registry' : ''; -export { POLL_INTERVAL, DEV_MODE, AUTH_HEADER, USERNAME, IMAGE_DIR, LOGO_LIGHT, MOCK_AUTH }; +export { + POLL_INTERVAL, + DEV_MODE, + AUTH_HEADER, + USERNAME, + IMAGE_DIR, + LOGO_LIGHT, + MOCK_AUTH, + URL_PREFIX, +}; diff --git a/clients/ui/manifests/base/README.md b/clients/ui/manifests/README.md similarity index 92% rename from clients/ui/manifests/base/README.md rename to clients/ui/manifests/README.md index 33b8e414e..559ec779d 100644 --- a/clients/ui/manifests/base/README.md +++ b/clients/ui/manifests/README.md @@ -79,3 +79,8 @@ Events: To fix this, you'll need to increase the amount of memory available to the VM. This can be done through either the Podman Desktop or Docker Desktop GUI. 6-8GB of memory is generally a sufficient amount to use. +## Running with Kubeflow and Istio +Alternatively, if you'd like to run the UI and BFF pods with an Istio configuration for the KF Central Dashboard, you can apply the manifests by running: +```shell +kubectl apply -k overlays/kubeflow -n kubeflow +``` \ No newline at end of file diff --git a/clients/ui/manifests/base/kustomization.yaml b/clients/ui/manifests/base/kustomization.yaml index 6ad609840..0ab619941 100644 --- a/clients/ui/manifests/base/kustomization.yaml +++ b/clients/ui/manifests/base/kustomization.yaml @@ -5,14 +5,14 @@ resources: - model-registry-bff-role.yaml - model-registry-bff-service.yaml - model-registry-bff-deployment.yaml +- model-registry-bff-service-account.yaml - model-registry-ui-service.yaml - model-registry-ui-deployment.yaml -- model-registry-service-account.yaml images: -- name: model-registry-bff-image - newName: kubeflow/model-registry-bff - newTag: latest - name: model-registry-ui-image - newName: kubeflow/model-registry-ui + newName: docker.io/kubeflow/model-registry-ui + newTag: latest +- name: model-registry-bff-image + newName: docker.io/kubeflow/model-registry-bff newTag: latest diff --git a/clients/ui/manifests/base/model-registry-service-account.yaml b/clients/ui/manifests/base/model-registry-bff-service-account.yaml similarity index 59% rename from clients/ui/manifests/base/model-registry-service-account.yaml rename to clients/ui/manifests/base/model-registry-bff-service-account.yaml index 86cbfc9b6..5cbafe203 100644 --- a/clients/ui/manifests/base/model-registry-service-account.yaml +++ b/clients/ui/manifests/base/model-registry-bff-service-account.yaml @@ -1,4 +1,5 @@ +--- kind: ServiceAccount apiVersion: v1 metadata: - name: model-registry-bff \ No newline at end of file + name: model-registry-bff diff --git a/clients/ui/manifests/base/model-registry-bff-service.yaml b/clients/ui/manifests/base/model-registry-bff-service.yaml index 20c1e0df1..929022cdb 100644 --- a/clients/ui/manifests/base/model-registry-bff-service.yaml +++ b/clients/ui/manifests/base/model-registry-bff-service.yaml @@ -2,10 +2,14 @@ apiVersion: v1 kind: Service metadata: name: model-registry-bff-service + labels: + app: model-registry-bff + run: model-registry-bff spec: selector: app: model-registry-bff ports: - protocol: TCP port: 4000 - targetPort: 4000 \ No newline at end of file + targetPort: 4000 + name: http \ No newline at end of file diff --git a/clients/ui/manifests/base/model-registry-ui-deployment.yaml b/clients/ui/manifests/base/model-registry-ui-deployment.yaml index 23c55eb07..0ef0cd6c2 100644 --- a/clients/ui/manifests/base/model-registry-ui-deployment.yaml +++ b/clients/ui/manifests/base/model-registry-ui-deployment.yaml @@ -13,7 +13,7 @@ spec: metadata: labels: app: model-registry-ui - spec: + spec: containers: - name: model-registry-ui image: model-registry-ui-image diff --git a/clients/ui/manifests/base/model-registry-ui-service.yaml b/clients/ui/manifests/base/model-registry-ui-service.yaml index 10211cd1f..c907d5918 100644 --- a/clients/ui/manifests/base/model-registry-ui-service.yaml +++ b/clients/ui/manifests/base/model-registry-ui-service.yaml @@ -2,11 +2,15 @@ apiVersion: v1 kind: Service metadata: name: model-registry-ui-service + labels: + app: model-registry-ui + run: model-registry-ui spec: selector: app: model-registry-ui ports: - - protocol: TCP + - name: http port: 8080 + protocol: TCP targetPort: 8080 - name: http + type: ClusterIP diff --git a/clients/ui/manifests/kubeflow/kubeflow-dashboard-rbac.yaml b/clients/ui/manifests/kubeflow/kubeflow-dashboard-rbac.yaml new file mode 100644 index 000000000..0b5896d6d --- /dev/null +++ b/clients/ui/manifests/kubeflow/kubeflow-dashboard-rbac.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: model-registry-retrieve-clusterrolebindings +rules: +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: model-registry-retrieve-clusterrolebindings-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: model-registry-retrieve-clusterrolebindings +subjects: +- kind: ServiceAccount + name: model-registry-bff + namespace: kubeflow +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: model-registry-create-sars +rules: +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: model-registry-create-sars-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: model-registry-create-sars +subjects: +- kind: ServiceAccount + name: model-registry-bff + namespace: kubeflow diff --git a/clients/ui/manifests/kubeflow/kustomization.yaml b/clients/ui/manifests/kubeflow/kustomization.yaml index 418e76423..64ebb3d52 100644 --- a/clients/ui/manifests/kubeflow/kustomization.yaml +++ b/clients/ui/manifests/kubeflow/kustomization.yaml @@ -1,6 +1,10 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization +resources: + - ../overlays/istio + - kubeflow-dashboard-rbac.yaml + patchesJson6902: - path: model-registry-ui-deployment.yaml target: @@ -8,7 +12,7 @@ patchesJson6902: version: v1 kind: Deployment name: model-registry-ui-deployment - - path: deployment.yaml + - path: model-registry-bff-deployment.yaml target: group: apps version: v1 diff --git a/clients/ui/manifests/kubeflow/model-registry-ui-deployment.yaml b/clients/ui/manifests/kubeflow/model-registry-ui-deployment.yaml index 1959e4bbb..ee036eea0 100644 --- a/clients/ui/manifests/kubeflow/model-registry-ui-deployment.yaml +++ b/clients/ui/manifests/kubeflow/model-registry-ui-deployment.yaml @@ -2,7 +2,7 @@ path: /spec/template/spec/containers/0/env value: - name: API_URL - value: "http://model-registry-bff-service:4000" + value: "http://model-registry-bff-service.kubeflow.svc.cluster.local:4000" - name: MOCK_AUTH value: "false" - name: DEPLOYMENT_MODE diff --git a/clients/ui/manifests/overlays/istio/authorization-policy-bff.yaml b/clients/ui/manifests/overlays/istio/authorization-policy-bff.yaml new file mode 100644 index 000000000..eed8522dd --- /dev/null +++ b/clients/ui/manifests/overlays/istio/authorization-policy-bff.yaml @@ -0,0 +1,13 @@ +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: model-registry-bff + labels: + app: model-registry-bff +spec: + action: ALLOW + rules: + - {} + selector: + matchLabels: + app: model-registry-bff diff --git a/clients/ui/manifests/overlays/istio/authorization-policy-ui.yaml b/clients/ui/manifests/overlays/istio/authorization-policy-ui.yaml new file mode 100644 index 000000000..60dd145d9 --- /dev/null +++ b/clients/ui/manifests/overlays/istio/authorization-policy-ui.yaml @@ -0,0 +1,16 @@ +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: model-registry-ui + labels: + app: model-registry-ui +spec: + action: ALLOW + rules: + - from: + - source: + principals: + - cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account + selector: + matchLabels: + app: model-registry-ui diff --git a/clients/ui/manifests/overlays/istio/destination-rule-bff.yaml b/clients/ui/manifests/overlays/istio/destination-rule-bff.yaml new file mode 100644 index 000000000..e149dc133 --- /dev/null +++ b/clients/ui/manifests/overlays/istio/destination-rule-bff.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: model-registry-bff + labels: + app: model-registry-bff +spec: + host: model-registry-bff-service.kubeflow.svc.cluster.local + trafficPolicy: + tls: + mode: ISTIO_MUTUAL diff --git a/clients/ui/manifests/overlays/istio/destination-rule-ui.yaml b/clients/ui/manifests/overlays/istio/destination-rule-ui.yaml new file mode 100644 index 000000000..330366fc2 --- /dev/null +++ b/clients/ui/manifests/overlays/istio/destination-rule-ui.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: DestinationRule +metadata: + name: model-registry-ui + labels: + app: model-registry-ui +spec: + host: model-registry-ui-service.kubeflow.svc.cluster.local + trafficPolicy: + tls: + mode: ISTIO_MUTUAL diff --git a/clients/ui/manifests/overlays/istio/kustomization.yaml b/clients/ui/manifests/overlays/istio/kustomization.yaml new file mode 100644 index 000000000..d40a96bdd --- /dev/null +++ b/clients/ui/manifests/overlays/istio/kustomization.yaml @@ -0,0 +1,17 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../base +- virtual-service.yaml +- destination-rule-ui.yaml +- destination-rule-bff.yaml +- authorization-policy-ui.yaml +- authorization-policy-bff.yaml + +patchesJson6902: + - path: model-registry-ui-service.yaml + target: + version: v1 + kind: Service + name: model-registry-ui-service \ No newline at end of file diff --git a/clients/ui/manifests/overlays/istio/model-registry-ui-service.yaml b/clients/ui/manifests/overlays/istio/model-registry-ui-service.yaml new file mode 100644 index 000000000..9bcead7b8 --- /dev/null +++ b/clients/ui/manifests/overlays/istio/model-registry-ui-service.yaml @@ -0,0 +1,3 @@ +- op: replace + path: /spec/ports/0/port + value: 80 diff --git a/clients/ui/manifests/overlays/istio/virtual-service.yaml b/clients/ui/manifests/overlays/istio/virtual-service.yaml new file mode 100644 index 000000000..109160025 --- /dev/null +++ b/clients/ui/manifests/overlays/istio/virtual-service.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: model-registry-ui + labels: + app: model-registry-ui +spec: + gateways: + - kubeflow-gateway + hosts: + - '*' + http: + - headers: + request: + add: + x-forwarded-prefix: /model-registry + match: + - uri: + prefix: /model-registry/ + rewrite: + uri: / + route: + - destination: + host: model-registry-ui-service.kubeflow.svc.cluster.local + port: + number: 80 diff --git a/clients/ui/manifests/standalone/kustomization.yaml b/clients/ui/manifests/standalone/kustomization.yaml index fda80e7db..f60c1fa46 100644 --- a/clients/ui/manifests/standalone/kustomization.yaml +++ b/clients/ui/manifests/standalone/kustomization.yaml @@ -11,7 +11,7 @@ patchesJson6902: version: v1 kind: Deployment name: model-registry-bff-deployment - - path: deployment.yaml + - path: model-registry-bff-deployment.yaml target: group: apps version: v1