@rancher/shell 0.5.1 → 0.5.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/assets/translations/en-us.yaml +8 -4
- package/components/ClusterIconMenu.vue +24 -9
- package/components/CodeMirror.vue +79 -18
- package/components/FixedBanner.vue +1 -0
- package/components/ResourceDetail/index.vue +1 -4
- package/components/ResourceYaml.vue +29 -5
- package/components/SideNav.vue +42 -64
- package/components/SortableTable/index.vue +1 -1
- package/components/YamlEditor.vue +1 -0
- package/components/__tests__/CodeMirror.spec.ts +99 -0
- package/components/form/BannerSettings.vue +3 -0
- package/components/form/FileSelector.vue +1 -0
- package/components/form/KeyValue.vue +1 -0
- package/components/formatter/WorkloadDetailEndpoints.vue +12 -22
- package/components/formatter/__tests__/WorkloadDetailEndpoints.test.ts +81 -0
- package/components/nav/Header.vue +1 -0
- package/components/nav/Jump.vue +19 -9
- package/components/nav/TopLevelMenu.vue +37 -15
- package/components/nav/Type.vue +15 -4
- package/components/nav/__tests__/TopLevelMenu.test.ts +1 -1
- package/components/nav/__tests__/Type.test.ts +30 -0
- package/core/types-provisioning.ts +7 -0
- package/detail/__tests__/provisioning.cattle.io.cluster.test.ts +77 -0
- package/detail/fleet.cattle.io.bundle.vue +1 -1
- package/detail/provisioning.cattle.io.cluster.vue +19 -4
- package/edit/management.cattle.io.setting.vue +1 -0
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/opsgenie.vue +1 -1
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/pagerduty.vue +1 -2
- package/edit/monitoring.coreos.com.alertmanagerconfig/types/slack.vue +1 -1
- package/edit/provisioning.cattle.io.cluster/index.vue +23 -10
- package/edit/provisioning.cattle.io.cluster/rke2.vue +22 -50
- package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +9 -11
- package/edit/provisioning.cattle.io.cluster/tabs/registries/RegistryConfigs.vue +3 -1
- package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +3 -0
- package/edit/token.vue +1 -0
- package/list/catalog.cattle.io.app.vue +1 -0
- package/list/management.cattle.io.setting.vue +1 -0
- package/machine-config/amazonec2.vue +1 -0
- package/models/__tests__/provisioning.cattle.io.cluster.test.ts +151 -0
- package/models/__tests__/secret.test.ts +37 -0
- package/models/__tests__/storage.k8s.io.storageclass.test.ts +22 -0
- package/models/management.cattle.io.kontainerdriver.js +2 -1
- package/models/provisioning.cattle.io.cluster.js +36 -1
- package/models/secret.js +9 -0
- package/models/storage.k8s.io.storageclass.js +1 -1
- package/package.json +1 -1
- package/pages/c/_cluster/settings/DefaultLinksEditor.vue +1 -0
- package/pages/c/_cluster/settings/brand.vue +3 -0
- package/pages/c/_cluster/uiplugins/AddExtensionRepos.vue +4 -4
- package/pages/c/_cluster/uiplugins/SetupUIPlugins.vue +5 -2
- package/pages/c/_cluster/uiplugins/__tests__/AddExtensionRepos.test.ts +96 -0
- package/pages/c/_cluster/uiplugins/__tests__/SetupUIPlugins.test.ts +128 -0
- package/plugins/dashboard-store/__tests__/actions.test.ts +196 -111
- package/plugins/dashboard-store/actions.js +4 -6
- package/plugins/dashboard-store/getters.js +60 -2
- package/plugins/dashboard-store/resource-class.js +6 -2
- package/plugins/steve/__tests__/getters.spec.ts +10 -0
- package/plugins/steve/__tests__/resource-utils.test.ts +159 -0
- package/plugins/steve/actions.js +3 -37
- package/plugins/steve/getters.js +6 -0
- package/plugins/steve/resource-utils.ts +38 -0
- package/scripts/extension/parse-tag-name +3 -3
- package/store/__tests__/type-map.test.ts +1122 -0
- package/store/index.js +3 -2
- package/store/plugins.js +7 -6
- package/store/type-map.js +145 -75
- package/types/shell/index.d.ts +2 -0
- package/utils/__tests__/create-yaml.test.ts +10 -0
- package/utils/create-yaml.js +5 -1
- package/utils/object.js +10 -0
|
@@ -123,7 +123,6 @@ export default {
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
|
|
127
126
|
};
|
|
128
127
|
</script>
|
|
129
128
|
|
|
@@ -185,7 +184,7 @@ export default {
|
|
|
185
184
|
<div class="row mb-20">
|
|
186
185
|
<div class="col span-12">
|
|
187
186
|
<LabeledInput
|
|
188
|
-
v-model="value.httpConfig.
|
|
187
|
+
v-model="value.httpConfig.proxyURL"
|
|
189
188
|
:mode="mode"
|
|
190
189
|
label="Proxy URL"
|
|
191
190
|
placeholder="e.g. http://my-proxy/"
|
|
@@ -301,11 +301,11 @@ export default {
|
|
|
301
301
|
const getters = this.$store.getters;
|
|
302
302
|
const isImport = this.isImport;
|
|
303
303
|
const isElementalActive = !!this.activeProducts.find((item) => item.name === ELEMENTAL_PRODUCT_NAME);
|
|
304
|
-
|
|
304
|
+
let out = [];
|
|
305
305
|
|
|
306
306
|
const templates = this.templateOptions;
|
|
307
307
|
const vueKontainerTypes = getters['plugins/clusterDrivers'];
|
|
308
|
-
const machineTypes = this.nodeDrivers.filter((x) => x.spec.active && x.state === 'active')
|
|
308
|
+
const machineTypes = this.nodeDrivers.filter((x) => x.spec.active && x.state === 'active');
|
|
309
309
|
|
|
310
310
|
this.kontainerDrivers.filter((x) => (isImport ? x.showImport : x.showCreate)).forEach((obj) => {
|
|
311
311
|
if ( vueKontainerTypes.includes(obj.driverName) ) {
|
|
@@ -330,14 +330,18 @@ export default {
|
|
|
330
330
|
});
|
|
331
331
|
|
|
332
332
|
if (this.isRke1 ) {
|
|
333
|
-
machineTypes.forEach((
|
|
334
|
-
|
|
333
|
+
machineTypes.forEach((type) => {
|
|
334
|
+
const id = type.spec.displayName || type.id;
|
|
335
|
+
|
|
336
|
+
addType(id, _RKE1, false, `/g/clusters/add/launch/${ id }`, this.iconClasses[id], type);
|
|
335
337
|
});
|
|
336
338
|
|
|
337
339
|
addType('custom', 'custom1', false, '/g/clusters/add/launch/custom');
|
|
338
340
|
} else {
|
|
339
|
-
machineTypes.forEach((
|
|
340
|
-
|
|
341
|
+
machineTypes.forEach((type) => {
|
|
342
|
+
const id = type.spec.displayName || type.id;
|
|
343
|
+
|
|
344
|
+
addType(id, _RKE2, false, null, undefined, type);
|
|
341
345
|
});
|
|
342
346
|
|
|
343
347
|
addType('custom', 'custom2', false);
|
|
@@ -348,12 +352,18 @@ export default {
|
|
|
348
352
|
}
|
|
349
353
|
|
|
350
354
|
// Add from extensions
|
|
351
|
-
// if th rke toggle is set to rke1, don't add extensions that specify rke2 group
|
|
352
|
-
// default group is rke2
|
|
353
355
|
this.extensions.forEach((ext) => {
|
|
356
|
+
// if the rke toggle is set to rke1, don't add extensions that specify rke2 group
|
|
357
|
+
// default group is rke2
|
|
354
358
|
if (!this.isRke2 && (ext.group === _RKE2 || !ext.group)) {
|
|
355
359
|
return;
|
|
356
360
|
}
|
|
361
|
+
// Do not show the extension provisioner on the import cluster page unless its explicitly set to do so
|
|
362
|
+
if (isImport && !ext.showImport) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
// Allow extensions to overwrite provisioners with the same id
|
|
366
|
+
out = out.filter((type) => type.id !== ext.id);
|
|
357
367
|
addExtensionType(ext, getters);
|
|
358
368
|
});
|
|
359
369
|
}
|
|
@@ -386,7 +396,7 @@ export default {
|
|
|
386
396
|
out.push(subtype);
|
|
387
397
|
}
|
|
388
398
|
|
|
389
|
-
function addType(id, group, disabled = false, emberLink = null, iconClass = undefined) {
|
|
399
|
+
function addType(id, group, disabled = false, emberLink = null, iconClass = undefined, providerConfig = undefined) {
|
|
390
400
|
const label = getters['i18n/withFallback'](`cluster.provider."${ id }"`, null, id);
|
|
391
401
|
const description = getters['i18n/withFallback'](`cluster.providerDescription."${ id }"`, null, '');
|
|
392
402
|
const tag = '';
|
|
@@ -412,7 +422,8 @@ export default {
|
|
|
412
422
|
group,
|
|
413
423
|
disabled,
|
|
414
424
|
emberLink,
|
|
415
|
-
tag
|
|
425
|
+
tag,
|
|
426
|
+
providerConfig
|
|
416
427
|
};
|
|
417
428
|
|
|
418
429
|
out.push(subtype);
|
|
@@ -632,6 +643,7 @@ export default {
|
|
|
632
643
|
:live-value="liveValue"
|
|
633
644
|
:mode="mode"
|
|
634
645
|
:provider="subType"
|
|
646
|
+
:provider-config="selectedSubType.providerConfig"
|
|
635
647
|
/>
|
|
636
648
|
<Rke2Config
|
|
637
649
|
v-else
|
|
@@ -640,6 +652,7 @@ export default {
|
|
|
640
652
|
:live-value="liveValue"
|
|
641
653
|
:mode="mode"
|
|
642
654
|
:provider="subType"
|
|
655
|
+
:provider-config="selectedSubType.providerConfig"
|
|
643
656
|
/>
|
|
644
657
|
</template>
|
|
645
658
|
|
|
@@ -126,6 +126,11 @@ export default {
|
|
|
126
126
|
type: String,
|
|
127
127
|
required: true,
|
|
128
128
|
},
|
|
129
|
+
|
|
130
|
+
providerConfig: {
|
|
131
|
+
type: Object,
|
|
132
|
+
default: () => null
|
|
133
|
+
}
|
|
129
134
|
},
|
|
130
135
|
|
|
131
136
|
async fetch() {
|
|
@@ -211,7 +216,6 @@ export default {
|
|
|
211
216
|
machinePoolValidation: {}, // map of validation states for each machine pool
|
|
212
217
|
machinePoolErrors: {},
|
|
213
218
|
allNamespaces: [],
|
|
214
|
-
initialCloudProvider: this.value?.agentConfig?.['cloud-provider-name'] || '',
|
|
215
219
|
extensionTabs: getApplicableExtensionEnhancements(this, ExtensionPoint.TAB, TabLocation.CLUSTER_CREATE_RKE2, this.$route, this),
|
|
216
220
|
};
|
|
217
221
|
},
|
|
@@ -326,6 +330,14 @@ export default {
|
|
|
326
330
|
|
|
327
331
|
const out = findBy(this.versionOptions, 'value', str);
|
|
328
332
|
|
|
333
|
+
// Adding the option 'none' to Container Network select (used in Basics component)
|
|
334
|
+
// https://github.com/rancher/dashboard/issues/10338
|
|
335
|
+
// there's an update loop on refresh that might include 'none'
|
|
336
|
+
// multiple times... Prevent that
|
|
337
|
+
if (out.serverArgs?.cni?.options && !out.serverArgs?.cni?.options.includes('none')) {
|
|
338
|
+
out.serverArgs.cni.options.push('none');
|
|
339
|
+
}
|
|
340
|
+
|
|
329
341
|
return out;
|
|
330
342
|
},
|
|
331
343
|
|
|
@@ -351,7 +363,7 @@ export default {
|
|
|
351
363
|
},
|
|
352
364
|
|
|
353
365
|
needCredential() {
|
|
354
|
-
if ( this.provider === 'custom' || this.provider === 'import' || this.isElementalCluster || this.mode === _VIEW ) {
|
|
366
|
+
if ( this.provider === 'custom' || this.provider === 'import' || this.isElementalCluster || this.mode === _VIEW || (this.providerConfig?.spec?.builtin === false && this.providerConfig?.spec?.addCloudCredential === false) ) {
|
|
355
367
|
return false;
|
|
356
368
|
}
|
|
357
369
|
|
|
@@ -577,30 +589,8 @@ export default {
|
|
|
577
589
|
|
|
578
590
|
const cur = this.agentConfig?.['cloud-provider-name'];
|
|
579
591
|
|
|
580
|
-
if (cur && !out.find((x) => x.value === cur)) {
|
|
581
|
-
|
|
582
|
-
// Look up cur in the localization file
|
|
583
|
-
const label = this.$store.getters['i18n/withFallback'](`cluster.cloudProvider."${ cur }".label`, null, cur);
|
|
584
|
-
|
|
585
|
-
out.unshift({
|
|
586
|
-
label: `${ label } (Current)`,
|
|
587
|
-
value: cur,
|
|
588
|
-
unsupported: true,
|
|
589
|
-
disabled: true
|
|
590
|
-
});
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
const initial = this.initialCloudProvider;
|
|
594
|
-
|
|
595
|
-
if (cur !== initial && initial && !out.find((x) => x.value === initial)) {
|
|
596
|
-
const label = this.$store.getters['i18n/withFallback'](`cluster.cloudProvider."${ initial }".label`, null, initial);
|
|
597
|
-
|
|
598
|
-
out.unshift({
|
|
599
|
-
label: `${ label } (Current)`,
|
|
600
|
-
value: initial,
|
|
601
|
-
unsupported: true,
|
|
602
|
-
disabled: true
|
|
603
|
-
});
|
|
592
|
+
if ( cur && !out.find((x) => x.value === cur) ) {
|
|
593
|
+
out.unshift({ label: `${ cur } (Current)`, value: cur });
|
|
604
594
|
}
|
|
605
595
|
|
|
606
596
|
return out;
|
|
@@ -708,14 +698,6 @@ export default {
|
|
|
708
698
|
|
|
709
699
|
return validRequiredPools && base;
|
|
710
700
|
},
|
|
711
|
-
unsupportedCloudProvider() {
|
|
712
|
-
// The current cloud provider
|
|
713
|
-
const cur = this.initialCloudProvider;
|
|
714
|
-
|
|
715
|
-
const provider = cur && this.cloudProviderOptions.find((x) => x.value === cur);
|
|
716
|
-
|
|
717
|
-
return !!provider?.unsupported;
|
|
718
|
-
},
|
|
719
701
|
},
|
|
720
702
|
|
|
721
703
|
watch: {
|
|
@@ -1431,7 +1413,9 @@ export default {
|
|
|
1431
1413
|
for ( const chartName of this.addonNames ) {
|
|
1432
1414
|
const entry = this.chartVersions[chartName];
|
|
1433
1415
|
|
|
1434
|
-
|
|
1416
|
+
// prevent fetching of addon config for 'none' CNI option
|
|
1417
|
+
// https://github.com/rancher/dashboard/issues/10338
|
|
1418
|
+
if ( this.versionInfo[chartName] || chartName.includes('none')) {
|
|
1435
1419
|
continue;
|
|
1436
1420
|
}
|
|
1437
1421
|
|
|
@@ -1568,8 +1552,7 @@ export default {
|
|
|
1568
1552
|
set(regs, 'mirrors', {});
|
|
1569
1553
|
}
|
|
1570
1554
|
|
|
1571
|
-
const
|
|
1572
|
-
const config = regs.configs[hostname];
|
|
1555
|
+
const config = regs.configs[this.registryHost];
|
|
1573
1556
|
|
|
1574
1557
|
if ( config ) {
|
|
1575
1558
|
registrySecret = config.authConfigSecretName;
|
|
@@ -1866,18 +1849,6 @@ export default {
|
|
|
1866
1849
|
if (this.isHarvesterDriver && this.mode === _CREATE && this.isHarvesterIncompatible) {
|
|
1867
1850
|
this.setHarvesterDefaultCloudProvider();
|
|
1868
1851
|
}
|
|
1869
|
-
|
|
1870
|
-
// Cloud Provider check
|
|
1871
|
-
// If the cloud provider is unsupported, switch provider to 'external'
|
|
1872
|
-
if (this.unsupportedCloudProvider) {
|
|
1873
|
-
set(this.agentConfig, 'cloud-provider-name', 'external');
|
|
1874
|
-
} else {
|
|
1875
|
-
// Switch the cloud provider back to the initial value
|
|
1876
|
-
// Use changed the Kubernetes version back to a version where the initial cloud provider is valid - so switch back to this one
|
|
1877
|
-
// to undo the change to external that we may have made
|
|
1878
|
-
// Note: Cloud Provider can only be changed on edit when the initial provider is no longer supported
|
|
1879
|
-
set(this.agentConfig, 'cloud-provider-name', this.initialCloudProvider);
|
|
1880
|
-
}
|
|
1881
1852
|
}
|
|
1882
1853
|
},
|
|
1883
1854
|
|
|
@@ -2048,11 +2019,13 @@ export default {
|
|
|
2048
2019
|
:cancel="cancelCredential"
|
|
2049
2020
|
:showing-form="showForm"
|
|
2050
2021
|
:default-on-cancel="true"
|
|
2022
|
+
data-testid="select-credential"
|
|
2051
2023
|
class="mt-20"
|
|
2052
2024
|
/>
|
|
2053
2025
|
|
|
2054
2026
|
<div
|
|
2055
2027
|
v-if="showForm"
|
|
2028
|
+
data-testid="form"
|
|
2056
2029
|
class="mt-20"
|
|
2057
2030
|
>
|
|
2058
2031
|
<NameNsDescription
|
|
@@ -2182,7 +2155,6 @@ export default {
|
|
|
2182
2155
|
:have-arg-info="haveArgInfo"
|
|
2183
2156
|
:show-cni="showCni"
|
|
2184
2157
|
:show-cloud-provider="showCloudProvider"
|
|
2185
|
-
:unsupported-cloud-provider="unsupportedCloudProvider"
|
|
2186
2158
|
:cloud-provider-options="cloudProviderOptions"
|
|
2187
2159
|
@cilium-values-changed="handleCiliumValuesChanged"
|
|
2188
2160
|
@enabled-system-services-changed="handleEnabledSystemServicesChanged"
|
|
@@ -103,10 +103,6 @@ export default {
|
|
|
103
103
|
type: Boolean,
|
|
104
104
|
required: true
|
|
105
105
|
},
|
|
106
|
-
unsupportedCloudProvider: {
|
|
107
|
-
type: Boolean,
|
|
108
|
-
required: true
|
|
109
|
-
},
|
|
110
106
|
cloudProviderOptions: {
|
|
111
107
|
type: Array,
|
|
112
108
|
required: true
|
|
@@ -369,7 +365,7 @@ export default {
|
|
|
369
365
|
},
|
|
370
366
|
|
|
371
367
|
canNotEditCloudProvider() {
|
|
372
|
-
const canNotEdit = this.isEdit
|
|
368
|
+
const canNotEdit = this.isEdit;
|
|
373
369
|
|
|
374
370
|
return canNotEdit;
|
|
375
371
|
},
|
|
@@ -421,12 +417,20 @@ export default {
|
|
|
421
417
|
>
|
|
422
418
|
<span v-clean-html="t('cluster.banner.cloudProviderAddConfig', {}, true)" />
|
|
423
419
|
</Banner>
|
|
420
|
+
<Banner
|
|
421
|
+
v-if="serverConfig.cni === 'none'"
|
|
422
|
+
color="warning"
|
|
423
|
+
data-testid="clusterBasics__noneOptionSelectedForCni"
|
|
424
|
+
>
|
|
425
|
+
<span v-clean-html="t('cluster.rke2.cni.cniNoneBanner', {}, true)" />
|
|
426
|
+
</Banner>
|
|
424
427
|
<div class="row mb-10">
|
|
425
428
|
<div class="col span-6">
|
|
426
429
|
<LabeledSelect
|
|
427
430
|
v-model="value.spec.kubernetesVersion"
|
|
428
431
|
:mode="mode"
|
|
429
432
|
:options="versionOptions"
|
|
433
|
+
data-testid="clusterBasics__kubernetesVersions"
|
|
430
434
|
label-key="cluster.kubernetesVersion.label"
|
|
431
435
|
@input="$emit('kubernetes-changed', $event)"
|
|
432
436
|
/>
|
|
@@ -495,12 +499,6 @@ export default {
|
|
|
495
499
|
<div class="spacer" />
|
|
496
500
|
|
|
497
501
|
<div class="col span-12">
|
|
498
|
-
<Banner
|
|
499
|
-
v-if="unsupportedCloudProvider"
|
|
500
|
-
class="error mt-5"
|
|
501
|
-
>
|
|
502
|
-
{{ t('cluster.rke2.cloudProvider.unsupported') }}
|
|
503
|
-
</Banner>
|
|
504
502
|
<h3>
|
|
505
503
|
{{ t('cluster.rke2.cloudProvider.header') }}
|
|
506
504
|
</h3>
|
|
@@ -138,13 +138,14 @@ export default {
|
|
|
138
138
|
:mode="mode"
|
|
139
139
|
@input="update"
|
|
140
140
|
>
|
|
141
|
-
<template #default="{row}">
|
|
141
|
+
<template #default="{row, i}">
|
|
142
142
|
<div class="row">
|
|
143
143
|
<div class="col span-6">
|
|
144
144
|
<LabeledInput
|
|
145
145
|
v-model="row.value.hostname"
|
|
146
146
|
label="Registry Hostname"
|
|
147
147
|
:mode="mode"
|
|
148
|
+
:data-testid="`registry-auth-host-input-${i}`"
|
|
148
149
|
/>
|
|
149
150
|
|
|
150
151
|
<SelectOrCreateAuthSecret
|
|
@@ -158,6 +159,7 @@ export default {
|
|
|
158
159
|
:namespace="value.metadata.namespace"
|
|
159
160
|
:mode="mode"
|
|
160
161
|
generate-name="registryconfig-auth-"
|
|
162
|
+
:data-testid="`registry-auth-select-or-create-${i}`"
|
|
161
163
|
/>
|
|
162
164
|
</div>
|
|
163
165
|
<div class="col span-6">
|
|
@@ -79,6 +79,7 @@ export default {
|
|
|
79
79
|
:value="showCustomRegistryInput"
|
|
80
80
|
class="mb-20"
|
|
81
81
|
:label="t('cluster.privateRegistry.label')"
|
|
82
|
+
data-testid="registries-enable-checkbox"
|
|
82
83
|
@input="$emit('custom-registry-changed', $event)"
|
|
83
84
|
/>
|
|
84
85
|
</div>
|
|
@@ -92,6 +93,7 @@ export default {
|
|
|
92
93
|
label-key="catalog.chart.registry.custom.inputLabel"
|
|
93
94
|
placeholder-key="catalog.chart.registry.custom.placeholder"
|
|
94
95
|
:min-height="30"
|
|
96
|
+
data-testid="registry-host-input"
|
|
95
97
|
@input="$emit('registry-host-changed', $event)"
|
|
96
98
|
/>
|
|
97
99
|
<SelectOrCreateAuthSecret
|
|
@@ -118,6 +120,7 @@ export default {
|
|
|
118
120
|
class="col span-12 advanced"
|
|
119
121
|
:is-open-by-default="showCustomRegistryAdvancedInput"
|
|
120
122
|
:mode="mode"
|
|
123
|
+
data-testid="registries-advanced-section"
|
|
121
124
|
>
|
|
122
125
|
<Banner
|
|
123
126
|
:closable="false"
|
package/edit/token.vue
CHANGED
|
@@ -39,6 +39,7 @@ export default {
|
|
|
39
39
|
:loading="loading"
|
|
40
40
|
:use-query-params-for-simple-filtering="useQueryParamsForSimpleFiltering"
|
|
41
41
|
:force-update-live-and-delayed="forceUpdateLiveAndDelayed"
|
|
42
|
+
data-testid="installed-app-catalog-list"
|
|
42
43
|
>
|
|
43
44
|
<template #cell:upgrade="{row}">
|
|
44
45
|
<span
|
|
@@ -475,6 +475,7 @@ export default {
|
|
|
475
475
|
:disabled="disabled"
|
|
476
476
|
:placeholder="t('cluster.machineConfig.amazonEc2.selectedNetwork.placeholder')"
|
|
477
477
|
:label="t('cluster.machineConfig.amazonEc2.selectedNetwork.label')"
|
|
478
|
+
data-testid="amazonEc2__selectedNetwork"
|
|
478
479
|
option-key="value"
|
|
479
480
|
@input="updateNetwork($event)"
|
|
480
481
|
>
|
|
@@ -26,6 +26,56 @@ describe('class ProvCluster', () => {
|
|
|
26
26
|
clusterName: 'test', provisioner: 'rke2', mgmt: { isLocal: false, providerForEmberParam: 'import' }, spec: { rkeConfig: {} }
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
const gkeClusterWithPrivateEndpoint = {
|
|
30
|
+
clusterName: 'test',
|
|
31
|
+
provisioner: 'GKE',
|
|
32
|
+
spec: { rkeConfig: {} },
|
|
33
|
+
mgmt: { spec: { gkeConfig: { privateClusterConfig: { enablePrivateEndpoint: true } } } }
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const eksClusterWithPrivateEndpoint = {
|
|
37
|
+
clusterName: 'test',
|
|
38
|
+
provisioner: 'EKS',
|
|
39
|
+
spec: { rkeConfig: {} },
|
|
40
|
+
mgmt: { spec: { eksConfig: { privateAccess: true } } }
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const aksClusterWithPrivateEndpoint = {
|
|
44
|
+
clusterName: 'test',
|
|
45
|
+
provisioner: 'AKS',
|
|
46
|
+
spec: { rkeConfig: {} },
|
|
47
|
+
mgmt: { spec: { aksConfig: { privateCluster: true } } }
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Related to https://github.com/rancher/dashboard/issues/9402
|
|
51
|
+
describe('isHostedKubernetesProvider + isPrivateHostedProvider', () => {
|
|
52
|
+
const testCases = [
|
|
53
|
+
[gkeClusterWithPrivateEndpoint, true],
|
|
54
|
+
[eksClusterWithPrivateEndpoint, true],
|
|
55
|
+
[aksClusterWithPrivateEndpoint, true],
|
|
56
|
+
];
|
|
57
|
+
const resetMocks = () => {
|
|
58
|
+
// Clear all mock function calls:
|
|
59
|
+
jest.clearAllMocks();
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
it.each(testCases)('should return the isHostedKubernetesProvider and isPrivateHostedProvider values properly based on the props data', (clusterData: Object, expected: Boolean) => {
|
|
63
|
+
const cluster = new ProvCluster({ spec: clusterData.spec });
|
|
64
|
+
|
|
65
|
+
jest.spyOn(cluster, 'mgmt', 'get').mockReturnValue(
|
|
66
|
+
clusterData.mgmt
|
|
67
|
+
);
|
|
68
|
+
jest.spyOn(cluster, 'provisioner', 'get').mockReturnValue(
|
|
69
|
+
clusterData.provisioner
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
expect(cluster.isRke2).toBe(expected);
|
|
73
|
+
expect(cluster.isHostedKubernetesProvider).toBe(expected);
|
|
74
|
+
expect(cluster.isPrivateHostedProvider).toBe(expected);
|
|
75
|
+
resetMocks();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
29
79
|
describe('isImported', () => {
|
|
30
80
|
const testCases = [
|
|
31
81
|
[importedClusterInfo, true],
|
|
@@ -84,6 +134,107 @@ describe('class ProvCluster', () => {
|
|
|
84
134
|
|
|
85
135
|
expect(cluster.mgmt).toBe(expected);
|
|
86
136
|
resetMocks();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('hasError', () => {
|
|
141
|
+
const conditionsWithoutError = [
|
|
142
|
+
{
|
|
143
|
+
error: false,
|
|
144
|
+
lastUpdateTime: '2022-10-17T23:09:15Z',
|
|
145
|
+
status: 'True',
|
|
146
|
+
transitioning: false,
|
|
147
|
+
type: 'Ready'
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
const conditionsWithoutReady = [
|
|
152
|
+
{
|
|
153
|
+
error: true,
|
|
154
|
+
lastUpdateTime: '2022-10-17T23:09:15Z',
|
|
155
|
+
status: 'False',
|
|
156
|
+
message: 'some-error-message',
|
|
157
|
+
transitioning: false,
|
|
158
|
+
type: 'Pending'
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
const noConditions:[] = [];
|
|
163
|
+
|
|
164
|
+
const conditionsWithReadyLatest = [
|
|
165
|
+
{
|
|
166
|
+
error: true,
|
|
167
|
+
lastUpdateTime: '2022-10-17T23:09:15Z',
|
|
168
|
+
status: 'False',
|
|
169
|
+
message: 'some-error-message',
|
|
170
|
+
transitioning: false,
|
|
171
|
+
type: 'Pending'
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
error: false,
|
|
175
|
+
lastUpdateTime: '2023-10-17T23:09:15Z',
|
|
176
|
+
status: 'True',
|
|
177
|
+
transitioning: false,
|
|
178
|
+
type: 'Ready'
|
|
179
|
+
}
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
const conditionsWithErrorLatest = [
|
|
183
|
+
{
|
|
184
|
+
error: false,
|
|
185
|
+
lastUpdateTime: '2022-10-17T23:09:15Z',
|
|
186
|
+
status: 'True',
|
|
187
|
+
transitioning: false,
|
|
188
|
+
type: 'Ready'
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
error: true,
|
|
192
|
+
lastUpdateTime: '2023-10-17T23:09:15Z',
|
|
193
|
+
status: 'False',
|
|
194
|
+
message: 'some-error-message',
|
|
195
|
+
transitioning: false,
|
|
196
|
+
type: 'Pending'
|
|
197
|
+
}
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
const conditionsWithProblemInLastUpdateTimeProp = [
|
|
201
|
+
{
|
|
202
|
+
error: true,
|
|
203
|
+
lastUpdateTime: '',
|
|
204
|
+
status: 'False',
|
|
205
|
+
message: 'some-error-message',
|
|
206
|
+
transitioning: false,
|
|
207
|
+
type: 'Pending'
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
error: false,
|
|
211
|
+
lastUpdateTime: '2023-10-17T23:09:15Z',
|
|
212
|
+
status: 'True',
|
|
213
|
+
transitioning: false,
|
|
214
|
+
type: 'Ready'
|
|
215
|
+
}
|
|
216
|
+
];
|
|
217
|
+
|
|
218
|
+
const testCases = [
|
|
219
|
+
['conditionsWithoutError', conditionsWithoutError, false],
|
|
220
|
+
['conditionsWithoutReady', conditionsWithoutReady, true],
|
|
221
|
+
['noConditions', noConditions, false],
|
|
222
|
+
['conditionsWithReadyLatest', conditionsWithReadyLatest, false],
|
|
223
|
+
['conditionsWithErrorLatest', conditionsWithErrorLatest, true],
|
|
224
|
+
['conditionsWithProblemInLastUpdateTimeProp', conditionsWithProblemInLastUpdateTimeProp, false],
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
const resetMocks = () => {
|
|
228
|
+
// Clear all mock function calls
|
|
229
|
+
jest.clearAllMocks();
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
it.each(testCases)('should return the hasError value properly based on the "status.conditions" props data for testcase %p', (testName: string, conditions: Array, expected: Boolean) => {
|
|
233
|
+
const ctx = { rootGetters: { 'management/byId': jest.fn() } };
|
|
234
|
+
const cluster = new ProvCluster({ status: { conditions } }, ctx);
|
|
235
|
+
|
|
236
|
+
expect(cluster.hasError).toBe(expected);
|
|
237
|
+
resetMocks();
|
|
87
238
|
}
|
|
88
239
|
);
|
|
89
240
|
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Secret from '@shell/models/secret';
|
|
2
|
+
|
|
3
|
+
describe('class Secret', () => {
|
|
4
|
+
it('should contains the type attribute if cleanForDownload', async() => {
|
|
5
|
+
const secret = new Secret({});
|
|
6
|
+
const yaml = `apiVersion: v1
|
|
7
|
+
kind: Secret
|
|
8
|
+
metadata:
|
|
9
|
+
name: my-secret
|
|
10
|
+
type: Opaque
|
|
11
|
+
`;
|
|
12
|
+
const cleanYaml = await secret.cleanForDownload(yaml);
|
|
13
|
+
|
|
14
|
+
expect(cleanYaml).toBe(yaml);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should remove id, links and actions keys if cleanForDownload', async() => {
|
|
18
|
+
const secret = new Secret({});
|
|
19
|
+
const expectedYamlStr = `apiVersion: v1
|
|
20
|
+
kind: Secret
|
|
21
|
+
metadata:
|
|
22
|
+
name: my-secret
|
|
23
|
+
namespace: default
|
|
24
|
+
type: Opaque
|
|
25
|
+
`;
|
|
26
|
+
const part = `id: test_id
|
|
27
|
+
links:
|
|
28
|
+
view: https://example.com
|
|
29
|
+
actions:
|
|
30
|
+
remove: https://example.com`;
|
|
31
|
+
const yaml = `${ expectedYamlStr }
|
|
32
|
+
${ part }`;
|
|
33
|
+
const cleanYaml = await secret.cleanForDownload(yaml);
|
|
34
|
+
|
|
35
|
+
expect(cleanYaml).toBe(expectedYamlStr);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import StorageClass, { PROVISIONER_OPTIONS } from '@shell/models/storage.k8s.io.storageclass';
|
|
2
|
+
|
|
3
|
+
describe('class StorageClass', () => {
|
|
4
|
+
describe('checking if provisionerDisplay', () => {
|
|
5
|
+
it.each([
|
|
6
|
+
['kubernetes.io/azure-disk', true],
|
|
7
|
+
['kubernetes.io/portworx-volume', true],
|
|
8
|
+
['rancher.io/local-path', false],
|
|
9
|
+
['some-random-string-as-provisioner', false],
|
|
10
|
+
])('should NOT show a suffix IF they are built-in (on the PROVISIONER_OPTIONS list)', (provisioner, expectation) => {
|
|
11
|
+
const storageClass = new StorageClass({
|
|
12
|
+
metadata: {},
|
|
13
|
+
spec: {},
|
|
14
|
+
provisioner
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
jest.spyOn(storageClass, '$rootGetters', 'get').mockReturnValue({ 'i18n/t': jest.fn() });
|
|
18
|
+
|
|
19
|
+
expect(!!PROVISIONER_OPTIONS.find((opt) => opt.value === provisioner)).toBe(expectation);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import HybridModel from '@shell/plugins/steve/hybrid-class';
|
|
2
2
|
|
|
3
|
-
const HIDDEN = ['rke', 'rancherkubernetesengine'
|
|
3
|
+
const HIDDEN = ['rke', 'rancherkubernetesengine'];
|
|
4
|
+
|
|
4
5
|
const V2 = ['amazoneks', 'googlegke', 'azureaks'];
|
|
5
6
|
const IMPORTABLE = ['amazoneks', 'googlegke', 'azureaks'];
|
|
6
7
|
|