@rancher/shell 3.0.12-rc.1 → 3.0.12-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/impl/apis.ts +6 -0
- package/apis/index.ts +26 -0
- package/apis/intf/resources-api/cluster-api.ts +18 -0
- package/apis/intf/resources-api/mgmt-api.ts +15 -0
- package/apis/intf/resources-api/resource-base.ts +107 -0
- package/apis/intf/resources-api/resource-constants.ts +147 -0
- package/apis/intf/resources-api/resources-api.ts +143 -0
- package/apis/intf/resources.ts +49 -0
- package/apis/intf/{modal.ts → shell-api/modal.ts} +21 -26
- package/apis/intf/shell-api/proxy.ts +216 -0
- package/apis/intf/{slide-in.ts → shell-api/slide-in.ts} +4 -3
- package/apis/intf/{system.ts → shell-api/system.ts} +4 -1
- package/apis/intf/shell.ts +12 -6
- package/apis/resources/__tests__/resources-api-class.test.ts +550 -0
- package/apis/resources/index.ts +22 -0
- package/apis/resources/resources-api-class.ts +187 -0
- package/apis/shell/__tests__/proxy.test.ts +369 -0
- package/apis/shell/index.ts +8 -1
- package/apis/shell/modal.ts +4 -1
- package/apis/shell/notifications.ts +9 -6
- package/apis/shell/proxy.ts +256 -0
- package/apis/shell/slide-in.ts +4 -1
- package/apis/vue-shim.d.ts +2 -1
- package/assets/data/aws-regions.json +4 -0
- package/assets/fonts/lato/LatoLatin-Black.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Black.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BlackItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Bold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-BoldItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Heavy.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-HeavyItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Italic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Light.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-LightItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Medium.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-MediumItalic.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Regular.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff +0 -0
- package/assets/fonts/lato/LatoLatin-Semibold.woff2 +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff +0 -0
- package/assets/fonts/lato/LatoLatin-SemiboldItalic.woff2 +0 -0
- package/assets/images/providers/entraid-black.svg +4 -0
- package/assets/images/providers/entraid.svg +9 -0
- package/assets/images/vendor/entraid.svg +9 -0
- package/assets/styles/app.scss +0 -1
- package/assets/styles/base/_variables.scss +2 -0
- package/assets/styles/fonts/_fontstack.scss +132 -8
- package/assets/translations/en-us.yaml +41 -22
- package/assets/translations/zh-hans.yaml +4 -8
- package/chart/__tests__/S3.test.ts +10 -3
- package/chart/monitoring/index.vue +10 -1
- package/components/ActionDropdownShell.vue +2 -1
- package/components/CountBox.vue +20 -0
- package/components/CreateDriver.vue +0 -12
- package/components/CruResourceFooter.vue +9 -5
- package/components/DetailText.vue +12 -3
- package/components/ExplorerProjectsNamespaces.vue +1 -1
- package/components/InstallHelmCharts.vue +2 -2
- package/components/LandingPagePreference.vue +14 -5
- package/components/Resource/Detail/Metadata/IdentifyingInformation/index.vue +15 -1
- package/components/Resource/Detail/Metadata/index.vue +6 -0
- package/components/Resource/Detail/ResourcePopover/index.vue +12 -1
- package/components/Resource/Detail/SpacedRow.vue +3 -1
- package/components/Resource/Detail/TitleBar/index.vue +10 -11
- package/components/ResourceList/Masthead.vue +12 -8
- package/components/SelectIconGrid.vue +5 -10
- package/components/SingleClusterInfo.vue +1 -0
- package/components/SortableTable/__tests__/sorting.test.ts +126 -0
- package/components/SortableTable/index.vue +6 -9
- package/components/SortableTable/selection.js +23 -5
- package/components/SortableTable/sorting.js +6 -3
- package/components/Wizard.vue +14 -13
- package/components/__tests__/CountBox.test.ts +72 -0
- package/components/__tests__/DetailText.test.ts +113 -0
- package/components/fleet/FleetBundles.vue +100 -12
- package/components/fleet/FleetClusterTargets/index.vue +54 -15
- package/components/fleet/__tests__/FleetClusterTargets.test.ts +149 -115
- package/components/fleet/__tests__/FleetClusters.test.ts +12 -12
- package/components/form/InputWithSelect.vue +18 -10
- package/components/form/KeyValue.vue +17 -1
- package/components/form/LabeledSelect.vue +101 -26
- package/components/form/NameNsDescription.vue +11 -0
- package/components/form/Security.vue +6 -2
- package/components/form/Select.vue +73 -56
- package/components/form/ServiceNameSelect.vue +13 -11
- package/components/form/WorkloadPorts.vue +2 -7
- package/components/form/__tests__/KeyValue.test.ts +66 -0
- package/components/form/__tests__/NodeScheduling.test.ts +9 -0
- package/components/form/__tests__/Security.test.ts +76 -0
- package/components/form/labeled-select-utils/useLabeledSelectPagination.ts +138 -0
- package/components/formatter/Autoscaler.vue +4 -4
- package/components/formatter/ClusterKubeVersion.vue +27 -0
- package/components/formatter/ClusterLink.vue +1 -7
- package/components/formatter/ClusterProvider.vue +6 -10
- package/components/formatter/FleetSummaryGraph.vue +0 -3
- package/components/formatter/MachineSummaryGraph.vue +1 -1
- package/components/formatter/PodsUsage.vue +2 -2
- package/components/formatter/__tests__/Autoscaler.test.ts +19 -22
- package/components/formatter/__tests__/FleetSummaryGraph.test.ts +216 -0
- package/components/formatter/__tests__/PodsUsage.test.ts +6 -10
- package/components/nav/Group.vue +7 -6
- package/components/nav/Header.vue +24 -3
- package/components/nav/NamespaceFilter.vue +2 -2
- package/components/nav/NotificationCenter/Notification.vue +4 -1
- package/components/nav/NotificationCenter/NotificationHeader.vue +20 -8
- package/components/nav/NotificationCenter/__tests__/NotificationHeader.test.ts +80 -0
- package/components/nav/TopLevelMenu.helper.ts +15 -3
- package/components/nav/TopLevelMenu.vue +16 -5
- package/components/nav/Type.vue +8 -7
- package/components/nav/WindowManager/index.vue +2 -1
- package/components/nav/WorkspaceSwitcher.vue +13 -0
- package/components/nav/__tests__/Group.test.ts +67 -0
- package/components/nav/__tests__/Header.test.ts +235 -0
- package/components/nav/__tests__/TopLevelMenu.test.ts +145 -21
- package/components/nav/__tests__/Type.test.ts +20 -3
- package/components/templates/default.vue +34 -4
- package/components/templates/home.vue +30 -25
- package/components/templates/plain.vue +31 -26
- package/components/templates/standalone.vue +17 -0
- package/composables/useFormValidation.ts +93 -0
- package/composables/useLabeledFormElement.ts +10 -2
- package/composables/useLabeledSelect.ts +60 -0
- package/composables/useUserRetentionValidation.ts +1 -49
- package/composables/useVeeValidateField.test.ts +159 -0
- package/composables/useVeeValidateField.ts +67 -0
- package/config/cookies.js +0 -1
- package/config/labels-annotations.js +1 -0
- package/config/pagination-table-headers.js +18 -1
- package/config/product/manager.js +82 -21
- package/config/query-params.js +1 -0
- package/config/router/routes.js +6 -8
- package/config/table-headers.js +20 -1
- package/config/types.js +2 -1
- package/core/__tests__/plugin-products.test.ts +1505 -30
- package/core/plugin-products-base.ts +137 -20
- package/core/plugin-products-helpers.ts +5 -4
- package/core/plugin-products.ts +4 -0
- package/core/plugin-types.ts +129 -4
- package/core/plugin.ts +15 -7
- package/core/productDebugger.js +9 -4
- package/core/types-provisioning.ts +43 -30
- package/core/types.ts +58 -19
- package/detail/__tests__/management.cattle.io.fleetworkspace.test.ts +128 -0
- package/detail/__tests__/pod.test.ts +41 -0
- package/detail/harvesterhci.io.management.cluster.vue +6 -2
- package/detail/management.cattle.io.fleetworkspace.vue +49 -0
- package/detail/pod.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +4 -10
- package/edit/__tests__/fleet.cattle.io.helmop.test.ts +9 -0
- package/edit/__tests__/kontainerDriver.test.ts +0 -13
- package/edit/__tests__/nodeDriver.test.ts +5 -11
- package/edit/__tests__/resources.cattle.io.restore.test.ts +9 -0
- package/edit/auditlog.cattle.io.auditpolicy/__tests__/__snapshots__/General.test.ts.snap +6 -0
- package/edit/auth/__tests__/azuread.test.ts +217 -34
- package/edit/auth/__tests__/oidc.test.ts +54 -0
- package/edit/auth/azuread.vue +123 -15
- package/edit/auth/oidc.vue +10 -2
- package/edit/kontainerDriver.vue +1 -2
- package/edit/networking.k8s.io.ingress/DefaultBackend.vue +13 -4
- package/edit/networking.k8s.io.ingress/RulePath.vue +8 -4
- package/edit/networking.k8s.io.ingress/index.vue +75 -20
- package/edit/nodeDriver.vue +0 -2
- package/edit/provisioning.cattle.io.cluster/AgentEnv.vue +1 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/AgentEnv.test.ts +25 -0
- package/edit/provisioning.cattle.io.cluster/__tests__/MachinePool.test.ts +104 -0
- package/edit/provisioning.cattle.io.cluster/index.vue +81 -106
- package/edit/provisioning.cattle.io.cluster/rke2.vue +8 -4
- package/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue +11 -0
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +37 -4
- package/edit/provisioning.cattle.io.cluster/tabs/registries/__tests__/RegistryConfigs.test.ts +132 -7
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -1
- package/edit/secret/__tests__/ssh.test.ts +5 -6
- package/edit/secret/basic.vue +31 -0
- package/edit/secret/index.vue +68 -17
- package/edit/secret/registry.vue +38 -0
- package/edit/secret/ssh.vue +29 -0
- package/edit/secret/tls.vue +30 -0
- package/edit/service.vue +4 -4
- package/edit/workload/Upgrading.vue +3 -3
- package/edit/workload/__tests__/Upgrading.test.ts +6 -9
- package/edit/workload/mixins/workload.js +2 -1
- package/initialize/App.vue +29 -2
- package/initialize/install-plugins.js +0 -2
- package/list/__tests__/management.cattle.io.feature.test.ts +105 -0
- package/list/catalog.cattle.io.app.vue +25 -5
- package/list/fleet.cattle.io.bundle.vue +7 -104
- package/list/fleet.cattle.io.clusterregistrationtoken.vue +20 -0
- package/list/management.cattle.io.feature.vue +1 -1
- package/list/management.cattle.io.fleetworkspace.vue +8 -0
- package/list/provisioning.cattle.io.cluster.vue +262 -180
- package/list/utils/management.cattle.io.cluster.utils.ts +128 -0
- package/machine-config/amazonec2.vue +1 -0
- package/mixins/__tests__/chart.test.ts +112 -0
- package/mixins/brand.js +2 -1
- package/mixins/chart.js +50 -15
- package/mixins/resource-fetch-api-pagination.js +41 -5
- package/models/__tests__/catalog.cattle.io.app.test.ts +15 -1
- package/models/__tests__/catalog.cattle.io.clusterrepo.test.ts +84 -0
- package/models/__tests__/chart.test.ts +99 -6
- package/models/__tests__/ext.cattle.io.kubeconfig.test.ts +67 -67
- package/models/__tests__/management.cattle.io.cluster.test.ts +1 -1
- package/models/__tests__/management.cattle.io.feature.test.ts +131 -0
- package/models/__tests__/management.cattle.io.node.ts +6 -5
- package/models/__tests__/management.cattle.io.nodepool.ts +5 -4
- package/models/__tests__/monitoring.coreos.com.alertmanagerconfig.test.ts +98 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +32 -11
- package/models/base-cluster.x-k8s.io.js +26 -0
- package/models/catalog.cattle.io.app.js +21 -17
- package/models/catalog.cattle.io.clusterrepo.js +39 -11
- package/models/chart.js +33 -19
- package/models/cluster.js +1 -1
- package/models/cluster.x-k8s.io.machine.js +4 -22
- package/models/cluster.x-k8s.io.machinedeployment.js +2 -20
- package/models/cluster.x-k8s.io.machineset.js +2 -20
- package/models/compliance.cattle.io.clusterscan.js +130 -2
- package/models/ext.cattle.io.kubeconfig.ts +4 -7
- package/models/fleet-application.js +4 -2
- package/models/fleet.cattle.io.bundle.js +1 -1
- package/models/kontainerdriver.js +11 -0
- package/models/management.cattle.io.authconfig.js +5 -1
- package/models/management.cattle.io.cluster.js +402 -78
- package/models/management.cattle.io.feature.js +3 -3
- package/models/management.cattle.io.kontainerdriver.js +1 -26
- package/models/management.cattle.io.node.js +6 -4
- package/models/management.cattle.io.nodepool.js +1 -1
- package/models/monitoring.coreos.com.alertmanagerconfig.js +31 -17
- package/models/networking.k8s.io.ingress.js +12 -4
- package/models/nodedriver.js +7 -0
- package/models/provisioning.cattle.io.cluster.js +47 -330
- package/models/rke.cattle.io.etcdsnapshot.js +1 -2
- package/package.json +20 -37
- package/pages/__tests__/readme.test.ts +49 -0
- package/pages/auth/setup.vue +2 -3
- package/pages/c/_cluster/apps/charts/__tests__/chart.test.ts +265 -0
- package/pages/c/_cluster/apps/charts/__tests__/index.test.ts +55 -0
- package/pages/c/_cluster/apps/charts/__tests__/install.test.ts +53 -0
- package/pages/c/_cluster/apps/charts/chart.vue +275 -39
- package/pages/c/_cluster/apps/charts/index.vue +2 -2
- package/pages/c/_cluster/apps/charts/install.vue +18 -10
- package/pages/c/_cluster/auth/user.retention/index.vue +55 -22
- package/pages/c/_cluster/explorer/__tests__/index.test.ts +23 -25
- package/pages/c/_cluster/explorer/index.vue +5 -49
- package/pages/c/_cluster/istio/__tests__/istio.index.test.ts +194 -0
- package/pages/c/_cluster/istio/index.vue +21 -6
- package/pages/c/_cluster/manager/drivers/kontainerDriver/index.vue +5 -7
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +40 -2
- package/pages/c/_cluster/uiplugins/__tests__/PluginInfoPanel.test.ts +61 -0
- package/pages/c/_cluster/uiplugins/__tests__/index.test.ts +735 -13
- package/pages/c/_cluster/uiplugins/index.vue +226 -222
- package/pages/diagnostic.vue +13 -17
- package/pages/fail-whale.vue +18 -0
- package/pages/home.vue +77 -260
- package/pages/readme.vue +88 -0
- package/plugins/dashboard-store/__tests__/resource-class.test.ts +88 -0
- package/plugins/dashboard-store/actions.js +40 -18
- package/plugins/dashboard-store/resource-class.js +5 -2
- package/plugins/steve/__tests__/subscribe.spec.ts +6 -3
- package/plugins/steve/steve-pagination-utils.ts +11 -3
- package/plugins/steve/subscribe.js +35 -5
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +211 -1
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +37 -4
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +1 -1
- package/rancher-components/RcButton/RcButton.test.ts +37 -1
- package/rancher-components/RcButton/RcButton.vue +38 -8
- package/rancher-components/RcDropdown/RcDropdownTrigger.vue +10 -8
- package/scripts/test-plugins-build.sh +5 -2
- package/server/server-middleware.js +2 -2
- package/static/humans.txt +1 -0
- package/static/robots.txt +34 -0
- package/static/welcome-cow.svg +18 -0
- package/store/__tests__/catalog.test.ts +276 -12
- package/store/__tests__/type-map.test.ts +556 -1
- package/store/action-menu.js +8 -3
- package/store/auth.js +1 -4
- package/store/aws.js +27 -16
- package/store/catalog.js +87 -11
- package/store/digitalocean.js +20 -38
- package/store/index.js +2 -0
- package/store/linode.js +25 -40
- package/store/pnap.js +1 -0
- package/store/type-map.js +111 -29
- package/tsconfig.paths.json +8 -8
- package/types/kube/kube-api.ts +14 -1
- package/types/rancher/steve.api.ts +12 -12
- package/types/resources/settings.d.ts +2 -1
- package/types/shell/index.d.ts +128 -24
- package/types/store/dashboard-store.types.ts +108 -11
- package/types/store/pagination.types.ts +6 -3
- package/utils/__tests__/alertmanagerconfig.test.ts +117 -0
- package/utils/__tests__/async.test.ts +87 -0
- package/utils/__tests__/aws.test.ts +140 -0
- package/utils/__tests__/banners.test.ts +176 -0
- package/utils/__tests__/chart.test.ts +64 -1
- package/utils/__tests__/color.test.ts +226 -0
- package/utils/__tests__/duration.test.ts +140 -0
- package/utils/__tests__/fleet.test.ts +340 -0
- package/utils/__tests__/git.test.ts +270 -0
- package/utils/__tests__/inactivity.test.ts +316 -0
- package/utils/__tests__/ingress.test.ts +553 -0
- package/utils/__tests__/kube.test.ts +68 -0
- package/utils/__tests__/namespace-filter.test.ts +109 -0
- package/utils/__tests__/object.test.ts +77 -0
- package/utils/__tests__/pagination-utils.test.ts +361 -0
- package/utils/__tests__/parse-externalid.test.ts +137 -0
- package/utils/__tests__/perf-setting.utils.test.ts +98 -0
- package/utils/__tests__/poller-sequential.test.ts +177 -0
- package/utils/__tests__/poller.test.ts +170 -0
- package/utils/__tests__/promise.test.ts +346 -0
- package/utils/__tests__/settings.test.ts +140 -0
- package/utils/__tests__/sort-utils.test.ts +301 -0
- package/utils/__tests__/string-utils.test.ts +798 -0
- package/utils/__tests__/string.test.ts +23 -1
- package/utils/__tests__/style.test.ts +154 -0
- package/utils/__tests__/svg-filter.test.ts +184 -0
- package/utils/__tests__/time.test.ts +14 -1
- package/utils/__tests__/units.test.ts +417 -0
- package/utils/__tests__/url.test.ts +246 -0
- package/utils/__tests__/versions.test.ts +128 -0
- package/utils/__tests__/xccdf.test.ts +391 -0
- package/utils/chart.js +36 -0
- package/utils/fleet.ts +13 -3
- package/utils/gatekeeper/__tests__/util.test.ts +174 -0
- package/utils/gc/__tests__/gc-interval.test.ts +119 -0
- package/utils/gc/__tests__/gc-root-store.test.ts +225 -0
- package/utils/gc/__tests__/gc-route-changed.test.ts +96 -0
- package/utils/gc/__tests__/gc.test.ts +487 -0
- package/utils/ingress.ts +9 -1
- package/utils/object.js +33 -2
- package/utils/pagination-utils.ts +2 -1
- package/utils/string.js +25 -2
- package/utils/time.ts +5 -0
- package/utils/uiplugins.ts +5 -5
- package/utils/validators/__tests__/cluster-name.test.ts +110 -0
- package/utils/validators/__tests__/cron-schedule.test.ts +79 -0
- package/utils/validators/__tests__/index.test.ts +481 -0
- package/utils/validators/__tests__/kubernetes-name.test.ts +163 -0
- package/utils/validators/__tests__/misc-validators.test.ts +246 -0
- package/utils/validators/__tests__/pod-affinity.test.ts +382 -0
- package/utils/validators/__tests__/prometheusrule.test.ts +211 -0
- package/utils/validators/__tests__/role-template.test.ts +149 -0
- package/utils/validators/__tests__/service.test.ts +283 -0
- package/utils/validators/__tests__/setting.test.js +32 -0
- package/utils/validators/formRules/__tests__/index.test.ts +50 -0
- package/utils/validators/formRules/index.ts +5 -5
- package/utils/validators/machine-pool.ts +1 -1
- package/utils/validators/setting.js +18 -3
- package/utils/xccdf.ts +418 -0
- package/vue.config.js +0 -9
- package/assets/fonts/lato/lato-v17-latin-700.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-700.woff2 +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff +0 -0
- package/assets/fonts/lato/lato-v17-latin-regular.woff2 +0 -0
- package/assets/images/providers/azuread-black.svg +0 -22
- package/assets/images/providers/azuread.svg +0 -25
- package/assets/images/vendor/azuread.svg +0 -18
- package/assets/styles/fonts/_dots.scss +0 -18
- package/components/EmberPage.vue +0 -622
- package/components/EmberPageView.vue +0 -39
- package/components/form/labeled-select-utils/labeled-select-pagination.ts +0 -116
- package/mixins/labeled-form-element.ts +0 -225
- package/pages/c/_cluster/explorer/tools/pages/_page.vue +0 -28
- package/pages/c/_cluster/manager/pages/_page.vue +0 -22
- package/pages/c/_cluster/mcapps/pages/_page.vue +0 -22
- package/plugins/ember-cookie.js +0 -17
- package/utils/ember-page.js +0 -30
|
@@ -87,21 +87,21 @@ export default {
|
|
|
87
87
|
path: 'spec.rules.http.paths.path', rules: ['absolutePath'], translationKey: 'ingress.rules.path.label'
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
|
-
path: 'spec.rules.http.paths.backend.service.port
|
|
90
|
+
path: 'spec.rules.http.paths.backend.service.port', rules: ['portRequired', 'portRange'], translationKey: 'ingress.rules.port.label'
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
path: 'spec.rules.http.paths.backend.service.name', rules: ['required'], translationKey: 'ingress.rules.target.label'
|
|
94
94
|
},
|
|
95
95
|
{ path: 'spec', rules: ['backEndOrRules'] },
|
|
96
96
|
{
|
|
97
|
-
path: 'spec.defaultBackend.service.name', rules: ['
|
|
97
|
+
path: 'spec.defaultBackend.service.name', rules: ['defaultBackendNameRequired'], translationKey: 'ingress.defaultBackend.targetService.label'
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
|
-
path: 'spec.defaultBackend.service.port
|
|
100
|
+
path: 'spec.defaultBackend.service.port', rules: ['defaultBackendPortRequired', 'portRange'], translationKey: 'ingress.defaultBackend.port.label'
|
|
101
101
|
},
|
|
102
102
|
{ path: 'spec.tls.hosts', rules: ['required', 'wildcardHostname'] }
|
|
103
103
|
],
|
|
104
|
-
fvReportedValidationPaths: ['spec.rules.http.paths.backend.service.port
|
|
104
|
+
fvReportedValidationPaths: ['spec.rules.http.paths.backend.service.port', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.name']
|
|
105
105
|
};
|
|
106
106
|
},
|
|
107
107
|
|
|
@@ -125,35 +125,89 @@ export default {
|
|
|
125
125
|
}
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
const portLabel = this.t('ingress.rules.port.label');
|
|
129
|
+
|
|
130
|
+
// Built-in `required` won't work: it passes for empty objects like {} or { name: '' }.
|
|
131
|
+
const portRequired = (port) => {
|
|
132
|
+
if (typeof port === 'string' || typeof port === 'number') {
|
|
133
|
+
if (!port) {
|
|
134
|
+
return this.t('validation.required', { key: portLabel });
|
|
135
|
+
}
|
|
136
|
+
} else if (!port || (!port.number && !port.name)) {
|
|
137
|
+
return this.t('validation.required', { key: portLabel });
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const portRange = (port) => {
|
|
142
|
+
let num;
|
|
143
|
+
|
|
144
|
+
if (typeof port === 'number') {
|
|
145
|
+
num = port;
|
|
146
|
+
} else if (typeof port === 'string') {
|
|
147
|
+
num = Number.parseInt(port);
|
|
148
|
+
} else if (port?.number) {
|
|
149
|
+
num = port.number;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (num !== undefined && !Number.isNaN(num) && (num < 1 || num > 65535)) {
|
|
153
|
+
return this.t('validation.number.between', {
|
|
154
|
+
key: portLabel, min: '1', max: '65535'
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const hasDefaultBackendService = () => {
|
|
160
|
+
const backend = get(this.value?.spec, this.value.defaultBackendPath);
|
|
161
|
+
|
|
162
|
+
return !!get(backend, this.value.serviceNamePath);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const nameLabel = this.t('ingress.defaultBackend.targetService.label');
|
|
166
|
+
|
|
167
|
+
// Only enforce required on the default backend when a service is selected.
|
|
168
|
+
// Selecting "None" means the user wants to remove the backend; willSave() handles cleanup.
|
|
169
|
+
const defaultBackendNameRequired = (name) => {
|
|
170
|
+
if (hasDefaultBackendService() && !name) {
|
|
171
|
+
return this.t('validation.required', { key: nameLabel });
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const defaultBackendPortRequired = (port) => {
|
|
176
|
+
if (!hasDefaultBackendService()) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return portRequired(port);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
backEndOrRules,
|
|
185
|
+
portRequired,
|
|
186
|
+
portRange,
|
|
187
|
+
defaultBackendNameRequired,
|
|
188
|
+
defaultBackendPortRequired,
|
|
189
|
+
};
|
|
129
190
|
},
|
|
130
191
|
tabErrors() {
|
|
131
192
|
return {
|
|
132
|
-
rules: this.fvGetPathErrors(['spec.rules.host', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.port
|
|
133
|
-
defaultBackend: this.fvGetPathErrors(['spec.defaultBackend.service.name', 'spec.defaultBackend.service.port
|
|
193
|
+
rules: this.fvGetPathErrors(['spec.rules.host', 'spec.rules.http.paths.path', 'spec.rules.http.paths.backend.service.port', 'spec.rules.http.paths.backend.service.name'])?.length > 0,
|
|
194
|
+
defaultBackend: this.fvGetPathErrors(['spec.defaultBackend.service.name', 'spec.defaultBackend.service.port'])?.length > 0
|
|
134
195
|
};
|
|
135
196
|
},
|
|
136
197
|
rulesPathRules() {
|
|
137
198
|
return {
|
|
138
199
|
requestHost: this.fvGetAndReportPathRules('spec.rules.host'),
|
|
139
200
|
path: this.fvGetAndReportPathRules('spec.rules.http.paths.path'),
|
|
140
|
-
port: this.fvGetAndReportPathRules('spec.rules.http.paths.backend.service.port
|
|
201
|
+
port: this.fvGetAndReportPathRules('spec.rules.http.paths.backend.service.port'),
|
|
141
202
|
target: this.fvGetAndReportPathRules('spec.rules.http.paths.backend.service.name'),
|
|
142
203
|
|
|
143
204
|
};
|
|
144
205
|
},
|
|
145
206
|
defaultBackendPathRules() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
name: this.fvGetAndReportPathRules('spec.defaultBackend.service.name'),
|
|
152
|
-
port: this.fvGetAndReportPathRules('spec.defaultBackend.service.port.number'),
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return { name: [], port: [] };
|
|
207
|
+
return {
|
|
208
|
+
name: this.fvGetAndReportPathRules('spec.defaultBackend.service.name'),
|
|
209
|
+
port: this.fvGetAndReportPathRules('spec.defaultBackend.service.port'),
|
|
210
|
+
};
|
|
157
211
|
},
|
|
158
212
|
serviceTargets() {
|
|
159
213
|
return this.ingressHelper.findAndMapServiceTargets(this.services);
|
|
@@ -188,7 +242,8 @@ export default {
|
|
|
188
242
|
willSave() {
|
|
189
243
|
const backend = get(this.value.spec, this.value.defaultBackendPath);
|
|
190
244
|
const serviceName = get(backend, this.value.serviceNamePath);
|
|
191
|
-
const servicePort = get(backend, this.value.servicePortPath)
|
|
245
|
+
const servicePort = get(backend, this.value.servicePortPath) ||
|
|
246
|
+
get(backend, this.value.servicePortNamePath);
|
|
192
247
|
|
|
193
248
|
if (backend && (!serviceName || !servicePort)) {
|
|
194
249
|
const path = this.value.defaultBackendPath;
|
package/edit/nodeDriver.vue
CHANGED
|
@@ -21,7 +21,6 @@ export default {
|
|
|
21
21
|
return {
|
|
22
22
|
fvFormRuleSets: [
|
|
23
23
|
{ path: 'url', rules: ['required', 'url'] },
|
|
24
|
-
{ path: 'uiUrl', rules: ['url'] },
|
|
25
24
|
{ path: 'checksum', rules: ['alphanumeric'] },
|
|
26
25
|
{ path: 'whitelistDomains', rules: ['wildcardHostname'] }
|
|
27
26
|
]
|
|
@@ -63,7 +62,6 @@ export default {
|
|
|
63
62
|
:value="value"
|
|
64
63
|
:rules="{
|
|
65
64
|
url: fvGetAndReportPathRules('url'),
|
|
66
|
-
uiUrl: fvGetAndReportPathRules('uiUrl'),
|
|
67
65
|
checksum: fvGetAndReportPathRules('checksum'),
|
|
68
66
|
whitelistDomains: fvGetAndReportPathRules('whitelistDomains')
|
|
69
67
|
}"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { mount } from '@vue/test-utils';
|
|
2
|
+
import AgentEnv from '@shell/edit/provisioning.cattle.io.cluster/AgentEnv.vue';
|
|
3
|
+
|
|
4
|
+
describe('component: AgentEnv', () => {
|
|
5
|
+
it('should only accept text files (not binary) on the KeyValue file upload', () => {
|
|
6
|
+
const wrapper = mount(AgentEnv, {
|
|
7
|
+
props: {
|
|
8
|
+
mode: 'edit',
|
|
9
|
+
value: { spec: { agentEnvVars: [] } },
|
|
10
|
+
},
|
|
11
|
+
global: {
|
|
12
|
+
mocks: { t: (key: string) => key },
|
|
13
|
+
stubs: {
|
|
14
|
+
Tab: { template: '<div><slot /></div>' },
|
|
15
|
+
KeyValue: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const keyValue = wrapper.findComponent({ name: 'KeyValue' });
|
|
21
|
+
|
|
22
|
+
expect(keyValue.exists()).toBe(true);
|
|
23
|
+
expect(keyValue.props('readAccept')).toBe('text/plain');
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { shallowMount } from '@vue/test-utils';
|
|
2
|
+
import MachinePool from '@shell/edit/provisioning.cattle.io.cluster/tabs/MachinePool.vue';
|
|
3
|
+
|
|
4
|
+
const TRANSLATION_KEY = '%cluster.machinePool.name.unique%';
|
|
5
|
+
|
|
6
|
+
function createPool(name: string, { remove = false } = {}) {
|
|
7
|
+
return {
|
|
8
|
+
id: `pool-${ name }`,
|
|
9
|
+
remove,
|
|
10
|
+
create: false,
|
|
11
|
+
update: true,
|
|
12
|
+
pool: {
|
|
13
|
+
name,
|
|
14
|
+
etcdRole: false,
|
|
15
|
+
controlPlaneRole: false,
|
|
16
|
+
workerRole: true,
|
|
17
|
+
quantity: 1,
|
|
18
|
+
},
|
|
19
|
+
config: null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function mountMachinePool(currentPool: ReturnType<typeof createPool>, allPools: ReturnType<typeof createPool>[]) {
|
|
24
|
+
return shallowMount(MachinePool, {
|
|
25
|
+
props: {
|
|
26
|
+
value: currentPool,
|
|
27
|
+
mode: 'create',
|
|
28
|
+
provider: 'custom',
|
|
29
|
+
idx: 0,
|
|
30
|
+
machinePools: allPools,
|
|
31
|
+
poolId: currentPool.id,
|
|
32
|
+
poolCreateMode: true,
|
|
33
|
+
},
|
|
34
|
+
global: {
|
|
35
|
+
mocks: {
|
|
36
|
+
$store: {
|
|
37
|
+
getters: {
|
|
38
|
+
'i18n/t': (key: string) => key,
|
|
39
|
+
'i18n/exists': () => false,
|
|
40
|
+
'type-map/hasCustomMachineConfigComponent': () => false,
|
|
41
|
+
'type-map/importMachineConfig': () => null,
|
|
42
|
+
'features/get': () => false,
|
|
43
|
+
},
|
|
44
|
+
dispatch: jest.fn(),
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
stubs: {
|
|
48
|
+
LabeledInput: true,
|
|
49
|
+
Checkbox: true,
|
|
50
|
+
Taints: true,
|
|
51
|
+
KeyValue: true,
|
|
52
|
+
AdvancedSection: true,
|
|
53
|
+
Banner: true,
|
|
54
|
+
UnitInput: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
describe('component: MachinePool', () => {
|
|
61
|
+
describe('uniquePoolName validation', () => {
|
|
62
|
+
it('should return undefined when the name is empty', () => {
|
|
63
|
+
const pool = createPool('');
|
|
64
|
+
const wrapper = mountMachinePool(pool, [pool]);
|
|
65
|
+
|
|
66
|
+
expect(wrapper.vm.fvExtraRules.uniquePoolName('')).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should return undefined when the pool name is unique', () => {
|
|
70
|
+
const pool1 = createPool('pool1');
|
|
71
|
+
const pool2 = createPool('pool2');
|
|
72
|
+
const wrapper = mountMachinePool(pool1, [pool1, pool2]);
|
|
73
|
+
|
|
74
|
+
expect(wrapper.vm.fvExtraRules.uniquePoolName('pool1')).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should return an error message when the pool name is duplicated', () => {
|
|
78
|
+
const pool1 = createPool('same-name');
|
|
79
|
+
const pool2 = createPool('same-name');
|
|
80
|
+
const wrapper = mountMachinePool(pool1, [pool1, pool2]);
|
|
81
|
+
|
|
82
|
+
expect(wrapper.vm.fvExtraRules.uniquePoolName('same-name')).toStrictEqual(TRANSLATION_KEY);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should ignore pools marked for removal', () => {
|
|
86
|
+
const pool1 = createPool('same-name');
|
|
87
|
+
const pool2 = createPool('same-name', { remove: true });
|
|
88
|
+
const wrapper = mountMachinePool(pool1, [pool1, pool2]);
|
|
89
|
+
|
|
90
|
+
expect(wrapper.vm.fvExtraRules.uniquePoolName('same-name')).toBeUndefined();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it.each([
|
|
94
|
+
['Pool1', 'pool1'],
|
|
95
|
+
['POOL', 'pool'],
|
|
96
|
+
])('should flag names that differ only by case as duplicates (%s vs %s)', (nameA, nameB) => {
|
|
97
|
+
const pool1 = createPool(nameA);
|
|
98
|
+
const pool2 = createPool(nameB);
|
|
99
|
+
const wrapper = mountMachinePool(pool1, [pool1, pool2]);
|
|
100
|
+
|
|
101
|
+
expect(wrapper.vm.fvExtraRules.uniquePoolName(nameA)).toStrictEqual(TRANSLATION_KEY);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -4,9 +4,8 @@ import Loading from '@shell/components/Loading';
|
|
|
4
4
|
import { Banner } from '@components/Banner';
|
|
5
5
|
import CruResource from '@shell/components/CruResource';
|
|
6
6
|
import SelectIconGrid from '@shell/components/SelectIconGrid';
|
|
7
|
-
import EmberPage from '@shell/components/EmberPage';
|
|
8
7
|
import {
|
|
9
|
-
CHART, FROM_CLUSTER, SUB_TYPE, RKE_TYPE, _EDIT, _IMPORT, _CONFIG, _VIEW
|
|
8
|
+
CHART, FROM_CLUSTER, SUB_TYPE, RKE_TYPE, _EDIT, _IMPORT, _CONFIG, _VIEW, _CREATE
|
|
10
9
|
} from '@shell/config/query-params';
|
|
11
10
|
import { mapGetters } from 'vuex';
|
|
12
11
|
import { sortBy } from '@shell/utils/sort';
|
|
@@ -18,8 +17,8 @@ import { mapFeature, RKE2 as RKE2_FEATURE } from '@shell/store/features';
|
|
|
18
17
|
import { allHash } from '@shell/utils/promise';
|
|
19
18
|
import { BLANK_CLUSTER } from '@shell/store/store-types.js';
|
|
20
19
|
import { ELEMENTAL_PRODUCT_NAME, ELEMENTAL_CLUSTER_PROVIDER } from '../../config/elemental-types';
|
|
20
|
+
import { KONTAINER_TO_DRIVER } from '@shell/models/management.cattle.io.kontainerdriver';
|
|
21
21
|
import Rke2Config from './rke2';
|
|
22
|
-
import { DRIVER_TO_IMPORT } from '@shell/models/management.cattle.io.kontainerdriver';
|
|
23
22
|
import { requireAsset } from '@shell/utils/require-asset';
|
|
24
23
|
|
|
25
24
|
const SORT_GROUPS = {
|
|
@@ -44,7 +43,6 @@ export default {
|
|
|
44
43
|
|
|
45
44
|
components: {
|
|
46
45
|
CruResource,
|
|
47
|
-
EmberPage,
|
|
48
46
|
Loading,
|
|
49
47
|
Rke2Config,
|
|
50
48
|
SelectIconGrid,
|
|
@@ -82,16 +80,20 @@ export default {
|
|
|
82
80
|
},
|
|
83
81
|
|
|
84
82
|
async fetch() {
|
|
85
|
-
const hash = {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
const hash = {};
|
|
84
|
+
|
|
85
|
+
if (this.mode === _CREATE) {
|
|
86
|
+
// After we create we wait for these to exist, so start watching
|
|
87
|
+
await this.$store.dispatch('management/watch', { type: MANAGEMENT.CLUSTER, registerType: true });
|
|
88
|
+
await this.$store.dispatch('management/watch', { type: CAPI.RANCHER_CLUSTER, registerType: true });
|
|
89
|
+
} else {
|
|
90
|
+
hash.mgmtClusters = this.value.waitForMgmt();
|
|
91
|
+
}
|
|
90
92
|
|
|
91
93
|
// No need to fetch charts when editing an RKE1 cluster
|
|
92
94
|
// The computed property `isRke1` in this file is based on the RKE1/RKE2 toggle, which is not applicable in this case
|
|
93
95
|
// Instead, we should rely on the value from the model: `this.value.isRke1`
|
|
94
|
-
if (!this.value.isRke1 || (this.value.isRke1 && this.mode !==
|
|
96
|
+
if (!this.value.isRke1 || (this.value.isRke1 && this.mode !== _EDIT)) {
|
|
95
97
|
hash['catalog'] = this.$store.dispatch('catalog/load');
|
|
96
98
|
}
|
|
97
99
|
|
|
@@ -103,19 +105,6 @@ export default {
|
|
|
103
105
|
hash.kontainerDrivers = this.$store.dispatch('management/findAll', { type: MANAGEMENT.KONTAINER_DRIVER });
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
// Not sure if needed for legacy hosted cluster?
|
|
107
|
-
if ( this.value.id && !this.value.isRke2 ) {
|
|
108
|
-
// These are needed to resolve references in the mgmt cluster -> node pool -> node template to figure out what provider the cluster is using
|
|
109
|
-
// so that the edit iframe for ember pages can go to the right place.
|
|
110
|
-
if (this.$store.getters[`management/canList`](MANAGEMENT.NODE_POOL)) {
|
|
111
|
-
hash.rke1NodePools = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_POOL });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (this.$store.getters[`management/canList`](MANAGEMENT.NODE_TEMPLATE)) {
|
|
115
|
-
hash.rke1NodeTemplates = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_TEMPLATE });
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
108
|
const res = await allHash(hash);
|
|
120
109
|
|
|
121
110
|
this.nodeDrivers = res.nodeDrivers || [];
|
|
@@ -172,11 +161,50 @@ export default {
|
|
|
172
161
|
if ( this.$route.query[SUB_TYPE]) {
|
|
173
162
|
subType = this.$route.query[SUB_TYPE];
|
|
174
163
|
} else if (this.value.isImported) {
|
|
164
|
+
// Default imported clusters to the generic imported subType.
|
|
165
|
+
// Imported hosted clusters (e.g. AKS, EKS, GKE) that have an extension-provided
|
|
166
|
+
// component will be overridden below to load the correct custom form.
|
|
175
167
|
subType = IMPORTED;
|
|
176
168
|
} else if (this.value.isLocal) {
|
|
177
169
|
subType = LOCAL;
|
|
178
170
|
}
|
|
179
171
|
|
|
172
|
+
// For imported hosted clusters, check if the provisioner has a matching extension
|
|
173
|
+
// component and override the subType so the correct custom form loads instead of
|
|
174
|
+
// the generic imported configuration page.
|
|
175
|
+
if (subType === IMPORTED && this.value?.id && this.value.provisioner) {
|
|
176
|
+
const provisionerLower = this.value.provisioner.toLowerCase();
|
|
177
|
+
const hasExtension = this.extensions.some((ext) => ext.id === provisionerLower);
|
|
178
|
+
|
|
179
|
+
if (hasExtension) {
|
|
180
|
+
subType = provisionerLower;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Auto-detect subType for existing clusters being edited
|
|
185
|
+
if ( !subType && this.value?.id ) {
|
|
186
|
+
// Check for extension annotation first
|
|
187
|
+
const fromAnnotation = this.value.annotations?.[CAPI_ANNOTATIONS.UI_CUSTOM_PROVIDER];
|
|
188
|
+
|
|
189
|
+
if (fromAnnotation) {
|
|
190
|
+
subType = fromAnnotation;
|
|
191
|
+
} else if ( this.value.isRke2 ) {
|
|
192
|
+
// For custom RKE2 clusters
|
|
193
|
+
if ( this.value.isCustom && (this.realMode === _EDIT || (this.as === _CONFIG && this.realMode === _VIEW)) ) {
|
|
194
|
+
subType = 'custom';
|
|
195
|
+
} else if ( this.value.machineProvider ) {
|
|
196
|
+
// For RKE2/K3s clusters provisioned in Rancher, use the machine pool provisioner
|
|
197
|
+
subType = this.value.machineProvider;
|
|
198
|
+
}
|
|
199
|
+
} else if ( this.value.provisioner ) {
|
|
200
|
+
// For non-RKE2 clusters, try to match against extension-provided subtypes
|
|
201
|
+
const provisionerLower = this.value.provisioner.toLowerCase();
|
|
202
|
+
|
|
203
|
+
// This will be checked against available subtypes after they're computed
|
|
204
|
+
subType = provisionerLower;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
180
208
|
this.subType = subType;
|
|
181
209
|
},
|
|
182
210
|
|
|
@@ -217,74 +245,6 @@ export default {
|
|
|
217
245
|
},
|
|
218
246
|
_RKE2: () => _RKE2,
|
|
219
247
|
|
|
220
|
-
emberLink() {
|
|
221
|
-
if (this.value) {
|
|
222
|
-
// set subtype if editing EKS/GKE/AKS cluster -- this ensures that the component provided by extension is loaded instead of iframing old ember ui
|
|
223
|
-
if (this.value.provisioner) {
|
|
224
|
-
const matchingSubtype = this.subTypes.find((st) => {
|
|
225
|
-
const typeLower = st.id.toLowerCase();
|
|
226
|
-
const provisionerLower = this.value.provisioner.toLowerCase();
|
|
227
|
-
|
|
228
|
-
// This allows extensions to provide type for edit without breaking edit for Ember kontainer providers
|
|
229
|
-
return (!!st.component && (typeLower === provisionerLower)) || (DRIVER_TO_IMPORT[typeLower] === provisionerLower);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
if (matchingSubtype) {
|
|
233
|
-
this.selectType(matchingSubtype.id, false);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// subType set by the ui during cluster creation
|
|
238
|
-
// this is likely from a ui extension trying to load custom ui to edit the cluster
|
|
239
|
-
const fromAnnotation = this.value.annotations?.[CAPI_ANNOTATIONS.UI_CUSTOM_PROVIDER];
|
|
240
|
-
|
|
241
|
-
if (fromAnnotation) {
|
|
242
|
-
this.selectType(fromAnnotation, false);
|
|
243
|
-
|
|
244
|
-
return '';
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// For custom RKE2 clusters, don't load an Ember page.
|
|
248
|
-
// It should be the dashboard.
|
|
249
|
-
if ( this.value.isRke2 && ((this.value.isCustom && this.mode === _EDIT) || (this.value.isCustom && this.as === _CONFIG && this.mode === _VIEW) || (this.subType || '').toLowerCase() === 'custom')) {
|
|
250
|
-
// For admins, this.value.isCustom is used to check if it is a custom cluster.
|
|
251
|
-
// For cluster owners, this.subtype is used.
|
|
252
|
-
this.selectType('custom', false);
|
|
253
|
-
|
|
254
|
-
return '';
|
|
255
|
-
}
|
|
256
|
-
// For existing RKE2/K3s clusters provisioned in Rancher,
|
|
257
|
-
// set the subtype using the machine pool provisioner
|
|
258
|
-
// do not use an iFramed Ember page.
|
|
259
|
-
if ( this.value.isRke2 && this.value.machineProvider ) {
|
|
260
|
-
this.selectType(this.value.machineProvider, false);
|
|
261
|
-
|
|
262
|
-
return '';
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if ( this.subType ) {
|
|
266
|
-
// if driver type has a custom form component, don't load an ember page
|
|
267
|
-
if (this.selectedSubType?.component) {
|
|
268
|
-
return '';
|
|
269
|
-
}
|
|
270
|
-
// For RKE1 and hosted Kubernetes Clusters, set the ember link
|
|
271
|
-
// so that we load the page rather than using RKE2 create
|
|
272
|
-
if (this.selectedSubType?.emberLink) {
|
|
273
|
-
return this.selectedSubType.emberLink;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return '';
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if ( this.value.mgmt?.emberEditPath ) {
|
|
280
|
-
// Iframe an old page
|
|
281
|
-
return this.value.mgmt.emberEditPath;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
return '';
|
|
286
|
-
},
|
|
287
|
-
|
|
288
248
|
rke2Enabled: mapFeature(RKE2_FEATURE),
|
|
289
249
|
|
|
290
250
|
// todo nb is this info stored anywhere else..?
|
|
@@ -310,6 +270,24 @@ export default {
|
|
|
310
270
|
return this.value.isRke2;
|
|
311
271
|
},
|
|
312
272
|
|
|
273
|
+
isEmberKontainerDriver() {
|
|
274
|
+
// RKE2/K3s clusters are never legacy Ember kontainer drivers
|
|
275
|
+
if (!this.value?.id || !this.value?.provisioner || this.value.isRke2) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const provisioner = this.value.provisioner.toLowerCase();
|
|
280
|
+
// Resolve the provisioner to a driver name using the KONTAINER_TO_DRIVER map
|
|
281
|
+
const resolvedName = KONTAINER_TO_DRIVER[provisioner] || provisioner;
|
|
282
|
+
|
|
283
|
+
const driver = this.kontainerDrivers.find((d) => {
|
|
284
|
+
return d.driverName === resolvedName || d.driverName === provisioner || d.id === provisioner;
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// If the driver exists and is not built-in, it's a legacy ember driver
|
|
288
|
+
return !!driver && !driver.spec?.builtIn;
|
|
289
|
+
},
|
|
290
|
+
|
|
313
291
|
templateOptions() {
|
|
314
292
|
if ( !this.rke2Enabled ) {
|
|
315
293
|
return [];
|
|
@@ -327,16 +305,14 @@ export default {
|
|
|
327
305
|
let out = [];
|
|
328
306
|
|
|
329
307
|
const templates = this.templateOptions;
|
|
330
|
-
const vueKontainerTypes = getters['plugins/clusterDrivers'];
|
|
331
308
|
const machineTypes = this.nodeDrivers.filter((x) => x.spec.active && x.state === 'active');
|
|
332
309
|
|
|
333
|
-
//
|
|
310
|
+
// Kontainer drivers that don't have an extension-provided component are legacy Ember-based
|
|
311
|
+
// and no longer functional. Show them as disabled with an informational tooltip.
|
|
312
|
+
const emberRemovalTooltip = getters['i18n/t']('drivers.kontainer.emberRemovalTooltip');
|
|
313
|
+
|
|
334
314
|
this.kontainerDrivers.filter((x) => (isImport ? x.showImport : x.showCreate)).forEach((obj) => {
|
|
335
|
-
|
|
336
|
-
addType(this.$extension, obj.driverName, 'hosted', false);
|
|
337
|
-
} else {
|
|
338
|
-
addType(this.$extension, obj.driverName, 'hosted', false, (isImport ? obj.emberImportPath : obj.emberCreatePath));
|
|
339
|
-
}
|
|
315
|
+
addType(this.$extension, obj.driverName, 'hosted', true, undefined, undefined, emberRemovalTooltip);
|
|
340
316
|
});
|
|
341
317
|
if (!isImport) {
|
|
342
318
|
templates.forEach((chart) => {
|
|
@@ -360,7 +336,7 @@ export default {
|
|
|
360
336
|
machineTypes.forEach((type) => {
|
|
361
337
|
const id = type.spec.displayName || type.id;
|
|
362
338
|
|
|
363
|
-
addType(this.$extension, id, _RKE2, false,
|
|
339
|
+
addType(this.$extension, id, _RKE2, false, undefined, type);
|
|
364
340
|
});
|
|
365
341
|
|
|
366
342
|
addType(this.$extension, 'custom', 'custom2', false);
|
|
@@ -409,7 +385,7 @@ export default {
|
|
|
409
385
|
out.push(subtype);
|
|
410
386
|
}
|
|
411
387
|
|
|
412
|
-
function addType(plugin, id, group, disabled = false,
|
|
388
|
+
function addType(plugin, id, group, disabled = false, iconClass = undefined, providerConfig = undefined, tooltip = undefined) {
|
|
413
389
|
const label = getters['i18n/withFallback'](`cluster.provider."${ id }"`, null, id);
|
|
414
390
|
const description = getters['i18n/withFallback'](`cluster.providerDescription."${ id }"`, null, '');
|
|
415
391
|
const tag = '';
|
|
@@ -439,8 +415,8 @@ export default {
|
|
|
439
415
|
iconClass,
|
|
440
416
|
group,
|
|
441
417
|
disabled,
|
|
442
|
-
emberLink,
|
|
443
418
|
tag,
|
|
419
|
+
tooltip,
|
|
444
420
|
providerConfig
|
|
445
421
|
};
|
|
446
422
|
|
|
@@ -594,12 +570,11 @@ export default {
|
|
|
594
570
|
/>
|
|
595
571
|
</div>
|
|
596
572
|
<div
|
|
597
|
-
v-else-if="
|
|
598
|
-
class="embed"
|
|
573
|
+
v-else-if="isEmberKontainerDriver"
|
|
599
574
|
>
|
|
600
|
-
<
|
|
601
|
-
|
|
602
|
-
|
|
575
|
+
<Banner
|
|
576
|
+
color="warning"
|
|
577
|
+
label-key="drivers.kontainer.emberRemovalMessage"
|
|
603
578
|
/>
|
|
604
579
|
</div>
|
|
605
580
|
<CruResource
|
|
@@ -174,7 +174,7 @@ export default {
|
|
|
174
174
|
Object.entries(this.chartValues).forEach(([name, value]) => {
|
|
175
175
|
const key = this.chartVersionKey(name);
|
|
176
176
|
|
|
177
|
-
this.
|
|
177
|
+
this.userChartValues[key] = value;
|
|
178
178
|
});
|
|
179
179
|
this.setAgentConfiguration();
|
|
180
180
|
},
|
|
@@ -298,6 +298,7 @@ export default {
|
|
|
298
298
|
isEmpty,
|
|
299
299
|
AGENT_CONFIGURATION_TYPES,
|
|
300
300
|
basicsValid: true,
|
|
301
|
+
registryConfigValid: true,
|
|
301
302
|
originalIngressController: this.value.spec.rkeConfig.machineGlobalConfig?.[INGRESS_CONTROLLER] || INGRESS_NONE,
|
|
302
303
|
};
|
|
303
304
|
},
|
|
@@ -906,7 +907,8 @@ export default {
|
|
|
906
907
|
return this.validationPassed &&
|
|
907
908
|
this.fvFormIsValid &&
|
|
908
909
|
this.etcdConfigValid &&
|
|
909
|
-
this.basicsValid
|
|
910
|
+
this.basicsValid &&
|
|
911
|
+
this.registryConfigValid;
|
|
910
912
|
},
|
|
911
913
|
nginxSupported() {
|
|
912
914
|
if (this.serverArgs?.disable?.options.includes(RKE2_INGRESS_NGINX)) {
|
|
@@ -2518,14 +2520,14 @@ export default {
|
|
|
2518
2520
|
>
|
|
2519
2521
|
<template
|
|
2520
2522
|
v-for="(obj, idx) in machinePools"
|
|
2521
|
-
:key="
|
|
2523
|
+
:key="obj.id"
|
|
2522
2524
|
>
|
|
2523
2525
|
<Tab
|
|
2524
2526
|
v-if="!obj.remove"
|
|
2525
2527
|
:key="obj.id"
|
|
2526
2528
|
:weight="-1 * idx"
|
|
2527
2529
|
:name="obj.id"
|
|
2528
|
-
:label="obj.pool.name || '
|
|
2530
|
+
:label="obj.pool.name || t('cluster.machinePool.name.notNamed')"
|
|
2529
2531
|
:show-header="false"
|
|
2530
2532
|
:error="!machinePoolValidation[obj.id]"
|
|
2531
2533
|
>
|
|
@@ -2688,6 +2690,7 @@ export default {
|
|
|
2688
2690
|
<Tab
|
|
2689
2691
|
:name="REGISTRIES_TAB_NAME"
|
|
2690
2692
|
label-key="cluster.tabs.registry"
|
|
2693
|
+
:error="!registryConfigValid"
|
|
2691
2694
|
>
|
|
2692
2695
|
<Registries
|
|
2693
2696
|
v-if="isActiveTabRegistries"
|
|
@@ -2703,6 +2706,7 @@ export default {
|
|
|
2703
2706
|
@custom-registry-changed="toggleCustomRegistry"
|
|
2704
2707
|
@registry-host-changed="handleRegistryHostChanged"
|
|
2705
2708
|
@registry-secret-changed="handleRegistrySecretChanged"
|
|
2709
|
+
@registry-validation-changed="(val) => registryConfigValid = val"
|
|
2706
2710
|
/>
|
|
2707
2711
|
</Tab>
|
|
2708
2712
|
|
|
@@ -106,6 +106,16 @@ export default {
|
|
|
106
106
|
const max = this.value?.pool?.autoscalingMaxSize || 0;
|
|
107
107
|
|
|
108
108
|
return max - min >= 0 ? undefined : this.t('cluster.machinePool.autoscaler.validation.isAutoscalerMaxGreaterThanMin');
|
|
109
|
+
},
|
|
110
|
+
uniquePoolName: (name) => {
|
|
111
|
+
if (!name) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const otherPools = (this.machinePools || []).filter((p) => !p.remove && p !== this.value);
|
|
116
|
+
const isDuplicate = otherPools.some((p) => p.pool.name?.toLowerCase() === name.toLowerCase());
|
|
117
|
+
|
|
118
|
+
return isDuplicate ? this.t('cluster.machinePool.name.unique') : undefined;
|
|
109
119
|
}
|
|
110
120
|
}
|
|
111
121
|
};
|
|
@@ -295,6 +305,7 @@ export default {
|
|
|
295
305
|
:label="t('cluster.machinePool.name.label')"
|
|
296
306
|
:required="true"
|
|
297
307
|
:disabled="!value.config || !!value.config.id || busy"
|
|
308
|
+
:require-dirty="false"
|
|
298
309
|
:rules="fvGetAndReportPathRules(MACHINE_POOL_VALIDATION.FIELDS.NAME)"
|
|
299
310
|
data-testid="machine-pool-name-input"
|
|
300
311
|
/>
|