@rancher/shell 0.3.16 → 0.3.18
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/assets/images/wechat-qr-code.jpg +0 -0
- package/assets/translations/en-us.yaml +75 -16
- package/assets/translations/zh-hans.yaml +151 -15
- package/chart/__tests__/S3.test.ts +50 -0
- package/chart/rancher-backup/S3.vue +21 -0
- package/chart/rancher-backup/index.vue +4 -0
- package/components/AsyncButton.vue +1 -1
- package/components/CommunityLinks.vue +1 -0
- package/components/FileDiff.vue +92 -85
- package/components/Inactivity.vue +10 -0
- package/components/LazyImage.vue +2 -2
- package/components/PromptRestore.vue +7 -5
- package/components/ResourceDetail/Masthead.vue +1 -1
- package/components/ResourceDetail/index.vue +8 -14
- package/components/ResourceList/index.vue +1 -1
- package/components/ResourceTable.vue +50 -2
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/PromptRestore.test.ts +72 -0
- package/components/auth/AzureWarning.vue +1 -1
- package/components/auth/RoleDetailEdit.vue +1 -0
- package/components/fleet/FleetResources.vue +3 -64
- package/components/form/FileImageSelector.vue +9 -0
- package/components/form/FileSelector.vue +2 -1
- package/components/form/MatchExpressions.vue +1 -3
- package/components/form/NameNsDescription.vue +28 -12
- package/components/form/NodeAffinity.vue +2 -2
- package/components/form/PodAffinity.vue +2 -2
- package/components/form/ResourceTabs/index.vue +8 -2
- package/components/form/Select.vue +16 -0
- package/components/form/__tests__/FileImageSelector.test.ts +42 -0
- package/components/form/__tests__/FileSelector.test.ts +76 -0
- package/components/form/__tests__/NodeAffinity.test.ts +38 -0
- package/components/form/__tests__/PodAffinity.test.ts +46 -0
- package/components/formatter/ClusterLink.vue +8 -4
- package/components/formatter/ClusterProvider.vue +3 -1
- package/components/formatter/ImageName.vue +23 -0
- package/components/formatter/PodImages.vue +7 -1
- package/components/formatter/__tests__/ClusterLink.test.ts +101 -0
- package/components/formatter/__tests__/ClusterProvider.test.ts +24 -0
- package/components/nav/Header.vue +2 -2
- package/components/nav/WindowManager/ContainerShell.vue +60 -36
- package/components/nav/WindowManager/__tests__/ContainerShell.test.ts +561 -0
- package/config/__test__/home-links.test.ts +62 -0
- package/config/home-links.js +15 -3
- package/config/labels-annotations.js +7 -2
- package/config/persistentVolume.ts +108 -0
- package/config/product/manager.js +5 -1
- package/config/router.js +0 -4
- package/config/settings.ts +4 -0
- package/config/table-headers.js +6 -5
- package/config/types.js +2 -0
- package/config/uiplugins.js +50 -5
- package/core/plugin-helpers.js +39 -15
- package/core/plugin.ts +9 -0
- package/core/plugins.js +1 -1
- package/core/types-provisioning.ts +253 -0
- package/core/types.ts +21 -3
- package/detail/autoscaling.horizontalpodautoscaler/index.vue +50 -1
- package/detail/fleet.cattle.io.gitrepo.vue +10 -2
- package/detail/node.vue +6 -6
- package/detail/pod.vue +38 -9
- package/detail/provisioning.cattle.io.cluster.vue +46 -7
- package/detail/workload/index.vue +49 -18
- package/edit/__tests__/fleet.cattle.io.gitrepo.test.ts +62 -0
- package/edit/__tests__/ui.cattle.io.navlink.test.ts +110 -0
- package/edit/auth/github.vue +1 -0
- package/edit/autoscaling.horizontalpodautoscaler/hpa-scaling-rule.vue +130 -0
- package/edit/autoscaling.horizontalpodautoscaler/index.vue +79 -0
- package/edit/fleet.cattle.io.clustergroup.vue +14 -3
- package/edit/fleet.cattle.io.gitrepo.vue +18 -1
- package/edit/namespace.vue +9 -1
- package/edit/networking.k8s.io.ingress/RulePath.vue +0 -2
- package/edit/persistentvolume/__tests__/persistentvolume.test.ts +82 -0
- package/edit/persistentvolume/index.vue +2 -1
- package/edit/persistentvolume/plugins/csi.vue +3 -1
- package/edit/persistentvolume/plugins/longhorn.vue +12 -12
- package/edit/provisioning.cattle.io.cluster/AgentConfiguration.vue +1 -30
- package/edit/provisioning.cattle.io.cluster/RegistryConfigs.vue +15 -11
- package/edit/provisioning.cattle.io.cluster/__tests__/rke2.test.ts +79 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +53 -1
- package/edit/provisioning.cattle.io.cluster/rke2.vue +335 -151
- package/edit/storage.k8s.io.storageclass/index.vue +1 -2
- package/edit/ui.cattle.io.navlink.vue +213 -186
- package/initialize/App.js +3 -13
- package/initialize/layouts.ts +26 -0
- package/layouts/default.vue +1 -1
- package/list/group.principal.vue +1 -1
- package/list/provisioning.cattle.io.cluster.vue +8 -1
- package/middleware/authenticated.js +101 -5
- package/mixins/brand.js +39 -3
- package/mixins/child-hook.js +2 -2
- package/mixins/create-edit-view/impl.js +4 -4
- package/models/chart.js +1 -1
- package/models/fleet.cattle.io.cluster.js +33 -4
- package/models/fleet.cattle.io.gitrepo.js +113 -38
- package/models/management.cattle.io.kontainerdriver.js +14 -0
- package/models/persistentvolume.js +2 -111
- package/models/pod.js +30 -0
- package/models/provisioning.cattle.io.cluster.js +9 -1
- package/models/rke.cattle.io.etcdsnapshot.js +10 -7
- package/package.json +2 -2
- package/pages/about.vue +8 -2
- package/pages/auth/login.vue +1 -1
- package/pages/auth/logout.vue +11 -3
- package/pages/c/_cluster/apps/charts/index.vue +5 -2
- package/pages/c/_cluster/apps/charts/install.vue +5 -0
- package/pages/c/_cluster/auth/group.principal/assign-edit.vue +1 -1
- package/pages/c/_cluster/auth/roles/index.vue +1 -1
- package/pages/c/_cluster/explorer/index.vue +2 -11
- package/pages/c/_cluster/manager/cloudCredential/_id.vue +0 -1
- package/pages/c/_cluster/manager/cloudCredential/create.vue +0 -1
- package/pages/c/_cluster/settings/brand.vue +11 -8
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +177 -0
- package/pages/c/_cluster/uiplugins/PluginInfoPanel.vue +19 -3
- package/pages/c/_cluster/uiplugins/RemoveUIPlugins.vue +90 -21
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +107 -37
- package/pages/c/_cluster/uiplugins/index.vue +160 -44
- package/pages/docs/_doc.vue +9 -3
- package/pages/home.vue +6 -6
- package/pages/support/index.vue +10 -4
- package/pkg/auto-import.js +1 -1
- package/plugins/clean-tooltip-directive.js +1 -1
- package/plugins/dashboard-store/__tests__/actions.spec.ts +165 -0
- package/plugins/dashboard-store/__tests__/getters.spec.ts +100 -0
- package/plugins/dashboard-store/__tests__/{mutations.spec.js → mutations.spec.ts} +2 -2
- package/plugins/dashboard-store/actions.js +1 -1
- package/plugins/dashboard-store/resource-class.js +39 -2
- package/plugins/plugin.js +9 -1
- package/plugins/steve/__tests__/getters.spec.ts +93 -0
- package/plugins/steve/getters.js +21 -1
- package/plugins/steve/subscribe.js +1 -3
- package/rancher-components/BadgeState/BadgeState.vue +5 -1
- package/rancher-components/Banner/Banner.test.ts +51 -1
- package/rancher-components/Banner/Banner.vue +134 -53
- package/rancher-components/Card/Card.test.ts +37 -0
- package/rancher-components/Card/Card.vue +24 -7
- package/rancher-components/Form/Checkbox/Checkbox.test.ts +20 -29
- package/rancher-components/Form/Checkbox/Checkbox.vue +45 -20
- package/rancher-components/Form/LabeledInput/LabeledInput.test.ts +2 -8
- package/rancher-components/Form/LabeledInput/LabeledInput.vue +22 -10
- package/rancher-components/Form/Radio/RadioButton.test.ts +31 -0
- package/rancher-components/Form/Radio/RadioButton.vue +30 -13
- package/rancher-components/Form/Radio/RadioGroup.vue +26 -7
- package/rancher-components/Form/TextArea/TextAreaAutoGrow.vue +7 -6
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.test.ts +25 -38
- package/rancher-components/Form/ToggleSwitch/ToggleSwitch.vue +23 -11
- package/rancher-components/LabeledTooltip/LabeledTooltip.vue +19 -5
- package/rancher-components/StringList/StringList.test.ts +453 -49
- package/rancher-components/StringList/StringList.vue +44 -26
- package/scripts/extension/publish +2 -2
- package/scripts/typegen.sh +11 -2
- package/server/server-middleware.js +4 -12
- package/store/index.js +14 -3
- package/store/prefs.js +0 -3
- package/store/store-types.js +2 -0
- package/store/type-map.js +17 -29
- package/types/api.d.ts +1 -0
- package/types/fleet.d.ts +1 -0
- package/types/shell/index.d.ts +931 -85
- package/types/userPreferences.d.ts +1 -1
- package/utils/__mocks__/socket.js +21 -0
- package/utils/grafana.js +23 -11
- package/utils/kube.js +9 -0
- package/utils/object.js +27 -0
- package/utils/selector.js +2 -1
- package/utils/settings.ts +2 -2
- package/utils/validators/formRules/index.ts +3 -3
- package/vue.config.js +3 -2
- package/components/.DS_Store +0 -0
- package/components/__tests__/.DS_Store +0 -0
- package/creators/pkg/package-lock.json +0 -37
- package/pages/safeMode.vue +0 -17
- package/plugins/steve/urloptions.js +0 -47
- package/yarn-error.log +0 -196
|
@@ -6,10 +6,12 @@ import merge from 'lodash/merge';
|
|
|
6
6
|
import { mapGetters } from 'vuex';
|
|
7
7
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
8
8
|
import FormValidation from '@shell/mixins/form-validation';
|
|
9
|
+
import { normalizeName } from '@shell/utils/kube';
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
12
|
CAPI,
|
|
12
13
|
MANAGEMENT,
|
|
14
|
+
NAMESPACE,
|
|
13
15
|
NORMAN,
|
|
14
16
|
SCHEMA,
|
|
15
17
|
DEFAULT_WORKSPACE,
|
|
@@ -42,7 +44,7 @@ import { LabeledInput } from '@components/Form/LabeledInput';
|
|
|
42
44
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
43
45
|
import Loading from '@shell/components/Loading';
|
|
44
46
|
import MatchExpressions from '@shell/components/form/MatchExpressions';
|
|
45
|
-
import NameNsDescription
|
|
47
|
+
import NameNsDescription from '@shell/components/form/NameNsDescription';
|
|
46
48
|
import { RadioGroup } from '@components/Form/Radio';
|
|
47
49
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
48
50
|
import Tabbed from '@shell/components/Tabbed';
|
|
@@ -69,7 +71,9 @@ import S3Config from './S3Config';
|
|
|
69
71
|
import SelectCredential from './SelectCredential';
|
|
70
72
|
import AdvancedSection from '@shell/components/AdvancedSection.vue';
|
|
71
73
|
import { ELEMENTAL_SCHEMA_IDS, KIND, ELEMENTAL_CLUSTER_PROVIDER } from '../../config/elemental-types';
|
|
72
|
-
import AgentConfiguration
|
|
74
|
+
import AgentConfiguration from './AgentConfiguration';
|
|
75
|
+
import { getApplicableExtensionEnhancements } from '@shell/core/plugin-helpers';
|
|
76
|
+
import { ExtensionPoint, TabLocation } from '@shell/core/types';
|
|
73
77
|
|
|
74
78
|
const PUBLIC = 'public';
|
|
75
79
|
const PRIVATE = 'private';
|
|
@@ -154,122 +158,9 @@ export default {
|
|
|
154
158
|
},
|
|
155
159
|
|
|
156
160
|
async fetch() {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if ( !this.rke2Versions ) {
|
|
161
|
-
const hash = {
|
|
162
|
-
rke2Versions: this.$store.dispatch('management/request', { url: '/v1-rke2-release/releases' }),
|
|
163
|
-
k3sVersions: this.$store.dispatch('management/request', { url: '/v1-k3s-release/releases' }),
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
if ( this.$store.getters['management/canList'](MANAGEMENT.POD_SECURITY_POLICY_TEMPLATE) ) {
|
|
167
|
-
hash.allPSPs = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.POD_SECURITY_POLICY_TEMPLATE });
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (this.$store.getters['management/canList'](MANAGEMENT.PSA)) {
|
|
171
|
-
hash.allPSAs = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PSA });
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Get the latest versions from the global settings if possible
|
|
175
|
-
const globalSettings = await this.$store.getters['management/all'](MANAGEMENT.SETTING) || [];
|
|
176
|
-
const defaultRke2Setting = globalSettings.find((setting) => setting.id === 'rke2-default-version') || {};
|
|
177
|
-
const defaultK3sSetting = globalSettings.find((setting) => setting.id === 'k3s-default-version') || {};
|
|
178
|
-
|
|
179
|
-
let defaultRke2 = defaultRke2Setting?.value || defaultRke2Setting?.default;
|
|
180
|
-
let defaultK3s = defaultK3sSetting?.value || defaultK3sSetting?.default;
|
|
181
|
-
|
|
182
|
-
// RKE2: Use the channel if we can not get the version from the settings
|
|
183
|
-
if (!defaultRke2) {
|
|
184
|
-
hash.rke2Channels = this.$store.dispatch('management/request', { url: '/v1-rke2-release/channels' });
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// K3S: Use the channel if we can not get the version from the settings
|
|
188
|
-
if (!defaultK3s) {
|
|
189
|
-
hash.k3sChannels = this.$store.dispatch('management/request', { url: '/v1-k3s-release/channels' });
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const res = await allHash(hash);
|
|
193
|
-
|
|
194
|
-
this.allPSPs = res.allPSPs || [];
|
|
195
|
-
this.allPSAs = res.allPSAs || [];
|
|
196
|
-
this.rke2Versions = res.rke2Versions.data || [];
|
|
197
|
-
this.k3sVersions = res.k3sVersions.data || [];
|
|
198
|
-
|
|
199
|
-
if (!defaultRke2) {
|
|
200
|
-
const rke2Channels = res.rke2Channels.data || [];
|
|
201
|
-
|
|
202
|
-
defaultRke2 = rke2Channels.find((x) => x.id === 'default')?.latest;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
if (!defaultK3s) {
|
|
206
|
-
const k3sChannels = res.k3sChannels.data || [];
|
|
207
|
-
|
|
208
|
-
defaultK3s = k3sChannels.find((x) => x.id === 'default')?.latest;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if ( !this.rke2Versions.length && !this.k3sVersions.length ) {
|
|
212
|
-
throw new Error('No version info found in KDM');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Store default versions
|
|
216
|
-
this.defaultRke2 = defaultRke2;
|
|
217
|
-
this.defaultK3s = defaultK3s;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if ( !this.value.spec ) {
|
|
221
|
-
set(this.value, 'spec', {});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if ( !this.value.spec.machineSelectorConfig ) {
|
|
225
|
-
set(this.value.spec, 'machineSelectorConfig', []);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if ( !this.value.spec.machineSelectorConfig.find((x) => !x.machineLabelSelector) ) {
|
|
229
|
-
this.value.spec.machineSelectorConfig.unshift({ config: {} });
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if ( this.value.spec.cloudCredentialSecretName ) {
|
|
233
|
-
await this.$store.dispatch('rancher/findAll', { type: NORMAN.CLOUD_CREDENTIAL });
|
|
234
|
-
this.credentialId = `${ this.value.spec.cloudCredentialSecretName }`;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if ( !this.value.spec.kubernetesVersion ) {
|
|
238
|
-
set(this.value.spec, 'kubernetesVersion', this.defaultVersion);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if ( this.rkeConfig.etcd?.s3?.bucket ) {
|
|
242
|
-
this.s3Backup = true;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if ( !this.rkeConfig.etcd ) {
|
|
246
|
-
set(this.rkeConfig, 'etcd', {
|
|
247
|
-
disableSnapshots: false,
|
|
248
|
-
s3: null,
|
|
249
|
-
snapshotRetention: 5,
|
|
250
|
-
snapshotScheduleCron: '0 */5 * * *',
|
|
251
|
-
});
|
|
252
|
-
} else if (typeof this.rkeConfig.etcd.disableSnapshots === 'undefined') {
|
|
253
|
-
const disableSnapshots = !this.rkeConfig.etcd.snapshotRetention && !this.rkeConfig.etcd.snapshotScheduleCron;
|
|
254
|
-
|
|
255
|
-
set(this.rkeConfig.etcd, 'disableSnapshots', disableSnapshots);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if ( !this.machinePools ) {
|
|
259
|
-
await this.initMachinePools(this.value.spec.rkeConfig.machinePools);
|
|
260
|
-
if ( this.mode === _CREATE && !this.machinePools.length ) {
|
|
261
|
-
await this.addMachinePool();
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if ( this.value.spec.defaultPodSecurityPolicyTemplateName === undefined ) {
|
|
266
|
-
set(this.value.spec, 'defaultPodSecurityPolicyTemplateName', '');
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if ( this.value.spec.defaultPodSecurityAdmissionConfigurationTemplateName === undefined ) {
|
|
270
|
-
set(this.value.spec, 'defaultPodSecurityAdmissionConfigurationTemplateName', '');
|
|
271
|
-
}
|
|
272
|
-
|
|
161
|
+
this.psps = await this.getPsps();
|
|
162
|
+
await this.fetchRke2Versions();
|
|
163
|
+
await this.initSpecs();
|
|
273
164
|
await this.initAddons();
|
|
274
165
|
await this.initRegistry();
|
|
275
166
|
|
|
@@ -279,17 +170,7 @@ export default {
|
|
|
279
170
|
this.userChartValues[key] = value;
|
|
280
171
|
});
|
|
281
172
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
// Cluster Agent Configuration
|
|
285
|
-
if ( !this.value.spec[CLUSTER_AGENT_CUSTOMIZATION]) {
|
|
286
|
-
set(this.value.spec, CLUSTER_AGENT_CUSTOMIZATION, {});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Fleet Agent Configuration
|
|
290
|
-
if ( !this.value.spec[FLEET_AGENT_CUSTOMIZATION] ) {
|
|
291
|
-
set(this.value.spec, FLEET_AGENT_CUSTOMIZATION, {});
|
|
292
|
-
}
|
|
173
|
+
this.setAgentConfiguration();
|
|
293
174
|
},
|
|
294
175
|
|
|
295
176
|
data() {
|
|
@@ -362,7 +243,9 @@ export default {
|
|
|
362
243
|
truncateHostnames: truncateLimit === NETBIOS_TRUNCATION_LENGTH,
|
|
363
244
|
truncateLimit,
|
|
364
245
|
busy: false,
|
|
365
|
-
machinePoolValidation: {} // map of validation states for each machine pool
|
|
246
|
+
machinePoolValidation: {}, // map of validation states for each machine pool
|
|
247
|
+
allNamespaces: [],
|
|
248
|
+
extensionTabs: getApplicableExtensionEnhancements(this, ExtensionPoint.TAB, TabLocation.CLUSTER_CREATE_RKE2, this.$route, this),
|
|
366
249
|
};
|
|
367
250
|
},
|
|
368
251
|
|
|
@@ -370,6 +253,7 @@ export default {
|
|
|
370
253
|
...mapGetters({ allCharts: 'catalog/charts' }),
|
|
371
254
|
...mapGetters(['currentCluster']),
|
|
372
255
|
...mapGetters({ features: 'features/get' }),
|
|
256
|
+
...mapGetters(['namespaces']),
|
|
373
257
|
|
|
374
258
|
PUBLIC: () => PUBLIC,
|
|
375
259
|
PRIVATE: () => PRIVATE,
|
|
@@ -734,6 +618,33 @@ export default {
|
|
|
734
618
|
return (this.machinePools || []).filter((x) => !x.remove);
|
|
735
619
|
},
|
|
736
620
|
|
|
621
|
+
/**
|
|
622
|
+
* Extension provider where being provisioned by an extension
|
|
623
|
+
*/
|
|
624
|
+
extensionProvider() {
|
|
625
|
+
const extClass = this.$plugin.getDynamic('provisioner', this.provider);
|
|
626
|
+
|
|
627
|
+
if (extClass) {
|
|
628
|
+
return new extClass({
|
|
629
|
+
dispatch: this.$store.dispatch,
|
|
630
|
+
getters: this.$store.getters,
|
|
631
|
+
axios: this.$store.$axios,
|
|
632
|
+
$plugin: this.$store.app.$plugin,
|
|
633
|
+
$t: this.t,
|
|
634
|
+
isCreate: this.isCreate
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return undefined;
|
|
639
|
+
},
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Is a namespace needed? Only supported for providers from extensions, otherwise default is no
|
|
643
|
+
*/
|
|
644
|
+
needsNamespace() {
|
|
645
|
+
return this.extensionProvider ? !!this.extensionProvider.namespaced : false;
|
|
646
|
+
},
|
|
647
|
+
|
|
737
648
|
machineConfigSchema() {
|
|
738
649
|
let schema;
|
|
739
650
|
|
|
@@ -745,6 +656,19 @@ export default {
|
|
|
745
656
|
schema = `${ CAPI.MACHINE_CONFIG_GROUP }.${ this.provider }config`;
|
|
746
657
|
}
|
|
747
658
|
|
|
659
|
+
// If this is an extension provider then the extension can provide the schema
|
|
660
|
+
const extensionSchema = this.extensionProvider?.machineConfigSchema;
|
|
661
|
+
|
|
662
|
+
if (extensionSchema) {
|
|
663
|
+
// machineConfigSchema can either be the schema name (string) or the schema itself (object)
|
|
664
|
+
if (typeof extensionSchema === 'object') {
|
|
665
|
+
return extensionSchema;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Name of schema to use
|
|
669
|
+
schema = extensionSchema;
|
|
670
|
+
}
|
|
671
|
+
|
|
748
672
|
return this.$store.getters['management/schemaFor'](schema);
|
|
749
673
|
},
|
|
750
674
|
|
|
@@ -1033,7 +957,7 @@ export default {
|
|
|
1033
957
|
validationPassed() {
|
|
1034
958
|
const validRequiredPools = this.hasMachinePools ? this.hasRequiredNodes() : true;
|
|
1035
959
|
|
|
1036
|
-
let base = (this.provider === 'custom' || this.isElementalCluster || !!this.credentialId);
|
|
960
|
+
let base = (this.provider === 'custom' || this.isElementalCluster || !!this.credentialId || !this.needCredential);
|
|
1037
961
|
|
|
1038
962
|
// and in all of the validation statuses for each machine pool
|
|
1039
963
|
Object.values(this.machinePoolValidation).forEach((v) => (base = base && v));
|
|
@@ -1121,19 +1045,198 @@ export default {
|
|
|
1121
1045
|
created() {
|
|
1122
1046
|
this.registerBeforeHook(this.saveMachinePools, 'save-machine-pools');
|
|
1123
1047
|
this.registerBeforeHook(this.setRegistryConfig, 'set-registry-config');
|
|
1124
|
-
this.registerBeforeHook(this.agentConfigurationCleanup, 'cleanup-agent-config');
|
|
1125
1048
|
this.registerAfterHook(this.cleanupMachinePools, 'cleanup-machine-pools');
|
|
1126
1049
|
this.registerAfterHook(this.saveRoleBindings, 'save-role-bindings');
|
|
1050
|
+
|
|
1051
|
+
// Register any hooks for this extension provider
|
|
1052
|
+
if (this.extensionProvider?.registerSaveHooks) {
|
|
1053
|
+
this.extensionProvider.registerSaveHooks(this.registerBeforeHook, this.registerAfterHook, this.value);
|
|
1054
|
+
}
|
|
1127
1055
|
},
|
|
1128
1056
|
|
|
1129
1057
|
methods: {
|
|
1130
1058
|
nlToBr,
|
|
1131
1059
|
set,
|
|
1132
1060
|
|
|
1061
|
+
/**
|
|
1062
|
+
* Initialize all the cluster specs
|
|
1063
|
+
*/
|
|
1064
|
+
async initSpecs() {
|
|
1065
|
+
if ( !this.value.spec ) {
|
|
1066
|
+
set(this.value, 'spec', {});
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
if ( !this.value.spec.machineSelectorConfig ) {
|
|
1070
|
+
set(this.value.spec, 'machineSelectorConfig', []);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
if ( !this.value.spec.machineSelectorConfig.find((x) => !x.machineLabelSelector) ) {
|
|
1074
|
+
this.value.spec.machineSelectorConfig.unshift({ config: {} });
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
if ( this.value.spec.cloudCredentialSecretName ) {
|
|
1078
|
+
await this.$store.dispatch('rancher/findAll', { type: NORMAN.CLOUD_CREDENTIAL });
|
|
1079
|
+
this.credentialId = `${ this.value.spec.cloudCredentialSecretName }`;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
if ( !this.value.spec.kubernetesVersion ) {
|
|
1083
|
+
set(this.value.spec, 'kubernetesVersion', this.defaultVersion);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
if ( this.rkeConfig.etcd?.s3?.bucket ) {
|
|
1087
|
+
this.s3Backup = true;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
if ( !this.rkeConfig.etcd ) {
|
|
1091
|
+
set(this.rkeConfig, 'etcd', {
|
|
1092
|
+
disableSnapshots: false,
|
|
1093
|
+
s3: null,
|
|
1094
|
+
snapshotRetention: 5,
|
|
1095
|
+
snapshotScheduleCron: '0 */5 * * *',
|
|
1096
|
+
});
|
|
1097
|
+
} else if (typeof this.rkeConfig.etcd.disableSnapshots === 'undefined') {
|
|
1098
|
+
const disableSnapshots = !this.rkeConfig.etcd.snapshotRetention && !this.rkeConfig.etcd.snapshotScheduleCron;
|
|
1099
|
+
|
|
1100
|
+
set(this.rkeConfig.etcd, 'disableSnapshots', disableSnapshots);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// Namespaces if required - this is mainly for custom provisioners via extensions that want
|
|
1104
|
+
// to allow creating their resources in a different namespace
|
|
1105
|
+
if (this.needsNamespace) {
|
|
1106
|
+
this.allNamespaces = await this.$store.dispatch('management/findAll', { type: NAMESPACE });
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
if ( !this.machinePools ) {
|
|
1110
|
+
await this.initMachinePools(this.value.spec.rkeConfig.machinePools);
|
|
1111
|
+
if ( this.mode === _CREATE && !this.machinePools.length ) {
|
|
1112
|
+
await this.addMachinePool();
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
if ( this.value.spec.defaultPodSecurityPolicyTemplateName === undefined ) {
|
|
1117
|
+
set(this.value.spec, 'defaultPodSecurityPolicyTemplateName', '');
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if ( this.value.spec.defaultPodSecurityAdmissionConfigurationTemplateName === undefined ) {
|
|
1121
|
+
set(this.value.spec, 'defaultPodSecurityAdmissionConfigurationTemplateName', '');
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Fetch RKE versions and their configurations to be mapped to the form
|
|
1127
|
+
*/
|
|
1128
|
+
async fetchRke2Versions() {
|
|
1129
|
+
if ( !this.rke2Versions ) {
|
|
1130
|
+
const hash = {
|
|
1131
|
+
rke2Versions: this.$store.dispatch('management/request', { url: '/v1-rke2-release/releases' }),
|
|
1132
|
+
k3sVersions: this.$store.dispatch('management/request', { url: '/v1-k3s-release/releases' }),
|
|
1133
|
+
};
|
|
1134
|
+
|
|
1135
|
+
if ( this.$store.getters['management/canList'](MANAGEMENT.POD_SECURITY_POLICY_TEMPLATE) ) {
|
|
1136
|
+
hash.allPSPs = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.POD_SECURITY_POLICY_TEMPLATE });
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
if (this.$store.getters['management/canList'](MANAGEMENT.PSA)) {
|
|
1140
|
+
hash.allPSAs = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.PSA });
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
// Get the latest versions from the global settings if possible
|
|
1144
|
+
const globalSettings = await this.$store.getters['management/all'](MANAGEMENT.SETTING) || [];
|
|
1145
|
+
const defaultRke2Setting = globalSettings.find((setting) => setting.id === 'rke2-default-version') || {};
|
|
1146
|
+
const defaultK3sSetting = globalSettings.find((setting) => setting.id === 'k3s-default-version') || {};
|
|
1147
|
+
|
|
1148
|
+
let defaultRke2 = defaultRke2Setting?.value || defaultRke2Setting?.default;
|
|
1149
|
+
let defaultK3s = defaultK3sSetting?.value || defaultK3sSetting?.default;
|
|
1150
|
+
|
|
1151
|
+
// RKE2: Use the channel if we can not get the version from the settings
|
|
1152
|
+
if (!defaultRke2) {
|
|
1153
|
+
hash.rke2Channels = this.$store.dispatch('management/request', { url: '/v1-rke2-release/channels' });
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// K3S: Use the channel if we can not get the version from the settings
|
|
1157
|
+
if (!defaultK3s) {
|
|
1158
|
+
hash.k3sChannels = this.$store.dispatch('management/request', { url: '/v1-k3s-release/channels' });
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
const res = await allHash(hash);
|
|
1162
|
+
|
|
1163
|
+
this.allPSPs = res.allPSPs || [];
|
|
1164
|
+
this.allPSAs = res.allPSAs || [];
|
|
1165
|
+
this.rke2Versions = res.rke2Versions.data || [];
|
|
1166
|
+
this.k3sVersions = res.k3sVersions.data || [];
|
|
1167
|
+
|
|
1168
|
+
if (!defaultRke2) {
|
|
1169
|
+
const rke2Channels = res.rke2Channels.data || [];
|
|
1170
|
+
|
|
1171
|
+
defaultRke2 = rke2Channels.find((x) => x.id === 'default')?.latest;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
if (!defaultK3s) {
|
|
1175
|
+
const k3sChannels = res.k3sChannels.data || [];
|
|
1176
|
+
|
|
1177
|
+
defaultK3s = k3sChannels.find((x) => x.id === 'default')?.latest;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if ( !this.rke2Versions.length && !this.k3sVersions.length ) {
|
|
1181
|
+
throw new Error('No version info found in KDM');
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// Store default versions
|
|
1185
|
+
this.defaultRke2 = defaultRke2;
|
|
1186
|
+
this.defaultK3s = defaultK3s;
|
|
1187
|
+
}
|
|
1188
|
+
},
|
|
1189
|
+
|
|
1190
|
+
cleanAgentConfiguration(model, key) {
|
|
1191
|
+
if (!model || !model[key]) {
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
const v = model[key];
|
|
1196
|
+
|
|
1197
|
+
if (Array.isArray(v) && v.length === 0) {
|
|
1198
|
+
delete model[key];
|
|
1199
|
+
} else if (v && typeof v === 'object') {
|
|
1200
|
+
Object.keys(v).forEach((k) => {
|
|
1201
|
+
// delete these auxiliary props used in podAffinity and nodeAffinity that shouldn't be sent to the server
|
|
1202
|
+
if (k === '_namespaceOption' || k === '_namespaces' || k === '_anti' || k === '_id') {
|
|
1203
|
+
delete v[k];
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// prevent cleanup of "namespaceSelector" when an empty object because it represents all namespaces in pod/node affinity
|
|
1207
|
+
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#podaffinityterm-v1-core
|
|
1208
|
+
if (k !== 'namespaceSelector') {
|
|
1209
|
+
this.cleanAgentConfiguration(v, k);
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
if (Object.keys(v).length === 0) {
|
|
1214
|
+
delete model[key];
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
},
|
|
1218
|
+
|
|
1219
|
+
/**
|
|
1220
|
+
* Clean agent configuration objects, so we only send values when the user has configured something
|
|
1221
|
+
*/
|
|
1133
1222
|
agentConfigurationCleanup() {
|
|
1134
|
-
|
|
1135
|
-
cleanAgentConfiguration(this.value.spec,
|
|
1136
|
-
|
|
1223
|
+
this.cleanAgentConfiguration(this.value.spec, CLUSTER_AGENT_CUSTOMIZATION);
|
|
1224
|
+
this.cleanAgentConfiguration(this.value.spec, FLEET_AGENT_CUSTOMIZATION);
|
|
1225
|
+
},
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* Ensure we have empty models for the two agent configurations
|
|
1229
|
+
*/
|
|
1230
|
+
setAgentConfiguration() {
|
|
1231
|
+
// Cluster Agent Configuration
|
|
1232
|
+
if ( !this.value.spec[CLUSTER_AGENT_CUSTOMIZATION]) {
|
|
1233
|
+
set(this.value.spec, CLUSTER_AGENT_CUSTOMIZATION, {});
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// Fleet Agent Configuration
|
|
1237
|
+
if ( !this.value.spec[FLEET_AGENT_CUSTOMIZATION] ) {
|
|
1238
|
+
set(this.value.spec, FLEET_AGENT_CUSTOMIZATION, {});
|
|
1239
|
+
}
|
|
1137
1240
|
},
|
|
1138
1241
|
|
|
1139
1242
|
/**
|
|
@@ -1213,18 +1316,27 @@ export default {
|
|
|
1213
1316
|
},
|
|
1214
1317
|
|
|
1215
1318
|
async addMachinePool(idx) {
|
|
1319
|
+
// this.machineConfigSchema is the schema for the Machine Pool's machine configuration for the given provider
|
|
1216
1320
|
if ( !this.machineConfigSchema ) {
|
|
1217
1321
|
return;
|
|
1218
1322
|
}
|
|
1219
1323
|
|
|
1220
1324
|
const numCurrentPools = this.machinePools.length || 0;
|
|
1221
1325
|
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1326
|
+
let config;
|
|
1327
|
+
|
|
1328
|
+
if (this.extensionProvider?.createMachinePoolMachineConfig) {
|
|
1329
|
+
config = await this.extensionProvider.createMachinePoolMachineConfig(idx, this.machinePools, this.value);
|
|
1330
|
+
} else {
|
|
1331
|
+
// Default - use the schema
|
|
1332
|
+
config = await this.$store.dispatch('management/createPopulated', {
|
|
1333
|
+
type: this.machineConfigSchema.id,
|
|
1334
|
+
metadata: { namespace: DEFAULT_WORKSPACE }
|
|
1335
|
+
});
|
|
1226
1336
|
|
|
1227
|
-
|
|
1337
|
+
// If there is no specific model, the applyDefaults does nothing by default
|
|
1338
|
+
config.applyDefaults(idx, this.machinePools);
|
|
1339
|
+
}
|
|
1228
1340
|
|
|
1229
1341
|
const name = `pool${ ++this.lastIdx }`;
|
|
1230
1342
|
const pool = {
|
|
@@ -1233,6 +1345,7 @@ export default {
|
|
|
1233
1345
|
remove: false,
|
|
1234
1346
|
create: true,
|
|
1235
1347
|
update: false,
|
|
1348
|
+
uid: name,
|
|
1236
1349
|
pool: {
|
|
1237
1350
|
name,
|
|
1238
1351
|
etcdRole: numCurrentPools === 0,
|
|
@@ -1243,7 +1356,7 @@ export default {
|
|
|
1243
1356
|
quantity: 1,
|
|
1244
1357
|
unhealthyNodeTimeout: '0m',
|
|
1245
1358
|
machineConfigRef: {
|
|
1246
|
-
kind: this.machineConfigSchema.attributes
|
|
1359
|
+
kind: this.machineConfigSchema.attributes?.kind,
|
|
1247
1360
|
name: null,
|
|
1248
1361
|
},
|
|
1249
1362
|
},
|
|
@@ -1301,6 +1414,11 @@ export default {
|
|
|
1301
1414
|
async saveMachinePools() {
|
|
1302
1415
|
const finalPools = [];
|
|
1303
1416
|
|
|
1417
|
+
// If the extension provider wants to do this, let them
|
|
1418
|
+
if (this.extensionProvider?.saveMachinePoolConfigs) {
|
|
1419
|
+
return await this.extensionProvider.saveMachinePoolConfigs(this.machinePools, this.value);
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1304
1422
|
for ( const entry of this.machinePools ) {
|
|
1305
1423
|
if ( entry.remove ) {
|
|
1306
1424
|
continue;
|
|
@@ -1420,7 +1538,24 @@ export default {
|
|
|
1420
1538
|
async saveOverride(btnCb) {
|
|
1421
1539
|
this.$set(this, 'busy', true);
|
|
1422
1540
|
|
|
1423
|
-
|
|
1541
|
+
// If the provider is from an extension, let it do the provision step
|
|
1542
|
+
if (this.extensionProvider?.provision) {
|
|
1543
|
+
const errors = await this.extensionProvider?.provision(this.value, this.machinePools);
|
|
1544
|
+
const okay = (errors || []).length === 0;
|
|
1545
|
+
|
|
1546
|
+
this.errors = errors;
|
|
1547
|
+
this.$set(this, 'busy', false);
|
|
1548
|
+
|
|
1549
|
+
btnCb(okay);
|
|
1550
|
+
|
|
1551
|
+
if (okay) {
|
|
1552
|
+
// If saved okay, go to the done route
|
|
1553
|
+
return this.done();
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// Default save
|
|
1558
|
+
return this._doSaveOverride((done) => {
|
|
1424
1559
|
this.$set(this, 'busy', false);
|
|
1425
1560
|
|
|
1426
1561
|
return btnCb(done);
|
|
@@ -1428,6 +1563,9 @@ export default {
|
|
|
1428
1563
|
},
|
|
1429
1564
|
|
|
1430
1565
|
async _doSaveOverride(btnCb) {
|
|
1566
|
+
// We cannot use the hook, because it is triggered on YAML toggle without restore initialized data
|
|
1567
|
+
this.agentConfigurationCleanup();
|
|
1568
|
+
|
|
1431
1569
|
if ( this.errors ) {
|
|
1432
1570
|
clear(this.errors);
|
|
1433
1571
|
}
|
|
@@ -1507,7 +1645,11 @@ export default {
|
|
|
1507
1645
|
const harvesterKubeconfigSecret = await this.createKubeconfigSecret(kubeconfig);
|
|
1508
1646
|
|
|
1509
1647
|
set(this.agentConfig, 'cloud-provider-config', `secret://fleet-default:${ harvesterKubeconfigSecret?.metadata?.name }`);
|
|
1510
|
-
|
|
1648
|
+
|
|
1649
|
+
if (this.isCreate) {
|
|
1650
|
+
set(this.chartValues, `${ HARVESTER_CLOUD_PROVIDER }.global.cattle.clusterName`, this.value.metadata.name);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1511
1653
|
set(this.chartValues, `${ HARVESTER_CLOUD_PROVIDER }.cloudConfigPath`, '/var/lib/rancher/rke2/etc/config-files/cloud-provider-config');
|
|
1512
1654
|
}
|
|
1513
1655
|
} catch (err) {
|
|
@@ -1523,10 +1665,10 @@ export default {
|
|
|
1523
1665
|
delete this.value.spec.rkeConfig.machineGlobalConfig.profile;
|
|
1524
1666
|
}
|
|
1525
1667
|
|
|
1526
|
-
//
|
|
1527
|
-
//
|
|
1528
|
-
const clusterAgentDeploymentCustomization = JSON.parse(JSON.stringify(this.value.spec[CLUSTER_AGENT_CUSTOMIZATION]));
|
|
1529
|
-
const fleetAgentDeploymentCustomization = JSON.parse(JSON.stringify(this.value.spec[FLEET_AGENT_CUSTOMIZATION]));
|
|
1668
|
+
// Store the current data for fleet and cluster agent so that we can re-apply it later if the save fails
|
|
1669
|
+
// The cleanup occurs before save with agentConfigurationCleanup()
|
|
1670
|
+
const clusterAgentDeploymentCustomization = this.value.spec[CLUSTER_AGENT_CUSTOMIZATION] ? JSON.parse(JSON.stringify(this.value.spec[CLUSTER_AGENT_CUSTOMIZATION])) : null;
|
|
1671
|
+
const fleetAgentDeploymentCustomization = this.value.spec[FLEET_AGENT_CUSTOMIZATION] ? JSON.parse(JSON.stringify(this.value.spec[FLEET_AGENT_CUSTOMIZATION])) : null;
|
|
1530
1672
|
|
|
1531
1673
|
await this.save(btnCb);
|
|
1532
1674
|
|
|
@@ -1538,6 +1680,24 @@ export default {
|
|
|
1538
1680
|
set(this.value.spec, FLEET_AGENT_CUSTOMIZATION, fleetAgentDeploymentCustomization);
|
|
1539
1681
|
}
|
|
1540
1682
|
},
|
|
1683
|
+
|
|
1684
|
+
async actuallySave(url) {
|
|
1685
|
+
if (this.extensionProvider?.saveCluster) {
|
|
1686
|
+
return await this.extensionProvider?.saveCluster(this.value, this.schema);
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
if ( this.isCreate ) {
|
|
1690
|
+
url = url || this.schema.linkFor('collection');
|
|
1691
|
+
const res = await this.value.save({ url });
|
|
1692
|
+
|
|
1693
|
+
if (res) {
|
|
1694
|
+
Object.assign(this.value, res);
|
|
1695
|
+
}
|
|
1696
|
+
} else {
|
|
1697
|
+
await this.value.save();
|
|
1698
|
+
}
|
|
1699
|
+
},
|
|
1700
|
+
|
|
1541
1701
|
// create a secret to reference the harvester cluster kubeconfig in rkeConfig
|
|
1542
1702
|
async createKubeconfigSecret(kubeconfig = '') {
|
|
1543
1703
|
const clusterName = this.value.metadata.name;
|
|
@@ -1982,10 +2142,9 @@ export default {
|
|
|
1982
2142
|
},
|
|
1983
2143
|
|
|
1984
2144
|
/**
|
|
1985
|
-
*
|
|
1986
|
-
* Consider exclusively RKE2 provisioned clusters in edit mode
|
|
2145
|
+
* Get provisioned RKE2 cluster PSPs in edit mode
|
|
1987
2146
|
*/
|
|
1988
|
-
async
|
|
2147
|
+
async getPsps() {
|
|
1989
2148
|
// As server returns 500 we exclude all the possible cases
|
|
1990
2149
|
if (
|
|
1991
2150
|
this.mode !== _CREATE &&
|
|
@@ -2142,7 +2301,8 @@ export default {
|
|
|
2142
2301
|
v-if="!isView"
|
|
2143
2302
|
v-model="value"
|
|
2144
2303
|
:mode="mode"
|
|
2145
|
-
:namespaced="
|
|
2304
|
+
:namespaced="needsNamespace"
|
|
2305
|
+
:namespace-options="allNamespaces"
|
|
2146
2306
|
name-label="cluster.name.label"
|
|
2147
2307
|
name-placeholder="cluster.name.placeholder"
|
|
2148
2308
|
description-label="cluster.description.label"
|
|
@@ -2916,7 +3076,9 @@ export default {
|
|
|
2916
3076
|
label-key="cluster.agentConfig.tabs.cluster"
|
|
2917
3077
|
>
|
|
2918
3078
|
<AgentConfiguration
|
|
3079
|
+
v-if="value.spec.clusterAgentDeploymentCustomization"
|
|
2919
3080
|
v-model="value.spec.clusterAgentDeploymentCustomization"
|
|
3081
|
+
data-testid="rke2-cluster-agent-config"
|
|
2920
3082
|
type="cluster"
|
|
2921
3083
|
:mode="mode"
|
|
2922
3084
|
/>
|
|
@@ -2928,7 +3090,9 @@ export default {
|
|
|
2928
3090
|
label-key="cluster.agentConfig.tabs.fleet"
|
|
2929
3091
|
>
|
|
2930
3092
|
<AgentConfiguration
|
|
3093
|
+
v-if="value.spec.fleetAgentDeploymentCustomization"
|
|
2931
3094
|
v-model="value.spec.fleetAgentDeploymentCustomization"
|
|
3095
|
+
data-testid="rke2-fleet-agent-config"
|
|
2932
3096
|
type="fleet"
|
|
2933
3097
|
:mode="mode"
|
|
2934
3098
|
/>
|
|
@@ -3026,6 +3190,26 @@ export default {
|
|
|
3026
3190
|
v-model="value"
|
|
3027
3191
|
:mode="mode"
|
|
3028
3192
|
/>
|
|
3193
|
+
|
|
3194
|
+
<!-- Extension tabs -->
|
|
3195
|
+
<Tab
|
|
3196
|
+
v-for="tab, i in extensionTabs"
|
|
3197
|
+
:key="`${tab.name}${i}`"
|
|
3198
|
+
:name="tab.name"
|
|
3199
|
+
:label="tab.label"
|
|
3200
|
+
:label-key="tab.labelKey"
|
|
3201
|
+
:weight="tab.weight"
|
|
3202
|
+
:tooltip="tab.tooltip"
|
|
3203
|
+
:show-header="tab.showHeader"
|
|
3204
|
+
:display-alert-icon="tab.displayAlertIcon"
|
|
3205
|
+
:error="tab.error"
|
|
3206
|
+
:badge="tab.badge"
|
|
3207
|
+
>
|
|
3208
|
+
<component
|
|
3209
|
+
:is="tab.component"
|
|
3210
|
+
:resource="value"
|
|
3211
|
+
/>
|
|
3212
|
+
</Tab>
|
|
3029
3213
|
</Tabbed>
|
|
3030
3214
|
</div>
|
|
3031
3215
|
|
|
@@ -11,8 +11,7 @@ import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
|
11
11
|
import { _CREATE, _VIEW } from '@shell/config/query-params';
|
|
12
12
|
import { PROVISIONER_OPTIONS } from '@shell/models/storage.k8s.io.storageclass';
|
|
13
13
|
import { mapFeature, UNSUPPORTED_STORAGE_DRIVERS } from '@shell/store/features';
|
|
14
|
-
import { CSI_DRIVER } from '@shell/config/types';
|
|
15
|
-
import { LONGHORN_DRIVER } from '@shell/models/persistentvolume';
|
|
14
|
+
import { CSI_DRIVER, LONGHORN_DRIVER } from '@shell/config/types';
|
|
16
15
|
|
|
17
16
|
export default {
|
|
18
17
|
name: 'StorageClass',
|