From 25279b5ad3c9aac50a5adca352adc172de1754aa Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 26 Jun 2024 11:26:25 +0800 Subject: [PATCH 01/16] modify deployNIMServiceModal and AcceleratorProfileSelectField --- .../NIMServiceModal/DeployNIMServiceModal.tsx | 74 +++++++++---------- .../server/AcceleratorProfileSelectField.tsx | 31 +++++++- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx index cddda667b0..d8a1b9c121 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx @@ -163,46 +163,46 @@ const DeployNIMServiceModal: React.FC = ({ setActionInProgress(true); onSuccess(); - // const servingRuntimeName = 'nim'; + const servingRuntimeName = 'nim'; - // const submitServingRuntimeResources = getSubmitServingRuntimeResourcesFn( - // servingRuntimeSelected, - // createDataServingRuntime, - // customServingRuntimesEnabled, - // namespace, - // editInfo?.servingRuntimeEditInfo, - // false, - // acceleratorProfileState, - // NamespaceApplicationCase.KSERVE_PROMOTION, - // projectContext?.currentProject, - // servingRuntimeName, - // false, - // ); + const submitServingRuntimeResources = getSubmitServingRuntimeResourcesFn( + servingRuntimeSelected, + createDataServingRuntime, + customServingRuntimesEnabled, + namespace, + editInfo?.servingRuntimeEditInfo, + false, + acceleratorProfileState, + NamespaceApplicationCase.KSERVE_PROMOTION, + projectContext?.currentProject, + servingRuntimeName, + false, + ); - // const submitInferenceServiceResource = getSubmitInferenceServiceResourceFn( - // createDataInferenceService, - // editInfo?.inferenceServiceEditInfo, - // servingRuntimeName, - // false, - // acceleratorProfileState, - // allowCreate, - // editInfo?.secrets, - // ); + const submitInferenceServiceResource = getSubmitInferenceServiceResourceFn( + createDataInferenceService, + editInfo?.inferenceServiceEditInfo, + servingRuntimeName, + false, + acceleratorProfileState, + allowCreate, + editInfo?.secrets, + ); - // Promise.all([ - // submitServingRuntimeResources({ dryRun: true }), - // submitInferenceServiceResource({ dryRun: true }), - // ]) - // .then(() => - // Promise.all([ - // submitServingRuntimeResources({ dryRun: false }), - // submitInferenceServiceResource({ dryRun: false }), - // ]), - // ) - // .then(() => onSuccess()) - // .catch((e) => { - // setErrorModal(e); - // }); + Promise.all([ + submitServingRuntimeResources({ dryRun: true }), + submitInferenceServiceResource({ dryRun: true }), + ]) + .then(() => + Promise.all([ + submitServingRuntimeResources({ dryRun: false }), + submitInferenceServiceResource({ dryRun: false }), + ]), + ) + .then(() => onSuccess()) + .catch((e) => { + setErrorModal(e); + }); }; return ( diff --git a/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx b/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx index 5286276709..662f027f7b 100644 --- a/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx +++ b/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx @@ -206,8 +206,37 @@ const AcceleratorProfileSelectField: React.FC )} + {acceleratorProfile && ( + + + + onStep(1)} + onMinus={() => onStep(-1)} + onChange={(event) => { + if (isHTMLInputElement(event.target)) { + const newSize = Number(event.target.value); + setAcceleratorProfileState('count', Math.max(newSize, 1)); + } + }} + /> + + + + )} + {acceleratorCountWarning && ( + + + + )} ); }; -export default AcceleratorProfileSelectField; +export default AcceleratorProfileSelectField; \ No newline at end of file From 932705216d2b6e87319063d1b07abe43ce814d56 Mon Sep 17 00:00:00 2001 From: pnaik1 Date: Wed, 19 Jun 2024 14:08:28 +0530 Subject: [PATCH 02/16] upgrade patternfly packages --- frontend/package-lock.json | 342 +++++++++++++++++-------------------- frontend/package.json | 20 +-- 2 files changed, 171 insertions(+), 191 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 177a1f4edd..3ffb5a7ef9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -11,20 +11,20 @@ "dependencies": { "@openshift/dynamic-plugin-sdk": "^4.0.0", "@openshift/dynamic-plugin-sdk-utils": "^4.0.1", - "@patternfly/patternfly": "^5.2.1", - "@patternfly/quickstarts": "^5.1.0", + "@patternfly/patternfly": "^5.3.1", + "@patternfly/quickstarts": "^5.3.0", "@patternfly/react-catalog-view-extension": "^5.0.0", - "@patternfly/react-charts": "^7.1.1", - "@patternfly/react-code-editor": "^5.2.1", - "@patternfly/react-core": "^5.2.1", + "@patternfly/react-charts": "^7.3.1", + "@patternfly/react-code-editor": "^5.3.3", + "@patternfly/react-core": "^5.3.3", "@patternfly/react-drag-drop": "^5.3.3", - "@patternfly/react-icons": "^5.2.1", + "@patternfly/react-icons": "^5.3.2", "@patternfly/react-log-viewer": "^5.2.0", - "@patternfly/react-styles": "^5.2.1", - "@patternfly/react-table": "^5.2.1", - "@patternfly/react-tokens": "^5.2.1", + "@patternfly/react-styles": "^5.3.1", + "@patternfly/react-table": "^5.3.3", + "@patternfly/react-tokens": "^5.3.1", "@patternfly/react-topology": "^5.4.0-prerelease.9", - "@patternfly/react-virtualized-extension": "^5.0.0", + "@patternfly/react-virtualized-extension": "^5.1.0", "@types/classnames": "^2.3.1", "axios": "^1.6.4", "classnames": "^2.2.6", @@ -3919,14 +3919,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@patternfly/patternfly": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-5.2.1.tgz", - "integrity": "sha512-n5xFjyj1J4eIFZ7XeU6K44POKRAuDlO5yALPbn084y+jPy1j861AaQ+zIUbzCi4IzBlHrvoXVKij7p1zy7Ditg==" + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-5.3.1.tgz", + "integrity": "sha512-KYIr9pKRTzHZNGuDuaa5j5CaZyLltvotPFGG1BiJalBDBGSOyk0BZCgHLowm4txKZXrLhorEuuv9XLrMQL8eoA==" }, "node_modules/@patternfly/quickstarts": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@patternfly/quickstarts/-/quickstarts-5.1.0.tgz", - "integrity": "sha512-ql5Q8IlW+Yp1Y7rqDqrsoDhYrSv3/HTp+1BYg7n4vyOsTc9QL+PxW4+PI8mLLk/tB6Z93yS7l76b5gaACPgH2g==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@patternfly/quickstarts/-/quickstarts-5.3.0.tgz", + "integrity": "sha512-2+nKrLag8z8p9d9caQvlSMqcMGkfd8uRl54SGykpjkdp7UDT6VER/nsb4gAZkJA7udrY+yJ8EockNFY6eCiGbA==", "dependencies": { "@patternfly/react-catalog-view-extension": "^5.0.0", "dompurify": "^2.2.6", @@ -3953,32 +3953,32 @@ } }, "node_modules/@patternfly/react-charts": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-charts/-/react-charts-7.1.1.tgz", - "integrity": "sha512-X5T+wlbh+sNKIVScx3ykivu1+EIEcQvEdjv6vfyBlsBU8CzACgMRQff4buBL6um3Zv2kT4LPefd6zxoaerJdkg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@patternfly/react-charts/-/react-charts-7.3.1.tgz", + "integrity": "sha512-2E2KxfrlSOyTiK2+51tx9BOJSyvrf88Bq0ErHAzy9XKEf6JHmFIvJXSGbmrhCycJoFHR1LZqQukLyPASKiHtpw==", "dependencies": { - "@patternfly/react-styles": "^5.1.1", - "@patternfly/react-tokens": "^5.1.1", + "@patternfly/react-styles": "^5.3.1", + "@patternfly/react-tokens": "^5.3.1", "hoist-non-react-statics": "^3.3.0", - "lodash": "^4.17.19", + "lodash": "^4.17.21", "tslib": "^2.5.0", - "victory-area": "^36.6.11", - "victory-axis": "^36.6.11", - "victory-bar": "^36.6.11", - "victory-box-plot": "^36.6.11", - "victory-chart": "^36.6.11", - "victory-core": "^36.6.11", - "victory-create-container": "^36.6.11", - "victory-cursor-container": "^36.6.11", - "victory-group": "^36.6.11", - "victory-legend": "^36.6.11", - "victory-line": "^36.6.11", - "victory-pie": "^36.6.11", - "victory-scatter": "^36.6.11", - "victory-stack": "^36.6.11", - "victory-tooltip": "^36.6.11", - "victory-voronoi-container": "^36.6.11", - "victory-zoom-container": "^36.6.11" + "victory-area": "^36.9.1", + "victory-axis": "^36.9.1", + "victory-bar": "^36.9.1", + "victory-box-plot": "^36.9.1", + "victory-chart": "^36.9.1", + "victory-core": "^36.9.1", + "victory-create-container": "^36.9.1", + "victory-cursor-container": "^36.9.1", + "victory-group": "^36.9.1", + "victory-legend": "^36.9.1", + "victory-line": "^36.9.1", + "victory-pie": "^36.9.1", + "victory-scatter": "^36.9.1", + "victory-stack": "^36.9.1", + "victory-tooltip": "^36.9.1", + "victory-voronoi-container": "^36.9.1", + "victory-zoom-container": "^36.9.1" }, "peerDependencies": { "react": "^17 || ^18", @@ -3986,14 +3986,14 @@ } }, "node_modules/@patternfly/react-code-editor": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-code-editor/-/react-code-editor-5.2.1.tgz", - "integrity": "sha512-waehn8842z/yCqpN9ZEE4/RxTm3j5uFscGQ6eroC94fy6LbK+S2eiHfk1bXwTyWi0gd6FEU75S43zN4Vz9y+8A==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@patternfly/react-code-editor/-/react-code-editor-5.3.3.tgz", + "integrity": "sha512-yXKzqNzztLw1PuujQArhRM0PktU5LFuUuR9anUpzaNXMiI/n+A5JXLI1i1E3NBWg+4hs1qpjMRdWd74o0QnjEQ==", "dependencies": { "@monaco-editor/react": "^4.6.0", - "@patternfly/react-core": "^5.2.1", - "@patternfly/react-icons": "^5.2.1", - "@patternfly/react-styles": "^5.2.1", + "@patternfly/react-core": "^5.3.3", + "@patternfly/react-icons": "^5.3.2", + "@patternfly/react-styles": "^5.3.1", "react-dropzone": "14.2.3", "tslib": "^2.5.0" }, @@ -4068,14 +4068,14 @@ "integrity": "sha512-H6uBoFH3bJjD6PP75qZ4k+2TtF59vxf9sIVerPpwrGJcRgBZbvbMZCniSC3+S2LQ8DgXLnDvieq78jJzHz0hiA==" }, "node_modules/@patternfly/react-table": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-5.2.1.tgz", - "integrity": "sha512-Kcuxhh8RjcHBwLMxdnhIAGsHKjh2t5OSC8BvRSaz2hlLCFqsQf73SALjs2w8IHHnzwSZ1fTBo4js2vPPjML3gg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-5.3.3.tgz", + "integrity": "sha512-uaRmsJABvVPH8gYTh+EUcDz61knIxe9qor/VGUYDLONYBL5G3IaltwG42IsJ9jShxiwFmIPy+QARPpaadTpv5w==", "dependencies": { - "@patternfly/react-core": "^5.2.1", - "@patternfly/react-icons": "^5.2.1", - "@patternfly/react-styles": "^5.2.1", - "@patternfly/react-tokens": "^5.2.1", + "@patternfly/react-core": "^5.3.3", + "@patternfly/react-icons": "^5.3.2", + "@patternfly/react-styles": "^5.3.1", + "@patternfly/react-tokens": "^5.3.1", "lodash": "^4.17.19", "tslib": "^2.5.0" }, @@ -4116,13 +4116,13 @@ } }, "node_modules/@patternfly/react-virtualized-extension": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@patternfly/react-virtualized-extension/-/react-virtualized-extension-5.0.0.tgz", - "integrity": "sha512-1DWr5KbIuQojVKEkyQpYOj310A1zlH82twQoV783vsjaAwfo6GDKd8PBSzthA3z+F8p1Yx2bNjjdun0qABtZTQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@patternfly/react-virtualized-extension/-/react-virtualized-extension-5.1.0.tgz", + "integrity": "sha512-qCBi5PeAiR54BqXcLHHG5eX4WMohGmSWgLUgENbV4NFyTOarJRzpErNb6Vx5L9D3w9p6Np17UVVnn0eH1pBKcw==", "dependencies": { - "@patternfly/react-core": "^5.0.0", - "@patternfly/react-icons": "^5.0.0", - "@patternfly/react-styles": "^5.0.0", + "@patternfly/react-core": "^5.1.1", + "@patternfly/react-icons": "^5.1.1", + "@patternfly/react-styles": "^5.1.1", "linear-layout-vector": "0.0.1", "react-virtualized": "^9.22.5", "tslib": "^2.5.2" @@ -22848,277 +22848,259 @@ "dev": true }, "node_modules/victory-area": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-area/-/victory-area-36.6.11.tgz", - "integrity": "sha512-M/wQ0ryms6WpqGzpv+BMNfCLy0dlOtIxAuYgXJYwwDu55noAMbWlFahIzfllpjTmFOyCpCXF7EDraC3n2xRRFQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-area/-/victory-area-36.9.2.tgz", + "integrity": "sha512-32aharvPf2RgdQB+/u1j3/ajYFNH/7ugLX9ZRpdd65gP6QEbtXL+58gS6CxvFw6gr/y8a0xMlkMKkpDVacXLpw==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11", - "victory-vendor": "^36.6.11" + "victory-core": "^36.9.2", + "victory-vendor": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-axis": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-axis/-/victory-axis-36.6.11.tgz", - "integrity": "sha512-f2PUbEsE5wYXKRrgSYdoPRV6QXKNrZjTcd8YlymVGWsouJEFRZFOig8N3yU5lM7OuP98tOdurk4I91Py6NlXrA==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-axis/-/victory-axis-36.9.2.tgz", + "integrity": "sha512-4Odws+IAjprJtBg2b2ZCxEPgrQ6LgIOa22cFkGghzOSfTyNayN4M3AauNB44RZyn2O/hDiM1gdBkEg1g9YDevQ==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-bar": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-bar/-/victory-bar-36.6.11.tgz", - "integrity": "sha512-ANXZIYiDcvC1k3fvGbE8qHOi0POGOsYbzTgP/SBHXh9VQYa/NaYGZT3RO1mxp8wgpwaF+NZYZNC8mMO1pvcB2w==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-bar/-/victory-bar-36.9.2.tgz", + "integrity": "sha512-R3LFoR91FzwWcnyGK2P8DHNVv9gsaWhl5pSr2KdeNtvLbZVEIvUkTeVN9RMBMzterSFPw0mbWhS1Asb3sV6PPw==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11", - "victory-vendor": "^36.6.11" + "victory-core": "^36.9.2", + "victory-vendor": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-box-plot": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-box-plot/-/victory-box-plot-36.6.11.tgz", - "integrity": "sha512-+J7Hb0Vf6cQe+qZyRhm6sM7V7AMS43jSTXnrFtRP7Bn+HdAb7p2S7h8abtgUhg3uVeTQa9UUqJBmC/maP8V3Nw==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-box-plot/-/victory-box-plot-36.9.2.tgz", + "integrity": "sha512-nUD45V/YHDkAKZyak7YDsz+Vk1F9N0ica3jWQe0AY0JqD9DleHa8RY/olSVws26kLyEj1I+fQqva6GodcLaIqQ==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11", - "victory-vendor": "^36.6.11" + "victory-core": "^36.9.2", + "victory-vendor": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-brush-container": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-brush-container/-/victory-brush-container-36.6.11.tgz", - "integrity": "sha512-o0pPKzfQhKRlYNYUx3tHjuv9iTXqvgRtmu59L/h6l11DPaRo+jcHDBKEDRuoZxTinR/a1yqfLEJ1i9QgSE8o6w==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-brush-container/-/victory-brush-container-36.9.2.tgz", + "integrity": "sha512-KcQjzFeo40tn52cJf1A02l5MqeR9GKkk3loDqM3T2hfi1PCyUrZXEUjGN5HNlLizDRvtcemaAHNAWlb70HbG/g==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-chart": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-chart/-/victory-chart-36.6.11.tgz", - "integrity": "sha512-t4RIeLT6PJxZaDqNeawtIPxuA48k98kBvYbEV9XEPrS3TPAYsrB6lgXjZKLoItYLh63Ry4nqZAnPti4RD0uTfQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-chart/-/victory-chart-36.9.2.tgz", + "integrity": "sha512-dMNcS0BpqL3YiGvI4BSEmPR76FCksCgf3K4CSZ7C/MGyrElqB6wWwzk7afnlB1Qr71YIHXDmdwsPNAl/iEwTtA==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-axis": "^36.6.11", - "victory-core": "^36.6.11", - "victory-polar-axis": "^36.6.11", - "victory-shared-events": "^36.6.11" + "victory-axis": "^36.9.2", + "victory-core": "^36.9.2", + "victory-polar-axis": "^36.9.2", + "victory-shared-events": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-core": { - "version": "36.8.3", - "resolved": "https://registry.npmjs.org/victory-core/-/victory-core-36.8.3.tgz", - "integrity": "sha512-dqU7qywnWBoumGg5vF1XHcfQ85m0U0HmomBbuRcVlv3APHKFYUiolDeKIUoBEc/MCYWvoXK+5VGhL6bxuX71Yg==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-core/-/victory-core-36.9.2.tgz", + "integrity": "sha512-AzmMy+9MYMaaRmmZZovc/Po9urHne3R3oX7bbXeQdVuK/uMBrlPiv11gVJnuEH2SXLVyep43jlKgaBp8ef9stQ==", "dependencies": { "lodash": "^4.17.21", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-vendor": "^36.8.3" + "victory-vendor": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-create-container": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-create-container/-/victory-create-container-36.6.11.tgz", - "integrity": "sha512-Ve96DE9XDifmT2Bh/6Ptz7cgIV5DC2GYsr0Rl6I0sF6S02IH3V02NLpkcTthTRJHAvC9MkHwjiBlvFEZsXHOtg==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-create-container/-/victory-create-container-36.9.2.tgz", + "integrity": "sha512-uA0dh1R0YDzuXyE/7StZvq4qshet+WYceY7R1UR5mR/F9079xy+iQsa2Ca4h97/GtVZoLO6r1eKLWBt9TN+U7A==", "dependencies": { "lodash": "^4.17.19", - "victory-brush-container": "^36.6.11", - "victory-core": "^36.6.11", - "victory-cursor-container": "^36.6.11", - "victory-selection-container": "^36.6.11", - "victory-voronoi-container": "^36.6.11", - "victory-zoom-container": "^36.6.11" + "victory-brush-container": "^36.9.2", + "victory-core": "^36.9.2", + "victory-cursor-container": "^36.9.2", + "victory-selection-container": "^36.9.2", + "victory-voronoi-container": "^36.9.2", + "victory-zoom-container": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-cursor-container": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-cursor-container/-/victory-cursor-container-36.6.11.tgz", - "integrity": "sha512-rdQAZb3RGYfijjqIQkuPGLNY5UOhuqyzlxQFaVtkpkDSZKiPMtbfLvR7F0Yfa9cs8OeQU0KAtAiK8R33o7su/Q==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-cursor-container/-/victory-cursor-container-36.9.2.tgz", + "integrity": "sha512-jidab4j3MaciF3fGX70jTj4H9rrLcY8o2LUrhJ67ZLvEFGGmnPtph+p8Fe97Umrag7E/DszjNxQZolpwlgUh3g==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-group": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-group/-/victory-group-36.6.11.tgz", - "integrity": "sha512-PTRrH31gsGk3KFzeTzAkyvgjtilWYHWkx06oouh70KuAJ7f+9pRMrRMal8v+npH6a8Wp0KKW198AqpkPaZqHyQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-group/-/victory-group-36.9.2.tgz", + "integrity": "sha512-wBmpsjBTKva8mxHvHNY3b8RE58KtnpLLItEyyAHaYkmExwt3Uj8Cld3sF3vmeuijn2iR64NPKeMbgMbfZJzycw==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-core": "^36.6.11", - "victory-shared-events": "^36.6.11" + "victory-core": "^36.9.2", + "victory-shared-events": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-legend": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-legend/-/victory-legend-36.6.11.tgz", - "integrity": "sha512-eL310Qh3WcZyjFI18hABVodwHpgZtokHD3r5HKpgZVY8MWkMD9mXErphWbkNHTVi5ya+I3QbRQ7ToRbPUl/Jog==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-legend/-/victory-legend-36.9.2.tgz", + "integrity": "sha512-cucFJpv6fty+yXp5pElQFQnHBk1TqA4guGUMI+XF/wLlnuM4bhdAtASobRIIBkz0mHGBaCAAV4PzL9azPU/9dg==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-line": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-line/-/victory-line-36.6.11.tgz", - "integrity": "sha512-SDQCS6qDSixnYPB1kHEQsue06N6x2cxkIA6uqL45LRFMkKWG4OtwTBORVhtK6lfKzq1OvJs3msoZ+uoRIW1gaA==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-line/-/victory-line-36.9.2.tgz", + "integrity": "sha512-kmYFZUo0o2xC8cXRsmt/oUBRQSZJVT2IJnAkboUepypoj09e6CY5tRH4TSdfEDGkBk23xQkn7d4IFgl4kAGnSA==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11", - "victory-vendor": "^36.6.11" + "victory-core": "^36.9.2", + "victory-vendor": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-pie": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-pie/-/victory-pie-36.6.11.tgz", - "integrity": "sha512-vQPAzrubo3BX/1pujSlKKTBGNSj/8fxUJ0vSZPZ6EE1y6SRnPJoLYi2OkDQVT1s3rM9xvW00SflCD3GO/Z3xWA==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-pie/-/victory-pie-36.9.2.tgz", + "integrity": "sha512-i3zWezvy5wQEkhXKt4rS9ILGH7Vr9Q5eF9fKO4GMwDPBdYOTE3Dh2tVaSrfDC8g9zFIc0DKzOtVoJRTb+0AkPg==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11", - "victory-vendor": "^36.6.11" + "victory-core": "^36.9.2", + "victory-vendor": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-polar-axis": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-polar-axis/-/victory-polar-axis-36.6.11.tgz", - "integrity": "sha512-wDkyY1rKQTRUVt4+e0QNQgSIJCqXazNhkjWXla8ZWj52GzPP/QSDuzr8SO1oHA3++1jOpdD0R2FTxm+pAea/Yw==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-polar-axis/-/victory-polar-axis-36.9.2.tgz", + "integrity": "sha512-HBR90FF4M56yf/atXjSmy3DMps1vSAaLXmdVXLM/A5g+0pUS7HO719r5x6dsR3I6Rm+8x6Kk8xJs0qgpnGQIEw==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-scatter": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-scatter/-/victory-scatter-36.6.11.tgz", - "integrity": "sha512-x46AfmhiKijXe59kqm7xI0CCjbY8J0VB02HUN3TynMx7xzhW2yOP+QQqgyk+C4im/MS33HKU402Q7cUfF3pgtw==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-scatter/-/victory-scatter-36.9.2.tgz", + "integrity": "sha512-hK9AtbJQfaW05i8BH7Lf1HK7vWMAfQofj23039HEQJqTKbCL77YT+Q0LhZw1a1BRCpC/5aSg9EuqblhfIYw2wg==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-selection-container": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-selection-container/-/victory-selection-container-36.6.11.tgz", - "integrity": "sha512-pRQz++0ERZVuIgxpmqLkDgf6hiCAS2m8iGcox8tryWzE1NpADG/IJiHh3AeJgGeiLNMeoJ48hsOZP1C9CCxwrQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-selection-container/-/victory-selection-container-36.9.2.tgz", + "integrity": "sha512-chboroEwqqVlMB60kveXM2WznJ33ZM00PWkFVCoJDzHHlYs7TCADxzhqet2S67SbZGSyvSprY2YztSxX8kZ+XQ==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-shared-events": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-shared-events/-/victory-shared-events-36.6.11.tgz", - "integrity": "sha512-ia6ijfgfYMb+gGFPEq4F6rqzB9p5EkjKpjvmEv4Ww7VjrtdORu7PPfAgTxXw/9QgFSq4iOUnDtzjObABua09fQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-shared-events/-/victory-shared-events-36.9.2.tgz", + "integrity": "sha512-W/atiw3Or6MnpBuhluFv6007YrixIRh5NtiRvtFLGxNuQJLYjaSh6koRAih5xJer5Pj7YUx0tL9x67jTRcJ6Dg==", "dependencies": { "json-stringify-safe": "^5.0.1", "lodash": "^4.17.19", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-stack": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-stack/-/victory-stack-36.6.11.tgz", - "integrity": "sha512-kE/915RdcKes69WpxZ5j6MyCIJqdzIZnzIg6OArBeDlD+LuinNb2oNxYpMXzur1KFSyk5PCUckHgEbR2XLoXrw==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-stack/-/victory-stack-36.9.2.tgz", + "integrity": "sha512-imR6FniVlDFlBa/B3Est8kTryNhWj2ZNpivmVOebVDxkKcVlLaDg3LotCUOI7NzOhBQaro0UzeE9KmZV93JcYA==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-core": "^36.6.11", - "victory-shared-events": "^36.6.11" + "victory-core": "^36.9.2", + "victory-shared-events": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-tooltip": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-tooltip/-/victory-tooltip-36.6.11.tgz", - "integrity": "sha512-YxAPkGAqTYOIW4aE5InGFABmYjiBfuQFjCe9hwFGvIC/Uqn202xgs5kYVEZXUX3vc9W8XOl7plaQJzmtr2ZZBQ==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-tooltip/-/victory-tooltip-36.9.2.tgz", + "integrity": "sha512-76seo4TWD1WfZHJQH87IP3tlawv38DuwrUxpnTn8+uW6/CUex82poQiVevYdmJzhataS9jjyCWv3w7pOmLBCLg==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-vendor": { - "version": "36.8.3", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.8.3.tgz", - "integrity": "sha512-G2aakSDHt2fXA1FQxxLnZ/K7Fnwf1swUIUDGiKxONXeilhncgS5upVX3hm2X8kouGPpMpDUCVCrjbk6bU4uYCw==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", @@ -23137,29 +23119,27 @@ } }, "node_modules/victory-voronoi-container": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-voronoi-container/-/victory-voronoi-container-36.6.11.tgz", - "integrity": "sha512-KNB814e5uhs00oNFdkPucXMlpNILnWabHM7iKLBz26nlgqiu6dctZZoWU+HKjxbPkHdic6JQsg28Nk5bThaulw==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-voronoi-container/-/victory-voronoi-container-36.9.2.tgz", + "integrity": "sha512-NIVYqck9N4OQnEz9mgQ4wILsci3OBWWK7RLuITGHyoD7Ne/+WH1i0Pv2y9eIx+f55rc928FUTugPPhkHvXyH3A==", "dependencies": { "delaunay-find": "0.0.6", "lodash": "^4.17.19", - "prop-types": "^15.8.1", "react-fast-compare": "^3.2.0", - "victory-core": "^36.6.11", - "victory-tooltip": "^36.6.11" + "victory-core": "^36.9.2", + "victory-tooltip": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" } }, "node_modules/victory-zoom-container": { - "version": "36.6.11", - "resolved": "https://registry.npmjs.org/victory-zoom-container/-/victory-zoom-container-36.6.11.tgz", - "integrity": "sha512-DRS12HZEmy5oJanlnSK9Wtp/6HQQbwvK0idVU+Lhf2lw3r9gauWp/ymWwWzaHd7Mn5cCODuNW1le2bqb71j3wg==", + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-zoom-container/-/victory-zoom-container-36.9.2.tgz", + "integrity": "sha512-pXa2Ji6EX/pIarKT6Hcmmu2n7IG/x8Vs0D2eACQ/nbpvZa+DXWIxCRW4hcg2Va35fmXcDIEpGaX3/soXzZ+pbw==", "dependencies": { "lodash": "^4.17.19", - "prop-types": "^15.8.1", - "victory-core": "^36.6.11" + "victory-core": "^36.9.2" }, "peerDependencies": { "react": ">=16.6.0" diff --git a/frontend/package.json b/frontend/package.json index 49d42f0ab1..ea20c525ec 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,20 +54,20 @@ "dependencies": { "@openshift/dynamic-plugin-sdk": "^4.0.0", "@openshift/dynamic-plugin-sdk-utils": "^4.0.1", - "@patternfly/patternfly": "^5.2.1", - "@patternfly/quickstarts": "^5.1.0", + "@patternfly/patternfly": "^5.3.1", + "@patternfly/quickstarts": "^5.3.0", "@patternfly/react-catalog-view-extension": "^5.0.0", - "@patternfly/react-charts": "^7.1.1", - "@patternfly/react-code-editor": "^5.2.1", - "@patternfly/react-core": "^5.2.1", + "@patternfly/react-charts": "^7.3.1", + "@patternfly/react-code-editor": "^5.3.3", + "@patternfly/react-core": "^5.3.3", "@patternfly/react-drag-drop": "^5.3.3", - "@patternfly/react-icons": "^5.2.1", + "@patternfly/react-icons": "^5.3.2", "@patternfly/react-log-viewer": "^5.2.0", - "@patternfly/react-styles": "^5.2.1", - "@patternfly/react-table": "^5.2.1", - "@patternfly/react-tokens": "^5.2.1", + "@patternfly/react-styles": "^5.3.1", + "@patternfly/react-table": "^5.3.3", + "@patternfly/react-tokens": "^5.3.1", "@patternfly/react-topology": "^5.4.0-prerelease.9", - "@patternfly/react-virtualized-extension": "^5.0.0", + "@patternfly/react-virtualized-extension": "^5.1.0", "@types/classnames": "^2.3.1", "axios": "^1.6.4", "classnames": "^2.2.6", From d58b7da67138b75ee61ca3844de0673e5810426e Mon Sep 17 00:00:00 2001 From: manosnoam Date: Mon, 10 Jun 2024 15:47:39 +0300 Subject: [PATCH 03/16] Create Dockerfile for running Cypress in CI In order to run Cypress tests in CI (Jenkins) a designated Dockerfile was added to /scripts/ci. It is based on Fedora 40 image (from Quay), and it uses NVM (Node Version Manager) to install Node v20. It is a rootless image that is supported to be running within Openshift and Podman. Building and Testing: To build the Dockerfile with Podman, run for example: `podman build --pull --rm -f "scripts/ci/Dockerfile" -t odh-cypress:latest ./` You can find such image builds, including build logs in Quay: https://quay.io/repository/nmanos/odh-dashboard?tab=builds Once the image build completed, you can pull it, for example from Quay: podman pull quay.io/nmanos/odh-dashboard:latest The image can then be consumed within a CI framework, such as Jenkins, that uses Containers for its execution runtime (e.g. with K8s plugin). Within the container runtime you can git clone `odh-dashboard` and then run 'frontend` Cypress tests (on the preinstalled Chrome). For example: ```` npm --verbose --prefix frontend ci") npm --verbose run test:cypress-ci -- -s '**/application.cy.ts'" ``` The Cypress test results and the HTML report will be created as well. Signed-off-by: manosnoam --- scripts/ci/Dockerfile | 78 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 scripts/ci/Dockerfile diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile new file mode 100644 index 0000000000..17817d5b5b --- /dev/null +++ b/scripts/ci/Dockerfile @@ -0,0 +1,78 @@ +FROM quay.io/fedora/fedora:40 + +ARG USER=cypress +ARG USER_HOME=/home/$USER +ARG NPM_CACHE=/opt/app-root/src/.npm-global +ARG CYPRESS_CACHE=/home/jenkins/.cypress-cache +ARG CHROME=https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm +ARG OCP_CLI=https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/openshift-client-linux.tar.gz +ARG NVM_INSTALLER=https://raw.githubusercontent.com/creationix/nvm/v0.39.7/install.sh +ARG NODE_VERSION=v20.10.0 + +USER root + +# Add local user to avoid permissions issues during job execution +RUN mkdir -p "$USER_HOME" +RUN useradd -m -g root "$USER" -d "$USER_HOME" --uid 1000 +RUN chgrp -R 0 "$USER_HOME" +RUN chmod -R g=u "$USER_HOME" +RUN mkdir -p $NPM_CACHE +RUN chgrp -R 0 "$NPM_CACHE" +RUN chmod -R 777 $NPM_CACHE + +# Install tools including Xvfb and Chrome +RUN dnf update -y +RUN dnf install --nodocs -y \ + wget \ + unzip \ + xz \ + jq \ + git \ + xorg-x11-server-Xvfb \ + "$CHROME" + +# Install OCP client +RUN wget -qO- "$OCP_CLI" | tar zxv -C /usr/local/bin/ oc kubectl + +# Clean system cache +RUN dnf clean all +RUN rm -rf /var/cache/yum + +# Set capability to adjust OOM score for Node +RUN echo CAP_SYS_NICE >> /etc/security/limits.conf + +# Copy NodeJS package.json from "frontend" directory +WORKDIR $USER_HOME +COPY ./frontend/package*.json ./ +RUN chown $USER:0 ./* + +# Switch to the user, export env variables, and prepare NVM directories +USER $USER +ENV USER $USER +ENV HOME $USER_HOME +ENV NVM_DIR $USER_HOME/nvm +ENV NODE_PATH "$NVM_DIR/versions/node/$NODE_VERSION/lib/node_modules" +ENV PATH "$NVM_DIR/versions/node/$NODE_VERSION/bin:/bin:$HOME/.local/bin:/root/.local/bin:$PATH" +RUN mkdir -p $NVM_DIR + +# Install Node Version Manager, Node Package Manager, and the "frontend" packages +RUN curl -o- $NVM_INSTALLER | bash +RUN /bin/bash -c "source $NVM_DIR/nvm.sh && \ + nvm install $NODE_VERSION && \ + nvm use --delete-prefix $NODE_VERSION && \ + npm config set prefix '$NPM_CACHE' && \ + echo 'export PATH=$PATH' >> '$USER_HOME/.profile' && \ + source $USER_HOME/.profile && \ + npm install -g npm@latest && \ + npm cache -g clean --force" + +# Export NPM and Cypress Cache directories (to be accesible by rootless user) +ENV NPM_CONFIG_CACHE $NPM_CACHE +ENV CYPRESS_CACHE_FOLDER $CYPRESS_CACHE + +# Label the Image +LABEL io.opendatahub.component="odh-cypress" \ + io.k8s.display-name="odh-cypress" \ + name="open-data-hub/odh-cypress" \ + summary="odh-cypress" \ + description="Image for Running Cypress Tests for Open Data Hub Dashboard" From 480a0cbca88a6e280c90f1c87280128d286a0c21 Mon Sep 17 00:00:00 2001 From: Robert Sun <107655677+rsun19@users.noreply.github.com> Date: Thu, 20 Jun 2024 23:45:10 -0400 Subject: [PATCH 04/16] refactored k8 resources --- .../api/k8s/__tests__/clusterQueues.spec.ts | 15 +- .../src/api/k8s/__tests__/configMaps.spec.ts | 42 +--- .../k8s/__tests__/inferenceServices.spec.ts | 35 +--- .../src/api/k8s/__tests__/localQueues.spec.ts | 15 +- .../src/api/k8s/__tests__/projects.spec.ts | 12 +- frontend/src/api/k8s/__tests__/pvcs.spec.ts | 19 +- .../api/k8s/__tests__/roleBindings.spec.ts | 78 ++----- .../src/api/k8s/__tests__/secrets.spec.ts | 23 ++- .../api/k8s/__tests__/servingRuntimes.spec.ts | 190 +++--------------- .../src/api/k8s/__tests__/workloads.spec.ts | 15 +- .../src/api/pipelines/__tests__/k8s.spec.ts | 65 ++---- .../storage/__tests__/useProjectPvcs.spec.ts | 7 +- 12 files changed, 102 insertions(+), 414 deletions(-) diff --git a/frontend/src/api/k8s/__tests__/clusterQueues.spec.ts b/frontend/src/api/k8s/__tests__/clusterQueues.spec.ts index ba6fcd1aac..0c550fa753 100644 --- a/frontend/src/api/k8s/__tests__/clusterQueues.spec.ts +++ b/frontend/src/api/k8s/__tests__/clusterQueues.spec.ts @@ -2,6 +2,7 @@ import { k8sListResourceItems } from '@openshift/dynamic-plugin-sdk-utils'; import { mockClusterQueueK8sResource } from '~/__mocks__/mockClusterQueueK8sResource'; import { ClusterQueueKind } from '~/k8sTypes'; import { listClusterQueues } from '~/api/k8s/clusterQueues'; +import { ClusterQueueModel } from '~/api/models/kueue'; jest.mock('@openshift/dynamic-plugin-sdk-utils', () => ({ k8sListResourceItems: jest.fn(), @@ -16,12 +17,7 @@ describe('listClusterQueues', () => { k8sListResourceItemsMock.mockResolvedValue([clusterQueueMock]); const result = await listClusterQueues(); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'kueue.x-k8s.io', - apiVersion: 'v1beta1', - kind: 'ClusterQueue', - plural: 'clusterqueues', - }, + model: ClusterQueueModel, queryOptions: {}, }); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); @@ -33,12 +29,7 @@ describe('listClusterQueues', () => { await expect(listClusterQueues()).rejects.toThrow('error1'); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'kueue.x-k8s.io', - apiVersion: 'v1beta1', - kind: 'ClusterQueue', - plural: 'clusterqueues', - }, + model: ClusterQueueModel, queryOptions: {}, }); }); diff --git a/frontend/src/api/k8s/__tests__/configMaps.spec.ts b/frontend/src/api/k8s/__tests__/configMaps.spec.ts index b685ce909c..bd712f9527 100644 --- a/frontend/src/api/k8s/__tests__/configMaps.spec.ts +++ b/frontend/src/api/k8s/__tests__/configMaps.spec.ts @@ -92,11 +92,7 @@ describe('createConfigMap', () => { expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { queryParams: {} }, resource: configMapMock, }); @@ -112,11 +108,7 @@ describe('createConfigMap', () => { expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { queryParams: {} }, resource: configMapMock, }); @@ -133,11 +125,7 @@ describe('replaceConfigMap', () => { expect(k8sUpdateResourceMock).toHaveBeenCalledTimes(1); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { queryParams: {} }, resource: configMapMock, }); @@ -153,11 +141,7 @@ describe('replaceConfigMap', () => { expect(k8sUpdateResourceMock).toHaveBeenCalledTimes(1); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { queryParams: {} }, resource: configMapMock, }); @@ -174,11 +158,7 @@ describe('deleteConfigMap', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { name: configMapName, ns: namespace, @@ -196,11 +176,7 @@ describe('deleteConfigMap', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { name: configMapName, ns: namespace, @@ -216,11 +192,7 @@ describe('deleteConfigMap', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiVersion: 'v1', - kind: 'ConfigMap', - plural: 'configmaps', - }, + model: ConfigMapModel, queryOptions: { name: configMapName, ns: namespace, diff --git a/frontend/src/api/k8s/__tests__/inferenceServices.spec.ts b/frontend/src/api/k8s/__tests__/inferenceServices.spec.ts index 9810d8973f..5b4da94a1e 100644 --- a/frontend/src/api/k8s/__tests__/inferenceServices.spec.ts +++ b/frontend/src/api/k8s/__tests__/inferenceServices.spec.ts @@ -328,12 +328,7 @@ describe('listInferenceService', () => { expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1beta1', - kind: 'InferenceService', - plural: 'inferenceservices', - }, + model: InferenceServiceModel, queryOptions: { queryParams: {} }, }); }); @@ -344,12 +339,7 @@ describe('listInferenceService', () => { expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1beta1', - kind: 'InferenceService', - plural: 'inferenceservices', - }, + model: InferenceServiceModel, queryOptions: { queryParams: {} }, }); }); @@ -598,12 +588,7 @@ describe('deleteInferenceService', () => { fetchOptions: { requestInit: {}, }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1beta1', - kind: 'InferenceService', - plural: 'inferenceservices', - }, + model: InferenceServiceModel, queryOptions: { name: 'test', ns: 'test-project', @@ -622,12 +607,7 @@ describe('deleteInferenceService', () => { fetchOptions: { requestInit: {}, }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1beta1', - kind: 'InferenceService', - plural: 'inferenceservices', - }, + model: InferenceServiceModel, queryOptions: { name: 'test', ns: 'test-project', @@ -645,12 +625,7 @@ describe('deleteInferenceService', () => { fetchOptions: { requestInit: {}, }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1beta1', - kind: 'InferenceService', - plural: 'inferenceservices', - }, + model: InferenceServiceModel, queryOptions: { name: 'test', ns: 'test-project', diff --git a/frontend/src/api/k8s/__tests__/localQueues.spec.ts b/frontend/src/api/k8s/__tests__/localQueues.spec.ts index dc36c9beb1..8ffa77e590 100644 --- a/frontend/src/api/k8s/__tests__/localQueues.spec.ts +++ b/frontend/src/api/k8s/__tests__/localQueues.spec.ts @@ -2,6 +2,7 @@ import { k8sListResourceItems } from '@openshift/dynamic-plugin-sdk-utils'; import { mockLocalQueueK8sResource } from '~/__mocks__/mockLocalQueueK8sResource'; import { LocalQueueKind } from '~/k8sTypes'; import { listLocalQueues } from '~/api/k8s/localQueues'; +import { LocalQueueModel } from '~/api/models/kueue'; jest.mock('@openshift/dynamic-plugin-sdk-utils', () => ({ k8sListResourceItems: jest.fn(), @@ -19,12 +20,7 @@ describe('listLocalQueues', () => { k8sListResourceItemsMock.mockResolvedValue([mockedLocalQueue]); const result = await listLocalQueues('test-project'); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'kueue.x-k8s.io', - apiVersion: 'v1beta1', - kind: 'LocalQueue', - plural: 'localqueues', - }, + model: LocalQueueModel, queryOptions: { ns: 'test-project' }, }); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); @@ -36,12 +32,7 @@ describe('listLocalQueues', () => { await expect(listLocalQueues('test-project')).rejects.toThrow('error1'); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'kueue.x-k8s.io', - apiVersion: 'v1beta1', - kind: 'LocalQueue', - plural: 'localqueues', - }, + model: LocalQueueModel, queryOptions: { ns: 'test-project' }, }); }); diff --git a/frontend/src/api/k8s/__tests__/projects.spec.ts b/frontend/src/api/k8s/__tests__/projects.spec.ts index 297f7a578f..a6a863a65f 100644 --- a/frontend/src/api/k8s/__tests__/projects.spec.ts +++ b/frontend/src/api/k8s/__tests__/projects.spec.ts @@ -17,7 +17,7 @@ import { updateProject, useProjects, } from '~/api/k8s/projects'; -import { ProjectModel } from '~/api/models'; +import { ProjectModel, ProjectRequestModel } from '~/api/models'; import { ODH_PRODUCT_NAME } from '~/utilities/const'; import { NamespaceApplicationCase } from '~/pages/projects/types'; import { ProjectKind } from '~/k8sTypes'; @@ -118,12 +118,6 @@ describe('createProject', () => { applied, }, }); - const projectRequest = { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'ProjectRequest', - plural: 'projectrequests', - }; it('should create a project when k8s name is given', async () => { const projectMock = mockProjectK8sResource({ k8sName }); @@ -133,7 +127,7 @@ describe('createProject', () => { expect(result).toStrictEqual(k8sName); expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ - model: projectRequest, + model: ProjectRequestModel, resource: { apiVersion: 'project.openshift.io/v1', kind: 'ProjectRequest', @@ -156,7 +150,7 @@ describe('createProject', () => { expect(result).toStrictEqual(displayName); expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ - model: projectRequest, + model: ProjectRequestModel, resource: { apiVersion: 'project.openshift.io/v1', kind: 'ProjectRequest', diff --git a/frontend/src/api/k8s/__tests__/pvcs.spec.ts b/frontend/src/api/k8s/__tests__/pvcs.spec.ts index 54ba19c8c4..b645fce99b 100644 --- a/frontend/src/api/k8s/__tests__/pvcs.spec.ts +++ b/frontend/src/api/k8s/__tests__/pvcs.spec.ts @@ -8,6 +8,7 @@ import { import { mock200Status, mock404Error } from '~/__mocks__/mockK8sStatus'; import { mockPVCK8sResource } from '~/__mocks__/mockPVCK8sResource'; import { assemblePvc, createPvc, deletePvc, getDashboardPvcs, updatePvc } from '~/api/k8s/pvcs'; +import { PVCModel } from '~/api/models/k8s'; import { PersistentVolumeClaimKind } from '~/k8sTypes'; import { CreatingStorageObject } from '~/pages/projects/types'; @@ -80,7 +81,7 @@ describe('getDashboardPvcs', () => { k8sListResourceItemsMock.mockResolvedValue([pvcMock]); const result = await getDashboardPvcs('projectName'); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { ns: 'projectName', queryParams: { labelSelector: 'opendatahub.io/dashboard=true' }, @@ -94,7 +95,7 @@ describe('getDashboardPvcs', () => { await expect(getDashboardPvcs('projectName')).rejects.toThrow('error1'); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { ns: 'projectName', queryParams: { labelSelector: 'opendatahub.io/dashboard=true' }, @@ -109,7 +110,7 @@ describe('createPvc', () => { const result = await createPvc(data, 'namespace'); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { queryParams: {} }, resource: createAssemblePvcs(['ReadWriteOnce']), }); @@ -122,7 +123,7 @@ describe('createPvc', () => { await expect(createPvc(data, 'namespace')).rejects.toThrow('error1'); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { queryParams: {} }, resource: createAssemblePvcs(['ReadWriteOnce']), }); @@ -136,7 +137,7 @@ describe('updatePvc', () => { const result = await updatePvc(data, assemblePvcResult, 'namespace'); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { queryParams: {} }, resource: createAssemblePvcs(['ReadWriteOnce']), }); @@ -150,7 +151,7 @@ describe('updatePvc', () => { expect(k8sUpdateResourceMock).toHaveBeenCalledTimes(1); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { queryParams: {} }, resource: createAssemblePvcs(['ReadWriteOnce']), }); @@ -163,7 +164,7 @@ describe('deletePvc', () => { k8sDeleteResourceMock.mockResolvedValue(mockK8sStatus); const result = await deletePvc('pvcName', 'namespace'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { name: 'pvcName', ns: 'namespace' }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -175,7 +176,7 @@ describe('deletePvc', () => { k8sDeleteResourceMock.mockResolvedValue(mockK8sStatus); const result = await deletePvc('pvcName', 'namespace'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { name: 'pvcName', ns: 'namespace' }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -187,7 +188,7 @@ describe('deletePvc', () => { await expect(deletePvc('pvcName', 'namespace')).rejects.toThrow('error1'); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ - model: { apiVersion: 'v1', kind: 'PersistentVolumeClaim', plural: 'persistentvolumeclaims' }, + model: PVCModel, queryOptions: { name: 'pvcName', ns: 'namespace' }, }); }); diff --git a/frontend/src/api/k8s/__tests__/roleBindings.spec.ts b/frontend/src/api/k8s/__tests__/roleBindings.spec.ts index 81e6b7ade5..7d79ff4f77 100644 --- a/frontend/src/api/k8s/__tests__/roleBindings.spec.ts +++ b/frontend/src/api/k8s/__tests__/roleBindings.spec.ts @@ -23,6 +23,7 @@ import { listRoleBindings, patchRoleBindingOwnerRef, } from '~/api/k8s/roleBindings'; +import { RoleBindingModel } from '~/api/models/k8s'; jest.mock('@openshift/dynamic-plugin-sdk-utils', () => ({ k8sListResource: jest.fn(), @@ -214,12 +215,7 @@ describe('listRoleBindings', () => { k8sListResourceMock.mockResolvedValue(mockK8sResourceList([roleBindingMock])); const result = await listRoleBindings(); expect(k8sListResourceMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: {}, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); @@ -230,12 +226,7 @@ describe('listRoleBindings', () => { k8sListResourceMock.mockResolvedValue(mockK8sResourceList([roleBindingMock])); const result = await listRoleBindings(namespace, 'labelSelector'); expect(k8sListResourceMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { ns: namespace, queryParams: { labelSelector: 'labelSelector' } }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); @@ -247,12 +238,7 @@ describe('listRoleBindings', () => { await expect(listRoleBindings()).rejects.toThrow('error1'); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: {}, }); }); @@ -263,12 +249,7 @@ describe('getRoleBinding', () => { k8sGetResourceMock.mockResolvedValue(roleBindingMock); const result = await getRoleBinding('projectName', 'rbName'); expect(k8sGetResourceMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { name: 'rbName', ns: 'projectName' }, }); expect(k8sGetResourceMock).toHaveBeenCalledTimes(1); @@ -280,12 +261,7 @@ describe('getRoleBinding', () => { await expect(getRoleBinding('projectName', 'rbName')).rejects.toThrow('error1'); expect(k8sGetResourceMock).toHaveBeenCalledTimes(1); expect(k8sGetResourceMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { name: 'rbName', ns: 'projectName' }, }); }); @@ -297,12 +273,7 @@ describe('createRoleBinding', () => { const result = await createRoleBinding(roleBindingMock); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { queryParams: {} }, resource: roleBindingMock, }); @@ -316,12 +287,7 @@ describe('createRoleBinding', () => { expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { queryParams: {} }, resource: roleBindingObject, }); @@ -335,12 +301,7 @@ describe('deleteRoleBinding', () => { const result = await deleteRoleBinding('rbName', namespace); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { name: 'rbName', ns: namespace, queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -353,12 +314,7 @@ describe('deleteRoleBinding', () => { const result = await deleteRoleBinding('rbName', namespace); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { name: 'rbName', ns: namespace, queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -371,12 +327,7 @@ describe('deleteRoleBinding', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, queryOptions: { name: 'rbName', ns: namespace, queryParams: {} }, }); }); @@ -387,12 +338,7 @@ describe('patchRoleBindingOwnerRef', () => { k8sPatchResourceMock.mockResolvedValue(roleBindingMock); const result = await patchRoleBindingOwnerRef('rbName', namespace, []); expect(k8sPatchResourceMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'rbac.authorization.k8s.io', - apiVersion: 'v1', - kind: 'RoleBinding', - plural: 'rolebindings', - }, + model: RoleBindingModel, patches: [{ op: 'replace', path: '/metadata/ownerReferences', value: [] }], queryOptions: { name: 'rbName', ns: namespace }, }); diff --git a/frontend/src/api/k8s/__tests__/secrets.spec.ts b/frontend/src/api/k8s/__tests__/secrets.spec.ts index 133b90725e..3ee1ce7519 100644 --- a/frontend/src/api/k8s/__tests__/secrets.spec.ts +++ b/frontend/src/api/k8s/__tests__/secrets.spec.ts @@ -20,6 +20,7 @@ import { getSecretsByLabel, replaceSecret, } from '~/api/k8s/secrets'; +import { SecretModel } from '~/api/models/k8s'; import { SecretKind } from '~/k8sTypes'; import { genRandomChars } from '~/utilities/string'; @@ -192,7 +193,7 @@ describe('getSecret', () => { const result = await getSecret('projectName', 'secretName'); expect(k8sGetResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { name: 'secretName', ns: 'projectName', queryParams: {} }, }); expect(k8sGetResourceMock).toHaveBeenCalledTimes(1); @@ -205,7 +206,7 @@ describe('getSecret', () => { expect(k8sGetResourceMock).toHaveBeenCalledTimes(1); expect(k8sGetResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { name: 'secretName', ns: 'projectName', queryParams: {} }, }); }); @@ -218,7 +219,7 @@ describe('getSecretsByLabel', () => { const result = await getSecretsByLabel('label', 'secretName'); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { ns: 'secretName', queryParams: { labelSelector: 'label' } }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); @@ -231,7 +232,7 @@ describe('getSecretsByLabel', () => { expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { ns: 'secretName', queryParams: { labelSelector: 'label' } }, }); }); @@ -244,7 +245,7 @@ describe('createSecret', () => { const result = await createSecret(assembleSecret('secret', data, 'aws')); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { queryParams: {} }, resource: { ...assembleSecretResult, @@ -260,7 +261,7 @@ describe('createSecret', () => { await expect(createSecret(assembleSecret('secret', data, 'aws'))).rejects.toThrow('error1'); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { queryParams: {} }, resource: { ...assembleSecretResult, @@ -278,7 +279,7 @@ describe('replaceSecret', () => { const result = await replaceSecret(assembleSecret('secret', data, 'aws')); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { queryParams: {} }, resource: { ...assembleSecretResult, @@ -294,7 +295,7 @@ describe('replaceSecret', () => { await expect(replaceSecret(assembleSecret('secret', data, 'aws'))).rejects.toThrow('error1'); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { queryParams: {} }, resource: { ...assembleSecretResult, @@ -312,7 +313,7 @@ describe('deleteSecret', () => { const result = await deleteSecret('projectName', 'secretName'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { name: 'secretName', ns: 'projectName', queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -325,7 +326,7 @@ describe('deleteSecret', () => { const result = await deleteSecret('projectName', 'secretName'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { name: 'secretName', ns: 'projectName', queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -338,7 +339,7 @@ describe('deleteSecret', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, queryOptions: { name: 'secretName', ns: 'projectName', queryParams: {} }, }); }); diff --git a/frontend/src/api/k8s/__tests__/servingRuntimes.spec.ts b/frontend/src/api/k8s/__tests__/servingRuntimes.spec.ts index 8651dbc3bc..e9fb706e01 100644 --- a/frontend/src/api/k8s/__tests__/servingRuntimes.spec.ts +++ b/frontend/src/api/k8s/__tests__/servingRuntimes.spec.ts @@ -23,6 +23,7 @@ import { listServingRuntimes, updateServingRuntime, } from '~/api/k8s/servingRuntimes'; +import { ProjectModel, ServingRuntimeModel } from '~/api/models'; import { ProjectKind, ServingRuntimeKind } from '~/k8sTypes'; import { AcceleratorProfileState } from '~/utilities/useAcceleratorProfileState'; @@ -211,12 +212,7 @@ describe('listServingRuntimes', () => { const result = await listServingRuntimes(); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); @@ -228,12 +224,7 @@ describe('listServingRuntimes', () => { const result = await listServingRuntimes('namespace', 'labelselector'); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'namespace', queryParams: { labelSelector: 'labelselector' } }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); @@ -246,12 +237,7 @@ describe('listServingRuntimes', () => { expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'namespace', queryParams: { labelSelector: 'labelselector' } }, }); }); @@ -269,24 +255,14 @@ describe('listScopedServingRuntimes', () => { expect(result).toStrictEqual([mock]); expect(k8sListResourceMock).toHaveBeenNthCalledWith(1, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'Project', - plural: 'projects', - }, + model: ProjectModel, queryOptions: { queryParams: { labelSelector: 'opendatahub.io/dashboard=true,modelmesh-enabled' }, }, }); expect(k8sListResourceMock).toHaveBeenNthCalledWith(2, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'test-model', queryParams: {} }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(2); @@ -301,24 +277,14 @@ describe('listScopedServingRuntimes', () => { expect(result).toStrictEqual([inferenceServiceMock]); expect(k8sListResourceMock).toHaveBeenNthCalledWith(1, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'Project', - plural: 'projects', - }, + model: ProjectModel, queryOptions: { queryParams: { labelSelector: 'opendatahub.io/dashboard=true,modelmesh-enabled' }, }, }); expect(k8sListResourceMock).toHaveBeenNthCalledWith(2, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'test-model', queryParams: { labelSelector: 'labelSelector' } }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(2); @@ -332,24 +298,14 @@ describe('listScopedServingRuntimes', () => { await expect(listScopedServingRuntimes('labelSelector')).rejects.toThrow('error'); expect(k8sListResourceMock).toHaveBeenNthCalledWith(1, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'Project', - plural: 'projects', - }, + model: ProjectModel, queryOptions: { queryParams: { labelSelector: 'opendatahub.io/dashboard=true,modelmesh-enabled' }, }, }); expect(k8sListResourceMock).toHaveBeenNthCalledWith(2, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'test-project', queryParams: { labelSelector: 'labelSelector' } }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(2); @@ -361,12 +317,7 @@ describe('listScopedServingRuntimes', () => { expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenNthCalledWith(1, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'Project', - plural: 'projects', - }, + model: ProjectModel, queryOptions: { queryParams: { labelSelector: 'opendatahub.io/dashboard=true,modelmesh-enabled' }, }, @@ -380,12 +331,7 @@ describe('getServingRuntimeContext', () => { const result = await getServingRuntimeContext('namespace', 'labelSelector'); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'namespace', queryParams: { labelSelector: 'labelSelector' } }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(1); @@ -402,24 +348,14 @@ describe('getServingRuntimeContext', () => { const result = await getServingRuntimeContext(); expect(k8sListResourceMock).toHaveBeenNthCalledWith(1, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'Project', - plural: 'projects', - }, + model: ProjectModel, queryOptions: { queryParams: { labelSelector: 'opendatahub.io/dashboard=true,modelmesh-enabled' }, }, }); expect(k8sListResourceMock).toHaveBeenNthCalledWith(2, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'test-model', queryParams: {} }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(2); @@ -433,24 +369,14 @@ describe('getServingRuntimeContext', () => { await expect(getServingRuntimeContext()).rejects.toThrow('error'); expect(k8sListResourceMock).toHaveBeenNthCalledWith(1, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'project.openshift.io', - apiVersion: 'v1', - kind: 'Project', - plural: 'projects', - }, + model: ProjectModel, queryOptions: { queryParams: { labelSelector: 'opendatahub.io/dashboard=true,modelmesh-enabled' }, }, }); expect(k8sListResourceMock).toHaveBeenNthCalledWith(2, { fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'test-project', queryParams: {} }, }); expect(k8sListResourceMock).toHaveBeenCalledTimes(2); @@ -462,12 +388,7 @@ describe('getServingRuntimeContext', () => { expect(k8sListResourceMock).toHaveBeenCalledTimes(1); expect(k8sListResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { ns: 'namespace', queryParams: { labelSelector: 'labelSelector' } }, }); }); @@ -479,12 +400,7 @@ describe('getServingRuntime', () => { const result = await getServingRuntime('name', 'namespace'); expect(k8sGetResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { name: 'name', ns: 'namespace', queryParams: {} }, }); expect(k8sGetResourceMock).toHaveBeenCalledTimes(1); @@ -496,12 +412,7 @@ describe('getServingRuntime', () => { expect(k8sGetResourceMock).toHaveBeenCalledTimes(1); expect(k8sGetResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { name: 'name', ns: 'namespace', queryParams: {} }, }); }); @@ -527,12 +438,7 @@ describe('updateServingRuntime', () => { const result = await updateServingRuntime(option); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, resource: existingData, }); @@ -550,12 +456,7 @@ describe('updateServingRuntime', () => { const result = await updateServingRuntime(option); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, resource: existingData, }); @@ -574,12 +475,7 @@ describe('updateServingRuntime', () => { expect(k8sUpdateResourceMock).toHaveBeenCalledTimes(1); expect(k8sUpdateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, resource: existingData, }); @@ -613,12 +509,7 @@ describe('createServingRuntime', () => { const result = await createServingRuntime(option); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, resource: { ...existingData, @@ -640,12 +531,7 @@ describe('createServingRuntime', () => { const result = await createServingRuntime(option); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, resource: existingData, }); @@ -664,12 +550,7 @@ describe('createServingRuntime', () => { expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { queryParams: {} }, resource: existingData, }); @@ -683,12 +564,7 @@ describe('deleteServingRuntime', () => { const result = await deleteServingRuntime('name', 'namespace'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { name: 'name', ns: 'namespace', queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -701,12 +577,7 @@ describe('deleteServingRuntime', () => { const result = await deleteServingRuntime('name', 'namespace'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { name: 'name', ns: 'namespace', queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -719,12 +590,7 @@ describe('deleteServingRuntime', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'serving.kserve.io', - apiVersion: 'v1alpha1', - kind: 'ServingRuntime', - plural: 'servingruntimes', - }, + model: ServingRuntimeModel, queryOptions: { name: 'name', ns: 'namespace', queryParams: {} }, }); }); diff --git a/frontend/src/api/k8s/__tests__/workloads.spec.ts b/frontend/src/api/k8s/__tests__/workloads.spec.ts index 54e9997658..6f892dd4e1 100644 --- a/frontend/src/api/k8s/__tests__/workloads.spec.ts +++ b/frontend/src/api/k8s/__tests__/workloads.spec.ts @@ -2,6 +2,7 @@ import { k8sListResourceItems } from '@openshift/dynamic-plugin-sdk-utils'; import { mockWorkloadK8sResource } from '~/__mocks__/mockWorkloadK8sResource'; import { WorkloadKind } from '~/k8sTypes'; import { listWorkloads } from '~/api/k8s/workloads'; +import { WorkloadModel } from '~/api/models/kueue'; jest.mock('@openshift/dynamic-plugin-sdk-utils', () => ({ k8sListResourceItems: jest.fn(), @@ -19,12 +20,7 @@ describe('listWorkloads', () => { k8sListResourceItemsMock.mockResolvedValue([mockedWorkload]); const result = await listWorkloads('test-project'); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'kueue.x-k8s.io', - apiVersion: 'v1beta1', - kind: 'Workload', - plural: 'workloads', - }, + model: WorkloadModel, queryOptions: { ns: 'test-project' }, }); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); @@ -36,12 +32,7 @@ describe('listWorkloads', () => { await expect(listWorkloads('test-project')).rejects.toThrow('error1'); expect(k8sListResourceItemsMock).toHaveBeenCalledTimes(1); expect(k8sListResourceItemsMock).toHaveBeenCalledWith({ - model: { - apiGroup: 'kueue.x-k8s.io', - apiVersion: 'v1beta1', - kind: 'Workload', - plural: 'workloads', - }, + model: WorkloadModel, queryOptions: { ns: 'test-project' }, }); }); diff --git a/frontend/src/api/pipelines/__tests__/k8s.spec.ts b/frontend/src/api/pipelines/__tests__/k8s.spec.ts index 3855b0088a..c85c31e9ba 100644 --- a/frontend/src/api/pipelines/__tests__/k8s.spec.ts +++ b/frontend/src/api/pipelines/__tests__/k8s.spec.ts @@ -9,6 +9,9 @@ import { mock200Status, mock404Error } from '~/__mocks__/mockK8sStatus'; import { mockRouteK8sResource } from '~/__mocks__/mockRouteK8sResource'; import { mockSecretK8sResource } from '~/__mocks__/mockSecretK8sResource'; import { + DataSciencePipelineApplicationModel, + RouteModel, + SecretModel, createPipelinesCR, deletePipelineCR, getElyraSecret, @@ -40,7 +43,7 @@ describe('getElyraSecret', () => { const result = await getElyraSecret('namespace', opts); expect(k8sGetResourceSecretKindMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, payload: { dryRun: ['All'] }, queryOptions: { name: 'ds-pipeline-config', ns: 'namespace', queryParams: { dryRun: 'All' } }, }); @@ -54,7 +57,7 @@ describe('getElyraSecret', () => { expect(k8sGetResourceSecretKindMock).toHaveBeenCalledTimes(1); expect(k8sGetResourceSecretKindMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiVersion: 'v1', kind: 'Secret', plural: 'secrets' }, + model: SecretModel, payload: { dryRun: ['All'] }, queryOptions: { name: 'ds-pipeline-config', ns: 'namespace', queryParams: { dryRun: 'All' } }, }); @@ -68,7 +71,7 @@ describe('getPipelineAPIRoute', () => { const result = await getPipelineAPIRoute('namespace', 'ds-pipeline-dspa'); expect(k8sGetResourceRouteKindMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { apiGroup: 'route.openshift.io', apiVersion: 'v1', kind: 'Route', plural: 'routes' }, + model: RouteModel, queryOptions: { name: 'ds-pipeline-dspa', ns: 'namespace', queryParams: {} }, }); expect(k8sGetResourceRouteKindMock).toHaveBeenCalledTimes(1); @@ -81,12 +84,7 @@ describe('getPipelineAPIRoute', () => { expect(k8sGetResourceRouteKindMock).toHaveBeenCalledTimes(1); expect(k8sGetResourceRouteKindMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'route.openshift.io', - apiVersion: 'v1', - kind: 'Route', - plural: 'routes', - }, + model: RouteModel, queryOptions: { name: 'ds-pipeline-dspa', ns: 'namespace', @@ -104,12 +102,7 @@ describe('createPipelinesCR', () => { const result = await createPipelinesCR('test-project', DSPipelinemock.spec); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { queryParams: {} }, resource: DSPipelinemock, }); @@ -123,12 +116,7 @@ describe('createPipelinesCR', () => { expect(k8sCreateResourceMock).toHaveBeenCalledTimes(1); expect(k8sCreateResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { queryParams: {} }, resource: DSPipelinemock, }); @@ -142,12 +130,7 @@ describe('getPipelinesCR', () => { const result = await getPipelinesCR('namespace', 'dspa'); expect(k8sGetResourceDSPipelineKindMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { name: 'dspa', ns: 'namespace', queryParams: {} }, }); expect(k8sGetResourceDSPipelineKindMock).toHaveBeenCalledTimes(1); @@ -160,12 +143,7 @@ describe('getPipelinesCR', () => { expect(k8sGetResourceDSPipelineKindMock).toHaveBeenCalledTimes(1); expect(k8sGetResourceDSPipelineKindMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { name: 'dspa', ns: 'namespace', queryParams: {} }, }); }); @@ -178,12 +156,7 @@ describe('deletePipelineCR', () => { const result = await deletePipelineCR('namespace', 'dspa'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { name: 'dspa', ns: 'namespace', queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -196,12 +169,7 @@ describe('deletePipelineCR', () => { const result = await deletePipelineCR('namespace', 'dspa'); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { name: 'dspa', ns: 'namespace', queryParams: {} }, }); expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); @@ -214,12 +182,7 @@ describe('deletePipelineCR', () => { expect(k8sDeleteResourceMock).toHaveBeenCalledTimes(1); expect(k8sDeleteResourceMock).toHaveBeenCalledWith({ fetchOptions: { requestInit: {} }, - model: { - apiGroup: 'datasciencepipelinesapplications.opendatahub.io', - apiVersion: 'v1alpha1', - kind: 'DataSciencePipelinesApplication', - plural: 'datasciencepipelinesapplications', - }, + model: DataSciencePipelineApplicationModel, queryOptions: { name: 'dspa', ns: 'namespace', queryParams: {} }, }); }); diff --git a/frontend/src/pages/projects/screens/detail/storage/__tests__/useProjectPvcs.spec.ts b/frontend/src/pages/projects/screens/detail/storage/__tests__/useProjectPvcs.spec.ts index 69fb512791..84b5ad0600 100644 --- a/frontend/src/pages/projects/screens/detail/storage/__tests__/useProjectPvcs.spec.ts +++ b/frontend/src/pages/projects/screens/detail/storage/__tests__/useProjectPvcs.spec.ts @@ -2,6 +2,7 @@ import { k8sListResourceItems } from '@openshift/dynamic-plugin-sdk-utils'; import { act } from '@testing-library/react'; import { mockPVCK8sResource } from '~/__mocks__/mockPVCK8sResource'; import { standardUseFetchState, testHook } from '~/__tests__/unit/testUtils/hooks'; +import { PVCModel } from '~/api'; import { LABEL_SELECTOR_DASHBOARD_RESOURCE } from '~/const'; import { PersistentVolumeClaimKind } from '~/k8sTypes'; import useProjectPvcs from '~/pages/projects/screens/detail/storage/useProjectPvcs'; @@ -16,11 +17,7 @@ describe('useProjectPVCs', () => { it('should return dashboard PVCs', async () => { const mockedPVC = [mockPVCK8sResource({})]; const options = { - model: { - apiVersion: 'v1', - kind: 'PersistentVolumeClaim', - plural: 'persistentvolumeclaims', - }, + model: PVCModel, queryOptions: { ns: 'namespace', queryParams: { labelSelector: LABEL_SELECTOR_DASHBOARD_RESOURCE }, From c4619f6dfe5c832e6e7ad6fc5cb6db33dfe00594 Mon Sep 17 00:00:00 2001 From: Robert Sun <107655677+rsun19@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:51:13 -0400 Subject: [PATCH 05/16] configured default environment for cypress --- frontend/.eslintrc | 16 ++++++++++++++++ .../cypress/pages/components/JupyterCard.ts | 2 +- .../cypress/tests/mocked/application.cy.ts | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/frontend/.eslintrc b/frontend/.eslintrc index ec95917b9b..23116e4c02 100755 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -327,6 +327,22 @@ } ] } + }, + { + "files": ["src/__tests__/cypress/**"], + "rules": { + "no-restricted-syntax": [ + "error", + { + "selector": "Literal[value=/\\bRed Hat OpenShift AI\\b/i],JSXText[value=/\\bRed Hat OpenShift AI\\b/i]", + "message": "Do not hard code product name `Red Hat OpenShift AI`. Use `Cypress.env('ODH_PRODUCT_NAME')` instead." + }, + { + "selector": "Literal[value=/\\bOpen Data Hub\\b/i],JSXText[value=/\\bOpen Data Hub\\b/i]", + "message": "Do not hard code product name `Open Data Hub`. Use `Cypress.env('ODH_PRODUCT_NAME')` instead." + } + ] + } } ] } diff --git a/frontend/src/__tests__/cypress/cypress/pages/components/JupyterCard.ts b/frontend/src/__tests__/cypress/cypress/pages/components/JupyterCard.ts index 693249946a..51d5579eaa 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/components/JupyterCard.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/components/JupyterCard.ts @@ -10,7 +10,7 @@ export class JupyterCard extends Card { .findByTestId('tooltip-img') .trigger('mouseenter') .then(() => { - cy.findByText('Open Data Hub certified and supported'); + cy.findByText(`${Cypress.env('ODH_PRODUCT_NAME')} certified and supported`); }); } diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/application.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/application.cy.ts index a75deaadc9..7ca21277ee 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/application.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/application.cy.ts @@ -30,7 +30,7 @@ describe('Application', () => { const applicationLauncher = appChrome.getApplicationLauncher(); applicationLauncher.toggleAppLauncherButton(); const applicationLauncherMenuGroup = applicationLauncher.getApplicationLauncherMenuGroup( - 'Open Data Hub Applications', + `${Cypress.env('ODH_PRODUCT_NAME')} Applications`, ); applicationLauncherMenuGroup.shouldHaveApplicationLauncherItem('OpenShift Cluster Manager'); applicationLauncher.toggleAppLauncherButton(); From 245fcd84e80b0833e98061e5be60c0a972575514 Mon Sep 17 00:00:00 2001 From: Jeff Puzzo Date: Fri, 14 Jun 2024 14:56:20 -0400 Subject: [PATCH 06/16] [RHOAIENG-7717] Make pipeline table name cell be a clickable link to the latest pipeline version details --- .../cypress/pages/pipelines/pipelinesTable.ts | 4 ++++ .../tests/mocked/pipelines/pipelines.cy.ts | 13 ++++++++++++ .../tables/pipeline/PipelinesTableRow.tsx | 21 +++++++++++++++++-- .../pipeline/usePipelineTableRowData.ts | 7 ++++--- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelinesTable.ts b/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelinesTable.ts index b6616269ed..9e98fb4f17 100644 --- a/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelinesTable.ts +++ b/frontend/src/__tests__/cypress/cypress/pages/pipelines/pipelinesTable.ts @@ -24,6 +24,10 @@ class PipelinesTableRow extends TableRow { ]) as unknown as Cypress.Chainable>, ); } + + findPipelineNameLink(value: string) { + return this.find().findByTestId('table-row-title').contains(value); + } } class PipelineVersionsTableRow extends TableRow { diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts index 1027f05a87..56b4ea1c40 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts @@ -866,6 +866,19 @@ describe('Pipelines', () => { ); }); + it('navigates to pipeline version details page via pipeline name', () => { + initIntercepts({}); + pipelinesGlobal.visit(projectName); + pipelinesTable.find(); + + const pipelineRow = pipelinesTable.getRowById(initialMockPipeline.pipeline_id); + pipelineRow.findPipelineNameLink(initialMockPipeline.display_name).click(); + + verifyRelativeURL( + `/pipelines/${projectName}/pipeline/view/${initialMockPipeline.pipeline_id}/${initialMockPipelineVersion.pipeline_version_id}`, + ); + }); + it('delete pipeline and versions', () => { initIntercepts({}); pipelinesGlobal.visit(projectName); diff --git a/frontend/src/concepts/pipelines/content/tables/pipeline/PipelinesTableRow.tsx b/frontend/src/concepts/pipelines/content/tables/pipeline/PipelinesTableRow.tsx index 2cd996c41a..816010e6a0 100644 --- a/frontend/src/concepts/pipelines/content/tables/pipeline/PipelinesTableRow.tsx +++ b/frontend/src/concepts/pipelines/content/tables/pipeline/PipelinesTableRow.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { Td, Tbody, Tr, ActionsColumn, TableText } from '@patternfly/react-table'; -import { useNavigate } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; import { Skeleton } from '@patternfly/react-core'; import { PipelineKFv2 } from '~/concepts/pipelines/kfTypes'; import { CheckboxTd, TableRowTitleDescription } from '~/components/table'; @@ -43,6 +43,7 @@ const PipelinesTableRow: React.FC = ({ const [isExpanded, setExpanded] = React.useState(false); const [importTarget, setImportTarget] = React.useState(null); const { + version, totalSize, updatedDate, loading, @@ -84,7 +85,23 @@ const PipelinesTableRow: React.FC = ({ /> {pipeline.display_name}} + title={ + loading ? ( + + ) : version?.pipeline_version_id ? ( + + {pipeline.display_name} + + ) : ( + {pipeline.display_name} + ) + } description={pipeline.description} descriptionAsMarkdown /> diff --git a/frontend/src/concepts/pipelines/content/tables/pipeline/usePipelineTableRowData.ts b/frontend/src/concepts/pipelines/content/tables/pipeline/usePipelineTableRowData.ts index ca0a91ed4f..f99da24a7f 100644 --- a/frontend/src/concepts/pipelines/content/tables/pipeline/usePipelineTableRowData.ts +++ b/frontend/src/concepts/pipelines/content/tables/pipeline/usePipelineTableRowData.ts @@ -6,6 +6,7 @@ import { FetchStateRefreshPromise } from '~/utilities/useFetchState'; const usePipelineTableRowData = ( pipeline: PipelineKFv2, ): { + version: PipelineVersionKFv2 | undefined; updatedDate: Date; totalSize: number; loading: boolean; @@ -19,10 +20,10 @@ const usePipelineTableRowData = ( sortDirection: 'desc', }, ); + const latestVersion = isLoaded ? items[0] : undefined; + const updatedDate = new Date(latestVersion?.created_at || pipeline.created_at); - const updatedDate = new Date(items[0]?.created_at || pipeline.created_at); - - return { updatedDate, totalSize, loading: !isLoaded, refresh }; + return { version: latestVersion, updatedDate, totalSize, loading: !isLoaded, refresh }; }; export default usePipelineTableRowData; From 9387090b945326d7c78ee51811d9e3b8343427c9 Mon Sep 17 00:00:00 2001 From: Ashley McEntee Date: Mon, 24 Jun 2024 15:57:41 -0400 Subject: [PATCH 07/16] Rename Edit Permission to Contributor --- frontend/src/pages/projects/projectSharing/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/projects/projectSharing/utils.ts b/frontend/src/pages/projects/projectSharing/utils.ts index 9c3f0dd760..72effd0662 100644 --- a/frontend/src/pages/projects/projectSharing/utils.ts +++ b/frontend/src/pages/projects/projectSharing/utils.ts @@ -15,4 +15,4 @@ export const firstSubject = (roleBinding: RoleBindingKind): string => roleBinding.subjects[0]?.name || ''; export const roleLabel = (value: ProjectSharingRoleType): string => - value === ProjectSharingRoleType.ADMIN ? 'Admin' : 'Edit'; + value === ProjectSharingRoleType.ADMIN ? 'Admin' : 'Contributor'; From 9ce6453a6dc35b5e0bf37ad6a93b294035a6d0c5 Mon Sep 17 00:00:00 2001 From: olavtar <94576904+olavtar@users.noreply.github.com> Date: Tue, 25 Jun 2024 11:15:46 -0700 Subject: [PATCH 08/16] feat: implemented NIM model name selection dropdown Signed-off-by: Olga Lavtar --- .../projects/EmptyNIMModelServingCard.tsx | 6 +- .../NIMServiceModal/NIMModelListSection.tsx | 82 ++++--------------- .../modelServing/screens/projects/utils.ts | 42 ++++++++-- 3 files changed, 58 insertions(+), 72 deletions(-) diff --git a/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx b/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx index 5d53cf3737..5dab6c0ef0 100644 --- a/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx +++ b/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx @@ -7,7 +7,7 @@ import { CardTitle, Text, TextContent, - TextVariants + TextVariants, } from '@patternfly/react-core'; import { ProjectDetailsContext } from '~/pages/projects/ProjectDetailsContext'; import { ServingRuntimePlatform } from '~/types'; @@ -65,7 +65,9 @@ const EmptyNIMModelServingCard: React.FC = () => { - Models are deployed using NVIDIA NIM microservices. Choose this option when you want to deploy your model within a NIM container. Please provide the API key to authenticate with the NIM service. + Models are deployed using NVIDIA NIM microservices. Choose this option when you want to + deploy your model within a NIM container. Please provide the API key to authenticate with + the NIM service. diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx index e268102937..626080c7cf 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx @@ -1,8 +1,10 @@ import * as React from 'react'; +import { useEffect, useState } from 'react'; import { FormGroup } from '@patternfly/react-core'; import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; import { CreatingInferenceServiceObject } from '~/pages/modelServing/screens/types'; import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; +import { fetchNIMModelNames } from '~/pages/modelServing/screens/projects/utils'; type NIMModelListSectionProps = { data: CreatingInferenceServiceObject; @@ -10,66 +12,22 @@ type NIMModelListSectionProps = { isEditing?: boolean; }; -const NIMModelListSection: React.FC = ({ - data, - setData, - isEditing, -}) => { +const NIMModelListSection: React.FC = ({ data, setData, isEditing }) => { + const [options, setOptions] = useState<{ key: string; label: string }[]>([]); - const options = [ - { - key: 'liama-2-7b', - label: 'Liama-2-7b', - }, - { - key: 'liama-2-13b', - label: 'Liama-2-13b', - }, - { - key: 'liama-2-70b', - label: 'Liama-2-70b', - }, - { - key: 'liama-2-7b-chat', - label: 'Liama-2-7b-chat', - }, - { - key: 'liama-2-13b-chat', - label: 'Liama-2-13b-chat', - }, - { - key: 'liama-2-70b-chat', - label: 'Liama-2-70b-chat', - }, - { - key:'mistral-7b-instruct', - label: 'Mistral-7b-instruct', - }, - { - key:'mixtral-8x7b', - label: 'Mixtral-8x7b', - }, - { - key:'Nemotron-8b-base', - label: 'Nemotron-8b-base', - }, - { - key:'nemotron-43b-chat', - label: 'Nemotron-43b-chat', - }, - { - key:'nemotron-43b-instruct', - label: 'Nemotron-43b-instruct', - }, - { - key:'starcoder', - label: 'Starcoder', - }, - { - key:'Starcoderplus', - label: 'Starcoderplus', - } - ]; + useEffect(() => { + const getModelNames = async () => { + const modelInfos = await fetchNIMModelNames(); + if (modelInfos !== undefined) { + const fetchedOptions = modelInfos.map((modelInfo) => ({ + key: modelInfo.name, + label: `${modelInfo.displayName} - ${modelInfo.latestTag}`, + })); + setOptions(fetchedOptions); + } + }; + getModelNames(); + }, []); return ( @@ -80,11 +38,7 @@ const NIMModelListSection: React.FC = ({ dataTestId="nim-model-list-selection" aria-label="Select NVIDIA model" options={options} - placeholder={ - isEditing - ? data.name - : 'Select NVIDIA model' - } + placeholder={isEditing ? data.name : 'Select NVIDIA model'} value={data.format.name} onChange={(name) => { setData('format', { name }); diff --git a/frontend/src/pages/modelServing/screens/projects/utils.ts b/frontend/src/pages/modelServing/screens/projects/utils.ts index 54c976b5c3..cd82cc995c 100644 --- a/frontend/src/pages/modelServing/screens/projects/utils.ts +++ b/frontend/src/pages/modelServing/screens/projects/utils.ts @@ -7,19 +7,15 @@ import { SecretKind, ServingRuntimeKind, } from '~/k8sTypes'; -import { - DataConnection, - NamespaceApplicationCase, - UpdateObjectAtPropAndValue, -} from '~/pages/projects/types'; +import { DataConnection, NamespaceApplicationCase, UpdateObjectAtPropAndValue } from '~/pages/projects/types'; import useGenericObjectState from '~/utilities/useGenericObjectState'; import { CreatingInferenceServiceObject, CreatingServingRuntimeObject, InferenceServiceStorageType, + ModelServingSize, ServingPlatformStatuses, ServingRuntimeEditInfo, - ModelServingSize, } from '~/pages/modelServing/screens/types'; import { ServingRuntimePlatform } from '~/types'; import { DEFAULT_MODEL_SERVER_SIZES } from '~/pages/modelServing/screens/const'; @@ -41,12 +37,16 @@ import { createInferenceService, createSecret, createServingRuntime, + getConfigMap, updateInferenceService, updateServingRuntime, } from '~/api'; import { isDataConnectionAWS } from '~/pages/projects/screens/detail/data-connections/utils'; import { removeLeadingSlash } from '~/utilities/string'; +const NAMESPACE = 'redhat-ods-applications'; +const CONFIGMAP = 'nvidia-nim-images-data'; + export const getServingRuntimeSizes = (config: DashboardConfigKind): ModelServingSize[] => { let sizes = config.spec.modelServerSizes || []; if (sizes.length === 0) { @@ -533,3 +533,33 @@ export const filterOutConnectionsWithoutBucket = ( connections.filter( (obj) => isDataConnectionAWS(obj) && obj.data.data.AWS_S3_BUCKET.trim() !== '', ); + +export interface ModelInfo { + name: string; + displayName: string; + shortDescription: string; + namespace: string; + tags: string[]; + latestTag: string; + updatedDate: string; +} + +export const fetchNIMModelNames = async (): Promise => { + const configMap = await getConfigMap(NAMESPACE, CONFIGMAP); + if (configMap.data) { + const modelInfos: ModelInfo[] = Object.entries(configMap.data).map(([key, value]) => { + const modelData = JSON.parse(value); // Parse the JSON string + return { + name: key, + displayName: modelData.displayName, + shortDescription: modelData.shortDescription, + namespace: modelData.namespace, + tags: modelData.tags, + latestTag: modelData.latestTag, + updatedDate: modelData.updatedDate, + }; + }); + return modelInfos; + } + return undefined; +}; From 282ee4eee5e70e36720e82bf6b514f5fc19d8c64 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Tue, 16 Jul 2024 12:25:12 -0400 Subject: [PATCH 09/16] Add authentication information banner --- .../NIMServiceModal/DeployNIMServiceModal.tsx | 54 ++++++++++----- .../KServeAutoscalerReplicaSection.tsx | 67 ------------------- .../NIMServingRuntimeSection.tsx | 52 -------------- 3 files changed, 36 insertions(+), 137 deletions(-) delete mode 100644 frontend/src/pages/modelServing/screens/projects/NIMServiceModal/KServeAutoscalerReplicaSection.tsx delete mode 100644 frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMServingRuntimeSection.tsx diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx index d8a1b9c121..f60b77b9ca 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx @@ -1,7 +1,8 @@ import * as React from 'react'; import { + Alert, + AlertActionCloseButton, Form, - FormSection, Modal, Stack, StackItem, @@ -26,7 +27,6 @@ import { getServingRuntimeFromName } from '~/pages/modelServing/customServingRun import useServingAcceleratorProfile from '~/pages/modelServing/screens/projects/useServingAcceleratorProfile'; import DashboardModalFooter from '~/concepts/dashboard/DashboardModalFooter'; import { - InferenceServiceStorageType, ServingRuntimeEditInfo, } from '~/pages/modelServing/screens/types'; import ServingRuntimeSizeSection from '~/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeSizeSection'; @@ -34,16 +34,13 @@ import NIMModelListSection from '~/pages/modelServing/screens/projects/NIMServic import NIMModelDeploymentNameSection from '~/pages/modelServing/screens/projects/NIMServiceModal/NIMModelDeploymentNameSection'; import ProjectSection from '~/pages/modelServing/screens/projects/InferenceServiceModal/ProjectSection'; import { DataConnection, NamespaceApplicationCase } from '~/pages/projects/types'; -import { AwsKeys } from '~/pages/projects/dataConnections/const'; -import { isAWSValid } from '~/pages/projects/screens/spawner/spawnerUtils'; -import DataConnectionSection from '~/pages/modelServing/screens/projects/InferenceServiceModal/DataConnectionSection'; import { getProjectDisplayName } from '~/concepts/projects/utils'; import { translateDisplayNameForK8s } from '~/concepts/k8s/utils'; -import { containsOnlySlashes, isS3PathValid } from '~/utilities/string'; -import AuthServingRuntimeSection from '~/pages/modelServing/screens/projects/ServingRuntimeModal/AuthServingRuntimeSection'; import { useAccessReview } from '~/api'; import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas'; -import KServeAutoscalerReplicaSection from './KServeAutoscalerReplicaSection'; +import KServeAutoscalerReplicaSection from '../kServeModal/KServeAutoscalerReplicaSection'; +import ServingRuntimeTemplateSection from '~/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeTemplateSection'; + const accessReviewResource: AccessReviewResourceAttributes = { group: 'rbac.authorization.k8s.io', @@ -115,27 +112,28 @@ const DeployNIMServiceModal: React.FC = ({ }, [currentProjectName, setCreateDataInferenceService, isOpen]); // Serving Runtime Validation + const isDisabledServingRuntime = namespace === '' || actionInProgress; + const baseInputValueValid = createDataServingRuntime.numReplicas >= 0 && resourcesArePositive(createDataServingRuntime.modelSize.resources) && requestsUnderLimits(createDataServingRuntime.modelSize.resources); - const isDisabledServingRuntime = namespace === '' || actionInProgress || !baseInputValueValid; - const isDisabledInferenceService = actionInProgress || createDataInferenceService.name.trim() === '' || createDataInferenceService.project === '' || - !isInferenceServiceNameWithinLimit + !isInferenceServiceNameWithinLimit || + !baseInputValueValid; const servingRuntimeSelected = React.useMemo( () => editInfo?.servingRuntimeEditInfo?.servingRuntime || getServingRuntimeFromName( - createDataServingRuntime.servingRuntimeTemplateName, + 'nvidia-runtime-gpu', servingRuntimeTemplates, ), - [editInfo, servingRuntimeTemplates, createDataServingRuntime.servingRuntimeTemplateName], + [editInfo, servingRuntimeTemplates], ); const onBeforeClose = (submitted: boolean) => { @@ -161,9 +159,8 @@ const DeployNIMServiceModal: React.FC = ({ const submit = () => { setError(undefined); setActionInProgress(true); - onSuccess(); - const servingRuntimeName = 'nim'; + const servingRuntimeName = editInfo?.inferenceServiceEditInfo?.spec.predictor.model?.runtime || translateDisplayNameForK8s(createDataInferenceService.name);; const submitServingRuntimeResources = getSubmitServingRuntimeResourcesFn( servingRuntimeSelected, @@ -176,7 +173,7 @@ const DeployNIMServiceModal: React.FC = ({ NamespaceApplicationCase.KSERVE_PROMOTION, projectContext?.currentProject, servingRuntimeName, - false, + true, ); const submitInferenceServiceResource = getSubmitInferenceServiceResourceFn( @@ -231,6 +228,27 @@ const DeployNIMServiceModal: React.FC = ({ }} > + {!isAuthorinoEnabled && alertVisible && ( + + setAlertVisible(false)} />} + > +

+ The NVIDIA NIM model serving platform used by this project allows deployed models to + be accessible via external routes. It is recommended that token authentication be + enabled to protect these routes. The serving platform requires the Authorino + operator be installed on the cluster for token authentication. Contact a cluster + administrator to install the operator. +

+
+
+ )} = ({ ; - infoContent?: string; -}; - -const KServeAutoscalerReplicaSection: React.FC = ({ - data, - setData, - infoContent, -}) => { - const MIN_SIZE = 0; - - const onStep = (step: number) => { - setData('minReplicas', normalizeBetween(data.minReplicas + step, MIN_SIZE)); - setData('maxReplicas', normalizeBetween(data.maxReplicas + step, MIN_SIZE)); - }; - - return ( - - {infoContent}}> - - - - - ) : undefined - } - > - onStep(1)} - onMinus={() => onStep(-1)} - onChange={(event) => { - if (isHTMLInputElement(event.target)) { - const newSize = Number(event.target.value); - setData( - 'minReplicas', - Number.isNaN(newSize) ? MIN_SIZE : normalizeBetween(newSize, MIN_SIZE), - ); - setData( - 'maxReplicas', - Number.isNaN(newSize) ? MIN_SIZE : normalizeBetween(newSize, MIN_SIZE), - ); - } - }} - /> - - - ); -}; - -export default KServeAutoscalerReplicaSection; diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMServingRuntimeSection.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMServingRuntimeSection.tsx deleted file mode 100644 index fbc77026c4..0000000000 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMServingRuntimeSection.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as React from 'react'; -import { - FormGroup, -} from '@patternfly/react-core'; -import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; -import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; -import { CreatingServingRuntimeObject } from '~/pages/modelServing/screens/types'; - - -type NIMServingRuntimeSectionProps = { - data: CreatingServingRuntimeObject; - setData: UpdateObjectAtPropAndValue; - isEditing?: boolean; -}; - -const NIMServingRuntimeSection: React.FC = ({ - data, - setData, - isEditing, -}) => { - - const options = [ - { - key: 'nvidia-nim-serving-runtime', - label: 'NVIDIA NIM serving runtime', - }, - ]; - - return ( - - { - setData('servingRuntimeTemplateName', name); - }} - /> - - ); -}; - -export default NIMServingRuntimeSection; From 59393fdcd050d600e6afcda3db9a4caba1f63a8b Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Tue, 16 Jul 2024 12:41:18 -0400 Subject: [PATCH 10/16] Fix dockerfile conflict --- scripts/ci/Dockerfile | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile index 9339af0af9..1504bb7e9e 100644 --- a/scripts/ci/Dockerfile +++ b/scripts/ci/Dockerfile @@ -48,11 +48,7 @@ RUN rm -rf /var/cache/yum # Set capability to adjust OOM score for Node RUN echo CAP_SYS_NICE >> /etc/security/limits.conf -<<<<<<< HEAD -# Copy NodeJS package.json from "frontend" directory -======= # Copy NodeJS packages lists (json files) from "frontend" directory ->>>>>>> main WORKDIR $USER_HOME COPY ./frontend/package*.json ./ RUN chown $USER:0 ./* @@ -66,11 +62,7 @@ ENV NODE_PATH "$NVM_DIR/versions/node/$NODE_VERSION/lib/node_modules" ENV PATH "$NVM_DIR/versions/node/$NODE_VERSION/bin:/bin:$HOME/.local/bin:/root/.local/bin:$PATH" RUN mkdir -p $NVM_DIR -<<<<<<< HEAD -# Install Node Version Manager, Node Package Manager, and the "frontend" packages -======= # Install Node Version Manager, NodeJS and the packages for CI (package-lock.json) ->>>>>>> main RUN curl -o- $NVM_INSTALLER | bash RUN /bin/bash -c "source $NVM_DIR/nvm.sh && \ nvm install $NODE_VERSION && \ @@ -78,13 +70,8 @@ RUN /bin/bash -c "source $NVM_DIR/nvm.sh && \ npm config set prefix '$NPM_CACHE' && \ echo 'export PATH=$PATH' >> '$USER_HOME/.profile' && \ source $USER_HOME/.profile && \ -<<<<<<< HEAD - npm install -g npm@latest && \ - npm cache -g clean --force" -======= npm cache -g clean --force && \ npm ci --cache=$NPM_CACHE" ->>>>>>> main # Export NPM and Cypress Cache directories (to be accesible by rootless user) ENV NPM_CONFIG_CACHE $NPM_CACHE From bc65ebe03939328436d10e5eb6d50f420a4ef0f8 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Tue, 16 Jul 2024 17:57:12 -0400 Subject: [PATCH 11/16] Modify the nim service deployment form --- frontend/src/api/k8s/servingRuntimes.ts | 14 ++++++++- .../NIMServiceModal/DeployNIMServiceModal.tsx | 11 ++++--- .../NIMServiceModal/NIMModelListSection.tsx | 31 ++++++++++++++----- .../src/pages/modelServing/screens/types.ts | 2 ++ 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/frontend/src/api/k8s/servingRuntimes.ts b/frontend/src/api/k8s/servingRuntimes.ts index e3b933dcb9..6593e5d5ef 100644 --- a/frontend/src/api/k8s/servingRuntimes.ts +++ b/frontend/src/api/k8s/servingRuntimes.ts @@ -31,7 +31,7 @@ export const assembleServingRuntime = ( acceleratorProfileState?: AcceleratorProfileState, isModelMesh?: boolean, ): ServingRuntimeKind => { - const { name: displayName, numReplicas, modelSize, externalRoute, tokenAuth } = data; + const { name: displayName, numReplicas, modelSize, externalRoute, tokenAuth, imageName, modelName } = data; const createName = isCustomServingRuntimesEnabled ? translateDisplayNameForK8s(displayName) : getModelServingRuntimeName(namespace); @@ -121,6 +121,10 @@ export const assembleServingRuntime = ( volumeMounts.push(getshmVolumeMount()); } + if (imageName) { + container.image = imageName; + } + const containerWithoutResources = _.omit(container, 'resources'); return { @@ -132,6 +136,14 @@ export const assembleServingRuntime = ( }, ); + if (modelName) { + if (updatedServingRuntime.spec.supportedModelFormats && updatedServingRuntime.spec.supportedModelFormats.length >= 1) { + updatedServingRuntime.spec.supportedModelFormats[0].name = modelName; + } else { + updatedServingRuntime.spec.supportedModelFormats?.push({ name: modelName }); + } + } + if (isModelMesh) { updatedServingRuntime.spec.tolerations = tolerations; } diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx index f60b77b9ca..adb96f6137 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx @@ -34,8 +34,7 @@ import NIMModelListSection from '~/pages/modelServing/screens/projects/NIMServic import NIMModelDeploymentNameSection from '~/pages/modelServing/screens/projects/NIMServiceModal/NIMModelDeploymentNameSection'; import ProjectSection from '~/pages/modelServing/screens/projects/InferenceServiceModal/ProjectSection'; import { DataConnection, NamespaceApplicationCase } from '~/pages/projects/types'; -import { getProjectDisplayName } from '~/concepts/projects/utils'; -import { translateDisplayNameForK8s } from '~/concepts/k8s/utils'; +import { getDisplayNameFromK8sResource, translateDisplayNameForK8s } from '~/concepts/k8s/utils'; import { useAccessReview } from '~/api'; import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas'; import KServeAutoscalerReplicaSection from '../kServeModal/KServeAutoscalerReplicaSection'; @@ -253,7 +252,7 @@ const DeployNIMServiceModal: React.FC = ({ = ({ diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx index 626080c7cf..575a2bc3da 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx @@ -2,17 +2,19 @@ import * as React from 'react'; import { useEffect, useState } from 'react'; import { FormGroup } from '@patternfly/react-core'; import { UpdateObjectAtPropAndValue } from '~/pages/projects/types'; -import { CreatingInferenceServiceObject } from '~/pages/modelServing/screens/types'; +import { CreatingInferenceServiceObject, CreatingServingRuntimeObject } from '~/pages/modelServing/screens/types'; import SimpleDropdownSelect from '~/components/SimpleDropdownSelect'; import { fetchNIMModelNames } from '~/pages/modelServing/screens/projects/utils'; type NIMModelListSectionProps = { - data: CreatingInferenceServiceObject; - setData: UpdateObjectAtPropAndValue; + inferenceServiceData: CreatingInferenceServiceObject; + servingRuntimeData: CreatingServingRuntimeObject; + setInferenceServiceData: UpdateObjectAtPropAndValue; + setServingRuntimeData: UpdateObjectAtPropAndValue; isEditing?: boolean; }; -const NIMModelListSection: React.FC = ({ data, setData, isEditing }) => { +const NIMModelListSection: React.FC = ({ inferenceServiceData, servingRuntimeData, setInferenceServiceData, setServingRuntimeData, isEditing }) => { const [options, setOptions] = useState<{ key: string; label: string }[]>([]); useEffect(() => { @@ -29,6 +31,19 @@ const NIMModelListSection: React.FC = ({ data, setData getModelNames(); }, []); + const getNIMModelName = (name: string) => { + return `nvidia-nim-${name}`; + }; + + const getNIMImageName = (name: string) => { + const imageInfo = options.find((option) => option.key === name); + if (imageInfo) { + return `nvcr.io/nim/meta/${name}:${imageInfo.label.split(' - ')[1]}`; + } else { + return ''; + } + } + return ( = ({ data, setData dataTestId="nim-model-list-selection" aria-label="Select NVIDIA model" options={options} - placeholder={isEditing ? data.name : 'Select NVIDIA model'} - value={data.format.name} + placeholder={isEditing ? inferenceServiceData.name : 'Select NVIDIA model'} + value={inferenceServiceData.format.name} onChange={(name) => { - setData('format', { name }); + setServingRuntimeData('modelName', getNIMModelName(name)); + setServingRuntimeData('imageName', getNIMImageName(name)); + setInferenceServiceData('format', { name }); }} /> diff --git a/frontend/src/pages/modelServing/screens/types.ts b/frontend/src/pages/modelServing/screens/types.ts index a8bf14fdb2..e314991243 100644 --- a/frontend/src/pages/modelServing/screens/types.ts +++ b/frontend/src/pages/modelServing/screens/types.ts @@ -40,6 +40,8 @@ export type CreatingServingRuntimeObject = { externalRoute: boolean; tokenAuth: boolean; tokens: ServingRuntimeToken[]; + imageName?: string; + modelName?: string; }; export type ServingRuntimeToken = { From f114a868afaab5ee3458a7e35a6d9a7f277ee9be Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 17 Jul 2024 14:51:33 -0400 Subject: [PATCH 12/16] Fix eslint issue --- frontend/src/api/k8s/servingRuntimes.ts | 18 +++++++-- .../NIMServiceModal/DeployNIMServiceModal.tsx | 24 +++++------- .../NIMModelDeploymentNameSection.tsx | 5 ++- .../NIMServiceModal/NIMModelListSection.tsx | 22 ++++++----- .../modelServing/screens/projects/utils.ts | 6 ++- .../server/AcceleratorProfileSelectField.tsx | 2 +- .../overview/serverModels/AddModelFooter.tsx | 2 +- .../overview/serverModels/SelectNIMCard.tsx | 39 +++++++++---------- 8 files changed, 67 insertions(+), 51 deletions(-) diff --git a/frontend/src/api/k8s/servingRuntimes.ts b/frontend/src/api/k8s/servingRuntimes.ts index 6593e5d5ef..702cee1aba 100644 --- a/frontend/src/api/k8s/servingRuntimes.ts +++ b/frontend/src/api/k8s/servingRuntimes.ts @@ -31,7 +31,15 @@ export const assembleServingRuntime = ( acceleratorProfileState?: AcceleratorProfileState, isModelMesh?: boolean, ): ServingRuntimeKind => { - const { name: displayName, numReplicas, modelSize, externalRoute, tokenAuth, imageName, modelName } = data; + const { + name: displayName, + numReplicas, + modelSize, + externalRoute, + tokenAuth, + imageName, + modelName, + } = data; const createName = isCustomServingRuntimesEnabled ? translateDisplayNameForK8s(displayName) : getModelServingRuntimeName(namespace); @@ -122,7 +130,8 @@ export const assembleServingRuntime = ( } if (imageName) { - container.image = imageName; + const containerObj = container; + containerObj.image = imageName; } const containerWithoutResources = _.omit(container, 'resources'); @@ -137,7 +146,10 @@ export const assembleServingRuntime = ( ); if (modelName) { - if (updatedServingRuntime.spec.supportedModelFormats && updatedServingRuntime.spec.supportedModelFormats.length >= 1) { + if ( + updatedServingRuntime.spec.supportedModelFormats && + updatedServingRuntime.spec.supportedModelFormats.length >= 1 + ) { updatedServingRuntime.spec.supportedModelFormats[0].name = modelName; } else { updatedServingRuntime.spec.supportedModelFormats?.push({ name: modelName }); diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx index adb96f6137..d8ed0ad886 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/DeployNIMServiceModal.tsx @@ -26,9 +26,7 @@ import useCustomServingRuntimesEnabled from '~/pages/modelServing/customServingR import { getServingRuntimeFromName } from '~/pages/modelServing/customServingRuntimes/utils'; import useServingAcceleratorProfile from '~/pages/modelServing/screens/projects/useServingAcceleratorProfile'; import DashboardModalFooter from '~/concepts/dashboard/DashboardModalFooter'; -import { - ServingRuntimeEditInfo, -} from '~/pages/modelServing/screens/types'; +import { ServingRuntimeEditInfo } from '~/pages/modelServing/screens/types'; import ServingRuntimeSizeSection from '~/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeSizeSection'; import NIMModelListSection from '~/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection'; import NIMModelDeploymentNameSection from '~/pages/modelServing/screens/projects/NIMServiceModal/NIMModelDeploymentNameSection'; @@ -37,9 +35,7 @@ import { DataConnection, NamespaceApplicationCase } from '~/pages/projects/types import { getDisplayNameFromK8sResource, translateDisplayNameForK8s } from '~/concepts/k8s/utils'; import { useAccessReview } from '~/api'; import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas'; -import KServeAutoscalerReplicaSection from '../kServeModal/KServeAutoscalerReplicaSection'; -import ServingRuntimeTemplateSection from '~/pages/modelServing/screens/projects/ServingRuntimeModal/ServingRuntimeTemplateSection'; - +import KServeAutoscalerReplicaSection from '~/pages/modelServing/screens/projects/kServeModal/KServeAutoscalerReplicaSection'; const accessReviewResource: AccessReviewResourceAttributes = { group: 'rbac.authorization.k8s.io', @@ -128,10 +124,7 @@ const DeployNIMServiceModal: React.FC = ({ const servingRuntimeSelected = React.useMemo( () => editInfo?.servingRuntimeEditInfo?.servingRuntime || - getServingRuntimeFromName( - 'nvidia-runtime-gpu', - servingRuntimeTemplates, - ), + getServingRuntimeFromName('nvidia-runtime-gpu', servingRuntimeTemplates), [editInfo, servingRuntimeTemplates], ); @@ -159,7 +152,9 @@ const DeployNIMServiceModal: React.FC = ({ setError(undefined); setActionInProgress(true); - const servingRuntimeName = editInfo?.inferenceServiceEditInfo?.spec.predictor.model?.runtime || translateDisplayNameForK8s(createDataInferenceService.name);; + const servingRuntimeName = + editInfo?.inferenceServiceEditInfo?.spec.predictor.model?.runtime || + translateDisplayNameForK8s(createDataInferenceService.name); const submitServingRuntimeResources = getSubmitServingRuntimeResourcesFn( servingRuntimeSelected, @@ -239,9 +234,9 @@ const DeployNIMServiceModal: React.FC = ({ actionClose={ setAlertVisible(false)} />} >

- The NVIDIA NIM model serving platform used by this project allows deployed models to - be accessible via external routes. It is recommended that token authentication be - enabled to protect these routes. The serving platform requires the Authorino + The NVIDIA NIM model serving platform used by this project allows deployed models + to be accessible via external routes. It is recommended that token authentication + be enabled to protect these routes. The serving platform requires the Authorino operator be installed on the cluster for token authentication. Contact a cluster administrator to install the operator.

@@ -268,7 +263,6 @@ const DeployNIMServiceModal: React.FC = ({ ; }; -const NIMModelDeploymentNameSection: React.FC = ({ data, setData }) => ( +const NIMModelDeploymentNameSection: React.FC = ({ + data, + setData, +}) => ( ; setServingRuntimeData: UpdateObjectAtPropAndValue; isEditing?: boolean; }; -const NIMModelListSection: React.FC = ({ inferenceServiceData, servingRuntimeData, setInferenceServiceData, setServingRuntimeData, isEditing }) => { +const NIMModelListSection: React.FC = ({ + inferenceServiceData, + setInferenceServiceData, + setServingRuntimeData, + isEditing, +}) => { const [options, setOptions] = useState<{ key: string; label: string }[]>([]); useEffect(() => { @@ -31,18 +38,15 @@ const NIMModelListSection: React.FC = ({ inferenceServ getModelNames(); }, []); - const getNIMModelName = (name: string) => { - return `nvidia-nim-${name}`; - }; + const getNIMModelName = (name: string) => `nvidia-nim-${name}`; const getNIMImageName = (name: string) => { const imageInfo = options.find((option) => option.key === name); if (imageInfo) { return `nvcr.io/nim/meta/${name}:${imageInfo.label.split(' - ')[1]}`; - } else { - return ''; } - } + return ''; + }; return ( diff --git a/frontend/src/pages/modelServing/screens/projects/utils.ts b/frontend/src/pages/modelServing/screens/projects/utils.ts index 8eccadca94..e4021d8fd8 100644 --- a/frontend/src/pages/modelServing/screens/projects/utils.ts +++ b/frontend/src/pages/modelServing/screens/projects/utils.ts @@ -7,7 +7,11 @@ import { SecretKind, ServingRuntimeKind, } from '~/k8sTypes'; -import { DataConnection, NamespaceApplicationCase, UpdateObjectAtPropAndValue } from '~/pages/projects/types'; +import { + DataConnection, + NamespaceApplicationCase, + UpdateObjectAtPropAndValue, +} from '~/pages/projects/types'; import useGenericObjectState from '~/utilities/useGenericObjectState'; import { CreatingInferenceServiceObject, diff --git a/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx b/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx index 662f027f7b..70ba984aa3 100644 --- a/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx +++ b/frontend/src/pages/notebookController/screens/server/AcceleratorProfileSelectField.tsx @@ -239,4 +239,4 @@ const AcceleratorProfileSelectField: React.FC = ({ selectedPlatform, isNIM onClose={onSubmit} /> ) : null} - {modalShown && isNIM ? ( + {modalShown && isNIM ? ( { - - return ( - - - - - Models are deployed using NVIDIA NIM microservices. Choose this option when you want to deploy your model within a NIM container. Please provide the API key to authenticate with the NIM service. - - - - - - ); -} +const SelectNIMCard: React.FC = () => ( + + + + + Models are deployed using NVIDIA NIM microservices. Choose this option when you want to + deploy your model within a NIM container. Please provide the API key to authenticate with + the NIM service. + + + + + +); export default SelectNIMCard; From cca658d1f68b8551f6d2df83063100085119785b Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 29 Jul 2024 14:14:20 -0400 Subject: [PATCH 13/16] Modify servingRuntimes to generate resources --- frontend/src/api/k8s/servingRuntimes.ts | 17 ++++++++++++----- .../NIMServiceModal/NIMModelListSection.tsx | 13 +++++++++++-- .../src/pages/modelServing/screens/types.ts | 9 ++++++++- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/frontend/src/api/k8s/servingRuntimes.ts b/frontend/src/api/k8s/servingRuntimes.ts index 702cee1aba..d6b79ee809 100644 --- a/frontend/src/api/k8s/servingRuntimes.ts +++ b/frontend/src/api/k8s/servingRuntimes.ts @@ -13,7 +13,7 @@ import { ServingRuntimeAnnotations, ServingRuntimeKind, } from '~/k8sTypes'; -import { CreatingServingRuntimeObject } from '~/pages/modelServing/screens/types'; +import { CreatingServingRuntimeObject, SupportedModelFormatsInfo } from '~/pages/modelServing/screens/types'; import { ContainerResources } from '~/types'; import { getModelServingRuntimeName } from '~/pages/modelServing/utils'; import { getDisplayNameFromK8sResource, translateDisplayNameForK8s } from '~/concepts/k8s/utils'; @@ -38,7 +38,7 @@ export const assembleServingRuntime = ( externalRoute, tokenAuth, imageName, - modelName, + supportedModelFormatsInfo, } = data; const createName = isCustomServingRuntimesEnabled ? translateDisplayNameForK8s(displayName) @@ -145,14 +145,21 @@ export const assembleServingRuntime = ( }, ); - if (modelName) { + if (supportedModelFormatsInfo) { + const supportedModelFormatsObj: SupportedModelFormatsInfo = { + name: supportedModelFormatsInfo.name, + version: supportedModelFormatsInfo.version, + autoSelect: true, + priority: 1 + }; + if ( updatedServingRuntime.spec.supportedModelFormats && updatedServingRuntime.spec.supportedModelFormats.length >= 1 ) { - updatedServingRuntime.spec.supportedModelFormats[0].name = modelName; + updatedServingRuntime.spec.supportedModelFormats[0] = supportedModelFormatsObj; } else { - updatedServingRuntime.spec.supportedModelFormats?.push({ name: modelName }); + updatedServingRuntime.spec.supportedModelFormats?.push(supportedModelFormatsObj); } } diff --git a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx index 651fd305a0..8b19e8d322 100644 --- a/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx +++ b/frontend/src/pages/modelServing/screens/projects/NIMServiceModal/NIMModelListSection.tsx @@ -38,7 +38,16 @@ const NIMModelListSection: React.FC = ({ getModelNames(); }, []); - const getNIMModelName = (name: string) => `nvidia-nim-${name}`; + const getSupportedModelFormatsInfo = (name: string) => { + const modelInfo = options.find((option) => option.key === name); + if (modelInfo) { + return { + name: modelInfo.key, + version: modelInfo.label.split(' - ')[1], + }; + } + return { name: '', version: '' }; + }; const getNIMImageName = (name: string) => { const imageInfo = options.find((option) => option.key === name); @@ -60,7 +69,7 @@ const NIMModelListSection: React.FC = ({ placeholder={isEditing ? inferenceServiceData.name : 'Select NVIDIA model'} value={inferenceServiceData.format.name} onChange={(name) => { - setServingRuntimeData('modelName', getNIMModelName(name)); + setServingRuntimeData('supportedModelFormatsInfo', getSupportedModelFormatsInfo(name)); setServingRuntimeData('imageName', getNIMImageName(name)); setInferenceServiceData('format', { name }); }} diff --git a/frontend/src/pages/modelServing/screens/types.ts b/frontend/src/pages/modelServing/screens/types.ts index e314991243..c6aaa9f22f 100644 --- a/frontend/src/pages/modelServing/screens/types.ts +++ b/frontend/src/pages/modelServing/screens/types.ts @@ -32,6 +32,13 @@ export type ModelStatus = { failedToSchedule: boolean; }; +export type SupportedModelFormatsInfo = { + name: string; + version: string; + autoSelect?: boolean; + priority?: number; +}; + export type CreatingServingRuntimeObject = { name: string; servingRuntimeTemplateName: string; @@ -41,7 +48,7 @@ export type CreatingServingRuntimeObject = { tokenAuth: boolean; tokens: ServingRuntimeToken[]; imageName?: string; - modelName?: string; + supportedModelFormatsInfo?: SupportedModelFormatsInfo; }; export type ServingRuntimeToken = { From 146279b7d63a412db07aea6e4a80227c6f7d3ad6 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 29 Jul 2024 14:30:58 -0400 Subject: [PATCH 14/16] lint fix --- frontend/src/api/k8s/servingRuntimes.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/api/k8s/servingRuntimes.ts b/frontend/src/api/k8s/servingRuntimes.ts index d6b79ee809..7392a2751e 100644 --- a/frontend/src/api/k8s/servingRuntimes.ts +++ b/frontend/src/api/k8s/servingRuntimes.ts @@ -13,7 +13,10 @@ import { ServingRuntimeAnnotations, ServingRuntimeKind, } from '~/k8sTypes'; -import { CreatingServingRuntimeObject, SupportedModelFormatsInfo } from '~/pages/modelServing/screens/types'; +import { + CreatingServingRuntimeObject, + SupportedModelFormatsInfo, +} from '~/pages/modelServing/screens/types'; import { ContainerResources } from '~/types'; import { getModelServingRuntimeName } from '~/pages/modelServing/utils'; import { getDisplayNameFromK8sResource, translateDisplayNameForK8s } from '~/concepts/k8s/utils'; @@ -150,9 +153,9 @@ export const assembleServingRuntime = ( name: supportedModelFormatsInfo.name, version: supportedModelFormatsInfo.version, autoSelect: true, - priority: 1 + priority: 1, }; - + if ( updatedServingRuntime.spec.supportedModelFormats && updatedServingRuntime.spec.supportedModelFormats.length >= 1 From 1ac0d1f427eaeccfa123f10c8b8b6f3590331545 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 29 Jul 2024 15:22:26 -0400 Subject: [PATCH 15/16] Fix test case --- .../tests/mocked/pipelines/pipelines.cy.ts | 15 +-------------- .../screens/projects/EmptyNIMModelServingCard.tsx | 2 +- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts index 5367536c1e..a91a388e9e 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts @@ -936,19 +936,6 @@ describe('Pipelines', () => { ); }); - it('navigates to pipeline version details page via pipeline name', () => { - initIntercepts({}); - pipelinesGlobal.visit(projectName); - pipelinesTable.find(); - - const pipelineRow = pipelinesTable.getRowById(initialMockPipeline.pipeline_id); - pipelineRow.findPipelineNameLink(initialMockPipeline.display_name).click(); - - verifyRelativeURL( - `/pipelines/${projectName}/pipeline/view/${initialMockPipeline.pipeline_id}/${initialMockPipelineVersion.pipeline_version_id}`, - ); - }); - it('delete pipeline and versions', () => { initIntercepts({}); pipelinesGlobal.visit(projectName); @@ -1332,4 +1319,4 @@ const createDeletePipelineIntercept = (pipelineId: string) => times: 1, }, mockSuccessGoogleRpcStatus({}), - ); + ); \ No newline at end of file diff --git a/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx b/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx index 5dab6c0ef0..34eb718335 100644 --- a/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx +++ b/frontend/src/pages/modelServing/screens/projects/EmptyNIMModelServingCard.tsx @@ -57,7 +57,7 @@ const EmptyNIMModelServingCard: React.FC = () => { border: '1px solid var(--pf-v5-global--BorderColor--100)', borderRadius: 16, }} - data-testid="single-serving-platform-card" + data-testid="nvidia-nim-model-serving-platform-card" > From 8383986b2c500c1fb2df72e035b06e19512f871f Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 29 Jul 2024 15:28:13 -0400 Subject: [PATCH 16/16] Fix lint issue --- .../cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts index a91a388e9e..c0d35e7d64 100644 --- a/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts +++ b/frontend/src/__tests__/cypress/cypress/tests/mocked/pipelines/pipelines.cy.ts @@ -1319,4 +1319,4 @@ const createDeletePipelineIntercept = (pipelineId: string) => times: 1, }, mockSuccessGoogleRpcStatus({}), - ); \ No newline at end of file + );